summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Staudinger <robsta@gnome.org>2009-06-17 17:21:01 +0200
committerRobert Staudinger <robsta@gnome.org>2009-06-17 17:21:01 +0200
commitccfc09b3169069f67fd71d362b71cedbc651628b (patch)
tree745f05dfd50df8c04b8bb1a590c8cb502eb5c13b
parent00ea696be2eefb537975cb1f9beead3fdabab724 (diff)
[ccss-gtk] Move over function hooks from the CSS engine.
-rw-r--r--ccss-gtk/Makefile.am4
-rw-r--r--ccss-gtk/ccss-gtk-color.c255
-rw-r--r--ccss-gtk/ccss-gtk-color.h53
-rw-r--r--ccss-gtk/ccss-gtk-functions.c385
-rw-r--r--ccss-gtk/ccss-gtk-functions.h40
-rw-r--r--ccss-gtk/ccss-gtk-grammar.c2
6 files changed, 739 insertions, 0 deletions
diff --git a/ccss-gtk/Makefile.am b/ccss-gtk/Makefile.am
index fc83a7a..118a339 100644
--- a/ccss-gtk/Makefile.am
+++ b/ccss-gtk/Makefile.am
@@ -29,6 +29,10 @@ libccss_gtk_1_la_LIBADD = \
libccss_gtk_1_la_SOURCES = \
$(headers_DATA) \
+ ccss-gtk-color.c \
+ ccss-gtk-color.h \
+ ccss-gtk-functions.c \
+ ccss-gtk-functions.h \
ccss-gtk-grammar.c \
ccss-gtk-property.c \
ccss-gtk-property.h \
diff --git a/ccss-gtk/ccss-gtk-color.c b/ccss-gtk/ccss-gtk-color.c
new file mode 100644
index 0000000..6e7e3ce
--- /dev/null
+++ b/ccss-gtk/ccss-gtk-color.c
@@ -0,0 +1,255 @@
+/* vim: set ts=8 sw=8 noexpandtab: */
+
+/* The Cairo CSS Drawing Library.
+ * Copyright (C) 2008 Robert Staudinger
+ *
+ * Portions of this file are derived from gtkrc.c, licensed under
+ * the GNU Lesser General Public License; either version 2 of the
+ * License, or (at your option) any later version. Copyright (C)
+ * the GTK+ Team, see the ChangeLog at ftp://ftp.gtk.org/pub/gtk/.
+ *
+ * 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 <gtk/gtk.h>
+#include "ccss-gtk-color.h"
+#include "config.h"
+
+bool
+ccss_gtk_color_lookup (char const *spec,
+ GdkColor *color)
+{
+ GtkSettings *settings;
+ GHashTable *colors;
+ GdkColor *system_color;
+
+ g_return_val_if_fail (spec, FALSE);
+
+ settings = gtk_settings_get_default ();
+ colors = NULL;
+ g_object_get (G_OBJECT (settings), "color-hash", &colors, NULL);
+ g_return_val_if_fail (colors, FALSE);
+
+ system_color = (GdkColor *) g_hash_table_lookup (colors, spec);
+ if (system_color) {
+ color->red = system_color->red;
+ color->green = system_color->green;
+ color->blue = system_color->blue;
+ return TRUE;
+ }
+
+ /* Try to parse the color. */
+ return gdk_color_parse (spec, color);
+}
+
+static void
+rgb_to_hls (gdouble *r,
+ gdouble *g,
+ gdouble *b)
+{
+ gdouble min;
+ gdouble max;
+ gdouble red;
+ gdouble green;
+ gdouble blue;
+ gdouble h, l, s;
+ gdouble delta;
+
+ red = *r;
+ green = *g;
+ blue = *b;
+
+ if (red > green)
+ {
+ if (red > blue)
+ max = red;
+ else
+ max = blue;
+
+ if (green < blue)
+ min = green;
+ else
+ min = blue;
+ }
+ else
+ {
+ if (green > blue)
+ max = green;
+ else
+ max = blue;
+
+ if (red < blue)
+ min = red;
+ else
+ min = blue;
+ }
+
+ l = (max + min) / 2;
+ s = 0;
+ h = 0;
+
+ if (max != min)
+ {
+ if (l <= 0.5)
+ s = (max - min) / (max + min);
+ else
+ s = (max - min) / (2 - max - min);
+
+ delta = max -min;
+ if (red == max)
+ h = (green - blue) / delta;
+ else if (green == max)
+ h = 2 + (blue - red) / delta;
+ else if (blue == max)
+ h = 4 + (red - green) / delta;
+
+ h *= 60;
+ if (h < 0.0)
+ h += 360;
+ }
+
+ *r = h;
+ *g = l;
+ *b = s;
+}
+
+static void
+hls_to_rgb (gdouble *h,
+ gdouble *l,
+ gdouble *s)
+{
+ gdouble hue;
+ gdouble lightness;
+ gdouble saturation;
+ gdouble m1, m2;
+ gdouble r, g, b;
+
+ lightness = *l;
+ saturation = *s;
+
+ if (lightness <= 0.5)
+ m2 = lightness * (1 + saturation);
+ else
+ m2 = lightness + saturation - lightness * saturation;
+ m1 = 2 * lightness - m2;
+
+ if (saturation == 0)
+ {
+ *h = lightness;
+ *l = lightness;
+ *s = lightness;
+ }
+ else
+ {
+ hue = *h + 120;
+ while (hue > 360)
+ hue -= 360;
+ while (hue < 0)
+ hue += 360;
+
+ if (hue < 60)
+ r = m1 + (m2 - m1) * hue / 60;
+ else if (hue < 180)
+ r = m2;
+ else if (hue < 240)
+ r = m1 + (m2 - m1) * (240 - hue) / 60;
+ else
+ r = m1;
+
+ hue = *h;
+ while (hue > 360)
+ hue -= 360;
+ while (hue < 0)
+ hue += 360;
+
+ if (hue < 60)
+ g = m1 + (m2 - m1) * hue / 60;
+ else if (hue < 180)
+ g = m2;
+ else if (hue < 240)
+ g = m1 + (m2 - m1) * (240 - hue) / 60;
+ else
+ g = m1;
+
+ hue = *h - 120;
+ while (hue > 360)
+ hue -= 360;
+ while (hue < 0)
+ hue += 360;
+
+ if (hue < 60)
+ b = m1 + (m2 - m1) * hue / 60;
+ else if (hue < 180)
+ b = m2;
+ else if (hue < 240)
+ b = m1 + (m2 - m1) * (240 - hue) / 60;
+ else
+ b = m1;
+
+ *h = r;
+ *l = g;
+ *s = b;
+ }
+}
+
+bool
+ccss_gtk_color_mix (double factor,
+ GdkColor const *color1,
+ GdkColor const *color2,
+ GdkColor *result)
+{
+ result->red = factor * color1->red + (1.0 - factor) * color2->red;
+ result->green = factor * color1->green + (1.0 - factor) * color2->green;
+ result->blue = factor * color1->blue + (1.0 - factor) * color2->blue;
+
+ return TRUE;
+}
+
+bool
+ccss_gtk_color_shade (double factor,
+ GdkColor *color)
+{
+ gdouble red;
+ gdouble green;
+ gdouble blue;
+
+ red = (gdouble) color->red / 65535.0;
+ green = (gdouble) color->green / 65535.0;
+ blue = (gdouble) color->blue / 65535.0;
+
+ rgb_to_hls (&red, &green, &blue);
+
+ green *= factor;
+ if (green > 1.0)
+ green = 1.0;
+ else if (green < 0.0)
+ green = 0.0;
+
+ blue *= factor;
+ if (blue > 1.0)
+ blue = 1.0;
+ else if (blue < 0.0)
+ blue = 0.0;
+
+ hls_to_rgb (&red, &green, &blue);
+
+ color->red = (guint16) (red * 65535.0);
+ color->green = (guint16) (green * 65535.0);
+ color->blue = (guint16) (blue * 65535.0);
+
+ return TRUE;
+}
+
diff --git a/ccss-gtk/ccss-gtk-color.h b/ccss-gtk/ccss-gtk-color.h
new file mode 100644
index 0000000..01e66cd
--- /dev/null
+++ b/ccss-gtk/ccss-gtk-color.h
@@ -0,0 +1,53 @@
+/* vim: set ts=8 sw=8 noexpandtab: */
+
+/* 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.
+ */
+
+#ifndef CCSS_GTK_COLOR_H
+#define CCSS_GTK_COLOR_H
+
+#ifndef CCSS_GTK_H
+ #ifndef CCSS_GTK_BUILD
+ #error "Only <ccss-gtk/ccss-gtk.h> can be included directly."
+ #endif
+#endif
+
+#include <ccss/ccss.h>
+#include <gdk/gdk.h>
+
+CCSS_BEGIN_DECLS
+
+bool
+ccss_gtk_color_lookup (char const *spec,
+ GdkColor *color);
+
+bool
+ccss_gtk_color_mix (double factor,
+ GdkColor const *color1,
+ GdkColor const *color2,
+ GdkColor *result);
+
+bool
+ccss_gtk_color_shade (double factor,
+ GdkColor *color);
+
+CCSS_END_DECLS
+
+#endif /* CCSS_GTK_COLOR_H */
+
diff --git a/ccss-gtk/ccss-gtk-functions.c b/ccss-gtk/ccss-gtk-functions.c
new file mode 100644
index 0000000..138ebf7
--- /dev/null
+++ b/ccss-gtk/ccss-gtk-functions.c
@@ -0,0 +1,385 @@
+/* vim: set ts=8 sw=8 noexpandtab: */
+
+/* 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/ccss.h>
+#include <gtk/gtk.h>
+#include "ccss-gtk-functions.h"
+#include "ccss-gtk-color.h"
+#include "config.h"
+
+#ifdef CCSS_WITH_SOUP
+#include <libsoup/soup.h>
+#endif
+
+/*
+ * FIXME: make this bullet proof wrt uri scheme.
+ */
+static char *
+url (GSList const *args,
+ void *user_data)
+{
+ char *resolved_path;
+ char *ret;
+#ifdef CCSS_WITH_SOUP
+ char *given_path;
+ SoupURI *uri;
+
+ g_return_val_if_fail (args, NULL);
+
+ given_path = g_strdup_printf ("file:///%s", (char const *) args->data);
+ uri = soup_uri_new (given_path);
+ g_free (given_path), given_path = NULL;
+
+ resolved_path = gtk_rc_find_pixmap_in_path (gtk_settings_get_default (), NULL, uri->path);
+ soup_uri_set_path (uri, resolved_path);
+ g_free (resolved_path), resolved_path = NULL;
+
+ ret = soup_uri_to_string (uri, FALSE);
+ soup_uri_free (uri), uri = NULL;
+#else
+ char const *given_path;
+
+ g_return_val_if_fail (args, NULL);
+
+ given_path = (char const *) args->data;
+ resolved_path = gtk_rc_find_pixmap_in_path (gtk_settings_get_default (), NULL, given_path);
+ ret = g_strdup_printf ("file:///%s", resolved_path);
+ g_free (resolved_path), resolved_path = NULL;
+#endif
+
+ return ret;
+}
+
+static gboolean
+color_walk_r (GdkColor *color,
+ GSList const **args,
+ char const *function)
+{
+ double factor;
+ char const *token;
+ gboolean ret;
+
+ g_return_val_if_fail (*args && (*args)->data, FALSE);
+
+ if (function)
+ token = function;
+ else
+ token = (char const *) (*args)->data;
+
+ if (0 == g_strcmp0 ("rgb(", token)) {
+
+ double red, green, blue;
+
+ if (!function) { *args = (*args)->next; if (!*args) return FALSE; }
+
+ /* red */
+ red = g_ascii_strtod ((char const *) (*args)->data, NULL);
+ *args = (*args)->next; if (!*args) return FALSE;
+
+ /* "," */
+ if (0 != g_strcmp0(",", (char const *) (*args)->data)) return FALSE;
+ *args = (*args)->next; if (!*args) return FALSE;
+
+ /* green */
+ green = g_ascii_strtod ((char const *) (*args)->data, NULL);
+ *args = (*args)->next; if (!*args) return FALSE;
+
+ /* "," */
+ if (0 != g_strcmp0(",", (char const *) (*args)->data)) return FALSE;
+ *args = (*args)->next; if (!*args) return FALSE;
+
+ /* blue */
+ blue = g_ascii_strtod ((char const *) (*args)->data, NULL);
+
+ if (!function) {
+ /* ")" */
+ *args = (*args)->next; if (!*args) return FALSE;
+ if (0 != g_strcmp0(")", (char const *) (*args)->data)) return FALSE;
+ }
+
+ color->red = (guint16) (red * 65535.0);
+ color->green = (guint16) (green * 65535.0);
+ color->blue = (guint16) (blue * 65535.0);
+
+ return TRUE;
+
+ } else if (0 == g_strcmp0 ("gtk-color(", token)) {
+
+ if (!function) { *args = (*args)->next; if (!*args) return FALSE; }
+
+ /* color */
+ ret = ccss_gtk_color_lookup ((char const *) (*args)->data, color);
+
+ if (!function) {
+ /* ")" */
+ *args = (*args)->next; if (!*args) return FALSE;
+ if (0 != g_strcmp0(")", (char const *) (*args)->data)) return FALSE;
+ }
+
+ return ret;
+
+ } else if (0 == g_strcmp0 ("gtk-mix(", token)) {
+
+ GdkColor color1;
+ GdkColor color2;
+
+ if (!function) { *args = (*args)->next; if (!*args) return FALSE; }
+
+ /* factor */
+ factor = g_ascii_strtod ((char const *) (*args)->data, NULL);
+ *args = (*args)->next; if (!*args) return FALSE;
+
+ /* "," */
+ if (0 != g_strcmp0(",", (char const *) (*args)->data)) return FALSE;
+ *args = (*args)->next; if (!*args) return FALSE;
+
+ /* color1 */
+ if (!color_walk_r (&color1, args, NULL)) return FALSE;
+
+ /* "," */
+ if (0 != g_strcmp0(",", (char const *) (*args)->data)) return FALSE;
+ *args = (*args)->next; if (!*args) return FALSE;
+
+ /* color2 */
+ if (!color_walk_r (&color2, args, NULL)) return FALSE;
+
+ if (!function) {
+ /* ")" */
+ *args = (*args)->next; if (!*args) return FALSE;
+ if (0 != g_strcmp0(")", (char const *) (*args)->data)) return FALSE;
+ }
+
+ return ccss_gtk_color_mix (factor, &color1, &color2, color);
+
+ } else if (0 == g_strcmp0 ("gtk-shade(", token)) {
+
+ if (!function) { *args = (*args)->next; if (!*args) return FALSE; }
+
+ /* factor */
+ factor = g_ascii_strtod ((char const *) (*args)->data, NULL);
+ *args = (*args)->next; if (!*args) return FALSE;
+
+ /* "," */
+ if (0 != g_strcmp0(",", (char const *) (*args)->data)) return FALSE;
+ *args = (*args)->next; if (!*args) return FALSE;
+
+ /* color */
+ if (!color_walk_r (color, args, NULL)) return FALSE;
+
+ if (!function) {
+ /* ")" */
+ *args = (*args)->next; if (!*args) return FALSE;
+ if (0 != g_strcmp0(")", (char const *) (*args)->data)) return FALSE;
+ }
+
+ return ccss_gtk_color_shade (factor, color);
+
+ } else if (0 == g_strcmp0 ("gtk-darker(", token)) {
+
+ if (!function) { *args = (*args)->next; if (!*args) return FALSE; }
+
+ /* color */
+ if (!color_walk_r (color, args, NULL)) return FALSE;
+
+ if (!function) {
+ /* ")" */
+ *args = (*args)->next; if (!*args) return FALSE;
+ if (0 != g_strcmp0(")", (char const *) (*args)->data)) return FALSE;
+ }
+
+ return ccss_gtk_color_shade (0.7, color);
+
+ } else if (0 == g_strcmp0 ("gtk-lighter(", token)) {
+
+ if (!function) { *args = (*args)->next; if (!*args) return FALSE; }
+
+ /* color */
+ if (!color_walk_r (color, args, NULL)) return FALSE;
+
+ if (!function) {
+ /* ")" */
+ *args = (*args)->next; if (!*args) return FALSE;
+ if (0 != g_strcmp0(")", (char const *) (*args)->data)) return FALSE;
+ }
+
+ return ccss_gtk_color_shade (1.3, color);
+
+ } else {
+
+ /* Color. */
+ ret = ccss_gtk_color_lookup (token, color);
+ *args = (*args)->next;
+ return ret;
+ }
+
+ return FALSE;
+}
+
+static char *
+dump (GSList const *args)
+{
+ GSList const *iter;
+ GString *str;
+
+ str = g_string_new (NULL);
+
+ for ( iter = args; iter != NULL; iter = iter->next) {
+ g_string_append (str, (char const *) iter->data);
+ }
+
+ return g_string_free (str, FALSE);
+}
+
+static char *
+color (GSList const *args,
+ void *user_data)
+{
+ GdkColor result;
+ gboolean ret;
+
+ g_return_val_if_fail (args && args->data, NULL);
+
+ ret = color_walk_r (&result, &args, "gtk-color(");
+ if (!ret) {
+ char *data;
+ data = dump (args);
+ g_warning ("Color could not be resolved: `gtk-color(%s)'", data);
+ return NULL;
+ }
+
+ return g_strdup_printf ("rgba(%f,%f,%f,1.0)", result.red / 65535.0,
+ result.green / 65535.0,
+ result.blue / 65535.0);
+}
+
+static char *
+mix (GSList const *args,
+ void *user_data)
+{
+ GSList const *iter;
+ GdkColor result;
+ gboolean ret;
+
+ g_return_val_if_fail (args && args->data, NULL);
+
+ iter = args;
+ ret = color_walk_r (&result, &iter, "gtk-mix(");
+ if (!ret) {
+ char *data;
+ data = dump (args);
+ g_warning ("Color could not be resolved: `gtk-mix(%s)'", data);
+ return NULL;
+ }
+
+ return g_strdup_printf ("rgba(%f,%f,%f,1.0)", result.red / 65535.0,
+ result.green / 65535.0,
+ result.blue / 65535.0);
+}
+
+static char *
+shade (GSList const *args,
+ void *user_data)
+{
+ GSList const *iter;
+ GdkColor result;
+ gboolean ret;
+
+ g_return_val_if_fail (args && args->data, NULL);
+
+ iter = args;
+ ret = color_walk_r (&result, &iter, "gtk-shade(");
+ if (!ret) {
+ char *data;
+ data = dump (args);
+ g_warning ("Color could not be resolved: `gtk-shade(%s)'", data);
+ return NULL;
+ }
+
+ return g_strdup_printf ("rgba(%f,%f,%f,1.0)", result.red / 65535.0,
+ result.green / 65535.0,
+ result.blue / 65535.0);
+}
+
+static char *
+lighter (GSList const *args,
+ void *user_data)
+{
+ GSList const *iter;
+ GdkColor result;
+ gboolean ret;
+
+ g_return_val_if_fail (args && args->data, NULL);
+
+ iter = args;
+ ret = color_walk_r (&result, &iter, "gtk-lighter(");
+ if (!ret) {
+ char *data;
+ data = dump (args);
+ g_warning ("Color could not be resolved: `gtk-lighter(%s)'", data);
+ return NULL;
+ }
+
+ return g_strdup_printf ("rgba(%f,%f,%f,1.0)", result.red / 65535.0,
+ result.green / 65535.0,
+ result.blue / 65535.0);
+}
+
+static char *
+darker (GSList const *args,
+ void *user_data)
+{
+ GSList const *iter;
+ GdkColor result;
+ gboolean ret;
+
+ g_return_val_if_fail (args && args->data, NULL);
+
+ iter = args;
+ ret = color_walk_r (&result, &iter, "gtk-darker(");
+ if (!ret) {
+ char *data;
+ data = dump (args);
+ g_warning ("Color could not be resolved: `gtk-darker(%s)'", data);
+ return NULL;
+ }
+
+ return g_strdup_printf ("rgba(%f,%f,%f,1.0)", result.red / 65535.0,
+ result.green / 65535.0,
+ result.blue / 65535.0);
+}
+
+static ccss_function_t const _functions[] =
+{
+ { "url", url, NULL },
+ { "gtk-color", color, NULL },
+ { "gtk-mix", mix, NULL },
+ { "gtk-shade", shade, NULL },
+ { "gtk-lighter", lighter, NULL },
+ { "gtk-darker", darker, NULL },
+ { NULL }
+};
+
+ccss_function_t const *
+ccss_gtk_functions_get_vtable (void)
+{
+ return _functions;
+}
+
diff --git a/ccss-gtk/ccss-gtk-functions.h b/ccss-gtk/ccss-gtk-functions.h
new file mode 100644
index 0000000..b79de14
--- /dev/null
+++ b/ccss-gtk/ccss-gtk-functions.h
@@ -0,0 +1,40 @@
+/* vim: set ts=8 sw=8 noexpandtab: */
+
+/* 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.
+ */
+
+#ifndef CCSS_GTK_FUNCTIONS_H
+#define CCSS_GTK_FUNCTIONS_H
+
+#ifndef CCSS_GTK_H
+ #ifndef CCSS_GTK_BUILD
+ #error "Only <ccss-gtk/ccss-gtk.h> can be included directly."
+ #endif
+#endif
+
+#include <ccss/ccss.h>
+
+CCSS_BEGIN_DECLS
+
+ccss_function_t const * ccss_gtk_functions_get_vtable (void);
+
+CCSS_END_DECLS
+
+#endif /* CCSS_GTK_FUNCTIONS_H */
+
diff --git a/ccss-gtk/ccss-gtk-grammar.c b/ccss-gtk/ccss-gtk-grammar.c
index 6b18bec..e1fe3c0 100644
--- a/ccss-gtk/ccss-gtk-grammar.c
+++ b/ccss-gtk/ccss-gtk-grammar.c
@@ -23,6 +23,7 @@
#include <gtk/gtk.h>
#include <ccss-cairo/ccss-cairo.h>
#include "ccss-gtk-grammar.h"
+#include "ccss-gtk-functions.h"
#include "ccss-gtk-property.h"
#include "config.h"
@@ -49,6 +50,7 @@ ccss_gtk_grammar_create (void)
ccss_gtk_property_set_fallback_class (fallback_property_class);
ccss_grammar_add_properties (self, ccss_gtk_property_get_property_classes ());
+ ccss_grammar_add_functions (self, ccss_gtk_functions_get_vtable ());
return self;
}