summaryrefslogtreecommitdiff
path: root/ccss-gtk
diff options
context:
space:
mode:
authorRobert Staudinger <robsta@gnome.org>2008-12-10 16:36:23 +0100
committerRobert Staudinger <robsta@gnome.org>2008-12-10 16:36:23 +0100
commit52b13b638a6cf9f9b1f7e079ed90f3d6776d7c64 (patch)
tree5022a2f666446cab5ca503f20388263784974271 /ccss-gtk
parenta5d66059fc09d64bd3c8928c0d53f30fa54be1e7 (diff)
* ccss-cairo/ccss-background-parser.c:
* ccss-cairo/ccss-border-parser.c: * ccss-cairo/ccss-cairo-grammar.c: * ccss-gtk/Makefile.am: * ccss-gtk/ccss-gtk-grammar.c (ccss_gtk_grammar_create): * ccss-gtk/ccss-gtk-property.c (parse_gboolean), (parse_gchararray), (parse_gfloat), (parse_gint), (parse_guchar), (parse_gdk_color), (parse_gtk_border), (parse_gtk_relief_style), (parse_gtk_requisition), (parse_gtk_shadow_type), (parse_gtk_toolbar_space_style), (parse_gtk_style_property), (property_destroy), (property_convert), (property_factory), (peek_property_class), (ccss_gtk_property_get_property_classes), (ccss_gtk_property_set_fallback_class), (ccss_gtk_property_is_style_property): * ccss-gtk/ccss-gtk-property.h: * ccss-gtk/ccss-gtk-style.c: * ccss-gtk/ccss-gtk-style.h: * ccss-gtk/ccss-gtk-stylesheet.c (get_type), (get_id), (get_pseudo_class), (style_iterator), (accumulate_state), (accumulate), (serialize_state), (serialize), (iter_func), (ccss_gtk_stylesheet_to_gtkrc): * ccss-gtk/ccss-gtk-stylesheet.h: * ccss-gtk/ccss-gtk.h: * ccss-gtk/ccss-gtk.sym: * ccss/ccss-stylesheet.c (ccss_stylesheet_foreach): * ccss/ccss-stylesheet.h: Stylesheet gtkrc serialisation infrastructure.
Diffstat (limited to 'ccss-gtk')
-rw-r--r--ccss-gtk/Makefile.am6
-rw-r--r--ccss-gtk/ccss-gtk-grammar.c666
-rw-r--r--ccss-gtk/ccss-gtk-property.c570
-rw-r--r--ccss-gtk/ccss-gtk-property.h56
-rw-r--r--ccss-gtk/ccss-gtk-style.c29
-rw-r--r--ccss-gtk/ccss-gtk-stylesheet.c431
-rw-r--r--ccss-gtk/ccss-gtk-stylesheet.h (renamed from ccss-gtk/ccss-gtk-style.h)8
-rw-r--r--ccss-gtk/ccss-gtk.h2
-rw-r--r--ccss-gtk/ccss-gtk.sym2
9 files changed, 1075 insertions, 695 deletions
diff --git a/ccss-gtk/Makefile.am b/ccss-gtk/Makefile.am
index 7bde7e4..7fa595f 100644
--- a/ccss-gtk/Makefile.am
+++ b/ccss-gtk/Makefile.am
@@ -22,14 +22,16 @@ libccss_gtk_1_la_SOURCES = \
$(headers_DATA) \
ccss-gtk.c \
ccss-gtk-grammar.c \
- ccss-gtk-style.c
+ ccss-gtk-property.c \
+ ccss-gtk-property.h \
+ ccss-gtk-stylesheet.c
headersdir = $(includedir)/libccss-1/ccss-gtk
headers_DATA = \
ccss-gtk.h \
ccss-gtk-grammar.h \
- ccss-gtk-style.h
+ ccss-gtk-stylesheet.h
EXTRA_DIST = \
ccss-gtk.sym
diff --git a/ccss-gtk/ccss-gtk-grammar.c b/ccss-gtk/ccss-gtk-grammar.c
index d587609..87da913 100644
--- a/ccss-gtk/ccss-gtk-grammar.c
+++ b/ccss-gtk/ccss-gtk-grammar.c
@@ -17,664 +17,13 @@
* MA 02110-1301, USA.
*/
-#include <math.h>
#include <string.h>
#include <gtk/gtk.h>
#include <ccss-cairo/ccss-cairo.h>
#include "ccss-gtk-grammar.h"
+#include "ccss-gtk-property.h"
#include "config.h"
-typedef struct {
- ccss_property_base_t base;
- char *class_name;
- char *property_name;
- GType gtype;
- union {
- gboolean gboolean_val;
- gchararray gchararray_val;
- gfloat gfloat_val;
- gint gint_val;
- guchar guchar_val;
- GdkColor gdkcolor_val;
- GtkBorder gtkborder_val;
- GtkReliefStyle gtkreliefstyle_val;
- GtkRequisition gtkrequisition_val;
- GtkShadowType gtkshadowtype_val;
- GtkToolbarSpaceStyle gtktoolbarspacestyle_val;
- } content;
-} ccss_gtk_property_t;
-
-static ccss_property_class_t const *
-peek_property_class (void);
-
-static ccss_property_class_t const *_generic_property_class = NULL;
-
-static bool
-parse_gboolean (CRTerm const *values,
- ccss_gtk_property_t *property)
-{
- char const *str;
- bool ret;
-
- g_return_val_if_fail (values && property, false);
-
- ret = false;
- switch (values->type) {
- case TERM_IDENT:
- case TERM_STRING:
- ret = true;
- str = cr_string_peek_raw_str (values->content.str);
- if (0 == g_ascii_strcasecmp ("true", str))
- property->content.gboolean_val = true;
- else if (0 == g_ascii_strcasecmp ("false", str))
- property->content.gboolean_val = false;
- else
- ret = false;
- break;
- default:
- /* Shut up compiler. */
- ret = false;
- }
-
- return ret;
-}
-
-static bool
-parse_gchararray (CRTerm const *values,
- ccss_gtk_property_t *property)
-{
- char const *str;
- bool ret;
-
- g_return_val_if_fail (values && property, false);
-
- ret = false;
- switch (values->type) {
- case TERM_IDENT:
- case TERM_STRING:
- str = cr_string_peek_raw_str (values->content.str);
- property->content.gchararray_val = g_strdup (str);
- ret = true;
- break;
- default:
- /* Shut up compiler. */
- ret = false;
- }
-
- return ret;
-}
-
-static bool
-parse_gfloat (CRTerm const *values,
- ccss_gtk_property_t *property)
-{
- bool ret;
-
- g_return_val_if_fail (values && property, false);
-
- ret = false;
- switch (values->type) {
- case TERM_NUMBER:
- property->content.gfloat_val = values->content.num->val;
- ret = true;
- break;
- default:
- /* Shut up compiler. */
- ret = false;
- }
-
- return ret;
-}
-
-static bool
-parse_gint (CRTerm const *values,
- ccss_gtk_property_t *property)
-{
- bool ret;
-
- g_return_val_if_fail (values && property, false);
-
- ret = false;
- switch (values->type) {
- case TERM_NUMBER:
- /* Be strict about fractionals. */
- if (lround (values->content.num->val) == values->content.num->val) {
- property->content.gint_val = (int) values->content.num->val;
- ret = true;
- }
- break;
- default:
- /* Shut up compiler. */
- ret = false;
- }
-
- return ret;
-}
-
-static bool
-parse_guchar (CRTerm const *values,
- ccss_gtk_property_t *property)
-{
- bool ret;
-
- g_return_val_if_fail (values && property, false);
-
- ret = false;
- switch (values->type) {
- case TERM_NUMBER:
- /* Be strict about fractionals. */
- if (lround (values->content.num->val) == values->content.num->val) {
- if (values->content.num->val > G_MAXUINT8)
- property->content.guchar_val = G_MAXUINT8;
- else if (values->content.num->val < 0)
- property->content.guchar_val = 0;
- else
- property->content.guchar_val = (guchar) values->content.num->val;
- ret = true;
- }
- break;
- default:
- /* Shut up compiler. */
- ret = false;
- }
-
- return ret;
-}
-
-static bool
-parse_gdk_color (ccss_grammar_t const *grammar,
- CRTerm const *values,
- void *user_data,
- ccss_gtk_property_t *property)
-{
- ccss_cairo_color_t color;
- bool ret;
-
- g_return_val_if_fail (values && property, false);
-
- memset (&color, 0, sizeof (color));
- ret = ccss_cairo_color_parse (&color, grammar, user_data, &values);
- if (ret) {
- property->content.gdkcolor_val.red = color.red * 65535;
- property->content.gdkcolor_val.green = color.green * 65535;
- property->content.gdkcolor_val.blue = color.blue * 65535;
- }
-
- return ret;
-}
-
-static bool
-parse_gtk_border (CRTerm const *values,
- ccss_gtk_property_t *property)
-{
- gint *border_ptr;
- int i;
-
- g_return_val_if_fail (values && property, false);
-
- border_ptr = (gint *) &property->content.gtkborder_val;
- for (i = 0; i < 4; i++) {
-
- if (!values) {
- break;
- }
-
- /* Be strict about fractionals. */
- if (TERM_NUMBER == values->type &&
- lround (values->content.num->val) == values->content.num->val) {
-
- border_ptr[i] = (gint) values->content.num->val;
- values = values->next;
- }
- }
-
- return i == 4;
-}
-
-static bool
-parse_gtk_relief_style (CRTerm const *values,
- ccss_gtk_property_t *property)
-{
- char const *str;
- bool ret;
-
- g_return_val_if_fail (values && property, false);
-
- ret = false;
- switch (values->type) {
- case TERM_IDENT:
- case TERM_STRING:
- ret = true;
- str = cr_string_peek_raw_str (values->content.str);
- if (0 == g_ascii_strcasecmp ("normal", str))
- property->content.gtkreliefstyle_val = GTK_RELIEF_NORMAL;
- else if (0 == g_ascii_strcasecmp ("half", str))
- property->content.gtkreliefstyle_val = GTK_RELIEF_HALF;
- else if (0 == g_ascii_strcasecmp ("none", str))
- property->content.gtkreliefstyle_val = GTK_RELIEF_NONE;
- else
- ret = false;
- break;
- default:
- /* Shut up compiler. */
- ret = false;
- }
-
- return ret;
-}
-
-static bool
-parse_gtk_requisition (CRTerm const *values,
- ccss_gtk_property_t *property)
-{
- gint *border_ptr;
- int i;
-
- g_return_val_if_fail (values && property, false);
-
- border_ptr = (gint *) &property->content.gtkrequisition_val;
- for (i = 0; i < 2; i++) {
-
- if (!values) {
- break;
- }
-
- /* Be strict about fractionals. */
- if (TERM_NUMBER == values->type &&
- lround (values->content.num->val) == values->content.num->val) {
-
- border_ptr[i] = (gint) values->content.num->val;
- values = values->next;
- }
- }
-
- return i == 2;
-}
-
-static bool
-parse_gtk_shadow_type (CRTerm const *values,
- ccss_gtk_property_t *property)
-{
- char const *str;
- bool ret;
-
- g_return_val_if_fail (values && property, false);
-
- ret = false;
- switch (values->type) {
- case TERM_IDENT:
- case TERM_STRING:
- ret = true;
- str = cr_string_peek_raw_str (values->content.str);
- if (0 == g_ascii_strcasecmp ("none", str))
- property->content.gtkshadowtype_val = GTK_SHADOW_NONE;
- else if (0 == g_ascii_strcasecmp ("in", str))
- property->content.gtkreliefstyle_val = GTK_SHADOW_IN;
- else if (0 == g_ascii_strcasecmp ("out", str))
- property->content.gtkreliefstyle_val = GTK_SHADOW_OUT;
- else if (0 == g_ascii_strcasecmp ("etched-in", str))
- property->content.gtkreliefstyle_val = GTK_SHADOW_ETCHED_IN;
- else if (0 == g_ascii_strcasecmp ("etched-out", str))
- property->content.gtkreliefstyle_val = GTK_SHADOW_ETCHED_OUT;
- else
- ret = false;
- break;
- default:
- /* Shut up compiler. */
- ret = false;
- }
-
- return ret;
-}
-
-static bool
-parse_gtk_toolbar_space_style (CRTerm const *values,
- ccss_gtk_property_t *property)
-{
- char const *str;
- bool ret;
-
- g_return_val_if_fail (values && property, false);
-
- ret = false;
- switch (values->type) {
- case TERM_IDENT:
- case TERM_STRING:
- ret = true;
- str = cr_string_peek_raw_str (values->content.str);
- if (0 == g_ascii_strcasecmp ("empty", str))
- property->content.gtktoolbarspacestyle_val = GTK_TOOLBAR_SPACE_EMPTY;
- else if (0 == g_ascii_strcasecmp ("line", str))
- property->content.gtktoolbarspacestyle_val = GTK_TOOLBAR_SPACE_LINE;
- else
- ret = false;
- break;
- default:
- /* Shut up compiler. */
- ret = false;
- }
-
- return ret;
-}
-
-static ccss_gtk_property_t *
-parse_gtk_style_property (ccss_grammar_t const *grammar,
- char const *name,
- CRTerm const *values,
- void *user_data)
-{
- char **tokens;
- char *class_name = NULL;
- char *property_name = NULL;
- GtkBuilder *builder = NULL;
- GType type = 0;
- GtkWidget *widget = NULL;
- GParamSpec *property = NULL;
- ccss_gtk_property_t *self = NULL, s;
-
- /* Parse property name. */
- tokens = g_strsplit (name, "-", 2);
- if (tokens && tokens[0]) {
- class_name = tokens[0];
- } else {
- goto bail;
- }
- if (tokens && tokens[1]) {
- property_name = tokens[1];
- } else {
- goto bail;
- }
-
- /* Introspect property type. */
- builder = gtk_builder_new ();
- type = gtk_builder_get_type_from_name (builder, class_name);
- if (0 == type)
- goto bail;
-
- widget = GTK_WIDGET (g_object_new (type, NULL));
- if (NULL == widget)
- goto bail;
-
- property = gtk_widget_class_find_style_property (GTK_WIDGET_GET_CLASS (widget),
- property_name);
- if (NULL == property)
- goto bail;
-
- /* Parse value. */
- memset (&s, 0, sizeof (s));
- ccss_property_init (&self->base, peek_property_class ());
- if (G_TYPE_BOOLEAN == property->value_type) {
- if (parse_gboolean (values, &s)) {
- s.gtype = property->value_type;
- self = g_new0 (ccss_gtk_property_t, 1);
- *self = s;
- }
- } else if (G_TYPE_STRING == property->value_type) {
- if (parse_gchararray (values, &s)) {
- s.gtype = property->value_type;
- self = g_new0 (ccss_gtk_property_t, 1);
- *self = s;
- }
- } else if (G_TYPE_FLOAT == property->value_type) {
- if (parse_gfloat (values, &s)) {
- s.gtype = property->value_type;
- self = g_new0 (ccss_gtk_property_t, 1);
- *self = s;
- }
- } else if (G_TYPE_INT == property->value_type) {
- if (parse_gint (values, &s)) {
- s.gtype = property->value_type;
- self = g_new0 (ccss_gtk_property_t, 1);
- *self = s;
- }
- } else if (G_TYPE_UCHAR == property->value_type) {
- if (parse_guchar (values, &s)) {
- s.gtype = property->value_type;
- self = g_new0 (ccss_gtk_property_t, 1);
- *self = s;
- }
- } else if (GDK_TYPE_COLOR == property->value_type) {
- if (parse_gdk_color (grammar, values, user_data, &s)) {
- s.gtype = property->value_type;
- self = g_new0 (ccss_gtk_property_t, 1);
- *self = s;
- }
- } else if (GTK_TYPE_BORDER == property->value_type) {
- if (parse_gtk_border (values, &s)) {
- s.gtype = property->value_type;
- self = g_new0 (ccss_gtk_property_t, 1);
- *self = s;
- }
- } else if (GTK_TYPE_RELIEF_STYLE == property->value_type) {
- if (parse_gtk_relief_style (values, &s)) {
- s.gtype = property->value_type;
- self = g_new0 (ccss_gtk_property_t, 1);
- *self = s;
- }
- } else if (GTK_TYPE_REQUISITION == property->value_type) {
- if (parse_gtk_requisition (values, &s)) {
- s.gtype = property->value_type;
- self = g_new0 (ccss_gtk_property_t, 1);
- *self = s;
- }
- } else if (GTK_TYPE_SHADOW_TYPE == property->value_type) {
- if (parse_gtk_shadow_type (values, &s)) {
- s.gtype = property->value_type;
- self = g_new0 (ccss_gtk_property_t, 1);
- *self = s;
- }
- } else if (GTK_TYPE_TOOLBAR_SPACE_STYLE == property->value_type) {
- if (parse_gtk_toolbar_space_style (values, &s)) {
- s.gtype = property->value_type;
- self = g_new0 (ccss_gtk_property_t, 1);
- *self = s;
- }
- } else {
- g_assert_not_reached ();
- }
-
- if (self) {
- self->class_name = class_name, class_name = NULL;
- self->property_name = property_name, property_name = NULL;
- }
-
-bail:
- if (tokens)
- g_free (tokens);
- if (class_name)
- g_free (class_name);
- if (property_name)
- g_free (property_name);
- if (builder)
- g_object_unref (G_OBJECT (builder));
- if (widget)
- gtk_widget_destroy (widget);
-
- return self;
-}
-
-static void
-property_destroy (ccss_gtk_property_t *self)
-{
- g_return_if_fail (self);
-
- if (G_TYPE_STRING == self->gtype && self->content.gchararray_val) {
- g_free (self->content.gchararray_val);
- }
- g_free (self);
-}
-
-static bool
-property_convert (ccss_gtk_property_t const *self,
- ccss_property_type_t target,
- void *value)
-{
- char *prefix;
-
- g_return_val_if_fail (self, false);
- g_return_val_if_fail (value, false);
-
- if (CCSS_PROPERTY_TYPE_DOUBLE == target) {
- return false;
- }
-
- if (self->class_name) {
- prefix = g_strdup_printf ("%s::", self->class_name);
- } else {
- prefix = g_strdup ("");
- }
-
- if (G_TYPE_BOOLEAN == self->gtype) {
- * (char **) value = g_strdup_printf ("%s%s = %s",
- prefix, self->property_name,
- self->content.gboolean_val ?
- "TRUE" : "FALSE");
- } else if (G_TYPE_STRING == self->gtype) {
- * (char **) value = g_strdup_printf ("%s%s = \"%s\"",
- prefix, self->property_name,
- self->content.gchararray_val);
- } else if (G_TYPE_FLOAT == self->gtype) {
- * (char **) value = g_strdup_printf ("%s%s = %f",
- prefix, self->property_name,
- self->content.gfloat_val);
- } else if (G_TYPE_INT == self->gtype) {
- * (char **) value = g_strdup_printf ("%s%s = %d",
- prefix, self->property_name,
- self->content.gint_val);
- } else if (G_TYPE_UCHAR == self->gtype) {
- * (char **) value = g_strdup_printf ("%s%s = %d",
- prefix, self->property_name,
- self->content.guchar_val);
- } else if (GDK_TYPE_COLOR == self->gtype) {
- char *val;
- val = gdk_color_to_string (&self->content.gdkcolor_val);
- * (char **) value = g_strdup_printf ("%s%s = %s",
- prefix, self->property_name,
- val);
- g_free (val);
- } else if (GTK_TYPE_BORDER == self->gtype) {
- * (char **) value = g_strdup_printf ("%s%s = { %d, %d, %d, %d }",
- prefix, self->property_name,
- self->content.gtkborder_val.left,
- self->content.gtkborder_val.right,
- self->content.gtkborder_val.top,
- self->content.gtkborder_val.bottom);
- } else if (GTK_TYPE_RELIEF_STYLE == self->gtype) {
- char const *val;
- val = self->content.gtkreliefstyle_val == GTK_RELIEF_NORMAL ? "NORMAL" :
- self->content.gtkreliefstyle_val == GTK_RELIEF_HALF ? "HALF" :
- self->content.gtkreliefstyle_val == GTK_RELIEF_NONE ? "NONE" : "";
- * (char **) value = g_strdup_printf ("%s%s = %s",
- prefix, self->property_name,
- val);
- } else if (GTK_TYPE_REQUISITION == self->gtype) {
- * (char **) value = g_strdup_printf ("%s%s = { %d, %d }",
- prefix, self->property_name,
- self->content.gtkrequisition_val.width,
- self->content.gtkrequisition_val.height);
- } else if (GTK_TYPE_SHADOW_TYPE == self->gtype) {
- char const *val;
- val = self->content.gtkshadowtype_val == GTK_SHADOW_NONE ? "NONE" :
- self->content.gtkshadowtype_val == GTK_SHADOW_IN ? "IN" :
- self->content.gtkshadowtype_val == GTK_SHADOW_OUT ? "OUT" :
- self->content.gtkshadowtype_val == GTK_SHADOW_ETCHED_IN ? "ETCHED_IN" :
- self->content.gtkshadowtype_val == GTK_SHADOW_ETCHED_OUT ? "ETCHED_OUT" : "";
- * (char **) value = g_strdup_printf ("%s%s = %s",
- prefix, self->property_name,
- val);
- } else if (GTK_TYPE_TOOLBAR_SPACE_STYLE == self->gtype) {
- char const *val;
- val = self->content.gtktoolbarspacestyle_val == GTK_TOOLBAR_SPACE_EMPTY ? "EMPTY" :
- self->content.gtktoolbarspacestyle_val == GTK_TOOLBAR_SPACE_LINE ? "LINE" : "";
- * (char **) value = g_strdup_printf ("%s%s = %s",
- prefix, self->property_name,
- val);
- } else {
- g_assert_not_reached ();
- }
-
- g_free (prefix), prefix = NULL;
- return true;
-}
-
-static bool
-property_factory (ccss_grammar_t const *grammar,
- ccss_block_t *block,
- char const *name,
- CRTerm const *values,
- void *user_data)
-{
- ccss_gtk_property_t s, *self;
-
- g_return_val_if_fail (grammar, false);
- g_return_val_if_fail (block, false);
- g_return_val_if_fail (name, false);
- g_return_val_if_fail (values, false);
-
- /* PONDERING: Handle things like GtkSettings `gtk-button-images' in the future? */
-
- memset (&s, 0, sizeof (s));
- ccss_property_init (&self->base, peek_property_class ());
-
- if (0 == g_strcmp0 (name, "xthickness")) {
- if (parse_gint (values, &s)) {
- s.class_name = NULL;
- s.property_name = g_strdup ("xthickness");
- self = g_new0 (ccss_gtk_property_t, 1);
- *self = s;
- ccss_block_add_property (block, "xthickness", &self->base);
- return true;
- }
- } else if (0 == g_strcmp0 (name, "ythickness")) {
- if (parse_gint (values, &s)) {
- s.class_name = NULL;
- s.property_name = g_strdup ("ythickness");
- self = g_new0 (ccss_gtk_property_t, 1);
- *self = s;
- ccss_block_add_property (block, "ythickness", &self->base);
- return true;
- }
- } else if (g_str_has_prefix (name, "Gtk")) {
- self = parse_gtk_style_property (grammar, name, values, user_data);
- if (self) {
- ccss_block_add_property (block, name, &self->base);
- }
- return (bool) self;
- } else if (g_ascii_isupper (name[0])) {
- // TODO introspect style property and feed back to gtk directly.
- // Non-gtk style properties (wnck, nautilus, ...) can't be
- // resolved offline because css2gtkrc doesn't link against them.
- // May cause some breakage, let's see how it goes.
- // TODO link css2gtkrc against gtk.
- }
-
-
- /* Fall back. */
- g_return_val_if_fail (_generic_property_class, false);
- g_return_val_if_fail (_generic_property_class->property_factory, false);
- return _generic_property_class->property_factory (grammar, block, name,
- values, user_data);
-}
-
-static ccss_property_class_t const _properties[] = {
- {
- .name = "*",
- .property_create = NULL,
- .property_destroy = (ccss_property_destroy_f) property_destroy,
- .property_convert = (ccss_property_convert_f) property_convert,
- .property_factory = property_factory,
- .property_inherit = NULL
- }, {
- .name = NULL
- }
-};
-
-static ccss_property_class_t const *
-peek_property_class (void)
-{
- return &_properties[0];
-}
-
/**
* ccss_gtk_grammar_create:
*
@@ -688,17 +37,18 @@ peek_property_class (void)
ccss_grammar_t *
ccss_gtk_grammar_create (void)
{
- ccss_grammar_t *self;
+ ccss_grammar_t *self;
+ ccss_property_class_t const *fallback_property_class;
self = ccss_cairo_grammar_create ();
- if (NULL == _generic_property_class) {
- _generic_property_class = ccss_grammar_lookup_property (self,
- "*");
- }
+ fallback_property_class = ccss_grammar_lookup_property (self, "*");
+ g_return_val_if_fail (fallback_property_class, NULL);
+ ccss_gtk_property_set_fallback_class (fallback_property_class);
- ccss_grammar_add_properties (self, _properties);
+ ccss_grammar_add_properties (self, ccss_gtk_property_get_property_classes ());
return self;
}
+
diff --git a/ccss-gtk/ccss-gtk-property.c b/ccss-gtk/ccss-gtk-property.c
new file mode 100644
index 0000000..bed8963
--- /dev/null
+++ b/ccss-gtk/ccss-gtk-property.c
@@ -0,0 +1,570 @@
+/* The Gtk+ CSS Drawing Library.
+ * Copyright (C) 2008 Robert Staudinger
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <math.h>
+#include <string.h>
+#include "ccss-gtk-property.h"
+
+static ccss_property_class_t const *
+peek_property_class (void);
+
+static ccss_property_class_t const *_fallback_property_class = NULL;
+
+static bool
+parse_gboolean (CRTerm const *values,
+ ccss_gtk_property_t *property)
+{
+ char const *str;
+ bool ret;
+
+ g_return_val_if_fail (values && property, false);
+
+ ret = false;
+ switch (values->type) {
+ case TERM_IDENT:
+ case TERM_STRING:
+ ret = true;
+ str = cr_string_peek_raw_str (values->content.str);
+ if (0 == g_ascii_strcasecmp ("true", str))
+ property->content.gboolean_val = true;
+ else if (0 == g_ascii_strcasecmp ("false", str))
+ property->content.gboolean_val = false;
+ else
+ ret = false;
+ break;
+ default:
+ /* Shut up compiler. */
+ ret = false;
+ }
+
+ return ret;
+}
+
+static bool
+parse_gchararray (CRTerm const *values,
+ ccss_gtk_property_t *property)
+{
+ char const *str;
+ bool ret;
+
+ g_return_val_if_fail (values && property, false);
+
+ ret = false;
+ switch (values->type) {
+ case TERM_IDENT:
+ case TERM_STRING:
+ str = cr_string_peek_raw_str (values->content.str);
+ property->content.gchararray_val = g_strdup (str);
+ ret = true;
+ break;
+ default:
+ /* Shut up compiler. */
+ ret = false;
+ }
+
+ return ret;
+}
+
+static bool
+parse_gfloat (CRTerm const *values,
+ ccss_gtk_property_t *property)
+{
+ bool ret;
+
+ g_return_val_if_fail (values && property, false);
+
+ ret = false;
+ switch (values->type) {
+ case TERM_NUMBER:
+ property->content.gfloat_val = values->content.num->val;
+ ret = true;
+ break;
+ default:
+ /* Shut up compiler. */
+ ret = false;
+ }
+
+ return ret;
+}
+
+static bool
+parse_gint (CRTerm const *values,
+ ccss_gtk_property_t *property)
+{
+ bool ret;
+
+ g_return_val_if_fail (values && property, false);
+
+ ret = false;
+ switch (values->type) {
+ case TERM_NUMBER:
+ /* Be strict about fractionals. */
+ if (lround (values->content.num->val) == values->content.num->val) {
+ property->content.gint_val = (int) values->content.num->val;
+ ret = true;
+ }
+ break;
+ default:
+ /* Shut up compiler. */
+ ret = false;
+ }
+
+ return ret;
+}
+
+static bool
+parse_guchar (CRTerm const *values,
+ ccss_gtk_property_t *property)
+{
+ bool ret;
+
+ g_return_val_if_fail (values && property, false);
+
+ ret = false;
+ switch (values->type) {
+ case TERM_NUMBER:
+ /* Be strict about fractionals. */
+ if (lround (values->content.num->val) == values->content.num->val) {
+ if (values->content.num->val > G_MAXUINT8)
+ property->content.guchar_val = G_MAXUINT8;
+ else if (values->content.num->val < 0)
+ property->content.guchar_val = 0;
+ else
+ property->content.guchar_val = (guchar) values->content.num->val;
+ ret = true;
+ }
+ break;
+ default:
+ /* Shut up compiler. */
+ ret = false;
+ }
+
+ return ret;
+}
+
+static bool
+parse_gdk_color (ccss_grammar_t const *grammar,
+ CRTerm const *values,
+ void *user_data,
+ ccss_gtk_property_t *property)
+{
+ ccss_cairo_color_t color;
+ bool ret;
+
+ g_return_val_if_fail (values && property, false);
+
+ memset (&color, 0, sizeof (color));
+ ret = ccss_cairo_color_parse (&color, grammar, user_data, &values);
+ if (ret) {
+ property->content.gdkcolor_val.red = color.red * 65535;
+ property->content.gdkcolor_val.green = color.green * 65535;
+ property->content.gdkcolor_val.blue = color.blue * 65535;
+ }
+
+ return ret;
+}
+
+static bool
+parse_gtk_border (CRTerm const *values,
+ ccss_gtk_property_t *property)
+{
+ gint *border_ptr;
+ int i;
+
+ g_return_val_if_fail (values && property, false);
+
+ border_ptr = (gint *) &property->content.gtkborder_val;
+ for (i = 0; i < 4; i++) {
+
+ if (!values) {
+ break;
+ }
+
+ /* Be strict about fractionals. */
+ if (TERM_NUMBER == values->type &&
+ lround (values->content.num->val) == values->content.num->val) {
+
+ border_ptr[i] = (gint) values->content.num->val;
+ values = values->next;
+ }
+ }
+
+ return i == 4;
+}
+
+static bool
+parse_gtk_relief_style (CRTerm const *values,
+ ccss_gtk_property_t *property)
+{
+ char const *str;
+ bool ret;
+
+ g_return_val_if_fail (values && property, false);
+
+ ret = false;
+ switch (values->type) {
+ case TERM_IDENT:
+ case TERM_STRING:
+ ret = true;
+ str = cr_string_peek_raw_str (values->content.str);
+ if (0 == g_ascii_strcasecmp ("normal", str))
+ property->content.gtkreliefstyle_val = GTK_RELIEF_NORMAL;
+ else if (0 == g_ascii_strcasecmp ("half", str))
+ property->content.gtkreliefstyle_val = GTK_RELIEF_HALF;
+ else if (0 == g_ascii_strcasecmp ("none", str))
+ property->content.gtkreliefstyle_val = GTK_RELIEF_NONE;
+ else
+ ret = false;
+ break;
+ default:
+ /* Shut up compiler. */
+ ret = false;
+ }
+
+ return ret;
+}
+
+static bool
+parse_gtk_requisition (CRTerm const *values,
+ ccss_gtk_property_t *property)
+{
+ gint *border_ptr;
+ int i;
+
+ g_return_val_if_fail (values && property, false);
+
+ border_ptr = (gint *) &property->content.gtkrequisition_val;
+ for (i = 0; i < 2; i++) {
+
+ if (!values) {
+ break;
+ }
+
+ /* Be strict about fractionals. */
+ if (TERM_NUMBER == values->type &&
+ lround (values->content.num->val) == values->content.num->val) {
+
+ border_ptr[i] = (gint) values->content.num->val;
+ values = values->next;
+ }
+ }
+
+ return i == 2;
+}
+
+static bool
+parse_gtk_shadow_type (CRTerm const *values,
+ ccss_gtk_property_t *property)
+{
+ char const *str;
+ bool ret;
+
+ g_return_val_if_fail (values && property, false);
+
+ ret = false;
+ switch (values->type) {
+ case TERM_IDENT:
+ case TERM_STRING:
+ ret = true;
+ str = cr_string_peek_raw_str (values->content.str);
+ if (0 == g_ascii_strcasecmp ("none", str))
+ property->content.gtkshadowtype_val = GTK_SHADOW_NONE;
+ else if (0 == g_ascii_strcasecmp ("in", str))
+ property->content.gtkreliefstyle_val = GTK_SHADOW_IN;
+ else if (0 == g_ascii_strcasecmp ("out", str))
+ property->content.gtkreliefstyle_val = GTK_SHADOW_OUT;
+ else if (0 == g_ascii_strcasecmp ("etched-in", str))
+ property->content.gtkreliefstyle_val = GTK_SHADOW_ETCHED_IN;
+ else if (0 == g_ascii_strcasecmp ("etched-out", str))
+ property->content.gtkreliefstyle_val = GTK_SHADOW_ETCHED_OUT;
+ else
+ ret = false;
+ break;
+ default:
+ /* Shut up compiler. */
+ ret = false;
+ }
+
+ return ret;
+}
+
+static bool
+parse_gtk_toolbar_space_style (CRTerm const *values,
+ ccss_gtk_property_t *property)
+{
+ char const *str;
+ bool ret;
+
+ g_return_val_if_fail (values && property, false);
+
+ ret = false;
+ switch (values->type) {
+ case TERM_IDENT:
+ case TERM_STRING:
+ ret = true;
+ str = cr_string_peek_raw_str (values->content.str);
+ if (0 == g_ascii_strcasecmp ("empty", str))
+ property->content.gtktoolbarspacestyle_val = GTK_TOOLBAR_SPACE_EMPTY;
+ else if (0 == g_ascii_strcasecmp ("line", str))
+ property->content.gtktoolbarspacestyle_val = GTK_TOOLBAR_SPACE_LINE;
+ else
+ ret = false;
+ break;
+ default:
+ /* Shut up compiler. */
+ ret = false;
+ }
+
+ return ret;
+}
+
+static bool
+parse_gtk_style_property (ccss_grammar_t const *grammar,
+ char const *name,
+ CRTerm const *values,
+ void *user_data,
+ ccss_gtk_property_t *property)
+{
+ char **tokens;
+ char *class_name = NULL;
+ char *property_name = NULL;
+ GtkBuilder *builder = NULL;
+ GType type = 0;
+ GtkWidget *widget = NULL;
+ GParamSpec *pspec = NULL;
+
+ /* Parse property name. */
+ tokens = g_strsplit (name, "-", 2);
+ if (tokens && tokens[0]) {
+ class_name = tokens[0];
+ } else {
+ goto bail;
+ }
+ if (tokens && tokens[1]) {
+ property_name = tokens[1];
+ } else {
+ goto bail;
+ }
+
+ /* Introspect property type. */
+ builder = gtk_builder_new ();
+ type = gtk_builder_get_type_from_name (builder, class_name);
+ if (0 == type)
+ goto bail;
+
+ widget = GTK_WIDGET (g_object_new (type, NULL));
+ if (NULL == widget)
+ goto bail;
+
+ pspec = gtk_widget_class_find_style_property (GTK_WIDGET_GET_CLASS (widget),
+ property_name);
+ if (NULL == pspec)
+ goto bail;
+
+ /* Parse value. */
+ property->gtype = 0;
+ if (G_TYPE_BOOLEAN == pspec->value_type) {
+ if (parse_gboolean (values, property)) {
+ property->gtype = pspec->value_type;
+ }
+ } else if (G_TYPE_STRING == pspec->value_type) {
+ if (parse_gchararray (values, property)) {
+ property->gtype = pspec->value_type;
+ }
+ } else if (G_TYPE_FLOAT == pspec->value_type) {
+ if (parse_gfloat (values, property)) {
+ property->gtype = pspec->value_type;
+ }
+ } else if (G_TYPE_INT == pspec->value_type) {
+ if (parse_gint (values, property)) {
+ property->gtype = pspec->value_type;
+ }
+ } else if (G_TYPE_UCHAR == pspec->value_type) {
+ if (parse_guchar (values, property)) {
+ property->gtype = pspec->value_type;
+ }
+ } else if (GDK_TYPE_COLOR == pspec->value_type) {
+ if (parse_gdk_color (grammar, values, user_data, property)) {
+ property->gtype = pspec->value_type;
+ }
+ } else if (GTK_TYPE_BORDER == pspec->value_type) {
+ if (parse_gtk_border (values, property)) {
+ property->gtype = pspec->value_type;
+ }
+ } else if (GTK_TYPE_RELIEF_STYLE == pspec->value_type) {
+ if (parse_gtk_relief_style (values, property)) {
+ property->gtype = pspec->value_type;
+ }
+ } else if (GTK_TYPE_REQUISITION == pspec->value_type) {
+ if (parse_gtk_requisition (values, property)) {
+ property->gtype = pspec->value_type;
+ }
+ } else if (GTK_TYPE_SHADOW_TYPE == pspec->value_type) {
+ if (parse_gtk_shadow_type (values, property)) {
+ property->gtype = pspec->value_type;
+ }
+ } else if (GTK_TYPE_TOOLBAR_SPACE_STYLE == pspec->value_type) {
+ if (parse_gtk_toolbar_space_style (values, property)) {
+ property->gtype = pspec->value_type;
+ }
+ } else {
+ g_assert_not_reached ();
+ }
+
+ if (property->gtype) {
+ property->class_name = class_name, class_name = NULL;
+ property->property_name = property_name, property_name = NULL;
+ }
+
+bail:
+ if (tokens)
+ g_free (tokens);
+ if (class_name)
+ g_free (class_name);
+ if (property_name)
+ g_free (property_name);
+ if (builder)
+ g_object_unref (G_OBJECT (builder));
+ if (widget)
+ gtk_widget_destroy (widget);
+
+ return (bool) property->gtype;
+}
+
+static void
+property_destroy (ccss_gtk_property_t *self)
+{
+ g_return_if_fail (self);
+
+ if (G_TYPE_STRING == self->gtype && self->content.gchararray_val) {
+ g_free (self->content.gchararray_val);
+ }
+ g_free (self);
+}
+
+static bool
+property_convert (ccss_gtk_property_t const *self,
+ ccss_property_type_t target,
+ void *value)
+{
+
+ return false;
+}
+
+static bool
+property_factory (ccss_grammar_t const *grammar,
+ ccss_block_t *block,
+ char const *name,
+ CRTerm const *values,
+ void *user_data)
+{
+ ccss_gtk_property_t s, *self;
+
+ g_return_val_if_fail (grammar, false);
+ g_return_val_if_fail (block, false);
+ g_return_val_if_fail (name, false);
+ g_return_val_if_fail (values, false);
+
+ /* PONDERING: Handle things like GtkSettings `gtk-button-images' in the future? */
+
+ memset (&s, 0, sizeof (s));
+ ccss_property_init (&s.base, peek_property_class ());
+
+ self = NULL;
+ if (0 == g_strcmp0 (name, "xthickness")) {
+ if (parse_gint (values, &s)) {
+ s.class_name = NULL;
+ s.property_name = g_strdup ("xthickness");
+ self = g_new0 (ccss_gtk_property_t, 1);
+ *self = s;
+ ccss_block_add_property (block, "xthickness", &self->base);
+ }
+ return (bool) self;
+ } else if (0 == g_strcmp0 (name, "ythickness")) {
+ if (parse_gint (values, &s)) {
+ s.class_name = NULL;
+ s.property_name = g_strdup ("ythickness");
+ self = g_new0 (ccss_gtk_property_t, 1);
+ *self = s;
+ ccss_block_add_property (block, "ythickness", &self->base);
+ }
+ return (bool) self;
+ } else if (g_str_has_prefix (name, "Gtk")) {
+ if (parse_gtk_style_property (grammar, name, values, user_data, &s)) {
+ self = g_new0 (ccss_gtk_property_t, 1);
+ *self = s;
+ ccss_block_add_property (block, name, &self->base);
+ }
+ return (bool) self;
+ } else if (g_ascii_isupper (name[0])) {
+ // TODO introspect style property and feed back to gtk directly.
+ // Non-gtk style properties (wnck, nautilus, ...) can't be
+ // resolved offline because css2gtkrc doesn't link against them.
+ // May cause some breakage, let's see how it goes.
+ // TODO link css2gtkrc against gtk.
+ }
+
+
+ /* Fall back. */
+ g_return_val_if_fail (_fallback_property_class, false);
+ g_return_val_if_fail (_fallback_property_class->property_factory, false);
+ return _fallback_property_class->property_factory (grammar, block, name,
+ values, user_data);
+}
+
+static ccss_property_class_t const _properties[] = {
+ {
+ .name = "*",
+ .property_create = NULL,
+ .property_destroy = (ccss_property_destroy_f) property_destroy,
+ .property_convert = (ccss_property_convert_f) property_convert,
+ .property_factory = property_factory,
+ .property_inherit = NULL
+ }, {
+ .name = NULL
+ }
+};
+
+static ccss_property_class_t const *
+peek_property_class (void)
+{
+ return &_properties[0];
+}
+
+ccss_property_class_t const *
+ccss_gtk_property_get_property_classes (void)
+{
+ return _properties;
+}
+
+void
+ccss_gtk_property_set_fallback_class (ccss_property_class_t const *property_class)
+{
+ g_return_if_fail (property_class);
+
+ _fallback_property_class = property_class;
+}
+
+bool
+ccss_gtk_property_is_style_property (ccss_property_base_t const *self)
+{
+ return self->property_class->property_destroy ==
+ (ccss_property_destroy_f) property_destroy;
+}
+
diff --git a/ccss-gtk/ccss-gtk-property.h b/ccss-gtk/ccss-gtk-property.h
new file mode 100644
index 0000000..1841bea
--- /dev/null
+++ b/ccss-gtk/ccss-gtk-property.h
@@ -0,0 +1,56 @@
+/* The Gtk+ CSS Drawing Library.
+ * Copyright (C) 2008 Robert Staudinger
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <ccss-cairo/ccss-cairo.h>
+#include <gtk/gtk.h>
+
+#ifndef CCSS_GTK_PROPERTY_H
+#define CCSS_GTK_PROPERTY_H
+
+typedef struct {
+ ccss_property_base_t base;
+ char *class_name;
+ char *property_name;
+ GType gtype;
+ union {
+ gboolean gboolean_val;
+ gchararray gchararray_val;
+ gfloat gfloat_val;
+ gint gint_val;
+ guchar guchar_val;
+ GdkColor gdkcolor_val;
+ GtkBorder gtkborder_val;
+ GtkReliefStyle gtkreliefstyle_val;
+ GtkRequisition gtkrequisition_val;
+ GtkShadowType gtkshadowtype_val;
+ GtkToolbarSpaceStyle gtktoolbarspacestyle_val;
+ } content;
+} ccss_gtk_property_t;
+
+bool
+ccss_gtk_property_is_style_property (ccss_property_base_t const *self);
+
+ccss_property_class_t const *
+ccss_gtk_property_get_property_classes (void);
+
+void
+ccss_gtk_property_set_fallback_class (ccss_property_class_t const *property_class);
+
+#endif /* CCSS_GTK_PROPERTY_H */
+
diff --git a/ccss-gtk/ccss-gtk-style.c b/ccss-gtk/ccss-gtk-style.c
deleted file mode 100644
index 1be89a7..0000000
--- a/ccss-gtk/ccss-gtk-style.c
+++ /dev/null
@@ -1,29 +0,0 @@
-/* The Gtk+ CSS Drawing Library.
- * Copyright (C) 2008 Robert Staudinger
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- */
-
-#include "ccss-gtk-style.h"
-#include "config.h"
-
-char *
-ccss_gtk_style_serialize (ccss_style_t const *self)
-{
- /* TODO */
- return NULL;
-}
-
diff --git a/ccss-gtk/ccss-gtk-stylesheet.c b/ccss-gtk/ccss-gtk-stylesheet.c
new file mode 100644
index 0000000..87f2efe
--- /dev/null
+++ b/ccss-gtk/ccss-gtk-stylesheet.c
@@ -0,0 +1,431 @@
+/* The Gtk+ CSS Drawing Library.
+ * Copyright (C) 2008 Robert Staudinger
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <string.h>
+#include "ccss-gtk-property.h"
+#include "ccss-gtk-stylesheet.h"
+#include "config.h"
+
+/*
+ * Node implementation for querying the stylesheet.
+ */
+
+typedef struct {
+ ccss_node_t parent;
+ char const *type_name;
+ char const *id;
+ char const *pseudo_class;
+} Node;
+
+static char const *
+get_type (Node const *self)
+{
+ return self->type_name;
+}
+
+static char const *
+get_id (Node const *self)
+{
+ return self->id;
+}
+
+static char const *
+get_pseudo_class (Node const *self)
+{
+ return self->pseudo_class;
+}
+
+static ccss_node_class_t _node_class = {
+ .is_a = NULL,
+ .get_container = NULL,
+ .get_base_style = NULL,
+ .get_id = (ccss_node_get_id_f) get_id,
+ .get_type = (ccss_node_get_type_f) get_type,
+ .get_class = NULL,
+ .get_pseudo_class = (ccss_node_get_pseudo_class_f) get_pseudo_class,
+ .get_attribute = NULL,
+ .get_viewport = NULL,
+ .release = NULL
+};
+
+/*
+ * Gtkrc creation infrastructure.
+ */
+
+enum { NORMAL = 0, ACTIVE, PRELIGHT, SELECTED, INSENSITIVE, N_STATES };
+enum {
+ FG_SET = 1 << 0,
+ BG_SET = 1 << 1,
+ BASE_SET = 1 << 2,
+ TEXT_SET = 1 << 3
+};
+enum {
+ NORMAL_SET = 1 << 0,
+ ACTIVE_SET = 1 << 1,
+ PRELIGHT_SET = 1 << 2,
+ SELECTED_SET = 1 << 3,
+ INSENSITIVE_SET = 1 << 4
+};
+
+struct RcBlock {
+ struct RcState {
+ char fg[8];
+ char bg[8];
+ char base[8];
+ char text[8];
+ guint flags;
+ } colors[N_STATES];
+ guint flags;
+ char const *type_name;
+ GSList *style_properties;
+};
+
+static void
+style_iterator (ccss_style_t const *style,
+ char const *property_name,
+ GSList **style_properties)
+{
+ ccss_property_base_t const *property;
+ ccss_gtk_property_t const *self;
+ char *prefix;
+ char *rc_string;
+
+ self = NULL;
+ property = NULL;
+ ccss_style_get_property (style, property_name, &property);
+ if (property && ccss_gtk_property_is_style_property (property)) {
+ self = (ccss_gtk_property_t const *) property;
+ } else {
+ return;
+ }
+
+ if (self->class_name) {
+ prefix = g_strdup_printf ("%s::", self->class_name);
+ } else {
+ prefix = g_strdup ("");
+ }
+
+ rc_string = NULL;
+ if (G_TYPE_BOOLEAN == self->gtype) {
+ rc_string = g_strdup_printf ("%s%s = %s",
+ prefix, self->property_name,
+ self->content.gboolean_val ?
+ "TRUE" : "FALSE");
+ } else if (G_TYPE_STRING == self->gtype) {
+ rc_string = g_strdup_printf ("%s%s = \"%s\"",
+ prefix, self->property_name,
+ self->content.gchararray_val);
+ } else if (G_TYPE_FLOAT == self->gtype) {
+ rc_string = g_strdup_printf ("%s%s = %f",
+ prefix, self->property_name,
+ self->content.gfloat_val);
+ } else if (G_TYPE_INT == self->gtype) {
+ rc_string = g_strdup_printf ("%s%s = %d",
+ prefix, self->property_name,
+ self->content.gint_val);
+ } else if (G_TYPE_UCHAR == self->gtype) {
+ rc_string = g_strdup_printf ("%s%s = %d",
+ prefix, self->property_name,
+ self->content.guchar_val);
+ } else if (GDK_TYPE_COLOR == self->gtype) {
+ char *val;
+ val = gdk_color_to_string (&self->content.gdkcolor_val);
+ rc_string = g_strdup_printf ("%s%s = %s",
+ prefix, self->property_name,
+ val);
+ g_free (val);
+ } else if (GTK_TYPE_BORDER == self->gtype) {
+ rc_string = g_strdup_printf ("%s%s = { %d, %d, %d, %d }",
+ prefix, self->property_name,
+ self->content.gtkborder_val.left,
+ self->content.gtkborder_val.right,
+ self->content.gtkborder_val.top,
+ self->content.gtkborder_val.bottom);
+ } else if (GTK_TYPE_RELIEF_STYLE == self->gtype) {
+ char const *val;
+ val = self->content.gtkreliefstyle_val == GTK_RELIEF_NORMAL ? "NORMAL" :
+ self->content.gtkreliefstyle_val == GTK_RELIEF_HALF ? "HALF" :
+ self->content.gtkreliefstyle_val == GTK_RELIEF_NONE ? "NONE" : "";
+ rc_string = g_strdup_printf ("%s%s = %s",
+ prefix, self->property_name,
+ val);
+ } else if (GTK_TYPE_REQUISITION == self->gtype) {
+ rc_string = g_strdup_printf ("%s%s = { %d, %d }",
+ prefix, self->property_name,
+ self->content.gtkrequisition_val.width,
+ self->content.gtkrequisition_val.height);
+ } else if (GTK_TYPE_SHADOW_TYPE == self->gtype) {
+ char const *val;
+ val = self->content.gtkshadowtype_val == GTK_SHADOW_NONE ? "NONE" :
+ self->content.gtkshadowtype_val == GTK_SHADOW_IN ? "IN" :
+ self->content.gtkshadowtype_val == GTK_SHADOW_OUT ? "OUT" :
+ self->content.gtkshadowtype_val == GTK_SHADOW_ETCHED_IN ? "ETCHED_IN" :
+ self->content.gtkshadowtype_val == GTK_SHADOW_ETCHED_OUT ? "ETCHED_OUT" : "";
+ rc_string = g_strdup_printf ("%s%s = %s",
+ prefix, self->property_name,
+ val);
+ } else if (GTK_TYPE_TOOLBAR_SPACE_STYLE == self->gtype) {
+ char const *val;
+ val = self->content.gtktoolbarspacestyle_val == GTK_TOOLBAR_SPACE_EMPTY ? "EMPTY" :
+ self->content.gtktoolbarspacestyle_val == GTK_TOOLBAR_SPACE_LINE ? "LINE" : "";
+ rc_string = g_strdup_printf ("%s%s = %s",
+ prefix, self->property_name,
+ val);
+ } else {
+ g_assert_not_reached ();
+ }
+
+ if (rc_string) {
+ *style_properties = g_slist_prepend (*style_properties, rc_string);
+ }
+}
+
+static gboolean
+accumulate_state (ccss_stylesheet_t *stylesheet,
+ char const *type_name,
+ char const *state_name,
+ struct RcState *state,
+ GSList **style_properties)
+{
+ ccss_style_t *style;
+ Node node;
+ char *color;
+ gboolean ret;
+
+ ccss_node_init ((ccss_node_t *) &node, &_node_class);
+ node.type_name = type_name;
+ node.id = NULL;
+ node.pseudo_class = state_name;
+
+ style = ccss_style_create ();
+ ret = ccss_stylesheet_query (stylesheet,
+ (ccss_node_t const *) &node, style);
+ if (!ret) {
+ return false;
+ }
+
+ color = NULL;
+
+ ret = ccss_style_get_string (style, "color", &color);
+ if (ret && color) {
+ state->flags |= TEXT_SET;
+ strncpy (state->text, color, 8);
+ g_free (color), color = NULL;
+ }
+
+ ret = ccss_style_get_string (style, "background-color", &color);
+ if (ret) {
+ state->flags |= BG_SET;
+ strncpy (state->bg, color, 8);
+ /* FIXME: also setting "base" to the background color, let's see how this works out. */
+ state->flags |= BASE_SET;
+ strncpy (state->base, color, 8);
+ g_free (color), color = NULL;
+ }
+
+ ret = ccss_style_get_string (style, "border-color", &color);
+ if (ret && color) {
+ state->flags |= FG_SET;
+ strncpy (state->fg, color, 8);
+ g_free (color), color = NULL;
+ }
+
+ /* Extract style properties, only for default state. */
+ if (style_properties) {
+ ccss_style_foreach (style, (ccss_style_iterator_f) style_iterator,
+ style_properties);
+ }
+
+ ccss_style_destroy (style), style = NULL;
+
+ /* Having colors or style properties means there's something to serialise. */
+ return (gboolean) state->flags ||
+ (gboolean) (style_properties && *style_properties);
+}
+
+static gboolean
+accumulate (ccss_stylesheet_t *stylesheet,
+ struct RcBlock *block)
+{
+ gboolean ret;
+
+ /* Querying for `normal' state without any- and with the `normal' pseudo class. */
+ ret = accumulate_state (stylesheet, block->type_name, NULL,
+ &block->colors[NORMAL], &block->style_properties);
+ if (ret) {
+ block->flags |= NORMAL_SET;
+ }
+ ret = accumulate_state (stylesheet, block->type_name, "normal",
+ &block->colors[NORMAL], NULL);
+ if (ret) {
+ block->flags |= NORMAL_SET;
+ }
+
+ ret = accumulate_state (stylesheet, block->type_name, "active",
+ &block->colors[ACTIVE], NULL);
+ if (ret) {
+ block->flags |= ACTIVE_SET;
+ }
+
+ ret = accumulate_state (stylesheet, block->type_name, "prelight",
+ &block->colors[PRELIGHT], NULL);
+ if (ret) {
+ block->flags |= PRELIGHT_SET;
+ }
+
+ ret = accumulate_state (stylesheet, block->type_name, "selected",
+ &block->colors[SELECTED], NULL);
+ if (ret) {
+ block->flags |= SELECTED_SET;
+ }
+
+ ret = accumulate_state (stylesheet, block->type_name, "insensitive",
+ &block->colors[INSENSITIVE], NULL);
+ if (ret) {
+ block->flags |= INSENSITIVE_SET;
+ }
+
+ return (gboolean) block->flags;
+}
+
+static void
+serialize_state (struct RcState const *state,
+ char const *state_name,
+ GString *rc_string)
+{
+ if (FG_SET & state->flags) {
+ g_string_append_printf (rc_string, "\tfg[%s] = '%s'\n", state_name, state->fg);
+ }
+
+ if (BG_SET & state->flags) {
+ g_string_append_printf (rc_string, "\tbg[%s] = '%s'\n", state_name, state->bg);
+ }
+
+ if (BASE_SET & state->flags) {
+ g_string_append_printf (rc_string, "\tbase[%s] = '%s'\n", state_name, state->base);
+ }
+
+ if (TEXT_SET & state->flags) {
+ g_string_append_printf (rc_string, "\ttext[%s] = '%s'\n", state_name, state->text);
+ }
+}
+
+static gboolean
+serialize (struct RcBlock const *block,
+ GString *rc_string)
+{
+ GSList const *iter;
+ char *style;
+ char *style_name;
+
+ if (strlen (block->type_name) > 3 &&
+ 0 == strncmp ("Gtk", block->type_name, 3)) {
+ style = g_ascii_strdown (block->type_name + 3, -1);
+ } else if (0 == strcmp ("*", block->type_name)) {
+ style = g_strdup ("default");
+ } else {
+ return FALSE;
+ }
+
+ style_name = g_strdup_printf ("gce-%s", style);
+ g_free (style), style = NULL;
+
+ g_string_append_printf (rc_string, "style \"%s\" {\n", style_name);
+
+ if (NORMAL_SET & block->flags) {
+ serialize_state (&block->colors[NORMAL], "NORMAL", rc_string);
+ }
+
+ if (ACTIVE_SET & block->flags) {
+ serialize_state (&block->colors[ACTIVE], "ACTIVE", rc_string);
+ }
+
+ if (PRELIGHT_SET & block->flags) {
+ serialize_state (&block->colors[PRELIGHT], "PRELIGHT", rc_string);
+ }
+
+ if (SELECTED_SET & block->flags) {
+ serialize_state (&block->colors[SELECTED], "SELECTED", rc_string);
+ }
+
+ if (INSENSITIVE_SET & block->flags) {
+ serialize_state (&block->colors[INSENSITIVE], "INSENSITIVE", rc_string);
+ }
+
+ /* Style properties. */
+ iter = block->style_properties;
+ while (iter) {
+ g_string_append_printf (rc_string, "\t%s\n", (char const *) iter->data);
+ iter = iter->next;
+ }
+
+ g_string_append (rc_string, "}\n");
+
+ g_string_append_printf (rc_string, "class \"%s\" style \"%s\"\n\n", block->type_name, style_name);
+ g_free (style_name), style_name = NULL;
+
+ return TRUE;
+}
+
+static void
+iter_func (ccss_stylesheet_t *stylesheet,
+ char const *type_name,
+ GString *rc_string)
+{
+ struct RcBlock block;
+ gboolean ret;
+
+ /* Only feed widget styles back into gtk, not primitives. */
+ if (strcmp ("*", type_name) != 0 &&
+ strncmp ("Gtk", type_name, 3) != 0) {
+ return;
+ }
+
+ memset (&block, 0, sizeof (block));
+ block.type_name = type_name;
+ ret = accumulate (stylesheet, &block);
+ if (ret) {
+ serialize (&block, rc_string);
+ }
+
+ /* Free style properties. */
+ while (block.style_properties) {
+ g_free (block.style_properties->data);
+ block.style_properties = g_slist_delete_link (block.style_properties,
+ block.style_properties);
+ }
+}
+
+char *
+ccss_gtk_stylesheet_to_gtkrc (ccss_stylesheet_t *self)
+{
+ GString *rc_string;
+ char *str;
+
+ rc_string = g_string_new ("");
+
+ ccss_stylesheet_foreach (self,
+ (ccss_stylesheet_iterator_f) iter_func,
+ rc_string);
+
+ str = rc_string->str;
+ g_string_free (rc_string, FALSE), rc_string = NULL;
+ return str;
+}
+
diff --git a/ccss-gtk/ccss-gtk-style.h b/ccss-gtk/ccss-gtk-stylesheet.h
index de49c18..f35b3a5 100644
--- a/ccss-gtk/ccss-gtk-style.h
+++ b/ccss-gtk/ccss-gtk-stylesheet.h
@@ -17,17 +17,17 @@
* MA 02110-1301, USA.
*/
-#ifndef CCSS_GTK_STYLE_H
-#define CCSS_GTK_STYLE_H
+#ifndef CCSS_GTK_STYLESHEET_H
+#define CCSS_GTK_STYLESHEET_H
#include <ccss-cairo/ccss-cairo.h>
CCSS_BEGIN_DECLS
char *
-ccss_gtk_style_serialize (ccss_style_t const *self);
+ccss_gtk_stylesheet_to_gtkrc (ccss_stylesheet_t *self);
CCSS_END_DECLS
-#endif /* CCSS_GTK_STYLE_H */
+#endif /* CCSS_GTK_STYLESHEET_H */
diff --git a/ccss-gtk/ccss-gtk.h b/ccss-gtk/ccss-gtk.h
index d1a4cf7..a0d209c 100644
--- a/ccss-gtk/ccss-gtk.h
+++ b/ccss-gtk/ccss-gtk.h
@@ -22,7 +22,7 @@
#include <ccss-cairo/ccss-cairo.h>
#include <ccss-gtk/ccss-gtk-grammar.h>
-#include <ccss-gtk/ccss-gtk-style.h>
+#include <ccss-gtk/ccss-gtk-stylesheet.h>
CCSS_BEGIN_DECLS
diff --git a/ccss-gtk/ccss-gtk.sym b/ccss-gtk/ccss-gtk.sym
index 8954eef..cf36f42 100644
--- a/ccss-gtk/ccss-gtk.sym
+++ b/ccss-gtk/ccss-gtk.sym
@@ -1,4 +1,4 @@
ccss_gtk_init
ccss_gtk_shutdown
ccss_gtk_grammar_create
-ccss_gtk_style_serialize
+ccss_gtk_stylesheet_to_gtkrc