1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 2010 Carlos Garnacho <carlosg@gnome.org>
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.
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.
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.
24 #include <gtk/gtkthemingengine.h>
25 #include <gtk/gtkstylecontext.h>
26 #include <gtk/gtkintl.h>
30 typedef struct GtkThemingEnginePrivate GtkThemingEnginePrivate;
39 struct GtkThemingEnginePrivate
41 GtkStyleContext *context;
44 #define GTK_THEMING_ENGINE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_THEMING_ENGINE, GtkThemingEnginePrivate))
46 static void gtk_theming_engine_render_check (GtkThemingEngine *engine,
52 static void gtk_theming_engine_render_option (GtkThemingEngine *engine,
58 static void gtk_theming_engine_render_arrow (GtkThemingEngine *engine,
64 static void gtk_theming_engine_render_background (GtkThemingEngine *engine,
70 static void gtk_theming_engine_render_frame (GtkThemingEngine *engine,
76 static void gtk_theming_engine_render_expander (GtkThemingEngine *engine,
82 static void gtk_theming_engine_render_focus (GtkThemingEngine *engine,
89 G_DEFINE_TYPE (GtkThemingEngine, gtk_theming_engine, G_TYPE_OBJECT)
92 typedef struct GtkThemingModule GtkThemingModule;
93 typedef struct GtkThemingModuleClass GtkThemingModuleClass;
95 struct GtkThemingModule
97 GTypeModule parent_instance;
100 GtkThemingEngine * (*create_engine) (void);
103 struct GtkThemingModuleClass
105 GTypeModuleClass parent_class;
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))
112 G_DEFINE_TYPE (GtkThemingModule, gtk_theming_module, G_TYPE_TYPE_MODULE);
115 gtk_theming_engine_class_init (GtkThemingEngineClass *klass)
117 GObjectClass *object_class = G_OBJECT_CLASS (klass);
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;
127 g_type_class_add_private (object_class, sizeof (GtkThemingEnginePrivate));
131 gtk_theming_engine_init (GtkThemingEngine *engine)
133 engine->priv = GTK_THEMING_ENGINE_GET_PRIVATE (engine);
137 _gtk_theming_engine_set_context (GtkThemingEngine *engine,
138 GtkStyleContext *context)
140 GtkThemingEnginePrivate *priv;
142 g_return_if_fail (GTK_IS_THEMING_ENGINE (engine));
143 g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
146 priv->context = context;
150 gtk_theming_engine_get_property (GtkThemingEngine *engine,
151 const gchar *property,
155 GtkThemingEnginePrivate *priv;
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);
163 gtk_style_context_get_property (priv->context, property, state, value);
167 gtk_theming_engine_get_valist (GtkThemingEngine *engine,
171 GtkThemingEnginePrivate *priv;
173 g_return_if_fail (GTK_IS_THEMING_ENGINE (engine));
174 g_return_if_fail (state < GTK_STATE_LAST);
177 gtk_style_context_get_valist (priv->context, state, args);
181 gtk_theming_engine_get (GtkThemingEngine *engine,
185 GtkThemingEnginePrivate *priv;
188 g_return_if_fail (GTK_IS_THEMING_ENGINE (engine));
189 g_return_if_fail (state < GTK_STATE_LAST);
193 va_start (args, state);
194 gtk_style_context_get_valist (priv->context, state, args);
199 gtk_theming_engine_get_state (GtkThemingEngine *engine)
201 GtkThemingEnginePrivate *priv;
203 g_return_val_if_fail (GTK_IS_THEMING_ENGINE (engine), 0);
206 return gtk_style_context_get_state (priv->context);
210 gtk_theming_engine_is_state_set (GtkThemingEngine *engine,
213 GtkThemingEnginePrivate *priv;
215 g_return_val_if_fail (GTK_IS_THEMING_ENGINE (engine), 0);
218 return gtk_style_context_is_state_set (priv->context, state);
221 G_CONST_RETURN GtkWidgetPath *
222 gtk_theming_engine_get_path (GtkThemingEngine *engine)
224 GtkThemingEnginePrivate *priv;
226 g_return_val_if_fail (GTK_IS_THEMING_ENGINE (engine), NULL);
229 return gtk_style_context_get_path (priv->context);
233 gtk_theming_engine_has_class (GtkThemingEngine *engine,
234 const gchar *style_class)
236 GtkThemingEnginePrivate *priv;
238 g_return_val_if_fail (GTK_IS_THEMING_ENGINE (engine), FALSE);
241 return gtk_style_context_has_class (priv->context, style_class);
245 gtk_theming_engine_has_child_class (GtkThemingEngine *engine,
246 const gchar *style_class,
247 GtkChildClassFlags *flags)
249 GtkThemingEnginePrivate *priv;
254 g_return_val_if_fail (GTK_IS_THEMING_ENGINE (engine), FALSE);
257 return gtk_style_context_has_child_class (priv->context, style_class, flags);
260 /* GtkThemingModule */
263 gtk_theming_module_load (GTypeModule *type_module)
265 GtkThemingModule *theming_module;
267 gchar *name, *module_path;
269 theming_module = GTK_THEMING_MODULE (type_module);
270 name = theming_module->name;
271 module_path = _gtk_find_module (name, "theming-engines");
275 g_warning (_("Unable to locate theme engine in module path: \"%s\","), name);
279 module = g_module_open (module_path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
280 g_free (module_path);
284 g_warning ("%s", g_module_error ());
288 if (!g_module_symbol (module, "create_engine",
289 (gpointer *) &theming_module->create_engine))
291 g_warning ("%s", g_module_error());
292 g_module_close (module);
297 g_module_make_resident (module);
303 gtk_theming_module_class_init (GtkThemingModuleClass *klass)
305 GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS (klass);
307 module_class->load = gtk_theming_module_load;
311 gtk_theming_module_init (GtkThemingModule *module)
315 G_CONST_RETURN GtkThemingEngine *
316 gtk_theming_engine_load (const gchar *name)
318 static GHashTable *engines = NULL;
319 static GtkThemingEngine *default_engine;
320 GtkThemingEngine *engine = NULL;
325 engines = g_hash_table_new (g_str_hash, g_str_equal);
327 engine = g_hash_table_lookup (engines, name);
331 GtkThemingModule *module;
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);
337 if (module && g_type_module_use (G_TYPE_MODULE (module)))
339 engine = (module->create_engine) ();
342 g_hash_table_insert (engines, module->name, engine);
350 default_engine = g_object_new (GTK_TYPE_THEMING_ENGINE, NULL);
352 engine = default_engine;
358 /* Paint method implementations */
360 gtk_theming_engine_render_check (GtkThemingEngine *engine,
367 GdkColor *fg_color, *base_color, *text_color;
368 const GtkWidgetPath *path;
372 flags = gtk_theming_engine_get_state (engine);
373 path = gtk_theming_engine_get_path (engine);
376 if (flags & GTK_STATE_FLAG_PRELIGHT)
377 state = GTK_STATE_PRELIGHT;
379 state = GTK_STATE_NORMAL;
381 gtk_theming_engine_get (engine, state,
382 "foreground-color", &fg_color,
383 "base-color", &base_color,
384 "text-color", &text_color,
387 if (!gtk_widget_path_has_parent (path, GTK_TYPE_MENU))
389 cairo_set_line_width (cr, 1);
393 width - 1, height - 1);
395 gdk_cairo_set_source_color (cr, base_color);
396 cairo_fill_preserve (cr);
398 if (gtk_widget_path_has_parent (path, GTK_TYPE_TREE_VIEW))
399 gdk_cairo_set_source_color (cr, text_color);
401 gdk_cairo_set_source_color (cr, fg_color);
406 cairo_set_line_width (cr, 1.5);
407 gdk_cairo_set_source_color (cr, text_color);
409 if (gtk_theming_engine_is_state_set (engine, GTK_STATE_INCONSISTENT))
411 cairo_move_to (cr, x + (width * 0.2), y + (height / 2));
412 cairo_line_to (cr, x + (width * 0.8), y + (height / 2));
414 else if (gtk_theming_engine_is_state_set (engine, GTK_STATE_ACTIVE))
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));
425 gdk_color_free (fg_color);
426 gdk_color_free (base_color);
427 gdk_color_free (text_color);
431 gtk_theming_engine_render_option (GtkThemingEngine *engine,
439 GdkColor *base_color, *fg_color, *text_color;
440 const GtkWidgetPath *path;
444 flags = gtk_theming_engine_get_state (engine);
445 path = gtk_theming_engine_get_path (engine);
446 radius = MIN (width, height) / 2 - 0.5;
449 cairo_set_line_width (cr, 1);
451 if (flags & GTK_STATE_FLAG_PRELIGHT)
452 state = GTK_STATE_PRELIGHT;
454 state = GTK_STATE_NORMAL;
456 gtk_theming_engine_get (engine, state,
457 "foreground-color", &fg_color,
458 "base-color", &base_color,
459 "text-color", &text_color,
462 if (!gtk_widget_path_has_parent (path, GTK_TYPE_MENU))
470 gdk_cairo_set_source_color (cr, base_color);
471 cairo_fill_preserve (cr);
473 if (gtk_widget_path_has_parent (path, GTK_TYPE_TREE_VIEW))
474 gdk_cairo_set_source_color (cr, text_color);
476 gdk_cairo_set_source_color (cr, fg_color);
481 if (gtk_widget_path_has_parent (path, GTK_TYPE_MENU))
482 gdk_cairo_set_source_color (cr, fg_color);
484 gdk_cairo_set_source_color (cr, text_color);
486 if (gtk_theming_engine_is_state_set (engine, GTK_STATE_INCONSISTENT))
488 cairo_move_to (cr, x + (width * 0.2), y + (height / 2));
489 cairo_line_to (cr, x + (width * 0.8), y + (height / 2));
492 if (gtk_theming_engine_is_state_set (engine, GTK_STATE_ACTIVE))
507 add_path_arrow (cairo_t *cr,
515 cairo_translate (cr, x + (size / 2), y + (size / 2));
516 cairo_rotate (cr, angle);
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);
527 gtk_theming_engine_render_arrow (GtkThemingEngine *engine,
540 flags = gtk_theming_engine_get_state (engine);
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;
547 state = GTK_STATE_NORMAL;
549 gtk_theming_engine_get (engine, state,
550 "foreground-color", &fg_color,
553 if (flags & GTK_STATE_FLAG_INSENSITIVE)
555 add_path_arrow (cr, angle, x + 1, y + 1, size);
556 cairo_set_source_rgb (cr, 1, 1, 1);
560 add_path_arrow (cr, angle, x, y, size);
561 gdk_cairo_set_source_color (cr, fg_color);
566 gdk_color_free (fg_color);
570 add_path_rounded_rectangle (cairo_t *cr,
580 if (sides & SIDE_BOTTOM)
582 /* Bottom left corner */
584 cairo_move_to (cr, x + 0.5, y + height - 0.5);
586 cairo_arc_negative (cr,
588 y + height - r - 0.5,
594 cairo_line_to (cr, x + width - r - 0.5, y + height - 0.5);
596 /* Bottom right corner */
598 cairo_arc_negative (cr,
600 y + height - r - 0.5,
606 if (sides & SIDE_RIGHT)
608 /* Bottom right corner */
611 if ((sides & SIDE_BOTTOM) == 0)
612 cairo_move_to (cr, x + width - 0.5, y + height - 0.5);
615 cairo_arc_negative (cr,
617 y + height - r - 0.5,
619 45 * (G_PI / 180), 0);
622 cairo_line_to (cr, x + width - 0.5, y + r);
624 /* Top right corner */
626 cairo_arc_negative (cr,
630 0, 315 * (G_PI / 180));
633 if (sides & SIDE_TOP)
635 /* Top right corner */
638 if ((sides & SIDE_RIGHT) == 0)
639 cairo_move_to (cr, x + width - 1, y + 0.5);
642 cairo_arc_negative (cr,
650 cairo_line_to (cr, x + 0.5 + r, y + 0.5);
652 /* Top left corner */
654 cairo_arc_negative (cr,
662 if (sides & SIDE_LEFT)
664 /* Top left corner */
667 if ((sides & SIDE_TOP) == 0)
668 cairo_move_to (cr, x + 0.5, y + 0.5);
671 cairo_arc_negative (cr,
679 cairo_line_to (cr, x + 0.5, y + height - r);
682 cairo_arc_negative (cr,
684 y + height - r + 0.5,
692 color_shade (const GdkColor *color,
694 GdkColor *color_return)
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);
702 gtk_theming_engine_render_background (GtkThemingEngine *engine,
714 flags = gtk_theming_engine_get_state (engine);
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;
721 state = GTK_STATE_NORMAL;
723 gtk_theming_engine_get (engine, state,
724 "background-color", &bg_color,
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);
732 gdk_cairo_set_source_color (cr, bg_color);
739 gtk_theming_engine_render_frame (GtkThemingEngine *engine,
749 GdkColor lighter, darker;
752 flags = gtk_theming_engine_get_state (engine);
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;
759 state = GTK_STATE_NORMAL;
761 cairo_set_line_width (cr, 1);
763 gtk_theming_engine_get (engine, state,
764 "background-color", &bg_color,
766 color_shade (bg_color, 0.7, &darker);
767 color_shade (bg_color, 1.3, &lighter);
769 if (flags & GTK_STATE_FLAG_ACTIVE)
771 add_path_rounded_rectangle (cr, 0,
772 SIDE_BOTTOM | SIDE_RIGHT,
773 x, y, width, height);
775 gdk_cairo_set_source_color (cr, &lighter);
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);
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);
792 add_path_rounded_rectangle (cr, 0,
793 SIDE_BOTTOM | SIDE_RIGHT,
794 x, y, width, height);
796 cairo_set_source_rgb (cr, 0, 0, 0);
799 add_path_rounded_rectangle (cr, 0,
800 SIDE_BOTTOM | SIDE_RIGHT,
801 x, y, width - 1, height - 1);
803 gdk_cairo_set_source_color (cr, &darker);
806 add_path_rounded_rectangle (cr, 0,
807 SIDE_TOP | SIDE_LEFT,
808 x, y, width, height);
810 gdk_cairo_set_source_color (cr, &lighter);
818 gtk_theming_engine_render_expander (GtkThemingEngine *engine,
826 GdkColor *bg_color, *fg_color, *base_color;
831 flags = gtk_theming_engine_get_state (engine);
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;
838 state = GTK_STATE_NORMAL;
840 gtk_theming_engine_get (engine, state,
841 "foreground-color", &fg_color,
842 "background-color", &bg_color,
843 "base-color", &base_color,
846 if (flags & GTK_STATE_FLAG_ACTIVE)
851 cairo_set_line_width (cr, 1);
852 add_path_arrow (cr, angle, x + 2, y + 2,
853 MIN (width - 1, height - 1) - 4);
855 if (flags & GTK_STATE_FLAG_PRELIGHT)
856 gdk_cairo_set_source_color (cr, fg_color);
858 gdk_cairo_set_source_color (cr, base_color);
860 cairo_fill_preserve (cr);
862 gdk_cairo_set_source_color (cr, fg_color);
867 gdk_color_free (base_color);
868 gdk_color_free (fg_color);
869 gdk_color_free (bg_color);
873 gtk_theming_engine_render_focus (GtkThemingEngine *engine,
880 const double dashes[] = { 0.5, 1.5 };
881 GdkColor *base_color;
886 flags = gtk_theming_engine_get_state (engine);
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;
893 state = GTK_STATE_NORMAL;
895 gtk_theming_engine_get (engine, state,
896 "base-color", &base_color,
899 cairo_set_line_width (cr, 1.0);
900 cairo_set_dash (cr, dashes, 2, 0);
908 gdk_cairo_set_source_color (cr, base_color);
913 gdk_color_free (base_color);
916 #define __GTK_THEMING_ENGINE_C__
917 #include "gtkaliasdef.c"