[monet/style-stylable] [style/stylable] add MnStyle and MnStylable objects
- From: Thomas Wood <thos src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [monet/style-stylable] [style/stylable] add MnStyle and MnStylable objects
- Date: Mon, 14 Sep 2009 22:23:02 +0000 (UTC)
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", &x_spacing,
+ * "bg-color", &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]