Compare commits
4 Commits
main
...
wip/css-me
Author | SHA1 | Date | |
---|---|---|---|
|
281aa2a6a7 | ||
|
94876a23ec | ||
|
b2e36bb85b | ||
|
cd189e515e |
@@ -20,14 +20,88 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <cairo-gobject.h>
|
||||
|
||||
#include "gtkcsscomputedvaluesprivate.h"
|
||||
|
||||
#include "gtkcssstylepropertyprivate.h"
|
||||
#include "gtkcsstypesprivate.h"
|
||||
#include "gtkprivatetypebuiltins.h"
|
||||
#include "gtkshadowprivate.h"
|
||||
#include "gtkanimationdescription.h"
|
||||
#include "gtkcssimageprivate.h"
|
||||
|
||||
G_DEFINE_TYPE (GtkCssComputedValues, _gtk_css_computed_values, G_TYPE_OBJECT)
|
||||
|
||||
|
||||
typedef GValue GtkCssValue;
|
||||
|
||||
static GHashTable *gtk_css_values;
|
||||
|
||||
static guint gtk_css_value_hash (GtkCssValue *css_value);
|
||||
static gboolean gtk_css_value_equal (GtkCssValue *css_value_a, GtkCssValue *css_value_b);
|
||||
|
||||
static GtkCssValue *
|
||||
gtk_css_value_ref (GtkCssValue *v)
|
||||
{
|
||||
v->data[1].v_int++;
|
||||
return v;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_css_value_unref (GtkCssValue *v)
|
||||
{
|
||||
if (--v->data[1].v_int == 0)
|
||||
{
|
||||
g_hash_table_remove (gtk_css_values, v);
|
||||
g_value_unset ((GValue *)v);
|
||||
}
|
||||
}
|
||||
|
||||
static GtkCssValue *
|
||||
gtk_css_value_dup_value (const GValue *v)
|
||||
{
|
||||
GtkCssValue *new;
|
||||
|
||||
if (v == NULL || !G_IS_VALUE (v))
|
||||
return NULL;
|
||||
|
||||
new = g_hash_table_lookup (gtk_css_values, v);
|
||||
if (new)
|
||||
return gtk_css_value_ref (new);
|
||||
|
||||
new = g_new0 (GtkCssValue, 1);
|
||||
g_value_init ((GValue *)new, G_VALUE_TYPE (v));
|
||||
g_value_copy (v, (GValue *)new);
|
||||
new->data[1].v_int = 1;
|
||||
|
||||
g_hash_table_insert (gtk_css_values, new, new);
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
|
||||
static GtkCssValue *
|
||||
gtk_css_value_ref_value (GValue *v)
|
||||
{
|
||||
|
||||
if (v == NULL || !G_IS_VALUE (v))
|
||||
return NULL;
|
||||
|
||||
/* Some magic to detect if the GValue is already a GtkCssValue so we can just ref it */
|
||||
if (v->data[1].v_int > 0)
|
||||
return gtk_css_value_ref ((GtkCssValue *)v);
|
||||
|
||||
return gtk_css_value_dup_value (v);
|
||||
}
|
||||
|
||||
const GValue *
|
||||
gtk_css_value_peek (GtkCssValue *v)
|
||||
{
|
||||
return (const GValue *)v;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_css_computed_values_dispose (GObject *object)
|
||||
{
|
||||
@@ -35,7 +109,7 @@ gtk_css_computed_values_dispose (GObject *object)
|
||||
|
||||
if (values->values)
|
||||
{
|
||||
g_array_free (values->values, TRUE);
|
||||
g_ptr_array_unref (values->values);
|
||||
values->values = NULL;
|
||||
}
|
||||
if (values->sections)
|
||||
@@ -47,18 +121,282 @@ gtk_css_computed_values_dispose (GObject *object)
|
||||
G_OBJECT_CLASS (_gtk_css_computed_values_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
strv_equal (char **a, char **b)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (a == b)
|
||||
return TRUE;
|
||||
|
||||
if (a == NULL || b == NULL)
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; a[i] != NULL && b[i] != NULL; i++)
|
||||
{
|
||||
if (strcmp (a[i], b[i]) != 0)
|
||||
return FALSE;
|
||||
}
|
||||
return a[i] == NULL && b[i] == NULL;
|
||||
}
|
||||
|
||||
static guint
|
||||
strv_hash (char **v)
|
||||
{
|
||||
int i;
|
||||
guint hash;
|
||||
|
||||
if (v == NULL)
|
||||
return 0;
|
||||
|
||||
hash = 0;
|
||||
for (i = 0; v[i] != NULL; i++)
|
||||
hash ^= g_str_hash (v[i]);
|
||||
return hash;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_css_value_equal (GtkCssValue *css_value_a, GtkCssValue *css_value_b)
|
||||
{
|
||||
GType type;
|
||||
const GValue *a = gtk_css_value_peek (css_value_a);
|
||||
const GValue *b = gtk_css_value_peek (css_value_b);
|
||||
|
||||
if (a == b)
|
||||
return TRUE;
|
||||
|
||||
if (a == NULL || b == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (a->g_type != b->g_type)
|
||||
return FALSE;
|
||||
|
||||
type = a->g_type;
|
||||
if (type == G_TYPE_INT || type == G_TYPE_BOOLEAN)
|
||||
{
|
||||
return a->data[0].v_int == b->data[0].v_int;
|
||||
}
|
||||
else if (type == G_TYPE_DOUBLE)
|
||||
{
|
||||
return a->data[0].v_double == b->data[0].v_double;
|
||||
}
|
||||
else if (type == G_TYPE_LONG ||
|
||||
G_TYPE_IS_ENUM (type) ||
|
||||
G_TYPE_IS_FLAGS (type))
|
||||
{
|
||||
return a->data[0].v_long == b->data[0].v_long;
|
||||
}
|
||||
else if (type == GDK_TYPE_RGBA)
|
||||
{
|
||||
return gdk_rgba_equal (a->data[0].v_pointer,
|
||||
b->data[0].v_pointer);
|
||||
}
|
||||
else if (type == G_TYPE_STRV)
|
||||
{
|
||||
return strv_equal (a->data[0].v_pointer,
|
||||
b->data[0].v_pointer);
|
||||
}
|
||||
else if (type == GTK_TYPE_CSS_NUMBER)
|
||||
{
|
||||
return _gtk_css_number_equal (a->data[0].v_pointer,
|
||||
b->data[0].v_pointer);
|
||||
}
|
||||
else if (type == GTK_TYPE_CSS_BORDER_IMAGE_REPEAT)
|
||||
{
|
||||
GtkCssBorderImageRepeat *aa = a->data[0].v_pointer;
|
||||
GtkCssBorderImageRepeat *bb = b->data[0].v_pointer;
|
||||
|
||||
if (aa == bb)
|
||||
return TRUE;
|
||||
if (aa == NULL || bb == NULL)
|
||||
return FALSE;
|
||||
|
||||
return
|
||||
aa->vrepeat == bb->vrepeat &&
|
||||
aa->hrepeat == bb->hrepeat;
|
||||
}
|
||||
else if (type == GTK_TYPE_CSS_BORDER_CORNER_RADIUS)
|
||||
{
|
||||
GtkCssBorderCornerRadius *aa = a->data[0].v_pointer;
|
||||
GtkCssBorderCornerRadius *bb = b->data[0].v_pointer;
|
||||
|
||||
if (aa == bb)
|
||||
return TRUE;
|
||||
if (aa == NULL || bb == NULL)
|
||||
return FALSE;
|
||||
|
||||
return
|
||||
_gtk_css_number_equal (&aa->horizontal, &bb->horizontal) &&
|
||||
_gtk_css_number_equal (&aa->vertical, &bb->vertical);
|
||||
}
|
||||
else if (type == GTK_TYPE_BORDER)
|
||||
{
|
||||
GtkBorder *aa = a->data[0].v_pointer;
|
||||
GtkBorder *bb = b->data[0].v_pointer;
|
||||
|
||||
if (aa == bb)
|
||||
return TRUE;
|
||||
if (aa == NULL || bb == NULL)
|
||||
return FALSE;
|
||||
|
||||
return
|
||||
aa->left == bb->left &&
|
||||
aa->right == bb->right &&
|
||||
aa->top == bb->top &&
|
||||
aa->bottom == bb->bottom;
|
||||
}
|
||||
else if (type == GTK_TYPE_CSS_BACKGROUND_SIZE)
|
||||
{
|
||||
GtkCssBackgroundSize *aa = a->data[0].v_pointer;
|
||||
GtkCssBackgroundSize *bb = b->data[0].v_pointer;
|
||||
|
||||
if (aa == bb)
|
||||
return TRUE;
|
||||
if (aa == NULL || bb == NULL)
|
||||
return FALSE;
|
||||
|
||||
return
|
||||
_gtk_css_number_equal (&aa->width, &bb->width) &&
|
||||
_gtk_css_number_equal (&aa->height, &bb->height) &&
|
||||
aa->cover == bb->cover &&
|
||||
aa->contain == bb->contain;
|
||||
}
|
||||
else if (type == GTK_TYPE_SHADOW ||
|
||||
type == G_TYPE_PTR_ARRAY ||
|
||||
type == CAIRO_GOBJECT_TYPE_PATTERN ||
|
||||
type == GTK_TYPE_THEMING_ENGINE ||
|
||||
type == GTK_TYPE_ANIMATION_DESCRIPTION||
|
||||
type == GTK_TYPE_CSS_IMAGE)
|
||||
{
|
||||
/* These are refcounted, compare by pointer */
|
||||
return a->data[0].v_pointer == b->data[0].v_pointer;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_error ("Can't handle CSS type %s\n", g_type_name (type));
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static guint
|
||||
gtk_css_value_hash (GtkCssValue *css_value)
|
||||
{
|
||||
GType type;
|
||||
const GValue *v = gtk_css_value_peek (css_value);
|
||||
|
||||
if (v == NULL)
|
||||
return 0;
|
||||
|
||||
if (v->g_type == 0)
|
||||
return 0;
|
||||
|
||||
type = v->g_type;
|
||||
|
||||
if (type == G_TYPE_INT || type == G_TYPE_BOOLEAN)
|
||||
{
|
||||
return (guint)v->data[0].v_int;
|
||||
}
|
||||
else if (type == G_TYPE_DOUBLE)
|
||||
{
|
||||
return (guint)v->data[0].v_double;
|
||||
}
|
||||
else if (type == G_TYPE_LONG ||
|
||||
G_TYPE_IS_ENUM (type) ||
|
||||
G_TYPE_IS_FLAGS (type))
|
||||
{
|
||||
return (guint)v->data[0].v_long;
|
||||
}
|
||||
else if (type == GDK_TYPE_RGBA)
|
||||
{
|
||||
return gdk_rgba_hash (v->data[0].v_pointer);
|
||||
}
|
||||
else if (type == G_TYPE_STRV)
|
||||
{
|
||||
return strv_hash (v->data[0].v_pointer);
|
||||
}
|
||||
else if (type == GTK_TYPE_CSS_NUMBER)
|
||||
{
|
||||
return _gtk_css_number_hash (v->data[0].v_pointer);
|
||||
}
|
||||
else if (type == GTK_TYPE_CSS_BORDER_IMAGE_REPEAT)
|
||||
{
|
||||
GtkCssBorderImageRepeat *vv = v->data[0].v_pointer;
|
||||
|
||||
if (vv == NULL)
|
||||
return 0;
|
||||
|
||||
return ((guint)vv->vrepeat) ^ ((guint)vv->hrepeat);
|
||||
}
|
||||
else if (type == GTK_TYPE_CSS_BORDER_CORNER_RADIUS)
|
||||
{
|
||||
GtkCssBorderCornerRadius *vv = v->data[0].v_pointer;
|
||||
|
||||
if (vv == NULL)
|
||||
return 0;
|
||||
|
||||
return
|
||||
_gtk_css_number_hash (&vv->horizontal) ^
|
||||
_gtk_css_number_hash (&vv->vertical);
|
||||
}
|
||||
else if (type == GTK_TYPE_BORDER)
|
||||
{
|
||||
GtkBorder *vv = v->data[0].v_pointer;
|
||||
|
||||
if (vv == NULL)
|
||||
return 0;
|
||||
|
||||
return
|
||||
((guint)vv->left) ^
|
||||
(((guint)vv->right) << 16) ^
|
||||
((guint)vv->top) ^
|
||||
(((guint)vv->bottom) << 16);
|
||||
}
|
||||
else if (type == GTK_TYPE_CSS_BACKGROUND_SIZE)
|
||||
{
|
||||
GtkCssBackgroundSize *vv = v->data[0].v_pointer;
|
||||
|
||||
if (vv == NULL)
|
||||
return 0;
|
||||
|
||||
return
|
||||
_gtk_css_number_hash (&vv->width) ^
|
||||
_gtk_css_number_hash (&vv->height) ^
|
||||
(((guint)vv->cover) << 9) ^
|
||||
(((guint)vv->contain) << 9);
|
||||
}
|
||||
else if (type == GTK_TYPE_SHADOW ||
|
||||
type == G_TYPE_PTR_ARRAY ||
|
||||
type == CAIRO_GOBJECT_TYPE_PATTERN ||
|
||||
type == GTK_TYPE_THEMING_ENGINE ||
|
||||
type == GTK_TYPE_ANIMATION_DESCRIPTION||
|
||||
type == GTK_TYPE_CSS_IMAGE)
|
||||
{
|
||||
/* These are refcounted, compare by pointer */
|
||||
return GPOINTER_TO_INT (v->data[0].v_pointer);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_error ("Can't handle CSS type %s\n", g_type_name (type));
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
_gtk_css_computed_values_class_init (GtkCssComputedValuesClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->dispose = gtk_css_computed_values_dispose;
|
||||
|
||||
gtk_css_values = g_hash_table_new ((GHashFunc)gtk_css_value_hash, (GEqualFunc)gtk_css_value_equal);
|
||||
}
|
||||
|
||||
static void
|
||||
_gtk_css_computed_values_init (GtkCssComputedValues *computed_values)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
GtkCssComputedValues *
|
||||
@@ -92,12 +430,9 @@ _gtk_css_computed_values_compute_value (GtkCssComputedValues *values,
|
||||
parent = gtk_style_context_get_parent (context);
|
||||
|
||||
if (values->values == NULL)
|
||||
{
|
||||
values->values = g_array_new (FALSE, TRUE, sizeof (GValue));
|
||||
g_array_set_clear_func (values->values, (GDestroyNotify) g_value_unset);
|
||||
}
|
||||
values->values = g_ptr_array_new_with_free_func ((GDestroyNotify)gtk_css_value_unref);
|
||||
if (id <= values->values->len)
|
||||
g_array_set_size (values->values, id + 1);
|
||||
g_ptr_array_set_size (values->values, id + 1);
|
||||
|
||||
/* http://www.w3.org/TR/css3-cascade/#cascade
|
||||
* Then, for every element, the value for each property can be found
|
||||
@@ -158,22 +493,27 @@ _gtk_css_computed_values_compute_value (GtkCssComputedValues *values,
|
||||
specified = _gtk_css_style_property_get_initial_value (prop);
|
||||
}
|
||||
|
||||
|
||||
/* Clear existing value, can't reuse as it may be shared */
|
||||
if (g_ptr_array_index (values->values, id) != NULL)
|
||||
gtk_css_value_unref (g_ptr_array_index (values->values, id));
|
||||
|
||||
if (specified)
|
||||
{
|
||||
GValue value = G_VALUE_INIT;
|
||||
_gtk_css_style_property_compute_value (prop,
|
||||
&g_array_index (values->values, GValue, id),
|
||||
&value,
|
||||
context,
|
||||
specified);
|
||||
g_ptr_array_index (values->values, id) = gtk_css_value_dup_value (&value);
|
||||
g_value_unset (&value);
|
||||
}
|
||||
else
|
||||
{
|
||||
const GValue *parent_value;
|
||||
GValue *value = &g_array_index (values->values, GValue, id);
|
||||
/* Set NULL here and do the inheritance upon lookup? */
|
||||
parent_value = _gtk_style_context_peek_property (parent,
|
||||
_gtk_style_property_get_name (GTK_STYLE_PROPERTY (prop)));
|
||||
g_value_init (value, G_VALUE_TYPE (parent_value));
|
||||
g_value_copy (parent_value, value);
|
||||
g_ptr_array_index (values->values, id) = gtk_css_value_ref_value ((GValue *)parent_value);
|
||||
}
|
||||
|
||||
if (section)
|
||||
@@ -193,23 +533,19 @@ _gtk_css_computed_values_set_value (GtkCssComputedValues *values,
|
||||
const GValue *value,
|
||||
GtkCssSection *section)
|
||||
{
|
||||
GValue *set;
|
||||
|
||||
g_return_if_fail (GTK_IS_CSS_COMPUTED_VALUES (values));
|
||||
g_return_if_fail (value == NULL || G_IS_VALUE (value));
|
||||
|
||||
if (values->values == NULL)
|
||||
{
|
||||
values->values = g_array_new (FALSE, TRUE, sizeof (GValue));
|
||||
g_array_set_clear_func (values->values, (GDestroyNotify) g_value_unset);
|
||||
}
|
||||
values->values = g_ptr_array_new_with_free_func ((GDestroyNotify)gtk_css_value_unref);
|
||||
if (id <= values->values->len)
|
||||
g_array_set_size (values->values, id + 1);
|
||||
g_ptr_array_set_size (values->values, id + 1);
|
||||
|
||||
/* Clear existing value, can't reuse as it may be shared */
|
||||
if (g_ptr_array_index (values->values, id) != NULL)
|
||||
gtk_css_value_unref (g_ptr_array_index (values->values, id));
|
||||
|
||||
set = &g_array_index (values->values, GValue, id);
|
||||
g_value_init (set, G_VALUE_TYPE (value));
|
||||
g_value_copy (value, set);
|
||||
g_ptr_array_index (values->values, id) = gtk_css_value_ref_value ((GValue *)value);
|
||||
|
||||
if (section)
|
||||
{
|
||||
@@ -226,19 +562,13 @@ const GValue *
|
||||
_gtk_css_computed_values_get_value (GtkCssComputedValues *values,
|
||||
guint id)
|
||||
{
|
||||
const GValue *v;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_CSS_COMPUTED_VALUES (values), NULL);
|
||||
|
||||
if (values->values == NULL ||
|
||||
id >= values->values->len)
|
||||
return NULL;
|
||||
|
||||
v = &g_array_index (values->values, GValue, id);
|
||||
if (!G_IS_VALUE (v))
|
||||
return NULL;
|
||||
|
||||
return v;
|
||||
return gtk_css_value_peek (g_ptr_array_index (values->values, id));
|
||||
}
|
||||
|
||||
const GValue *
|
||||
|
@@ -42,7 +42,7 @@ struct _GtkCssComputedValues
|
||||
{
|
||||
GObject parent;
|
||||
|
||||
GArray *values;
|
||||
GPtrArray *values;
|
||||
GPtrArray *sections;
|
||||
};
|
||||
|
||||
|
@@ -964,15 +964,19 @@
|
||||
|
||||
typedef struct GtkCssRuleset GtkCssRuleset;
|
||||
typedef struct _GtkCssScanner GtkCssScanner;
|
||||
typedef struct _PropertyValue PropertyValue;
|
||||
typedef struct _WidgetPropertyValue WidgetPropertyValue;
|
||||
typedef enum ParserScope ParserScope;
|
||||
typedef enum ParserSymbol ParserSymbol;
|
||||
|
||||
struct GtkCssRuleset
|
||||
{
|
||||
GtkCssSelector *selector;
|
||||
GHashTable *widget_style;
|
||||
GHashTable *style;
|
||||
WidgetPropertyValue *widget_style;
|
||||
PropertyValue *style;
|
||||
GtkBitmask *set_styles;
|
||||
guint owns_style : 1;
|
||||
guint owns_widget_style : 1;
|
||||
};
|
||||
|
||||
struct _GtkCssScanner
|
||||
@@ -1001,11 +1005,15 @@ enum {
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static gboolean gtk_keep_css_sections = FALSE;
|
||||
|
||||
static guint css_provider_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
static void gtk_css_provider_finalize (GObject *object);
|
||||
static void gtk_css_style_provider_iface_init (GtkStyleProviderIface *iface);
|
||||
static void gtk_css_style_provider_private_iface_init (GtkStyleProviderPrivateInterface *iface);
|
||||
static void property_value_list_free (PropertyValue *head);
|
||||
static void widget_property_value_list_free (WidgetPropertyValue *head);
|
||||
|
||||
static gboolean
|
||||
gtk_css_provider_load_internal (GtkCssProvider *css_provider,
|
||||
@@ -1078,6 +1086,9 @@ gtk_css_provider_class_init (GtkCssProviderClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
if (g_getenv ("GTK_CSS_DEBUG"))
|
||||
gtk_keep_css_sections = TRUE;
|
||||
|
||||
/**
|
||||
* GtkCssProvider::parsing-error:
|
||||
* @provider: the provider that had a parsing error
|
||||
@@ -1114,16 +1125,17 @@ gtk_css_provider_class_init (GtkCssProviderClass *klass)
|
||||
|
||||
static void
|
||||
gtk_css_ruleset_init_copy (GtkCssRuleset *new,
|
||||
const GtkCssRuleset *ruleset,
|
||||
GtkCssRuleset *ruleset,
|
||||
GtkCssSelector *selector)
|
||||
{
|
||||
memcpy (new, ruleset, sizeof (GtkCssRuleset));
|
||||
|
||||
new->selector = selector;
|
||||
if (new->widget_style)
|
||||
g_hash_table_ref (new->widget_style);
|
||||
if (new->style)
|
||||
g_hash_table_ref (new->style);
|
||||
/* First copy takes over ownership */
|
||||
if (ruleset->owns_style)
|
||||
ruleset->owns_style = FALSE;
|
||||
if (ruleset->owns_widget_style)
|
||||
ruleset->owns_widget_style = FALSE;
|
||||
if (new->set_styles)
|
||||
new->set_styles = _gtk_bitmask_copy (new->set_styles);
|
||||
}
|
||||
@@ -1131,59 +1143,200 @@ gtk_css_ruleset_init_copy (GtkCssRuleset *new,
|
||||
static void
|
||||
gtk_css_ruleset_clear (GtkCssRuleset *ruleset)
|
||||
{
|
||||
if (ruleset->style)
|
||||
g_hash_table_unref (ruleset->style);
|
||||
if (ruleset->owns_style)
|
||||
property_value_list_free (ruleset->style);
|
||||
if (ruleset->set_styles)
|
||||
_gtk_bitmask_free (ruleset->set_styles);
|
||||
if (ruleset->widget_style)
|
||||
g_hash_table_unref (ruleset->widget_style);
|
||||
if (ruleset->owns_widget_style)
|
||||
widget_property_value_list_free (ruleset->widget_style);
|
||||
if (ruleset->selector)
|
||||
_gtk_css_selector_free (ruleset->selector);
|
||||
|
||||
memset (ruleset, 0, sizeof (GtkCssRuleset));
|
||||
}
|
||||
|
||||
typedef struct _PropertyValue PropertyValue;
|
||||
struct _PropertyValue {
|
||||
GtkCssSection *section;
|
||||
GtkStyleProperty *property;
|
||||
PropertyValue *next;
|
||||
GValue value;
|
||||
};
|
||||
|
||||
typedef struct _PropertyValueWithSection PropertyValueWithSection;
|
||||
struct _PropertyValueWithSection {
|
||||
PropertyValue base;
|
||||
GtkCssSection *section;
|
||||
};
|
||||
|
||||
static PropertyValue *
|
||||
property_value_new (GtkCssSection *section)
|
||||
property_value_new (GtkStyleProperty *property, GtkCssSection *section)
|
||||
{
|
||||
PropertyValue *value;
|
||||
|
||||
value = g_slice_new0 (PropertyValue);
|
||||
if (gtk_keep_css_sections)
|
||||
value = (PropertyValue *)g_slice_new0 (PropertyValueWithSection);
|
||||
else
|
||||
value = g_slice_new0 (PropertyValue);
|
||||
|
||||
value->section = gtk_css_section_ref (section);
|
||||
value->property = property;
|
||||
|
||||
if (gtk_keep_css_sections)
|
||||
((PropertyValueWithSection *)value)->section = gtk_css_section_ref (section);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static GtkCssSection *
|
||||
property_value_get_section (PropertyValue *value)
|
||||
{
|
||||
if (gtk_keep_css_sections)
|
||||
return ((PropertyValueWithSection *)value)->section;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
property_value_free (PropertyValue *value)
|
||||
{
|
||||
GtkCssSection *section;
|
||||
|
||||
if (G_IS_VALUE (&value->value))
|
||||
g_value_unset (&value->value);
|
||||
|
||||
gtk_css_section_unref (value->section);
|
||||
section = property_value_get_section (value);
|
||||
if (section != NULL)
|
||||
gtk_css_section_unref (section);
|
||||
|
||||
g_slice_free (PropertyValue, value);
|
||||
}
|
||||
|
||||
static void
|
||||
property_value_list_free (PropertyValue *head)
|
||||
{
|
||||
PropertyValue *l, *next;
|
||||
for (l = head; l != NULL; l = next)
|
||||
{
|
||||
next = l->next;
|
||||
property_value_free (l);
|
||||
}
|
||||
}
|
||||
|
||||
static PropertyValue *
|
||||
property_value_list_remove_property (PropertyValue *head, GtkStyleProperty *property)
|
||||
{
|
||||
PropertyValue *l, **last;
|
||||
|
||||
last = &head;
|
||||
|
||||
for (l = head; l != NULL; l = l->next)
|
||||
{
|
||||
if (l->property == property)
|
||||
{
|
||||
*last = l->next;
|
||||
property_value_free (l);
|
||||
break;
|
||||
}
|
||||
|
||||
last = &l->next;
|
||||
}
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
struct _WidgetPropertyValue {
|
||||
char *name;
|
||||
WidgetPropertyValue *next;
|
||||
GValue value;
|
||||
};
|
||||
|
||||
typedef struct _WidgetPropertyValueWithSection WidgetPropertyValueWithSection;
|
||||
struct _WidgetPropertyValueWithSection {
|
||||
WidgetPropertyValue base;
|
||||
GtkCssSection *section;
|
||||
};
|
||||
|
||||
|
||||
static WidgetPropertyValue *
|
||||
widget_property_value_new (char *name, GtkCssSection *section)
|
||||
{
|
||||
WidgetPropertyValue *value;
|
||||
|
||||
if (gtk_keep_css_sections)
|
||||
value = (WidgetPropertyValue *)g_slice_new0 (WidgetPropertyValueWithSection);
|
||||
else
|
||||
value = g_slice_new0 (WidgetPropertyValue);
|
||||
|
||||
value->name = name;
|
||||
if (gtk_keep_css_sections)
|
||||
((WidgetPropertyValueWithSection *)value)->section = gtk_css_section_ref (section);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static GtkCssSection *
|
||||
widget_property_value_get_section (WidgetPropertyValue *value)
|
||||
{
|
||||
if (gtk_keep_css_sections)
|
||||
return ((WidgetPropertyValueWithSection *)value)->section;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
widget_property_value_free (WidgetPropertyValue *value)
|
||||
{
|
||||
GtkCssSection *section;
|
||||
|
||||
if (G_IS_VALUE (&value->value))
|
||||
g_value_unset (&value->value);
|
||||
|
||||
g_free (value->name);
|
||||
|
||||
section = widget_property_value_get_section (value);
|
||||
if (section != NULL)
|
||||
gtk_css_section_unref (section);
|
||||
|
||||
g_slice_free (WidgetPropertyValue, value);
|
||||
}
|
||||
|
||||
static void
|
||||
widget_property_value_list_free (WidgetPropertyValue *head)
|
||||
{
|
||||
WidgetPropertyValue *l, *next;
|
||||
for (l = head; l != NULL; l = next)
|
||||
{
|
||||
next = l->next;
|
||||
widget_property_value_free (l);
|
||||
}
|
||||
}
|
||||
|
||||
static WidgetPropertyValue *
|
||||
widget_property_value_list_remove_name (WidgetPropertyValue *head, const char *name)
|
||||
{
|
||||
WidgetPropertyValue *l, **last;
|
||||
|
||||
last = &head;
|
||||
|
||||
for (l = head; l != NULL; l = l->next)
|
||||
{
|
||||
if (strcmp (l->name, name) == 0)
|
||||
{
|
||||
*last = l->next;
|
||||
widget_property_value_free (l);
|
||||
break;
|
||||
}
|
||||
|
||||
last = &l->next;
|
||||
}
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_css_ruleset_add_style (GtkCssRuleset *ruleset,
|
||||
char *name,
|
||||
PropertyValue *value)
|
||||
WidgetPropertyValue *value)
|
||||
{
|
||||
if (ruleset->widget_style == NULL)
|
||||
ruleset->widget_style = g_hash_table_new_full (g_str_hash,
|
||||
g_str_equal,
|
||||
(GDestroyNotify) g_free,
|
||||
(GDestroyNotify) property_value_free);
|
||||
|
||||
g_hash_table_insert (ruleset->widget_style, name, value);
|
||||
value->next = widget_property_value_list_remove_name (ruleset->widget_style, name);
|
||||
ruleset->widget_style = value;
|
||||
ruleset->owns_widget_style = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1191,14 +1344,8 @@ gtk_css_ruleset_add (GtkCssRuleset *ruleset,
|
||||
GtkStyleProperty *prop,
|
||||
PropertyValue *value)
|
||||
{
|
||||
if (ruleset->style == NULL)
|
||||
{
|
||||
ruleset->style = g_hash_table_new_full (g_direct_hash,
|
||||
g_direct_equal,
|
||||
NULL,
|
||||
(GDestroyNotify) property_value_free);
|
||||
ruleset->set_styles = _gtk_bitmask_new ();
|
||||
}
|
||||
if (ruleset->set_styles == NULL)
|
||||
ruleset->set_styles = _gtk_bitmask_new ();
|
||||
|
||||
if (GTK_IS_CSS_SHORTHAND_PROPERTY (prop))
|
||||
{
|
||||
@@ -1212,7 +1359,8 @@ gtk_css_ruleset_add (GtkCssRuleset *ruleset,
|
||||
const GValue *sub = &g_array_index (array, GValue, i);
|
||||
PropertyValue *val;
|
||||
|
||||
val = property_value_new (value->section);
|
||||
val = property_value_new (GTK_STYLE_PROPERTY (child),
|
||||
property_value_get_section (value));
|
||||
g_value_init (&val->value, G_VALUE_TYPE (sub));
|
||||
g_value_copy (sub, &val->value);
|
||||
gtk_css_ruleset_add (ruleset, GTK_STYLE_PROPERTY (child), val);
|
||||
@@ -1227,7 +1375,10 @@ gtk_css_ruleset_add (GtkCssRuleset *ruleset,
|
||||
_gtk_bitmask_set (ruleset->set_styles,
|
||||
_gtk_css_style_property_get_id (GTK_CSS_STYLE_PROPERTY (prop)),
|
||||
TRUE);
|
||||
g_hash_table_insert (ruleset->style, prop, value);
|
||||
|
||||
value->next = property_value_list_remove_property (ruleset->style, prop);
|
||||
ruleset->style = value;
|
||||
ruleset->owns_style = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1426,8 +1577,7 @@ gtk_css_provider_get_style (GtkStyleProvider *provider,
|
||||
for (i = 0; i < priv->rulesets->len; i++)
|
||||
{
|
||||
GtkCssRuleset *ruleset;
|
||||
GHashTableIter iter;
|
||||
gpointer key, val;
|
||||
PropertyValue *value;
|
||||
|
||||
ruleset = &g_array_index (priv->rulesets, GtkCssRuleset, i);
|
||||
|
||||
@@ -1437,18 +1587,11 @@ gtk_css_provider_get_style (GtkStyleProvider *provider,
|
||||
if (!gtk_css_ruleset_matches (ruleset, path, 0))
|
||||
continue;
|
||||
|
||||
g_hash_table_iter_init (&iter, ruleset->style);
|
||||
|
||||
while (g_hash_table_iter_next (&iter, &key, &val))
|
||||
{
|
||||
GtkCssStyleProperty *prop = key;
|
||||
PropertyValue *value = val;
|
||||
|
||||
_gtk_style_properties_set_property_by_property (props,
|
||||
prop,
|
||||
_gtk_css_selector_get_state_flags (ruleset->selector),
|
||||
&value->value);
|
||||
}
|
||||
for (value = ruleset->style; value != NULL; value = value->next)
|
||||
_gtk_style_properties_set_property_by_property (props,
|
||||
GTK_CSS_STYLE_PROPERTY (value->property),
|
||||
_gtk_css_selector_get_state_flags (ruleset->selector),
|
||||
&value->value);
|
||||
}
|
||||
|
||||
return props;
|
||||
@@ -1463,7 +1606,7 @@ gtk_css_provider_get_style_property (GtkStyleProvider *provider,
|
||||
{
|
||||
GtkCssProvider *css_provider = GTK_CSS_PROVIDER (provider);
|
||||
GtkCssProviderPrivate *priv = css_provider->priv;
|
||||
PropertyValue *val;
|
||||
WidgetPropertyValue *val;
|
||||
gboolean found = FALSE;
|
||||
gchar *prop_name;
|
||||
gint i;
|
||||
@@ -1484,27 +1627,32 @@ gtk_css_provider_get_style_property (GtkStyleProvider *provider,
|
||||
if (!gtk_css_ruleset_matches (ruleset, path, state))
|
||||
continue;
|
||||
|
||||
val = g_hash_table_lookup (ruleset->widget_style, prop_name);
|
||||
for (val = ruleset->widget_style; val != NULL; val = val->next)
|
||||
{
|
||||
if (strcmp (val->name, prop_name) == 0)
|
||||
{
|
||||
GtkCssScanner *scanner;
|
||||
GtkCssSection *section;
|
||||
|
||||
if (val)
|
||||
{
|
||||
GtkCssScanner *scanner;
|
||||
section = widget_property_value_get_section (val);
|
||||
scanner = gtk_css_scanner_new (css_provider,
|
||||
NULL,
|
||||
section,
|
||||
section ? gtk_css_section_get_file (section) : NULL,
|
||||
g_value_get_string (&val->value));
|
||||
|
||||
scanner = gtk_css_scanner_new (css_provider,
|
||||
NULL,
|
||||
val->section,
|
||||
gtk_css_section_get_file (val->section),
|
||||
g_value_get_string (&val->value));
|
||||
found = _gtk_css_style_parse_value (value,
|
||||
scanner->parser,
|
||||
NULL);
|
||||
|
||||
found = _gtk_css_style_parse_value (value,
|
||||
scanner->parser,
|
||||
NULL);
|
||||
gtk_css_scanner_destroy (scanner);
|
||||
|
||||
gtk_css_scanner_destroy (scanner);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
break;
|
||||
}
|
||||
if (found)
|
||||
break;
|
||||
}
|
||||
|
||||
g_free (prop_name);
|
||||
@@ -1544,8 +1692,7 @@ gtk_css_style_provider_lookup (GtkStyleProviderPrivate *provider,
|
||||
for (i = priv->rulesets->len - 1; i >= 0; i--)
|
||||
{
|
||||
GtkCssRuleset *ruleset;
|
||||
GHashTableIter iter;
|
||||
gpointer key, val;
|
||||
PropertyValue *value;
|
||||
|
||||
ruleset = &g_array_index (priv->rulesets, GtkCssRuleset, i);
|
||||
|
||||
@@ -1559,18 +1706,17 @@ gtk_css_style_provider_lookup (GtkStyleProviderPrivate *provider,
|
||||
if (!gtk_css_ruleset_matches (ruleset, path, state))
|
||||
continue;
|
||||
|
||||
g_hash_table_iter_init (&iter, ruleset->style);
|
||||
|
||||
while (g_hash_table_iter_next (&iter, &key, &val))
|
||||
for (value = ruleset->style; value != NULL; value = value->next)
|
||||
{
|
||||
GtkCssStyleProperty *prop = key;
|
||||
PropertyValue *value = val;
|
||||
GtkCssStyleProperty *prop = GTK_CSS_STYLE_PROPERTY (value->property);
|
||||
guint id = _gtk_css_style_property_get_id (prop);
|
||||
|
||||
if (!_gtk_css_lookup_is_missing (lookup, id))
|
||||
continue;
|
||||
|
||||
_gtk_css_lookup_set (lookup, id, value->section, &value->value);
|
||||
_gtk_css_lookup_set (lookup, id,
|
||||
property_value_get_section (value),
|
||||
&value->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2385,7 +2531,7 @@ parse_declaration (GtkCssScanner *scanner,
|
||||
|
||||
gtk_css_scanner_push_section (scanner, GTK_CSS_SECTION_VALUE);
|
||||
|
||||
val = property_value_new (scanner->section);
|
||||
val = property_value_new (property, scanner->section);
|
||||
|
||||
if (_gtk_style_property_parse_value (property,
|
||||
&val->value,
|
||||
@@ -2431,9 +2577,9 @@ parse_declaration (GtkCssScanner *scanner,
|
||||
value_str = _gtk_css_parser_read_value (scanner->parser);
|
||||
if (value_str)
|
||||
{
|
||||
PropertyValue *val;
|
||||
WidgetPropertyValue *val;
|
||||
|
||||
val = property_value_new (scanner->section);
|
||||
val = widget_property_value_new (name, scanner->section);
|
||||
g_value_init (&val->value, G_TYPE_STRING);
|
||||
g_value_take_string (&val->value, value_str);
|
||||
|
||||
@@ -2972,15 +3118,27 @@ gtk_css_provider_get_named (const gchar *name,
|
||||
static int
|
||||
compare_properties (gconstpointer a, gconstpointer b)
|
||||
{
|
||||
return strcmp (_gtk_style_property_get_name ((GtkStyleProperty *) a),
|
||||
_gtk_style_property_get_name ((GtkStyleProperty *) b));
|
||||
const PropertyValue *aa = a;
|
||||
const PropertyValue *bb = b;
|
||||
return strcmp (_gtk_style_property_get_name ((GtkStyleProperty *)aa->property),
|
||||
_gtk_style_property_get_name ((GtkStyleProperty *)bb->property));
|
||||
}
|
||||
|
||||
static int
|
||||
compare_names (gconstpointer a, gconstpointer b)
|
||||
{
|
||||
const WidgetPropertyValue *aa = a;
|
||||
const WidgetPropertyValue *bb = b;
|
||||
return strcmp (aa->name, bb->name);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_css_ruleset_print (const GtkCssRuleset *ruleset,
|
||||
GString *str)
|
||||
{
|
||||
GList *keys, *walk;
|
||||
GList *values, *walk;
|
||||
PropertyValue *value;
|
||||
WidgetPropertyValue *widget_value;
|
||||
|
||||
_gtk_css_selector_print (ruleset->selector, str);
|
||||
|
||||
@@ -2988,14 +3146,18 @@ gtk_css_ruleset_print (const GtkCssRuleset *ruleset,
|
||||
|
||||
if (ruleset->style)
|
||||
{
|
||||
keys = g_hash_table_get_keys (ruleset->style);
|
||||
/* so the output is identical for identical selector styles */
|
||||
keys = g_list_sort (keys, compare_properties);
|
||||
values = NULL;
|
||||
for (value = ruleset->style; value != NULL; value = value->next)
|
||||
values = g_list_prepend (values, value);
|
||||
|
||||
for (walk = keys; walk; walk = walk->next)
|
||||
/* so the output is identical for identical selector styles */
|
||||
values = g_list_sort (values, compare_properties);
|
||||
|
||||
for (walk = values; walk; walk = walk->next)
|
||||
{
|
||||
GtkCssStyleProperty *prop = walk->data;
|
||||
const PropertyValue *value = g_hash_table_lookup (ruleset->style, prop);
|
||||
GtkCssStyleProperty *prop;
|
||||
value = walk->data;
|
||||
prop = GTK_CSS_STYLE_PROPERTY (value->property);
|
||||
|
||||
g_string_append (str, " ");
|
||||
g_string_append (str, _gtk_style_property_get_name (GTK_STYLE_PROPERTY (prop)));
|
||||
@@ -3004,28 +3166,30 @@ gtk_css_ruleset_print (const GtkCssRuleset *ruleset,
|
||||
g_string_append (str, ";\n");
|
||||
}
|
||||
|
||||
g_list_free (keys);
|
||||
g_list_free (values);
|
||||
}
|
||||
|
||||
if (ruleset->widget_style)
|
||||
{
|
||||
keys = g_hash_table_get_keys (ruleset->widget_style);
|
||||
/* so the output is identical for identical selector styles */
|
||||
keys = g_list_sort (keys, (GCompareFunc) strcmp);
|
||||
values = NULL;
|
||||
for (widget_value = ruleset->widget_style; widget_value != NULL; widget_value = widget_value->next)
|
||||
values = g_list_prepend (values, widget_value);
|
||||
|
||||
for (walk = keys; walk; walk = walk->next)
|
||||
/* so the output is identical for identical selector styles */
|
||||
values = g_list_sort (values, compare_names);
|
||||
|
||||
for (walk = values; walk; walk = walk->next)
|
||||
{
|
||||
const char *name = walk->data;
|
||||
const PropertyValue *value = g_hash_table_lookup (ruleset->widget_style, (gpointer) name);
|
||||
widget_value = walk->data;
|
||||
|
||||
g_string_append (str, " ");
|
||||
g_string_append (str, name);
|
||||
g_string_append (str, widget_value->name);
|
||||
g_string_append (str, ": ");
|
||||
g_string_append (str, g_value_get_string (&value->value));
|
||||
g_string_append (str, g_value_get_string (&widget_value->value));
|
||||
g_string_append (str, ";\n");
|
||||
}
|
||||
|
||||
g_list_free (keys);
|
||||
g_list_free (values);
|
||||
}
|
||||
|
||||
g_string_append (str, "}\n");
|
||||
|
@@ -54,6 +54,15 @@ _gtk_css_number_equal (const GtkCssNumber *one,
|
||||
one->value == two->value;
|
||||
}
|
||||
|
||||
guint
|
||||
_gtk_css_number_hash (const GtkCssNumber *number)
|
||||
{
|
||||
guint hash;
|
||||
|
||||
hash = (guint)number->value;
|
||||
hash ^= (guint)number->unit;
|
||||
}
|
||||
|
||||
double
|
||||
_gtk_css_number_get (const GtkCssNumber *number,
|
||||
double one_hundred_percent)
|
||||
|
@@ -142,6 +142,7 @@ void _gtk_css_number_init (GtkCssNumber
|
||||
GtkCssUnit unit);
|
||||
gboolean _gtk_css_number_equal (const GtkCssNumber *one,
|
||||
const GtkCssNumber *two);
|
||||
guint _gtk_css_number_hash (const GtkCssNumber *number);
|
||||
double _gtk_css_number_get (const GtkCssNumber *number,
|
||||
double one_hundred_percent);
|
||||
void _gtk_css_number_compute (GtkCssNumber *dest,
|
||||
|
Reference in New Issue
Block a user