diff options
author | Robert Staudinger <robsta@gnome.org> | 2008-12-10 16:36:23 +0100 |
---|---|---|
committer | Robert Staudinger <robsta@gnome.org> | 2008-12-10 16:36:23 +0100 |
commit | 52b13b638a6cf9f9b1f7e079ed90f3d6776d7c64 (patch) | |
tree | 5022a2f666446cab5ca503f20388263784974271 /ccss-gtk | |
parent | a5d66059fc09d64bd3c8928c0d53f30fa54be1e7 (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.am | 6 | ||||
-rw-r--r-- | ccss-gtk/ccss-gtk-grammar.c | 666 | ||||
-rw-r--r-- | ccss-gtk/ccss-gtk-property.c | 570 | ||||
-rw-r--r-- | ccss-gtk/ccss-gtk-property.h | 56 | ||||
-rw-r--r-- | ccss-gtk/ccss-gtk-style.c | 29 | ||||
-rw-r--r-- | ccss-gtk/ccss-gtk-stylesheet.c | 431 | ||||
-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.h | 2 | ||||
-rw-r--r-- | ccss-gtk/ccss-gtk.sym | 2 |
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 |