[monet/bberg-playground: 4/4] More changes, some basic features are working.
- From: Benjamin Berg <bberg src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [monet/bberg-playground: 4/4] More changes, some basic features are working.
- Date: Thu, 20 Aug 2009 16:56:40 +0000 (UTC)
commit 07ddbd8647d5e0cd12c158e570c3b6413a35bbff
Author: Benjamin Berg <benjamin sipsolutions net>
Date: Thu Aug 20 18:51:01 2009 +0200
More changes, some basic features are working.
configure.ac | 4 +
monet/mn-context.c | 415 ++++++++++++++++++++++++++++++++++++++++++++++++-
monet/mn-context.h | 31 ++++-
monet/mn-display.c | 13 ++-
monet/mn-display.h | 5 +-
monet/mn-stylesheet.c | 296 ++++++++++++++++++++++++++++++++++-
monet/mn-stylesheet.h | 21 +++-
monet/mn-theme-type.c | 18 ++
monet/mn-theme-type.h | 18 ++-
tests/Makefile.am | 8 +-
tests/test.c | 156 ++++++++++++++++++
11 files changed, 953 insertions(+), 32 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 8b00038..887a614 100644
--- a/configure.ac
+++ b/configure.ac
@@ -16,6 +16,10 @@ PKG_CHECK_MODULES(MONET, [cairo glib-2.0 gobject-2.0])
AC_SUBST(MONET_LIBS)
AC_SUBST(MONET_CFLAGS)
+PKG_CHECK_MODULES(MONET_TEST, [cairo glib-2.0 gobject-2.0 gdk-2.0])
+AC_SUBST(MONET_TEST_LIBS)
+AC_SUBST(MONET_TEST_CFLAGS)
+
AC_OUTPUT([
Makefile
monet/Makefile
diff --git a/monet/mn-context.c b/monet/mn-context.c
index d56a4e7..acf47be 100644
--- a/monet/mn-context.c
+++ b/monet/mn-context.c
@@ -6,26 +6,404 @@ G_DEFINE_TYPE (MnContext, mn_context, G_TYPE_OBJECT)
(G_TYPE_INSTANCE_GET_PRIVATE ((o), MN_TYPE_CONTEXT, MnContextPrivate))
typedef struct _MnContextPrivate MnContextPrivate;
+typedef struct _MnStackItem MnStackItem;
+
+enum {
+ PROP_DISPLAY = 1
+};
+
+struct _MnStackItem {
+ MnStackItem *prev;
+ MnStackItem *next;
+ gboolean props_resolved;
+
+ const gchar *type;
+ GSList *classes;
+ GSList *pseudo_classes;
+
+ const gchar *prop_type;
+ GSList *prop_classes;
+ GSList *prop_pseudo_classes;
+
+ GHashTable *properties;
+};
struct _MnContextPrivate {
- int dummy;
+ MnDisplay *display;
+ MnStackItem *stack;
+ MnStackItem *depth;
};
+
+MnDisplay*
+mn_context_get_display (MnContext* context)
+{
+ MnContextPrivate *priv = GET_PRIVATE (context);
+
+ return priv->display;
+}
+
+static void
+mn_g_value_free (GValue *value)
+{
+ g_value_unset (value);
+ g_slice_free (GValue, value);
+}
+
+static void
+mn_context_stack_item_clear (MnContext *context,
+ MnStackItem* stack_item,
+ gboolean clear_all)
+{
+ if (stack_item == NULL)
+ return;
+ mn_context_stack_item_clear (context, stack_item->next, clear_all);
+
+ stack_item->props_resolved = FALSE;
+
+ g_slist_free (stack_item->prop_classes);
+ stack_item->prop_classes = NULL;
+ g_slist_free (stack_item->prop_pseudo_classes);
+ stack_item->prop_pseudo_classes = NULL;
+
+ g_hash_table_remove_all (stack_item->properties);
+
+ if (!clear_all)
+ return;
+
+ stack_item->type = NULL;
+ g_slist_free (stack_item->classes);
+ stack_item->classes = NULL;
+ g_slist_free (stack_item->pseudo_classes);
+ stack_item->pseudo_classes = NULL;
+}
+
+static MnStackItem*
+mn_context_stack_item_new ()
+{
+ MnStackItem *stack_item;
+
+ stack_item = g_slice_new0 (MnStackItem);
+
+ stack_item->properties =
+ g_hash_table_new_full (g_direct_hash, g_direct_equal,
+ NULL, (GDestroyNotify) mn_g_value_free);
+
+ return stack_item;
+}
+
+static void
+mn_context_stack_item_free (MnStackItem *stack_item)
+{
+ if (stack_item == NULL)
+ return;
+
+ mn_context_stack_item_free (stack_item->next);
+ if (stack_item->prev)
+ stack_item->prev->next = NULL;
+
+ g_hash_table_unref (stack_item->properties);
+ g_slist_free (stack_item->classes);
+ g_slist_free (stack_item->pseudo_classes);
+
+ g_slist_free (stack_item->prop_classes);
+ g_slist_free (stack_item->prop_pseudo_classes);
+
+ g_slice_free (MnStackItem, stack_item);
+}
+
static void
-mn_context_get_property (GObject *object, guint property_id,
+mn_context_ensure_properties (MnContext *context, MnStackItem *stack_item)
+{
+ MnContextPrivate *priv = GET_PRIVATE (context);
+ MnThemeType *theme_type;
+ const GSList *stylesheets;
+ GList *properties = NULL;
+ GSList *item;
+ MnStylesheet *stylesheet;
+
+ if (stack_item == NULL)
+ return;
+
+ if (stack_item->props_resolved)
+ {
+ gboolean redo = FALSE;
+ GSList *itema, *itemb;
+
+ if (stack_item->prop_type != stack_item->type)
+ redo = TRUE;
+
+ itema = stack_item->classes;
+ itemb = stack_item->prop_classes;
+ while (itema && itemb && (itema->data == itemb->data))
+ {
+ itema = itema->next;
+ itemb = itemb->next;
+ }
+ if (itema || itemb)
+ redo = TRUE;
+
+ itema = stack_item->pseudo_classes;
+ itemb = stack_item->prop_pseudo_classes;
+ while (itema && itemb && (itema->data == itemb->data))
+ {
+ itema = itema->next;
+ itemb = itemb->next;
+ }
+ if (itema || itemb)
+ redo = TRUE;
+
+ if (redo == FALSE)
+ return;
+ }
+
+ mn_context_stack_item_clear (context, stack_item->next, FALSE);
+ mn_context_ensure_properties (context, stack_item->prev);
+
+ theme_type = mn_display_get_theme_type (priv->display);
+ stylesheets = mn_display_get_stylesheets (priv->display);
+
+ item = (GSList*) stylesheets;
+ while (item)
+ {
+ stylesheet = (MnStylesheet*) item->data;
+
+ properties = _mn_stylesheet_find_properties (stylesheet, context,
+ (gpointer) stack_item,
+ properties);
+
+ item = item->next;
+ }
+ _mn_stylesheet_resolve_properties (stylesheet, context, properties,
+ stack_item->properties,
+ stack_item->prev ?
+ stack_item->prev->properties :
+ NULL);
+ _mn_stylesheet_properties_list_free (stylesheet, properties);
+
+ stack_item->props_resolved = TRUE;
+ stack_item->type = stack_item->type;
+ stack_item->prop_classes = g_slist_copy (stack_item->classes);
+ stack_item->prop_pseudo_classes = g_slist_copy (stack_item->pseudo_classes);
+}
+
+void
+mn_context_push (MnContext *context, const gchar *type)
+{
+ MnContextPrivate *priv = GET_PRIVATE (context);
+
+ if (priv->depth == NULL || priv->depth->next == NULL)
+ {
+ MnStackItem *stack_item = mn_context_stack_item_new ();
+
+ stack_item->prev = priv->depth;
+
+ if (priv->depth != NULL)
+ {
+ priv->depth->next = stack_item;
+ }
+ else
+ {
+ priv->stack = stack_item;
+ }
+ priv->depth = stack_item;
+ }
+ else
+ {
+ priv->depth = priv->depth->next;
+ }
+
+ priv->depth->type = g_intern_string (type);
+
+ priv->depth->props_resolved = FALSE;
+
+ g_slist_free (priv->depth->classes);
+ g_slist_free (priv->depth->pseudo_classes);
+}
+
+void
+mn_context_pop (MnContext *context)
+{
+ MnContextPrivate *priv = GET_PRIVATE (context);
+
+ g_assert (priv->depth != NULL);
+
+ /* FIXME: Do not clear the thing, be a bit smarter. */
+ mn_context_stack_item_clear (context, priv->depth, TRUE);
+ priv->depth = priv->depth->prev;
+}
+
+
+void
+mn_context_clear_classes (MnContext *context)
+{
+ MnContextPrivate *priv = GET_PRIVATE (context);
+
+ g_return_if_fail (priv->depth != NULL);
+
+ g_slist_free (priv->depth->classes);
+ priv->depth->classes = NULL;
+}
+
+void
+mn_context_clear_pseudo_classes (MnContext *context)
+{
+ MnContextPrivate *priv = GET_PRIVATE (context);
+
+ g_return_if_fail (priv->depth != NULL);
+
+ g_slist_free (priv->depth->pseudo_classes);
+ priv->depth->pseudo_classes = NULL;
+}
+
+void
+mn_context_add_class (MnContext *context,
+ const gchar *class)
+{
+ MnContextPrivate *priv = GET_PRIVATE (context);
+
+ g_return_if_fail (priv->depth != NULL);
+
+ priv->depth->classes =
+ g_slist_prepend (priv->depth->classes,
+ (gpointer) g_intern_string (class));
+}
+
+void
+mn_context_add_pseudo_class (MnContext *context,
+ const gchar *pseudo_class)
+{
+ MnContextPrivate *priv = GET_PRIVATE (context);
+
+ g_return_if_fail (priv->depth != NULL);
+
+ priv->depth->pseudo_classes =
+ g_slist_prepend (priv->depth->pseudo_classes,
+ (gpointer) g_intern_string (pseudo_class));
+}
+
+void
+mn_context_remove_class (MnContext *context,
+ const gchar *class)
+{
+ MnContextPrivate *priv = GET_PRIVATE (context);
+
+ g_return_if_fail (priv->depth != NULL);
+
+ priv->depth->classes =
+ g_slist_remove (priv->depth->classes,
+ (gpointer) g_intern_string (class));
+}
+
+void
+mn_context_remove_pseudo_class (MnContext *context,
+ const gchar *pseudo_class)
+{
+ MnContextPrivate *priv = GET_PRIVATE (context);
+
+ g_return_if_fail (priv->depth != NULL);
+
+ priv->depth->pseudo_classes =
+ g_slist_remove (priv->depth->pseudo_classes,
+ (gpointer) g_intern_string (pseudo_class));
+}
+
+void
+mn_context_get_property (MnContext *context,
+ const gchar *property,
+ GValue *value)
+{
+ const gchar *name;
+ GValue *prop;
+ MnContextPrivate *priv = GET_PRIVATE (context);
+
+ g_return_if_fail (property != NULL);
+ g_return_if_fail (G_IS_VALUE (value));
+ g_return_if_fail (priv->depth != NULL);
+
+ name = g_intern_string (property);
+ mn_context_ensure_properties (context, priv->depth);
+ prop = g_hash_table_lookup (priv->depth->properties, name);
+
+ if (prop == NULL)
+ return;
+
+ if (G_VALUE_TYPE (value) == G_VALUE_TYPE (prop))
+ g_value_copy (prop, value);
+ else if (g_value_type_transformable (G_VALUE_TYPE (prop), G_VALUE_TYPE (value)))
+ g_value_transform (prop, value);
+ else
+ g_warning ("Cannot retrieve property '%s' of type '%s' as type '%s'.",
+ property,
+ G_VALUE_TYPE_NAME (value),
+ G_VALUE_TYPE_NAME (prop));
+}
+
+void
+mn_context_set_property (MnContext *context,
+ const gchar *property,
+ GValue *value)
+{
+ MnContextPrivate *priv = GET_PRIVATE (context);
+
+ g_return_if_fail (property != NULL);
+ g_return_if_fail (value != NULL);
+ g_return_if_fail (priv->depth != NULL);
+
+ /* XXX: FIXME NOT IMPLEMENTED */
+}
+
+void
+_mn_context_obj_get_info (MnContext *context,
+ gpointer obj,
+ const gchar **type,
+ const GSList **classes,
+ const GSList **pseudo_classes)
+{
+ MnStackItem *stack_item = (MnStackItem*) obj;
+ g_assert (stack_item != NULL);
+
+ *type = stack_item->type;
+ *classes = stack_item->classes;
+ *pseudo_classes = stack_item->pseudo_classes;
+}
+
+gpointer
+_mn_context_obj_get_parent (MnContext* context, gpointer obj)
+{
+ MnStackItem *stack_item = (MnStackItem*) obj;
+ g_assert (stack_item != NULL);
+
+ return stack_item->prev;
+}
+
+static void
+mn_context_get_gproperty (GObject *object, guint property_id,
GValue *value, GParamSpec *pspec)
{
+ MnContextPrivate *priv = GET_PRIVATE (object);
+
switch (property_id) {
+ case PROP_DISPLAY:
+ g_value_set_object (value, priv->display);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
-mn_context_set_property (GObject *object, guint property_id,
+mn_context_set_gproperty (GObject *object, guint property_id,
const GValue *value, GParamSpec *pspec)
{
+ MnContextPrivate *priv = GET_PRIVATE (object);
+
switch (property_id) {
+ case PROP_DISPLAY:
+ if (priv->display != NULL)
+ g_object_unref (G_OBJECT (priv->display));
+ priv->display = g_value_dup_object (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
@@ -34,12 +412,21 @@ mn_context_set_property (GObject *object, guint property_id,
static void
mn_context_dispose (GObject *object)
{
+ MnContextPrivate *priv = GET_PRIVATE (object);
+
+ g_object_unref (G_OBJECT (priv->display));
+
G_OBJECT_CLASS (mn_context_parent_class)->dispose (object);
}
static void
mn_context_finalize (GObject *object)
{
+ MnContextPrivate *priv = GET_PRIVATE (object);
+
+ mn_context_stack_item_free (priv->stack);
+ priv->stack = NULL;
+
G_OBJECT_CLASS (mn_context_parent_class)->finalize (object);
}
@@ -50,21 +437,35 @@ mn_context_class_init (MnContextClass *klass)
g_type_class_add_private (klass, sizeof (MnContextPrivate));
- object_class->get_property = mn_context_get_property;
- object_class->set_property = mn_context_set_property;
+ object_class->get_property = mn_context_get_gproperty;
+ object_class->set_property = mn_context_set_gproperty;
object_class->dispose = mn_context_dispose;
object_class->finalize = mn_context_finalize;
+
+ g_object_class_install_property(object_class, PROP_DISPLAY,
+ g_param_spec_object ("display",
+ "Monet Display",
+ "The display that this monet context is for.",
+ MN_TYPE_DISPLAY,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
}
static void
mn_context_init (MnContext *self)
{
+ MnContextPrivate *priv = GET_PRIVATE (self);
+
+ priv->stack = mn_context_stack_item_new ();
}
MnContext*
-mn_context_new (void)
+mn_context_new (MnDisplay *display)
{
- return g_object_new (MN_TYPE_CONTEXT, NULL);
+ g_return_val_if_fail (MN_IS_DISPLAY (display), NULL);
+
+ return g_object_new (MN_TYPE_CONTEXT,
+ "display", display,
+ NULL);
}
diff --git a/monet/mn-context.h b/monet/mn-context.h
index 15125be..1bbbcca 100644
--- a/monet/mn-context.h
+++ b/monet/mn-context.h
@@ -2,6 +2,7 @@
#define _MN_CONTEXT
#include <glib-object.h>
+typedef struct _MnContext MnContext;
#include "mn-display.h"
G_BEGIN_DECLS
@@ -23,9 +24,9 @@ G_BEGIN_DECLS
#define MN_CONTEXT_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), MN_TYPE_CONTEXT, MnContextClass))
-typedef struct {
+struct _MnContext {
GObject parent;
-} MnContext;
+};
typedef struct {
GObjectClass parent_class;
@@ -33,7 +34,31 @@ typedef struct {
GType mn_context_get_type (void);
-MnContext* mn_context_new_for_display (MnDisplay *display);
+MnContext* mn_context_new (MnDisplay *display);
+
+void mn_context_push (MnContext *context, const gchar *type);
+void mn_context_pop (MnContext *context);
+
+void mn_context_clear_classes (MnContext *context);
+void mn_context_clear_pseudo_classes (MnContext *context);
+
+void mn_context_add_class (MnContext *context, const gchar *class);
+void mn_context_add_pseudo_class (MnContext *context, const gchar *pseudo_class);
+
+void mn_context_remove_class (MnContext *context, const gchar *class);
+void mn_context_remove_pseudo_class (MnContext *context, const gchar *pseudo_class);
+
+void mn_context_get_property (MnContext *context, const gchar *property, GValue *value);
+void mn_context_set_property (MnContext *context, const gchar *property, GValue *value);
+
+MnDisplay* mn_context_get_display (MnContext* context);
+
+void _mn_context_obj_get_info (MnContext* context, gpointer obj,
+ const gchar **type,
+ const GSList **classes,
+ const GSList **pseudo_classes);
+
+gpointer _mn_context_obj_get_parent (MnContext* context, gpointer obj);
G_END_DECLS
diff --git a/monet/mn-display.c b/monet/mn-display.c
index d76be90..4282cf1 100644
--- a/monet/mn-display.c
+++ b/monet/mn-display.c
@@ -8,7 +8,7 @@ G_DEFINE_TYPE (MnDisplay, mn_display, G_TYPE_OBJECT)
typedef struct _MnDisplayPrivate MnDisplayPrivate;
struct _MnDisplayPrivate {
- gchar *theme_type;
+ MnThemeType *theme_type;
GSList *stylesheets;
};
@@ -31,7 +31,7 @@ mn_display_new (MnThemeType *theme_type)
NULL);
}
-const gchar*
+MnThemeType*
mn_display_get_theme_type (MnDisplay* display)
{
MnDisplayPrivate *priv = GET_PRIVATE (display);
@@ -63,7 +63,7 @@ mn_display_add_stylesheet (MnDisplay *display, MnStylesheet *stylesheet)
{
MnDisplayPrivate *priv = GET_PRIVATE (display);
- g_return_if_fail (g_slist_find (priv->stylesheets, stylesheet) != NULL);
+ g_return_if_fail (g_slist_find (priv->stylesheets, stylesheet) == NULL);
g_object_ref_sink (stylesheet);
g_signal_connect (G_OBJECT (stylesheet), "changed",
@@ -90,6 +90,13 @@ mn_display_remove_stylesheet (MnDisplay *display, MnStylesheet *stylesheet)
priv->stylesheets = g_slist_delete_link (priv->stylesheets, item);
}
+const GSList*
+mn_display_get_stylesheets (MnDisplay *display)
+{
+ MnDisplayPrivate *priv = GET_PRIVATE (display);
+
+ return priv->stylesheets;
+}
static void
mn_display_get_property (GObject *object, guint property_id,
diff --git a/monet/mn-display.h b/monet/mn-display.h
index 79f87b5..65f91a8 100644
--- a/monet/mn-display.h
+++ b/monet/mn-display.h
@@ -3,6 +3,7 @@
#include <glib-object.h>
#include "mn-stylesheet.h"
+#include "mn-theme-type.h"
G_BEGIN_DECLS
@@ -35,11 +36,13 @@ GType mn_display_get_type (void);
MnDisplay* mn_display_new (MnThemeType *theme_type);
-const gchar* mn_display_get_theme_type (MnDisplay* display);
+MnThemeType* mn_display_get_theme_type (MnDisplay* display);
void mn_display_add_stylesheet (MnDisplay *display, MnStylesheet *stylesheet);
void mn_display_remove_stylesheet (MnDisplay *display, MnStylesheet *stylesheet);
+const GSList* mn_display_get_stylesheets (MnDisplay *display);
+
G_END_DECLS
#endif /* _MN_DISPLAY */
diff --git a/monet/mn-stylesheet.c b/monet/mn-stylesheet.c
index 04a90f8..8c909a0 100644
--- a/monet/mn-stylesheet.c
+++ b/monet/mn-stylesheet.c
@@ -6,6 +6,10 @@ G_DEFINE_TYPE (MnStylesheet, mn_stylesheet, G_TYPE_OBJECT)
#define GET_PRIVATE(o) \
(G_TYPE_INSTANCE_GET_PRIVATE ((o), MN_TYPE_STYLESHEET, MnStylesheetPrivate))
+#define SHIFT_TYPE 0
+#define SHIFT_CLASS 8
+#define SHIFT_PSEUDO_CLASS 16
+#define SHIFT_PRIORITY 24
typedef struct _MnStylesheetPrivate MnStylesheetPrivate;
typedef struct _MnStyle MnStyle;
@@ -36,6 +40,7 @@ struct _MnProperty {
};
struct _MnSelector {
+ guint64 specifity;
MnStyle *style;
MnSelectorItem *sel;
};
@@ -112,6 +117,39 @@ mn_stylesheet_selector_item_free (MnSelectorItem *selitem)
g_slice_free (MnSelectorItem, selitem);
}
+static void
+mn_stylesheet_selector_calculate_specifity (MnStylesheet *stylesheet,
+ MnSelector *selector)
+{
+ MnStylesheetPrivate *priv = GET_PRIVATE (stylesheet);
+
+ MnSelectorItem *sel_item;
+ selector->specifity = ((guint64) priv->priority) << SHIFT_PRIORITY;
+ sel_item = selector->sel;
+
+ while (sel_item)
+ {
+ gchar **tmp;
+ if (sel_item->type)
+ selector->specifity += 1 << SHIFT_TYPE;
+
+ tmp = sel_item->classes;
+ while (tmp && *tmp)
+ {
+ selector->specifity += 1 << SHIFT_CLASS;
+ tmp++;
+ }
+
+ tmp = sel_item->pseudo_classes;
+ while (tmp && *tmp)
+ {
+ selector->specifity += 1 << SHIFT_PSEUDO_CLASS;
+ tmp++;
+ }
+ sel_item = sel_item->next;
+ }
+}
+
static MnSelector*
mn_stylesheet_selector_new ()
{
@@ -154,10 +192,13 @@ mn_stylesheet_add_style_with_selectors (MnStylesheet *stylesheet,
{
((MnSelector*)selector->data)->style = style;
+ mn_stylesheet_selector_calculate_specifity (stylesheet,
+ ((MnSelector*)selector->data));
selector = selector->next;
}
+
priv->selectors = g_slist_concat (priv->selectors, selectors);
- priv->styles = g_slist_append (priv->styles, style);
+ priv->styles = g_slist_prepend (priv->styles, style);
}
/***********************************************************/
@@ -322,7 +363,7 @@ scan_block_to_semicolon (GScanner *scanner)
g_free (tmp);
break;
default:
- g_print ("Not implemented! %c\n", token);
+ g_scanner_warn (scanner, "Not implemented! %c\n", token);
break;
}
@@ -354,8 +395,8 @@ mn_stylesheet_parse_selectors (MnStylesheet *stylesheet, GScanner *scanner)
GTokenType token;
GSList *selectors = NULL;
GSList *item;
- MnSelector *selector;
- MnSelectorItem *selector_item;
+ MnSelector *selector = NULL;
+ MnSelectorItem *selector_item = NULL;
gboolean new_selector = TRUE;
gboolean new_sel_item = TRUE;
enum {
@@ -386,8 +427,13 @@ mn_stylesheet_parse_selectors (MnStylesheet *stylesheet, GScanner *scanner)
if (new_selector)
{
+ if (selector_item)
+ selector_item->type = MN_SELECTOR_DIRECT_PARENT;
+
selector = mn_stylesheet_selector_new ();
selectors = g_slist_append (selectors, selector);
+ selector_item = NULL;
+ new_sel_item = TRUE;
new_selector = FALSE;
}
if (new_sel_item)
@@ -501,10 +547,14 @@ mn_stylesheet_parse_selectors (MnStylesheet *stylesheet, GScanner *scanner)
token = g_scanner_peek_next_token (scanner);
}
+ if (selector_item)
+ selector_item->type = MN_SELECTOR_DIRECT_PARENT;
+
scanner->config->cset_skip_characters = cset_skip_characters;
scanner->config->numbers_2_int = numbers_2_int;
scanner->config->scan_symbols = scan_symbols;
scanner->config->scan_float = scan_float;
+
return selectors;
BAIL_PARSE_SELECTORS:
@@ -566,7 +616,7 @@ mn_stylesheet_parse_style (MnStylesheet *stylesheet, GScanner *scanner)
if (token != ':')
{
g_free (identifier);
- g_print ("Expected ':', found something else!\n");
+ g_scanner_warn (scanner, "Expected ':', found something else!\n");
value = scan_block_to_semicolon (scanner);
g_free (value);
continue;
@@ -575,7 +625,7 @@ mn_stylesheet_parse_style (MnStylesheet *stylesheet, GScanner *scanner)
if (value == NULL)
{
g_free (identifier);
- g_print ("XXX: WARNING\n");
+ g_scanner_warn (scanner, "Error while parsing value. Ignoring the setting.\n");
continue;
}
@@ -583,7 +633,7 @@ mn_stylesheet_parse_style (MnStylesheet *stylesheet, GScanner *scanner)
style = mn_stylesheet_style_new ();
property = mn_stylesheet_property_new ();
- property->identifier = identifier;
+ property->identifier = (gchar*) g_intern_string (identifier);
property->value = value;
style->properties = g_slist_append(style->properties, property);
}
@@ -626,7 +676,10 @@ mn_stylesheet_parse (MnStylesheet *stylesheet)
{
mn_stylesheet_selectors_free (selectors);
}
- mn_stylesheet_add_style_with_selectors (stylesheet, style, selectors);
+ else
+ {
+ mn_stylesheet_add_style_with_selectors (stylesheet, style, selectors);
+ }
token = g_scanner_peek_next_token (scanner);
}
@@ -636,6 +689,233 @@ mn_stylesheet_parse (MnStylesheet *stylesheet)
/***********************************************************/
+typedef struct {
+ guint64 specifity;
+ const gchar *property;
+ const gchar *value;
+} MnPListItem;
+
+static GList*
+mn_stylesheet_find_properties_for_selectors (GList *plist, GList *selectors)
+{
+ while (selectors)
+ {
+ MnSelector *selector = (MnSelector*) selectors->data;
+ MnStyle *style = selector->style;
+ GSList *prop_li;
+ MnProperty *property;
+ GList *plist_item;
+ MnPListItem *p_item;
+
+ prop_li = style->properties;
+ while (prop_li)
+ {
+ GList *insert_before = NULL;
+ property = (MnProperty*) prop_li->data;
+
+ plist_item = plist;
+ insert_before = NULL;
+
+ while (plist_item && insert_before == NULL)
+ {
+ /* Search where it would be inserted. */
+ p_item = (MnPListItem*) plist_item->data;
+
+ if (selector->specifity < p_item->specifity)
+ insert_before = plist_item->prev;
+
+ plist_item = plist_item->next;
+ }
+
+ p_item = g_slice_new0 (MnPListItem);
+ p_item->specifity = selector->specifity;
+ p_item->property = property->identifier;
+ p_item->value = property->value;
+
+ plist = g_list_insert_before (plist, insert_before, p_item);
+
+ prop_li = prop_li->next;
+ }
+
+ selectors = selectors->next;
+ }
+
+ return plist;
+}
+
+GList*
+_mn_stylesheet_find_properties (MnStylesheet *stylesheet,
+ MnContext *context,
+ gpointer *obj,
+ GList *plist)
+{
+ MnStylesheetPrivate *priv = GET_PRIVATE (stylesheet);
+ MnSelector *selector;
+ MnSelectorItem *sel_item;
+ const gchar *type;
+ const GSList *classes;
+ const GSList *pseudo_classes;
+ GList *matched_selectors = NULL;
+ GSList *tmp_slist;
+ GList *tmp_s, *tmp_i;
+ GList *selectors = NULL;
+ GList *sel_items = NULL;
+
+ tmp_slist = priv->selectors;
+ while (tmp_slist)
+ {
+ selector = (MnSelector*) tmp_slist->data;
+ g_assert (selector->sel != NULL);
+ selectors = g_list_prepend (selectors, selector);
+ sel_items = g_list_prepend (sel_items, selector->sel);
+ tmp_slist = tmp_slist->next;
+ }
+
+ while (obj)
+ {
+ _mn_context_obj_get_info (context, obj, &type, &classes, &pseudo_classes);
+
+ tmp_s = selectors;
+ tmp_i = sel_items;
+ while (tmp_s)
+ {
+ gboolean match = TRUE;
+ gboolean remove = FALSE;
+ gchar **tmp;
+ selector = (MnSelector*) (tmp_s->data);
+ sel_item = (MnSelectorItem*) (tmp_i->data);
+
+ if ((sel_item->identifier != NULL) &&
+ (sel_item->identifier != type))
+ match = FALSE;
+
+ tmp = sel_item->classes;
+ while (tmp && *tmp && match)
+ {
+ if (g_slist_find ((GSList*) classes, *tmp) == NULL)
+ match = FALSE;
+ tmp++;
+ }
+
+ tmp = sel_item->pseudo_classes;
+ while (tmp && *tmp && match)
+ {
+ if (g_slist_find ((GSList*) pseudo_classes, *tmp) == NULL)
+ match = FALSE;
+ tmp++;
+ }
+
+ if (match == TRUE)
+ {
+ tmp_i->data = sel_item->next;
+ if (sel_item->next == NULL)
+ {
+ /* Found a match. */
+ matched_selectors = g_list_prepend (matched_selectors,
+ selector);
+
+ remove = TRUE;
+ }
+ }
+ else if (match == FALSE && sel_item->type == MN_SELECTOR_DIRECT_PARENT)
+ {
+ /* This selector cannot match anymore. */
+ remove = TRUE;
+ }
+
+ if (!remove)
+ {
+ tmp_s = tmp_s->next;
+ tmp_i = tmp_i->next;
+ }
+ else
+ {
+ GList *tmp;
+
+ tmp = tmp_s->next;
+ selectors = g_list_delete_link (selectors, tmp_s);
+ tmp_s = tmp;
+ tmp = tmp_i->next;
+ sel_items = g_list_delete_link (sel_items, tmp_i);
+ tmp_i = tmp;
+ }
+ }
+
+ obj = _mn_context_obj_get_parent (context, obj);
+ }
+
+ plist = mn_stylesheet_find_properties_for_selectors (plist, matched_selectors);
+
+ g_list_free (sel_items);
+ g_list_free (selectors);
+
+ return plist;
+}
+
+void
+_mn_stylesheet_resolve_properties (MnStylesheet *stylesheet,
+ MnContext *context,
+ GList *plist,
+ GHashTable *properties,
+ GHashTable *parent_properties)
+{
+ MnDisplay *display = mn_context_get_display (context);
+ MnThemeType *theme_type = mn_display_get_theme_type (display);
+ gboolean constant;
+ GValue *value;
+
+ while (plist)
+ {
+ MnPListItem *plist_item = (MnPListItem*) plist->data;
+ MnPropertyInfo *prop_info;
+ GValue *parent_value;
+ constant = TRUE;
+
+ prop_info = mn_theme_type_get_property_info (theme_type,
+ plist_item->property);
+
+ /* Can't resolve this property? Just ignore it! */
+ if (prop_info == NULL)
+ {
+ plist = plist->next;
+ continue;
+ }
+
+ if (parent_properties)
+ parent_value = g_hash_table_lookup (parent_properties, prop_info->priv);
+
+ value = g_slice_new0 (GValue);
+ g_value_init (value, prop_info->property_type);
+
+ prop_info->parser (prop_info,
+ plist_item->property,
+ context,
+ plist_item->value,
+ parent_value,
+ value,
+ &constant);
+
+ g_hash_table_insert (properties, prop_info->priv, value);
+
+ plist = plist->next;
+ }
+}
+
+void
+_mn_stylesheet_properties_list_free (MnStylesheet *stylesheet,
+ GList *plist)
+{
+ GList *tmp = plist;
+ MnPListItem *plist_item;
+
+ while (tmp)
+ {
+ plist_item = (MnPListItem*) tmp->data;
+ g_slice_free (MnPListItem, plist_item);
+ tmp = tmp->next;
+ }
+ g_list_free (plist);
+}
MnStylesheet*
mn_stylesheet_new_from_string (const gchar *string, MnPriority priority)
diff --git a/monet/mn-stylesheet.h b/monet/mn-stylesheet.h
index 3f2811e..44171e4 100644
--- a/monet/mn-stylesheet.h
+++ b/monet/mn-stylesheet.h
@@ -3,6 +3,10 @@
#include <glib-object.h>
+typedef struct _MnStylesheet MnStylesheet;
+
+#include "mn-context.h"
+
G_BEGIN_DECLS
#define MN_TYPE_STYLESHEET mn_stylesheet_get_type()
@@ -30,9 +34,9 @@ typedef enum
MN_PRIORITY_HIGH = 200
} MnPriority;
-typedef struct {
+struct _MnStylesheet {
GObject parent;
-} MnStylesheet;
+};
typedef struct {
GObjectClass parent_class;
@@ -57,6 +61,19 @@ GType mn_stylesheet_get_type (void);
MnStylesheet* mn_stylesheet_new_from_string (const gchar *string,
MnPriority priority);
+
+GList* _mn_stylesheet_find_properties (MnStylesheet *stylesheet,
+ MnContext *context,
+ gpointer *obj,
+ GList *plist);
+void _mn_stylesheet_resolve_properties (MnStylesheet *stylesheet,
+ MnContext *context,
+ GList *plist,
+ GHashTable *properties,
+ GHashTable *parent_properties);
+void _mn_stylesheet_properties_list_free (MnStylesheet *stylesheet,
+ GList *plist);
+
MnPriority mn_stylesheet_get_priority (MnStylesheet *stylesheet);
G_END_DECLS
diff --git a/monet/mn-theme-type.c b/monet/mn-theme-type.c
index 43fd09a..e748e24 100644
--- a/monet/mn-theme-type.c
+++ b/monet/mn-theme-type.c
@@ -44,6 +44,23 @@ mn_theme_type_get_name (MnThemeType* theme_type)
return priv->name;
}
+MnPropertyInfo*
+mn_theme_type_get_property_info (MnThemeType *theme_type,
+ const gchar *alias)
+{
+ MnThemeTypePrivate *priv = GET_PRIVATE (theme_type);
+ const gchar *real_alias;
+ MnPropertyInfo *result;
+
+ real_alias = g_intern_string (alias);
+
+ result = g_hash_table_lookup (priv->property_pool, real_alias);
+ if (result == NULL)
+ result = g_hash_table_lookup (priv->alias_pool, real_alias);
+
+ return result;
+}
+
void
mn_theme_type_install_property (MnThemeType *theme_type,
gchar *property,
@@ -57,6 +74,7 @@ mn_theme_type_install_property (MnThemeType *theme_type,
g_return_if_fail (info != NULL);
property = (gchar*) g_intern_string ((const gchar*) property);
+ info->priv = property;
g_hash_table_insert (priv->property_pool, property, info);
if (aliases == NULL)
diff --git a/monet/mn-theme-type.h b/monet/mn-theme-type.h
index b692561..c58e322 100644
--- a/monet/mn-theme-type.h
+++ b/monet/mn-theme-type.h
@@ -36,16 +36,22 @@ typedef struct _MnPropertyInfo MnPropertyInfo;
#include "mn-context.h"
/* XXX: Do we need the stylesheet here to open files? */
-typedef gboolean (*MnPropertyParser) (MnPropertyInfo *info,
- const gchar *alias,
- MnContext *context,
- const GString *rc_string,
- GValue *property_value);
+typedef void (*MnPropertyParser) (MnPropertyInfo *info,
+ const gchar *alias,
+ MnContext *context,
+ const gchar *rc_string,
+ GValue *parent_value,
+ GValue *property_value,
+ gboolean *constant);
struct _MnPropertyInfo {
+ /* < public > */
GType property_type;
MnPropertyParser parser;
GDestroyNotify free_func;
+
+ /* < private > */
+ void* priv;
};
GType mn_theme_type_get_type (void);
@@ -53,6 +59,8 @@ GType mn_theme_type_get_type (void);
MnThemeType* mn_theme_type_find (gchar *name);
MnThemeType* mn_theme_type_new (gchar *name);
+MnPropertyInfo* mn_theme_type_get_property_info (MnThemeType *theme_type,
+ const gchar *alias);
void mn_theme_type_install_property (MnThemeType *theme_type,
gchar *property,
GStrv aliases,
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 4032492..fa335a9 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,9 +1,11 @@
-AM_CFLAGS = $(MONET_CFLAGS)
+AM_CFLAGS = $(MONET_TEST_CFLAGS)
INCLUDES = -I$(top_srcdir)
-LDADD = $(MONET_LIBS) $(top_builddir)/monet/libmonet.la
+LDADD = $(MONET_TEST_LIBS) $(top_builddir)/monet/libmonet.la
-noinst_PROGRAMS = test-drawing
+noinst_PROGRAMS = test-drawing test
test_drawing_SOURCES = test-drawing.c
+test_SOURCES = test.c
+
-include $(top_srcdir)/git.mk
diff --git a/tests/test.c b/tests/test.c
new file mode 100644
index 0000000..2442362
--- /dev/null
+++ b/tests/test.c
@@ -0,0 +1,156 @@
+#include <monet/monet.h>
+#include <gdk/gdk.h>
+
+GType color_type;
+
+typedef struct {
+ gdouble r;
+ gdouble g;
+ gdouble b;
+ gdouble a;
+} TestColor;
+
+TestColor*
+color_copy (TestColor *src)
+{
+ TestColor *dest = g_slice_new (TestColor);
+ dest->r = src->r;
+ dest->g = src->g;
+ dest->b = src->b;
+ dest->a = src->a;
+
+ return dest;
+}
+
+void
+color_free (TestColor *color)
+{
+ g_slice_free (TestColor, color);
+}
+
+void
+color_parser (MnPropertyInfo *info,
+ const gchar *alias,
+ MnContext *context,
+ const gchar *rc_string,
+ GValue *parent_value,
+ GValue *property_value,
+ gboolean *constant)
+{
+ GdkColor gdk_color;
+ gboolean success;
+ TestColor color;
+
+ success = gdk_color_parse (rc_string, &gdk_color);
+ if (success)
+ {
+ color.r = (gdouble) gdk_color.red / 65535.0;
+ color.g = (gdouble) gdk_color.green / 65535.0;
+ color.b = (gdouble) gdk_color.blue / 65535.0;
+ color.a = 1.0;
+
+ g_value_set_boxed (property_value, &color);
+ }
+ else if (g_str_has_prefix (rc_string, "inherit"))
+ {
+ if (parent_value)
+ {
+ g_assert (G_VALUE_TYPE (parent_value) == G_VALUE_TYPE (property_value));
+ g_print ("inheriting!\n");
+ g_value_copy (parent_value, property_value);
+ }
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ MnThemeType *theme_type;
+ MnContext *context;
+ MnDisplay *display;
+ MnStylesheet *stylesheet;
+ MnPropertyInfo *color_prop = g_malloc (sizeof(MnPropertyInfo));
+ GValue value = {0};
+ TestColor *color;
+
+ gdk_init (&argc, &argv);
+ monet_init (&argc, &argv);
+
+ color_type = g_boxed_type_register_static (g_intern_static_string ("TestColor"),
+ (GBoxedCopyFunc)color_copy,
+ (GBoxedFreeFunc)color_free);
+
+ theme_type = mn_theme_type_new ("widget-test");
+
+ color_prop->property_type = color_type;
+ color_prop->free_func = g_free;
+ color_prop->parser = color_parser;
+
+ mn_theme_type_install_property (theme_type, "color", NULL, color_prop);
+
+ display = mn_display_new (theme_type);
+
+ stylesheet = mn_stylesheet_new_from_string (
+ "window > button { \n"
+ " color: gray; \n"
+ "} \n"
+ "button.urgent { \n"
+ " color: blue; \n"
+ "} \n"
+ ":prelight { \n"
+ " color: red; \n"
+ "} \n"
+ "window { \n"
+ " color: green; \n"
+ " background: black; \n"
+ "}\n",
+ MN_PRIORITY_DEFAULT);
+
+ mn_display_add_stylesheet (display, stylesheet);
+
+ context = mn_context_new (display);
+
+ mn_context_push (context, "window");
+ g_value_init (&value, color_type);
+ mn_context_get_property (context, "color", &value);
+ color = g_value_get_boxed (&value);
+ if (color)
+ g_print ("window: %f, %f, %f, %f\n", (float)color->r, (float)color->g, (float)color->b, (float)color->a);
+
+ mn_context_push (context, "button");
+
+ g_value_reset (&value);
+ mn_context_get_property (context, "color", &value);
+ color = g_value_get_boxed (&value);
+ if (color)
+ g_print ("window > button: %f, %f, %f, %f\n", (float)color->r, (float)color->g, (float)color->b, (float)color->a);
+
+ mn_context_add_class (context, "urgent");
+ /*mn_context_add_pseudo_class (context, "active");
+ mn_context_add_pseudo_class (context, "prelight");
+ mn_context_remove_pseudo_class (context, "active");
+ mn_context_clear_pseudo_classes (context);
+ mn_context_add_pseudo_class (context, "insensitive");*/
+
+ g_value_reset (&value);
+ mn_context_get_property (context, "color", &value);
+ color = g_value_get_boxed (&value);
+ if (color)
+ g_print ("window > button.urgent: %f, %f, %f, %f\n", (float)color->r, (float)color->g, (float)color->b, (float)color->a);
+
+ mn_context_add_pseudo_class (context, "prelight");
+ g_value_reset (&value);
+ mn_context_get_property (context, "color", &value);
+ color = g_value_get_boxed (&value);
+ if (color)
+ g_print ("window > button.urgent:prelight: %f, %f, %f, %f\n", (float)color->r, (float)color->g, (float)color->b, (float)color->a);
+
+ mn_context_pop (context);
+ mn_context_pop (context);
+
+ g_object_unref (context);
+ g_object_unref (stylesheet);
+ g_object_unref (display);
+
+ return 0;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]