[monet/style-stylable] [style/stylable] add MnStyle and MnStylable objects



commit 11f203b1e9cbbd18c3e78c8b004defb0de07f6a7
Author: Thomas Wood <thos gnome org>
Date:   Mon Sep 14 23:22:47 2009 +0100

    [style/stylable] add MnStyle and MnStylable objects

 configure.ac          |    2 +-
 monet/Makefile.am     |   29 ++-
 monet/mn-marshal.list |   12 +
 monet/mn-stylable.c   |  651 ++++++++++++++++++++++++++++++++++++++++
 monet/mn-stylable.h   |   93 ++++++
 monet/mn-style.c      |  797 +++++++++++++++++++++++++++++++++++++++++++++++++
 monet/mn-style.h      |   89 ++++++
 7 files changed, 1671 insertions(+), 2 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index c725406..df5b32b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -12,7 +12,7 @@ AC_HEADER_STDC
 AM_PROG_LIBTOOL
 AM_PATH_GLIB_2_0
 
-PKG_CHECK_MODULES(MONET, [cairo glib-2.0 gobject-2.0])
+PKG_CHECK_MODULES(MONET, [cairo glib-2.0 gobject-2.0 libccss-1 = 0.3.1])
 AC_SUBST(MONET_LIBS)
 AC_SUBST(MONET_CFLAGS)
 
diff --git a/monet/Makefile.am b/monet/Makefile.am
index 7e1ce29..07023f6 100644
--- a/monet/Makefile.am
+++ b/monet/Makefile.am
@@ -1,6 +1,8 @@
 AM_CFLAGS = $(MONET_CFLAGS) $(MONET_MAINTAINER_CFLAGS) -DMONET_COMPILATION
 
 BUILT_SOURCES = \
+	mn-marshal.h \
+	mn-marshal.c \
 	mn-enum-types.h \
 	mn-enum-types.c
 
@@ -12,6 +14,8 @@ source_h = \
 	mn-parts.h \
 	mn-types.h \
 	mn-widget.h \
+	mn-stylable.h \
+	mn-style.h \
 	monet.h
 
 mn-enum-types.h: stamp-mn-enum-types.h Makefile
@@ -36,6 +40,27 @@ mn-enum-types.c: stamp-mn-enum-types.h mn-enum-types.c.in
 	cp xgen-tetc mn-enum-types.c && \
 	rm -f xgen-tetc
 
+# marshal files
+mn-marshal.h: stamp-mn-marshal.h
+	@true
+stamp-mn-marshal.h: Makefile mn-marshal.list
+	$(GLIB_GENMARSHAL) \
+		--prefix=_mn_marshal \
+		--header \
+	$(srcdir)/mn-marshal.list > xgen-tmh && \
+	(cmp -s xgen-tmh mn-marshal.h || cp -f xgen-tmh mn-marshal.h) && \
+	rm -f xgen-tmh && \
+	echo timestamp > $(@F)
+
+mn-marshal.c: Makefile mn-marshal.list
+	(echo "#include \"mn-marshal.h\"" ; \
+	 $(GLIB_GENMARSHAL) \
+		--prefix=_mn_marshal \
+		--body \
+	 $(srcdir)/mn-marshal.list ) > xgen-tmc && \
+	cp -f xgen-tmc mn-marshal.c && \
+	rm -f xgen-tmc
+
 
 lib_LTLIBRARIES = libmonet.la
 libmonet_la_SOURCES = \
@@ -43,6 +68,8 @@ libmonet_la_SOURCES = \
 	$(source_h)	 \
 	mn-color.c	 \
 	monet.c		 \
+	mn-style.c	 \
+	mn-stylable.c	 \
 	mn-widget.c
 
 libmonet_la_LIBADD = $(MONET_LIBS)
@@ -52,7 +79,7 @@ monetinclude_DATA = \
 	$(source_h) \
 	$(top_builddir)/monet/mn-enum-types.h
 
-EXTRA_DIST = $(BUILT_SOURCES)
+EXTRA_DIST = $(BUILT_SOURCES) mn-marshal.list
 CLEANFILES = $(BUILT_SOURCES) $(STAMP_FILES)
 
 -include $(top_srcdir)/git.mk
diff --git a/monet/mn-marshal.list b/monet/mn-marshal.list
new file mode 100644
index 0000000..9b3bed6
--- /dev/null
+++ b/monet/mn-marshal.list
@@ -0,0 +1,12 @@
+VOID:OBJECT
+VOID:VOID
+VOID:PARAM
+VOID:POINTER
+VOID:UINT
+VOID:UINT,UINT
+VOID:OBJECT,OBJECT
+VOID:STRING,OBJECT
+VOID:OBJECT,OBJECT,INT,INT
+VOID:OBJECT,FLOAT,FLOAT,INT,ENUM
+VOID:FLOAT,FLOAT,INT,ENUM
+VOID:FLOAT,FLOAT
diff --git a/monet/mn-stylable.c b/monet/mn-stylable.c
new file mode 100644
index 0000000..632c996
--- /dev/null
+++ b/monet/mn-stylable.c
@@ -0,0 +1,651 @@
+/*
+ * mn-stylable.c: Interface for stylable objects
+ *
+ * Copyright 2008 Intel Corporation
+ * Copyright 2009 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Written by: Emmanuele Bassi <ebassi openedhand com>
+ *             Thomas Wood <thomas linux intel com>
+ *
+ */
+
+/**
+ * SECTION:mn-stylable
+ * @short_description: Interface for stylable objects
+ *
+ * Stylable objects are classes that can have "style properties", that is
+ * properties that can be changed by attaching a #MnStyle to them.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib-object.h>
+#include <gobject/gvaluecollector.h>
+#include <gobject/gobjectnotifyqueue.c>
+
+#include "mn-marshal.h"
+#include "mn-stylable.h"
+
+enum
+{
+  STYLE_CHANGED,
+  STYLE_NOTIFY,
+  CHANGED,
+
+  LAST_SIGNAL
+};
+
+static GObjectNotifyContext property_notify_context = { 0, };
+
+static GParamSpecPool *style_property_spec_pool = NULL;
+
+static GQuark          quark_real_owner         = 0;
+static GQuark          quark_style              = 0;
+
+static guint stylable_signals[LAST_SIGNAL] = { 0, };
+
+static void
+mn_stylable_notify_dispatcher (GObject     *gobject,
+                                 guint        n_pspecs,
+                                 GParamSpec **pspecs)
+{
+  guint i;
+
+  for (i = 0; i < n_pspecs; i++)
+    g_signal_emit (gobject, stylable_signals[STYLE_NOTIFY],
+                   g_quark_from_string (pspecs[i]->name),
+                   pspecs[i]);
+}
+
+static void
+mn_stylable_base_finalize (gpointer g_iface)
+{
+  GList *list, *node;
+
+  list = g_param_spec_pool_list_owned (style_property_spec_pool,
+                                       G_TYPE_FROM_INTERFACE (g_iface));
+
+  for (node = list; node; node = node->next)
+    {
+      GParamSpec *pspec = node->data;
+
+      g_param_spec_pool_remove (style_property_spec_pool, pspec);
+      g_param_spec_unref (pspec);
+    }
+
+  g_list_free (list);
+}
+
+#define MN_PARAM_READONLY G_PARAM_READABLE | G_PARAM_STATIC_STRINGS
+#define MN_PARAM_READWRITE G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS
+static void
+mn_stylable_base_init (gpointer g_iface)
+{
+  static gboolean initialised = FALSE;
+  GParamSpec *pspec;
+  GType iface_type = G_TYPE_FROM_INTERFACE (g_iface);
+
+  if (G_LIKELY (initialised))
+    return;
+
+  initialised = TRUE;
+
+  quark_real_owner =
+    g_quark_from_static_string ("mn-stylable-real-owner-quark");
+  quark_style = g_quark_from_static_string ("mn-stylable-style-quark");
+
+  style_property_spec_pool = g_param_spec_pool_new (FALSE);
+
+  property_notify_context.quark_notify_queue =
+    g_quark_from_static_string ("MnStylable-style-property-notify-queue");
+  property_notify_context.dispatcher = mn_stylable_notify_dispatcher;
+
+  pspec = g_param_spec_object ("style",
+                               "Style",
+                               "A style object",
+                               MN_TYPE_STYLE,
+                               MN_PARAM_READWRITE);
+  g_object_interface_install_property (g_iface, pspec);
+
+  pspec = g_param_spec_string ("type",
+                               "Type",
+                               "String representation of the item's type",
+                               "",
+                               MN_PARAM_READWRITE);
+  g_object_interface_install_property (g_iface, pspec);
+
+  pspec = g_param_spec_string ("class",
+                               "Class",
+                               "String representation of the item's class",
+                               "",
+                               MN_PARAM_READWRITE);
+  g_object_interface_install_property (g_iface, pspec);
+
+  pspec = g_param_spec_string ("id",
+                               "id",
+                               "String representation of the item's name",
+                               "",
+                               MN_PARAM_READWRITE);
+  g_object_interface_install_property (g_iface, pspec);
+
+  pspec = g_param_spec_string ("pseudo-class",
+                               "Pseudo Class",
+                               "Pseudo class, such as current state",
+                               "",
+                               MN_PARAM_READWRITE);
+  g_object_interface_install_property (g_iface, pspec);
+
+  /**
+   * MnStylable::style-changed:
+   * @stylable: the #MnStylable that received the signal
+   * @old_style: the previously set #MnStyle for @stylable
+   *
+   * The ::style-changed signal is emitted each time one of the style
+   * properties have changed.
+   */
+  stylable_signals[STYLE_CHANGED] =
+    g_signal_new ("style-changed",
+                  iface_type,
+                  G_SIGNAL_RUN_FIRST,
+                  G_STRUCT_OFFSET (MnStylableIface, style_changed),
+                  NULL, NULL,
+                  _mn_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+
+  /**
+   * MnStylable::stylable-changed:
+   * @actor: the actor that received the signal
+   *
+   * The ::changed signal is emitted each time any of the properties of the
+   * stylable has changed.
+   */
+  stylable_signals[CHANGED] =
+    g_signal_new ("stylable-changed",
+                  iface_type,
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (MnStylableIface, stylable_changed),
+                  NULL, NULL,
+                  _mn_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+
+  stylable_signals[STYLE_NOTIFY] =
+    g_signal_new ("style-notify",
+                  iface_type,
+                  G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED | G_SIGNAL_NO_HOOKS | G_SIGNAL_ACTION,
+                  G_STRUCT_OFFSET (MnStylableIface, style_notify),
+                  NULL, NULL,
+                  _mn_marshal_VOID__PARAM,
+                  G_TYPE_NONE, 1,
+                  G_TYPE_PARAM);
+}
+
+GType
+mn_stylable_get_type (void)
+{
+  static GType our_type = 0;
+
+  if (G_UNLIKELY (our_type == 0))
+    {
+      GTypeInfo stylable_info = {
+        sizeof (MnStylableIface),
+        mn_stylable_base_init,
+        mn_stylable_base_finalize
+      };
+
+      our_type = g_type_register_static (G_TYPE_INTERFACE,
+                                         "MnStylable",
+                                         &stylable_info, 0);
+    }
+
+  return our_type;
+}
+
+void
+mn_stylable_freeze_notify (MnStylable *stylable)
+{
+  g_return_if_fail (MN_IS_STYLABLE (stylable));
+
+  g_object_ref (stylable);
+  g_object_notify_queue_freeze (G_OBJECT (stylable), &property_notify_context);
+  g_object_unref (stylable);
+}
+
+void
+mn_stylable_thaw_notify (MnStylable *stylable)
+{
+  GObjectNotifyQueue *nqueue;
+
+  g_return_if_fail (MN_IS_STYLABLE (stylable));
+
+  g_object_ref (stylable);
+
+  nqueue = g_object_notify_queue_from_object (G_OBJECT (stylable),
+                                              &property_notify_context);
+
+  if (!nqueue || !nqueue->freeze_count)
+    g_warning ("%s: property-changed notification for %s(%p) is not frozen",
+               G_STRFUNC, G_OBJECT_TYPE_NAME (stylable), stylable);
+  else
+    g_object_notify_queue_thaw (G_OBJECT (stylable), nqueue);
+
+  g_object_unref (stylable);
+}
+
+void
+mn_stylable_notify (MnStylable *stylable,
+                      const gchar  *property_name)
+{
+  GParamSpec *pspec;
+    
+  g_return_if_fail (MN_IS_STYLABLE (stylable));
+  g_return_if_fail (property_name != NULL);
+
+  g_object_ref (stylable);
+
+  pspec = g_param_spec_pool_lookup (style_property_spec_pool,
+                                    property_name,
+                                    G_OBJECT_TYPE (stylable),
+                                    TRUE);
+
+  if (!pspec)
+    g_warning ("%s: object class `%s' has no style property named `%s'",
+               G_STRFUNC,
+               G_OBJECT_TYPE_NAME (stylable),
+               property_name);
+  else
+    {
+      GObjectNotifyQueue *nqueue;
+      
+      nqueue = g_object_notify_queue_freeze (G_OBJECT (stylable),
+                                              &property_notify_context);
+      g_object_notify_queue_add (G_OBJECT (stylable), nqueue, pspec);
+      g_object_notify_queue_thaw (G_OBJECT (stylable), nqueue);
+    }
+
+  g_object_unref (stylable);
+}
+
+/**
+ * mn_stylable_iface_install_property:
+ * @iface: a #MnStylableIface
+ * @owner_type: #GType of the style property owner
+ * @pspec: a #GParamSpec
+ *
+ * Installs a property for @owner_type using @pspec as the property
+ * description.
+ *
+ * This function should be used inside the #MnStylableIface initialization
+ * function of a class, for instance:
+ *
+ * <informalexample><programlisting>
+ * G_DEFINE_TYPE_WITH_CODE (FooActor, foo_actor, CLUTTER_TYPE_ACTOR,
+ *                          G_IMPLEMENT_INTERFACE (MN_TYPE_STYLABLE,
+ *                                                 mn_stylable_init));
+ * ...
+ * static void
+ * mn_stylable_init (MnStylableIface *iface)
+ * {
+ *   static gboolean is_initialized = FALSE;
+ *
+ *   if (!is_initialized)
+ *     {
+ *       ...
+ *       mn_stylable_iface_install_property (stylable,
+ *                                             FOO_TYPE_ACTOR,
+ *                                             g_param_spec_int ("x-spacing",
+ *                                                               "X Spacing",
+ *                                                               "Horizontal spacing",
+ *                                                               -1, G_MAXINT,
+ *                                                               2,
+ *                                                               G_PARAM_READWRITE));
+ *       ...
+ *     }
+ * }
+ * </programlisting></informalexample>
+ */
+void
+mn_stylable_iface_install_property (MnStylableIface *iface,
+                                      GType              owner_type,
+                                      GParamSpec        *pspec)
+{
+  g_return_if_fail (MN_IS_STYLABLE_IFACE (iface));
+  g_return_if_fail (owner_type != G_TYPE_INVALID);
+  g_return_if_fail (G_IS_PARAM_SPEC (pspec));
+  g_return_if_fail (pspec->flags & G_PARAM_READABLE);
+  g_return_if_fail (!(pspec->flags & (G_PARAM_CONSTRUCT_ONLY | G_PARAM_CONSTRUCT
+)));
+
+  if (g_param_spec_pool_lookup (style_property_spec_pool, pspec->name,
+                                owner_type,
+                                FALSE))
+    {
+      g_warning ("%s: class `%s' already contains a style property named `%s'",
+                 G_STRLOC,
+                 g_type_name (owner_type),
+                 pspec->name);
+      return;
+    }
+
+  g_param_spec_ref_sink (pspec);
+  g_param_spec_set_qdata_full (pspec, quark_real_owner,
+                               g_strdup (g_type_name (owner_type)),
+                               g_free);
+
+  g_param_spec_pool_insert (style_property_spec_pool,
+                            pspec,
+                            owner_type);
+}
+
+/**
+ * mn_stylable_list_properties:
+ * @stylable: a #MnStylable
+ * @n_props: return location for the number of properties, or %NULL
+ *
+ * Retrieves all the #GParamSpec<!-- -->s installed by @stylable.
+ *
+ * Return value: an array of #GParamSpec<!-- -->s. Free it with
+ *   g_free() when done.
+ */
+GParamSpec **
+mn_stylable_list_properties (MnStylable *stylable,
+                               guint        *n_props)
+{
+  GParamSpec **pspecs = NULL;
+  guint n;
+
+  g_return_val_if_fail (MN_IS_STYLABLE (stylable), NULL);
+
+  pspecs = g_param_spec_pool_list (style_property_spec_pool,
+                                   G_OBJECT_TYPE (stylable),
+                                   &n);
+  if (n_props)
+    *n_props = n;
+
+  return pspecs;
+}
+
+/**
+ * mn_stylable_find_property:
+ * @stylable: a #MnStylable
+ * @property_name: the name of the property to find
+ *
+ * Finds the #GParamSpec installed by @stylable for the property
+ * with @property_name.
+ *
+ * Return value: a #GParamSpec for the given property, or %NULL if
+ *   no property with that name was found
+ */
+GParamSpec *
+mn_stylable_find_property (MnStylable *stylable,
+                             const gchar  *property_name)
+{
+  g_return_val_if_fail (MN_IS_STYLABLE (stylable), NULL);
+  g_return_val_if_fail (property_name != NULL, NULL);
+
+  return g_param_spec_pool_lookup (style_property_spec_pool,
+                                   property_name,
+                                   G_OBJECT_TYPE (stylable),
+                                   TRUE);
+}
+
+static inline void
+mn_stylable_get_property_internal (MnStylable *stylable,
+                                     GParamSpec   *pspec,
+                                     GValue       *value)
+{
+  MnStyle *style;
+  GValue real_value = { 0, };
+
+  style = mn_stylable_get_style (stylable);
+
+  if (!style)
+    {
+      g_value_reset (value);
+      return;
+    }
+
+  mn_style_get_property (style, stylable, pspec, &real_value);
+
+  g_value_copy (&real_value, value);
+  g_value_unset (&real_value);
+
+}
+
+/**
+ * mn_stylable_get_property:
+ * @stylable: a #MnStylable
+ * @property_name: the name of the property
+ * @value: return location for an empty #GValue
+ *
+ * Retrieves the value of @property_name for @stylable, and puts it
+ * into @value.
+ */
+void
+mn_stylable_get_property (MnStylable *stylable,
+                            const gchar  *property_name,
+                            GValue       *value)
+{
+  GParamSpec *pspec;
+
+  g_return_if_fail (MN_IS_STYLABLE (stylable));
+  g_return_if_fail (property_name != NULL);
+  g_return_if_fail (value != NULL);
+
+  pspec = mn_stylable_find_property (stylable, property_name);
+  if (!pspec)
+    {
+      g_warning ("Stylable class `%s' doesn't have a property named `%s'",
+                 g_type_name (G_OBJECT_TYPE (stylable)),
+                 property_name);
+      return;
+    }
+
+  if (!(pspec->flags & G_PARAM_READABLE))
+    {
+      g_warning ("Style property `%s' of class `%s' is not readable",
+                 pspec->name,
+                 g_type_name (G_OBJECT_TYPE (stylable)));
+      return;
+    }
+
+  if (G_VALUE_TYPE (value) != G_PARAM_SPEC_VALUE_TYPE (pspec))
+    {
+      g_warning ("Passed value is not of the requested type `%s' for "
+                 "the style property `%s' of class `%s'",
+                 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
+                 pspec->name,
+                 g_type_name (G_OBJECT_TYPE (stylable)));
+      return;
+    }
+
+  mn_stylable_get_property_internal (stylable, pspec, value);
+}
+
+/**
+ * mn_stylable_get:
+ * @stylable: a #MnStylable
+ * @first_property_name: name of the first property to get
+ * @Varargs: return location for the first property, followed optionally
+ *   by more name/return location pairs, followed by %NULL
+ *
+ * Gets the style properties for @stylable.
+ *
+ * In general, a copy is made of the property contents and the called
+ * is responsible for freeing the memory in the appropriate manner for
+ * the property type.
+ *
+ * <example>
+ * <title>Using mn_stylable_get(<!-- -->)</title>
+ * <para>An example of using mn_stylable_get() to get the contents of
+ * two style properties - one of type #G_TYPE_INT and one of type
+ * #CLUTTER_TYPE_COLOR:</para>
+ * <programlisting>
+ *   gint x_spacing;
+ *   ClutterColor *bg_color;
+ *
+ *   mn_stylable_get (stylable,
+ *                      "x-spacing", &amp;x_spacing,
+ *                      "bg-color", &amp;bg_color,
+ *                      NULL);
+ *
+ *   /<!-- -->* do something with x_spacing and bg_color *<!-- -->/
+ *
+ *   clutter_color_free (bg_color);
+ * </programlisting>
+ * </example>
+ */
+void
+mn_stylable_get (MnStylable *stylable,
+                   const gchar  *first_property_name,
+                                 ...)
+{
+  MnStyle *style;
+  va_list args;
+
+  g_return_if_fail (MN_IS_STYLABLE (stylable));
+  g_return_if_fail (first_property_name != NULL);
+
+  style = mn_stylable_get_style (stylable);
+
+  va_start (args, first_property_name);
+  mn_style_get_valist (style, stylable, first_property_name, args);
+  va_end (args);
+}
+
+/**
+ * mn_stylable_get_default_value:
+ * @stylable: a #MnStylable
+ * @property_name: name of the property to query
+ * @value_out: return location for the default value
+ *
+ * Query @stylable for the default value of property @property_name and
+ * fill @value_out with the result.
+ *
+ * Returns: %TRUE if property @property_name exists and the default value has
+ * been returned.
+ */
+gboolean
+mn_stylable_get_default_value (MnStylable  *stylable,
+                                 const gchar   *property_name,
+                                 GValue        *value_out)
+{
+  GParamSpec *pspec;
+
+  pspec = mn_stylable_find_property (stylable, property_name);
+  if (!pspec)
+    {
+      g_warning ("%s: no style property named `%s' found for class `%s'",
+                  G_STRLOC,
+                  property_name,
+                  g_type_name (G_OBJECT_TYPE (stylable)));
+      return FALSE;
+    }
+
+  if (!(pspec->flags & G_PARAM_READABLE))
+    {
+      g_warning ("Style property `%s' of class `%s' is not readable",
+                  pspec->name,
+                  g_type_name (G_OBJECT_TYPE (stylable)));
+      return FALSE;
+    }
+
+  g_value_init (value_out, G_PARAM_SPEC_VALUE_TYPE (pspec));
+  g_param_value_set_default (pspec, value_out);
+  return TRUE;
+}
+
+/**
+ * mn_stylable_get_style:
+ * @stylable: a #MnStylable
+ *
+ * Retrieves the #MnStyle used by @stylable. This function does not
+ * alter the reference count of the returned object.
+ *
+ * Return value: a #MnStyle
+ */
+MnStyle *
+mn_stylable_get_style (MnStylable *stylable)
+{
+  MnStylableIface *iface;
+
+  g_return_val_if_fail (MN_IS_STYLABLE (stylable), NULL);
+
+  iface = MN_STYLABLE_GET_IFACE (stylable);
+  if (iface->get_style)
+    return iface->get_style (stylable);
+
+  return g_object_get_data (G_OBJECT (stylable), "mn-stylable-style");
+}
+
+/**
+ * mn_stylable_set_style:
+ * @stylable: a #MnStylable
+ * @style: a #MnStyle
+ *
+ * Sets @style as the new #MnStyle to be used by @stylable.
+ *
+ * The #MnStylable will take ownership of the passed #MnStyle.
+ *
+ * After the #MnStle has been set, the MnStylable::style-set signal
+ * will be emitted.
+ */
+void
+mn_stylable_set_style (MnStylable *stylable,
+                         MnStyle    *style)
+{
+  MnStylableIface *iface;
+  MnStyle *old_style;
+
+  g_return_if_fail (MN_IS_STYLABLE (stylable));
+  g_return_if_fail (MN_IS_STYLE (style));
+
+  iface = MN_STYLABLE_GET_IFACE (stylable);
+
+  old_style = mn_stylable_get_style (stylable);
+  g_object_ref (old_style);
+
+  if (iface->set_style)
+    iface->set_style (stylable, style);
+  else
+    {
+      g_object_set_qdata_full (G_OBJECT (stylable),
+                               quark_style,
+                               g_object_ref_sink (style),
+                               g_object_unref);
+    }
+
+  g_signal_emit (stylable, stylable_signals[STYLE_CHANGED], 0, old_style);
+  g_object_unref (old_style);
+
+  g_object_notify (G_OBJECT (stylable), "style");
+}
+
+/**
+ * mn_stylable_changed:
+ * @stylable: A #MnStylable
+ *
+ * Emit the "stylable-changed" signal on @stylable
+ */
+void
+mn_stylable_changed (MnStylable *stylable)
+{
+  g_signal_emit (stylable, stylable_signals[CHANGED], 0, NULL);
+}
diff --git a/monet/mn-stylable.h b/monet/mn-stylable.h
new file mode 100644
index 0000000..1e1a7d4
--- /dev/null
+++ b/monet/mn-stylable.h
@@ -0,0 +1,93 @@
+/*
+ * mn-stylable.h: Interface for stylable objects
+ *
+ * Copyright 2008, 2009 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * Boston, MA 02111-1307, USA.
+ *
+ * Written by: Emmanuele Bassi <ebassi openedhand com>
+ *             Thomas Wood <thomas linux intel com>
+ *
+ */
+
+#ifndef __MN_STYLABLE_H__
+#define __MN_STYLABLE_H__
+
+#include <glib-object.h>
+#include <mn-style.h>
+
+G_BEGIN_DECLS
+
+#define MN_TYPE_STYLABLE              (mn_stylable_get_type ())
+#define MN_STYLABLE(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), MN_TYPE_STYLABLE, MnStylable))
+#define MN_IS_STYLABLE(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MN_TYPE_STYLABLE))
+#define MN_STYLABLE_IFACE(iface)      (G_TYPE_CHECK_CLASS_CAST ((iface), MN_TYPE_STYLABLE, MnStylableIface))
+#define MN_IS_STYLABLE_IFACE(iface)   (G_TYPE_CHECK_CLASS_TYPE ((iface), MN_TYPE_STYLABLE))
+#define MN_STYLABLE_GET_IFACE(obj)    (G_TYPE_INSTANCE_GET_INTERFACE ((obj), MN_TYPE_STYLABLE, MnStylableIface))
+
+/* MnStylableIface is defined in mn-style.h */
+
+struct _MnStylableIface
+{
+  GTypeInterface g_iface;
+
+  /* virtual functions */
+  MnStyle *(* get_style) (MnStylable *stylable);
+  void     (* set_style) (MnStylable *stylable,
+                          MnStyle    *style);
+
+  /* context virtual functions */
+
+  /* signals, not vfuncs */
+  void (* style_notify)     (MnStylable *stylable,
+                             GParamSpec   *pspec);
+  void (* style_changed)    (MnStylable *stylable);
+
+  void (* stylable_changed) (MnStylable *stylable);
+};
+
+GType        mn_stylable_get_type               (void) G_GNUC_CONST;
+
+void         mn_stylable_iface_install_property (MnStylableIface *iface,
+                                                 GType              owner_type,
+                                                 GParamSpec        *pspec);
+
+void         mn_stylable_freeze_notify          (MnStylable      *stylable);
+void         mn_stylable_notify                 (MnStylable      *stylable,
+                                                 const gchar       *property_name);
+void         mn_stylable_thaw_notify            (MnStylable      *stylable);
+GParamSpec **mn_stylable_list_properties        (MnStylable      *stylable,
+                                                 guint             *n_props);
+GParamSpec * mn_stylable_find_property          (MnStylable      *stylable,
+                                                 const gchar       *property_name);
+void         mn_stylable_set_style              (MnStylable      *stylable,
+                                                 MnStyle         *style);
+MnStyle *    mn_stylable_get_style              (MnStylable      *stylable);
+
+void         mn_stylable_get                    (MnStylable      *stylable,
+                                                 const gchar       *first_property_name,
+                                                 ...) G_GNUC_NULL_TERMINATED;
+void         mn_stylable_get_property           (MnStylable      *stylable,
+                                                 const gchar       *property_name,
+                                                 GValue            *value);
+gboolean     mn_stylable_get_default_value      (MnStylable      *stylable,
+                                                 const gchar       *property_name,
+                                                 GValue            *value_out);
+
+
+void mn_stylable_changed (MnStylable *stylable);
+G_END_DECLS
+
+#endif /* __MN_STYLABLE_H__ */
diff --git a/monet/mn-style.c b/monet/mn-style.c
new file mode 100644
index 0000000..44a2d61
--- /dev/null
+++ b/monet/mn-style.c
@@ -0,0 +1,797 @@
+/*
+ * Copyright 2009 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+/**
+ * SECTION:mn-style
+ * @short_description: a data store for style properties
+ *
+ * #MnStyle is a property data store that can read properties from a style
+ * sheet. It is queried with objects that implement the MnStylable
+ * interface.
+ */
+
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib-object.h>
+#include <gobject/gvaluecollector.h>
+
+#include <ccss/ccss.h>
+
+#include "mn-stylable.h"
+
+#include "mn-marshal.h"
+#include "mn-style.h"
+#include "mn-types.h"
+#include "mn-color.h"
+
+enum
+{
+  CHANGED,
+
+  LAST_SIGNAL
+};
+
+#define MN_STYLE_GET_PRIVATE(obj) \
+        (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MN_TYPE_STYLE, MnStylePrivate))
+
+#define MN_STYLE_ERROR g_style_error_quark ()
+
+typedef struct {
+  GType value_type;
+  gchar *value_name;
+  GValue value;
+} StyleProperty;
+
+struct _MnStylePrivate
+{
+  ccss_stylesheet_t *stylesheet;
+  GList *image_paths;
+
+  GHashTable *style_hash;
+  GHashTable *node_hash;
+};
+
+typedef struct {
+  ccss_node_t parent;
+
+  gchar *id;
+  gchar *class;
+  gchar *type;
+  gchar *pseudo_class;
+
+  MnStylable *stylable;
+  MnStylableIface *iface;
+} mn_style_node_t;
+
+static ccss_function_t const * peek_css_functions (void);
+
+static ccss_node_class_t * peek_node_class (void);
+
+static guint style_signals[LAST_SIGNAL] = { 0, };
+
+static MnStyle *default_style = NULL;
+
+G_DEFINE_TYPE (MnStyle, mn_style, G_TYPE_OBJECT);
+
+static GQuark
+g_style_error_quark (void)
+{
+  return g_quark_from_static_string ("mn-style-error-quark");
+}
+
+static gboolean
+mn_style_real_load_from_file (MnStyle    *style,
+                                const gchar  *filename,
+                                GError      **error,
+                                gint          priority)
+{
+  MnStylePrivate *priv;
+  ccss_grammar_t *grammar;
+  GError *internal_error;
+  gchar *path;
+  GList *l;
+
+  g_return_val_if_fail (MN_IS_STYLE (style), FALSE);
+  g_return_val_if_fail (filename != NULL, FALSE);
+
+  priv = MN_STYLE (style)->priv;
+
+  if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR))
+    {
+      internal_error = g_error_new (MN_STYLE_ERROR,
+                                    MN_STYLE_ERROR_INVALID_FILE,
+                                    "Invalid theme file '%s'", filename);
+      g_propagate_error (error, internal_error);
+      return FALSE;
+    }
+
+
+  /* add the path of the stylesheet to the search path */
+  path = g_path_get_dirname (filename);
+
+  /* make sure path is valid */
+  if (!path)
+    return TRUE;
+
+  for (l = priv->image_paths; l; l = l->next)
+    {
+      if (g_str_equal ((gchar *)l->data, path))
+        {
+          /* we have this path already */
+          g_free (path);
+          path = NULL;
+        }
+    }
+
+  /* Add the new path */
+  if (path)
+    priv->image_paths = g_list_append (priv->image_paths, path);
+
+  /* now load the stylesheet */
+  if (!priv->stylesheet)
+    {
+      grammar = ccss_grammar_create_css ();
+      ccss_grammar_add_functions (grammar, peek_css_functions ());
+      priv->stylesheet = ccss_grammar_create_stylesheet_from_file (grammar,
+                                                                   filename,
+                                                                   path);
+      ccss_grammar_destroy (grammar);
+    }
+  else
+    {
+      ccss_stylesheet_add_from_file (priv->stylesheet, filename, priority, path);
+    }
+
+  g_signal_emit (style, style_signals[CHANGED], 0, NULL);
+
+  return TRUE;
+}
+
+/**
+ * mn_style_load_from_file:
+ * @style: a #MnStyle
+ * @filename: filename of the style sheet to load
+ * @error: a #GError or #NULL
+ *
+ * Load style information from the specified file.
+ *
+ * returns: TRUE if the style information was loaded successfully. Returns
+ * FALSE on error.
+ */
+gboolean
+mn_style_load_from_file (MnStyle    *style,
+                           const gchar  *filename,
+                           GError      **error)
+{
+  return mn_style_real_load_from_file (style, filename, error,
+                                         CCSS_STYLESHEET_AUTHOR);
+}
+
+static void
+mn_style_load (MnStyle *style)
+{
+  const gchar *env_var;
+  gchar *rc_file = NULL;
+  GError *error;
+
+  env_var = g_getenv ("MN_RC_FILE");
+  if (env_var && *env_var)
+    rc_file = g_strdup (env_var);
+
+  /*
+  if (!rc_file)
+    rc_file = g_build_filename (PACKAGE_DATA_DIR,
+                                "mn",
+                                "style",
+                                "default.css",
+                                NULL);
+  */
+
+  error = NULL;
+
+  if (g_file_test (rc_file, G_FILE_TEST_EXISTS))
+    {
+      /* load the default theme with lowest priority */
+      if (!mn_style_real_load_from_file (style, rc_file, &error, CCSS_STYLESHEET_USER_AGENT))
+        {
+          g_critical ("Unable to load resource file '%s': %s",
+                      rc_file,
+                      error->message);
+          g_error_free (error);
+        }
+    }
+
+  g_free (rc_file);
+}
+
+static void
+mn_style_finalize (GObject *gobject)
+{
+  MnStylePrivate *priv = ((MnStyle *)gobject)->priv;
+  GList *l;
+
+  for (l = priv->image_paths; l; l = g_list_delete_link (l, l))
+  {
+    g_free (l->data);
+  }
+
+  G_OBJECT_CLASS (mn_style_parent_class)->finalize (gobject);
+}
+
+static void
+mn_style_class_init (MnStyleClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (MnStylePrivate));
+
+  gobject_class->finalize = mn_style_finalize;
+
+  /**
+   * MnStyle::changed:
+   *
+   * Indicates that the style data has changed in some way. For example, a new
+   * stylesheet may have been loaded.
+   */
+
+  style_signals[CHANGED] =
+    g_signal_new ("changed",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (MnStyleClass, changed),
+                  NULL, NULL,
+                  _mn_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+}
+
+/* url loader for libccss */
+static char *
+ccss_url (GSList const  *args,
+          void          *user_data)
+{
+  const gchar *given_path, *filename;
+  gchar *test_path;
+
+  g_return_val_if_fail (args, NULL);
+
+  given_path = (char const *) args->data;
+
+  /* we can only deal with local paths */
+  if (!g_str_has_prefix (given_path, "file://"))
+    return NULL;
+  filename = &given_path[7];
+
+  /*
+   * Handle absolute paths correctly
+   */
+  if (*filename == '/')
+    return strdup (filename);
+
+  /* first try looking in the theme dir */
+  test_path = g_build_filename (g_get_user_config_dir (),
+                                "mn",
+                                filename,
+                                NULL);
+  if (g_file_test (test_path, G_FILE_TEST_IS_REGULAR))
+    return test_path;
+  g_free (test_path);
+
+  if (user_data)
+    {
+      test_path = g_build_filename ((gchar *) user_data, filename, NULL);
+
+      if (g_file_test (test_path, G_FILE_TEST_IS_REGULAR))
+        return test_path;
+
+      g_free (test_path);
+    }
+  else
+    {
+      g_warning ("No path available css url resolver!");
+    }
+
+  /* couldn't find the image anywhere, so just return the filename */
+  return strdup (given_path);
+}
+
+static ccss_function_t const *
+peek_css_functions (void)
+{
+  static ccss_function_t const ccss_functions[] =
+  {
+    { "url", ccss_url },
+    { NULL }
+  };
+
+  return ccss_functions;
+}
+
+
+static void
+mn_style_init (MnStyle *style)
+{
+  MnStylePrivate *priv;
+
+  style->priv = priv = MN_STYLE_GET_PRIVATE (style);
+
+  /* create a hash table to look up pointer keys and values */
+  style->priv->node_hash = g_hash_table_new_full (NULL, NULL,
+                                                  NULL, g_free);
+  style->priv->style_hash = g_hash_table_new_full (NULL, NULL,
+                                                   NULL, (GDestroyNotify) ccss_style_destroy);
+
+  mn_style_load (style);
+}
+
+/**
+ * mn_style_new:
+ *
+ * Creates a new #MnStyle object. This must be freed using #g_object_unref
+ * when no longer required.
+ *
+ * Returns: a newly allocated #MnStyle
+ */
+MnStyle *
+mn_style_new (void)
+{
+  return g_object_new (MN_TYPE_STYLE, NULL);
+}
+
+/**
+ * mn_style_get_default:
+ *
+ * Return the default MnStyle object. This includes the current theme (if
+ * any).
+ *
+ * Returns: a #MnStyle object. This must not be freed or unref'd by
+ * applications
+ */
+MnStyle *
+mn_style_get_default (void)
+{
+  if (G_LIKELY (default_style))
+    return default_style;
+
+  default_style = g_object_new (MN_TYPE_STYLE, NULL);
+
+  return default_style;
+}
+
+/* functions for ccss */
+
+static mn_style_node_t *
+get_container (mn_style_node_t *node)
+{
+  mn_style_node_t *container;
+  MnStylable      *parent;
+
+  g_return_val_if_fail (node, NULL);
+  g_return_val_if_fail (node->iface, NULL);
+  g_return_val_if_fail (node->stylable, NULL);
+
+  g_object_get (node->stylable, "parent", parent, NULL);
+  if (!parent)
+    return NULL;
+
+  container = g_new0 (mn_style_node_t, 1);
+  ccss_node_init ((ccss_node_t*) container, peek_node_class ());
+  container->iface = node->iface;
+  container->stylable = MN_STYLABLE (parent);
+  g_object_get (parent,
+                "id", container->id,
+                "class", container->class,
+                "type", container->type,
+                "pseudo-class", container->pseudo_class,
+                NULL);
+
+  g_object_unref (parent);
+
+  return container;
+}
+
+static const gchar*
+get_style_id (mn_style_node_t *node)
+{
+  return node->id;
+}
+
+static const gchar*
+get_style_type (mn_style_node_t *node)
+{
+  return node->type;
+}
+
+static const gchar*
+get_style_class (mn_style_node_t *node)
+{
+  return node->class;
+}
+
+static const gchar*
+get_pseudo_class (mn_style_node_t *node)
+{
+  return node->pseudo_class;
+}
+
+static void
+release (mn_style_node_t *node)
+{
+  g_return_if_fail (node);
+
+  g_free (node->type);
+  g_free (node->class);
+  g_free (node->id);
+  g_free (node->pseudo_class);
+
+  g_free (node);
+}
+
+static ccss_node_class_t *
+peek_node_class (void)
+{
+  static ccss_node_class_t _node_class = {
+    .is_a             = NULL,
+    .get_container    = (ccss_node_get_container_f) get_container,
+    .get_id           = (ccss_node_get_id_f) get_style_id,
+    .get_type         = (ccss_node_get_type_f) get_style_type,
+    .get_class        = (ccss_node_get_class_f) get_style_class,
+    .get_pseudo_class = (ccss_node_get_pseudo_class_f) get_pseudo_class,
+    .get_viewport     = NULL,
+    .get_attribute    = NULL,
+    .release          = (ccss_node_release_f) release
+  };
+
+  return &_node_class;
+}
+
+static void
+mn_style_fetch_ccss_property (ccss_style_t  *ccss_style,
+                                GParamSpec    *pspec,
+                                GValue        *value)
+{
+  gboolean value_set = FALSE;
+
+  g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec));
+
+  if (G_PARAM_SPEC_VALUE_TYPE (pspec))
+    {
+      double number;
+
+      if (G_IS_PARAM_SPEC_INT (pspec))
+        {
+          if (ccss_style_get_double (ccss_style, pspec->name, &number))
+            {
+              g_value_set_int (value, (gint) number);
+              value_set = TRUE;
+            }
+        }
+      else if (G_IS_PARAM_SPEC_UINT (pspec))
+        {
+          if (ccss_style_get_double (ccss_style, pspec->name, &number))
+            {
+              g_value_set_uint (value, (guint) number);
+              value_set = TRUE;
+            }
+        }
+      /*
+      else if (G_PARAM_SPEC_VALUE_TYPE (pspec) == MN_TYPE_BORDER_IMAGE &&
+               !g_strcmp0 ("border-image", pspec->name))
+        {
+              ccss_border_image_t const *border_image;
+
+          if (ccss_style_get_property (ccss_style,
+                                        "border-image",
+                                        (ccss_property_base_t const **) &border_image))
+            {
+              if (border_image &&
+                  border_image->base.state == CCSS_PROPERTY_STATE_SET)
+                {
+                  g_value_set_boxed (value, border_image);
+                  value_set = TRUE;
+                }
+            }
+        }
+      else if (MN_TYPE_PADDING == G_PARAM_SPEC_VALUE_TYPE (pspec) &&
+                0 == g_strcmp0 ("padding", pspec->name))
+        {
+          MnPadding padding = { 0, };
+          gboolean padding_set = 0;
+
+          if (ccss_style_get_double (ccss_style, "padding-top", &number))
+            {
+              padding.top = number;
+              padding_set = TRUE;
+            }
+
+          if (ccss_style_get_double (ccss_style, "padding-right", &number))
+            {
+              padding.right = number;
+              padding_set = TRUE;
+            }
+
+          if (ccss_style_get_double (ccss_style, "padding-bottom", &number))
+            {
+              padding.bottom = number;
+              padding_set = TRUE;
+            }
+
+          if (ccss_style_get_double (ccss_style, "padding-left", &number))
+            {
+              padding.left = number;
+              padding_set = TRUE;
+            }
+
+          if (padding_set)
+            {
+              g_value_set_boxed (value, &padding);
+              value_set = TRUE;
+            }
+        }
+      */
+      else
+        {
+          gchar *string = NULL;
+
+          ccss_style_get_string (ccss_style, pspec->name, &string);
+
+          if (string)
+            {
+              if (MN_IS_PARAM_SPEC_COLOR (pspec))
+                {
+                  MnColor color = { 0, };
+
+                  mn_color_from_string (&color, string);
+                  mn_value_set_color (value, &color);
+
+                  value_set = TRUE;
+                }
+              else
+                if (G_IS_PARAM_SPEC_STRING (pspec))
+                  {
+                    g_value_set_string (value, string);
+                    value_set = TRUE;
+                  }
+              g_free (string);
+            }
+        }
+    }
+
+  /* no value was found in css, so copy in the default value */
+  if (!value_set)
+    g_param_value_set_default (pspec, value);
+}
+
+static ccss_style_t*
+mn_style_get_ccss_query (MnStyle         *style,
+                         MnStylable      *stylable)
+{
+  MnStylableIface *iface = MN_STYLABLE_GET_IFACE (stylable);
+  ccss_style_t *ccss_style;
+  mn_style_node_t *ccss_node;
+
+  ccss_node = g_hash_table_lookup (style->priv->node_hash, stylable);
+
+  if (!ccss_node)
+    {
+      ccss_node = g_new0 (mn_style_node_t, 1);
+      ccss_node_init ((ccss_node_t*) ccss_node, peek_node_class ());
+      ccss_node->iface = iface;
+      ccss_node->stylable = stylable;
+      g_object_get (stylable,
+                    "id", ccss_node->id,
+                    "class", ccss_node->class,
+                    "type", ccss_node->type,
+                    "pseudo-class", ccss_node->pseudo_class,
+                    NULL);
+
+      g_hash_table_insert (style->priv->node_hash, stylable, ccss_node);
+      g_signal_connect_swapped (stylable, "stylable-changed",
+                                G_CALLBACK (g_hash_table_remove),
+                                style->priv->node_hash);
+
+
+      g_object_weak_ref ((GObject*) stylable,
+                        (GWeakNotify) g_hash_table_remove, style->priv->node_hash);
+    }
+
+
+  ccss_style = g_hash_table_lookup (style->priv->style_hash, stylable);
+
+  if (!ccss_style)
+    {
+      ccss_style = ccss_stylesheet_query (style->priv->stylesheet,
+                                          (ccss_node_t *) ccss_node);
+
+      g_hash_table_insert (style->priv->style_hash, stylable, ccss_style);
+
+      /* remove the cache if the stylable changes */
+      g_signal_connect_swapped (stylable, "stylable-changed",
+                                G_CALLBACK (g_hash_table_remove),
+                                style->priv->style_hash);
+
+      g_object_weak_ref ((GObject*) stylable,
+                         (GWeakNotify) g_hash_table_remove, style->priv->style_hash);
+    }
+
+  return ccss_style;
+
+}
+
+
+/**
+ * mn_style_get_property:
+ * @style: the style data store object
+ * @stylable: a stylable to retreive the data for
+ * @pspec: a #GParamSpec describing the property required
+ * @value: a #GValue to place the return value in
+ *
+ * Requests the property described in @pspec for the specified stylable
+ */
+
+void
+mn_style_get_property (MnStyle    *style,
+                         MnStylable *stylable,
+                         GParamSpec   *pspec,
+                         GValue       *value)
+{
+  MnStylePrivate *priv;
+  gboolean value_set = FALSE;
+
+  g_return_if_fail (MN_IS_STYLE (style));
+  g_return_if_fail (MN_IS_STYLABLE (stylable));
+  g_return_if_fail (pspec != NULL);
+  g_return_if_fail (value != NULL);
+
+  priv = style->priv;
+
+  /* look up the property in the css */
+  if (priv->stylesheet)
+    {
+      ccss_style_t *ccss_style;
+
+      ccss_style = mn_style_get_ccss_query (style, stylable);
+      if (ccss_style)
+        {
+          mn_style_fetch_ccss_property (ccss_style, pspec, value);
+          value_set = TRUE;
+        }
+    }
+
+  /* no value was found in css, so copy in the default value */
+  if (!value_set)
+    {
+      g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec));
+      g_param_value_set_default (pspec, value);
+    }
+}
+
+/**
+ * mn_style_get_valist:
+ * @style: a #MnStyle
+ * @stylable: a #MnStylable
+ * @first_property_name: name of the first property to get
+ * @va_args: return location for the first property, followed optionally
+ *   by more name/return location pairs, followed by %NULL
+ *
+ * Gets the style properties for @stylable from @style.
+ *
+ * Please refer to mn_style_get() for further information.
+ */
+void
+mn_style_get_valist (MnStyle     *style,
+                       MnStylable  *stylable,
+                       const gchar   *first_property_name,
+                       va_list        va_args)
+{
+  MnStylePrivate *priv;
+  const gchar *name = first_property_name;
+  gboolean values_set = FALSE;
+
+  g_return_if_fail (MN_IS_STYLE (style));
+  g_return_if_fail (MN_IS_STYLABLE (stylable));
+  g_return_if_fail (style->priv != NULL);
+
+  priv = style->priv;
+
+  /* look up the property in the css */
+  if (priv->stylesheet)
+    {
+      ccss_style_t *ccss_style;
+
+      ccss_style = mn_style_get_ccss_query (style, stylable);
+
+      if (ccss_style)
+        {
+          while (name)
+            {
+              GValue value = { 0, };
+              gchar *error = NULL;
+              GParamSpec *pspec = mn_stylable_find_property (stylable, name);
+              mn_style_fetch_ccss_property (ccss_style, pspec, &value);
+              G_VALUE_LCOPY (&value, va_args, 0, &error);
+              if (error)
+                {
+                  g_warning ("%s: %s", G_STRLOC, error);
+                  g_free (error);
+                  g_value_unset (&value);
+                  break;
+                }
+              g_value_unset (&value);
+              name = va_arg (va_args, gchar*);
+            }
+          values_set = TRUE;
+        }
+    }
+
+  if (!values_set)
+    {
+      /* Set the remaining properties to their default values
+       * even if broken out of the above loop. */
+      while (name)
+        {
+          GValue value = { 0, };
+          gchar *error = NULL;
+          mn_stylable_get_default_value (stylable, name, &value);
+          G_VALUE_LCOPY (&value, va_args, 0, &error);
+          if (error)
+            {
+              g_warning ("%s: %s", G_STRLOC, error);
+              g_free (error);
+              g_value_unset (&value);
+              break;
+            }
+          g_value_unset (&value);
+          name = va_arg (va_args, gchar*);
+        }
+    }
+}
+
+/**
+ * mn_style_get:
+ * @style: a #MnStyle
+ * @stylable: a #MnStylable
+ * @first_property_name: name of the first property to get
+ * @Varargs: return location for the first property, followed optionally
+ *   by more name/return location pairs, followed by %NULL
+ *
+ * Gets the style properties for @stylable from @style.
+ *
+ * In general, a copy is made of the property contents and the caller
+ * is responsible for freeing the memory in the appropriate manner for
+ * the property type.
+ */
+void
+mn_style_get (MnStyle     *style,
+                MnStylable  *stylable,
+                const gchar   *first_property_name,
+                ...)
+{
+  va_list va_args;
+
+  g_return_if_fail (MN_IS_STYLE (style));
+  g_return_if_fail (first_property_name != NULL);
+
+  va_start (va_args, first_property_name);
+  mn_style_get_valist (style, stylable, first_property_name, va_args);
+  va_end (va_args);
+}
+
diff --git a/monet/mn-style.h b/monet/mn-style.h
new file mode 100644
index 0000000..9a59cf9
--- /dev/null
+++ b/monet/mn-style.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2009 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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 program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef __MN_STYLE_H__
+#define __MN_STYLE_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define MN_TYPE_STYLE                 (mn_style_get_type ())
+#define MN_STYLE(obj)                 (G_TYPE_CHECK_INSTANCE_CAST ((obj), MN_TYPE_STYLE, MnStyle))
+#define MN_IS_STYLE(obj)              (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MN_TYPE_STYLE))
+#define MN_STYLE_CLASS(klass)         (G_TYPE_CHECK_CLASS_CAST ((klass), MN_TYPE_STYLE, MnStyleClass))
+#define MN_IS_STYLE_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass), MN_TYPE_STYLE))
+#define MN_STYLE_GET_CLASS(obj)       (G_TYPE_INSTANCE_GET_CLASS ((obj), MN_TYPE_STYLE, MnStyleClass))
+
+typedef struct _MnStyle               MnStyle;
+typedef struct _MnStylePrivate        MnStylePrivate;
+typedef struct _MnStyleClass          MnStyleClass;
+
+/* forward declaration */
+typedef struct _MnStylable            MnStylable; /* dummy typedef */
+typedef struct _MnStylableIface       MnStylableIface;
+
+typedef enum { /*< prefix=MN_STYLE_ERROR >*/
+  MN_STYLE_ERROR_INVALID_FILE
+} MnStyleError;
+
+/**
+ * MnStyle:
+ *
+ * The contents of this structure is private and should only be accessed using
+ * the provided API.
+ */
+struct _MnStyle
+{
+  /*< private >*/
+  GObject parent_instance;
+
+  MnStylePrivate *priv;
+};
+
+struct _MnStyleClass
+{
+  GObjectClass parent_class;
+
+  void (* changed) (MnStyle *style);
+};
+
+GType            mn_style_get_type     (void) G_GNUC_CONST;
+
+MnStyle *      mn_style_get_default  (void);
+MnStyle *      mn_style_new          (void);
+
+gboolean         mn_style_load_from_file (MnStyle     *style,
+                                            const gchar   *filename,
+                                            GError       **error);
+void             mn_style_get_property   (MnStyle     *style,
+                                            MnStylable  *stylable,
+                                            GParamSpec    *pspec,
+                                            GValue        *value);
+void             mn_style_get            (MnStyle     *style,
+                                            MnStylable  *stylable,
+                                            const gchar   *first_property_name,
+                                            ...) G_GNUC_NULL_TERMINATED;
+void             mn_style_get_valist     (MnStyle     *style,
+                                            MnStylable  *stylable,
+                                            const gchar   *first_property_name,
+                                            va_list        va_args);
+
+G_END_DECLS
+
+#endif /* __MN_STYLE_H__ */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]