Commit 4781f94d authored by Carlos Garnacho's avatar Carlos Garnacho

Move all theming stack to use GtkStateFlags.

This support goes from the theming engines, which are able to retrieve
style for different combined states to the CSS provider, where several
state pseudo-classes may be specified, such as:

GtkButton:active:prelight {}
parent 2c7c4d9a
......@@ -72,7 +72,7 @@ struct SelectorElement
struct SelectorPath
{
GSList *elements;
GtkStateType state;
GtkStateFlags state;
guint ref_count;
};
......@@ -149,7 +149,6 @@ selector_path_new (void)
SelectorPath *path;
path = g_slice_new0 (SelectorPath);
path->state = GTK_STATE_NORMAL;
path->ref_count = 1;
return path;
......@@ -541,7 +540,7 @@ struct StylePriorityInfo
{
guint64 score;
GHashTable *style;
GtkStateType state;
GtkStateFlags state;
};
static GArray *
......@@ -654,10 +653,7 @@ gtk_css_provider_get_style (GtkStyleProvider *provider,
!gtk_style_set_lookup_property (prop, NULL, NULL))
continue;
if (info->state == GTK_STATE_NORMAL)
gtk_style_set_set_default (set, key, value);
else
gtk_style_set_set_property (set, key, info->state, value);
gtk_style_set_set_property (set, key, info->state, value);
}
}
......@@ -880,14 +876,12 @@ css_provider_commit (GtkCssProvider *css_provider)
}
static GTokenType
parse_pseudo_class (GtkCssProvider *css_provider,
GScanner *scanner,
SelectorPath *selector,
GtkRegionFlags *flags)
parse_nth_child (GtkCssProvider *css_provider,
GScanner *scanner,
GtkRegionFlags *flags)
{
ParserSymbol symbol;
css_provider_push_scope (css_provider, SCOPE_PSEUDO_CLASS);
g_scanner_get_next_token (scanner);
if (scanner->token != G_TOKEN_SYMBOL)
......@@ -941,13 +935,51 @@ parse_pseudo_class (GtkCssProvider *css_provider,
*flags = GTK_REGION_LAST;
else
{
GtkStateType state;
*flags = 0;
return G_TOKEN_SYMBOL;
}
return G_TOKEN_NONE;
}
static GTokenType
parse_pseudo_class (GtkCssProvider *css_provider,
GScanner *scanner,
SelectorPath *selector)
{
GtkStateType state;
state = GPOINTER_TO_INT (scanner->value.v_symbol);
selector->state = state;
g_scanner_get_next_token (scanner);
if (scanner->token != G_TOKEN_SYMBOL)
return G_TOKEN_SYMBOL;
state = GPOINTER_TO_INT (scanner->value.v_symbol);
switch (state)
{
case GTK_STATE_ACTIVE:
selector->state |= GTK_STATE_FLAG_ACTIVE;
break;
case GTK_STATE_PRELIGHT:
selector->state |= GTK_STATE_FLAG_PRELIGHT;
break;
case GTK_STATE_SELECTED:
selector->state |= GTK_STATE_FLAG_SELECTED;
break;
case GTK_STATE_INSENSITIVE:
selector->state |= GTK_STATE_FLAG_INSENSITIVE;
break;
case GTK_STATE_INCONSISTENT:
selector->state |= GTK_STATE_FLAG_INCONSISTENT;
break;
case GTK_STATE_FOCUSED:
selector->state |= GTK_STATE_FLAG_FOCUSED;
break;
default:
return G_TOKEN_SYMBOL;
}
css_provider_pop_scope (css_provider);
return G_TOKEN_NONE;
}
......@@ -1030,18 +1062,39 @@ parse_selector (GtkCssProvider *css_provider,
region_name = g_strdup (scanner->value.v_identifier);
/* Parse nth-child type pseudo-class, and
* possibly a state pseudo-class after it.
*/
while (path->state == GTK_STATE_NORMAL &&
g_scanner_peek_next_token (scanner) == ':')
if (g_scanner_peek_next_token (scanner) == ':')
{
GTokenType token;
ParserSymbol symbol;
g_scanner_get_next_token (scanner);
css_provider_push_scope (css_provider, SCOPE_PSEUDO_CLASS);
/* Check for the next token being nth-child, parse in that
* case, and fallback into common state parsing if not.
*/
if (g_scanner_peek_next_token (scanner) != G_TOKEN_SYMBOL)
return G_TOKEN_SYMBOL;
symbol = GPOINTER_TO_INT (scanner->next_value.v_symbol);
if (symbol == SYMBOL_FIRST_CHILD ||
symbol == SYMBOL_LAST_CHILD ||
symbol == SYMBOL_NTH_CHILD)
{
GTokenType token;
if ((token = parse_pseudo_class (css_provider, scanner, path, &flags)) != G_TOKEN_NONE)
return token;
if ((token = parse_nth_child (css_provider, scanner, &flags)) != G_TOKEN_NONE)
return token;
css_provider_pop_scope (css_provider);
}
else
{
css_provider_pop_scope (css_provider);
selector_path_prepend_region (path, region_name, 0);
g_free (region_name);
break;
}
}
selector_path_prepend_region (path, region_name, flags);
......@@ -1054,10 +1107,6 @@ parse_selector (GtkCssProvider *css_provider,
g_scanner_get_next_token (scanner);
/* State is the last element in the selector */
if (path->state != GTK_STATE_NORMAL)
break;
if (scanner->token == '>')
{
selector_path_prepend_combinator (path, COMBINATOR_CHILD);
......@@ -1065,35 +1114,25 @@ parse_selector (GtkCssProvider *css_provider,
}
}
if (scanner->token == ':' &&
path->state == GTK_STATE_NORMAL)
if (scanner->token == ':')
{
GtkRegionFlags flags = 0;
GTokenType token;
/* Add glob selector if path is empty */
if (selector_path_depth (path) == 0)
selector_path_prepend_glob (path);
if ((token = parse_pseudo_class (css_provider, scanner, path, &flags)) != G_TOKEN_NONE)
return token;
css_provider_push_scope (css_provider, SCOPE_PSEUDO_CLASS);
if (flags != 0)
while (scanner->token == ':')
{
/* This means either a standalone :nth-child
* selector, or on a invalid element type.
*/
return G_TOKEN_SYMBOL;
GTokenType token;
if ((token = parse_pseudo_class (css_provider, scanner, path)) != G_TOKEN_NONE)
return token;
g_scanner_get_next_token (scanner);
}
g_scanner_get_next_token (scanner);
}
else if (scanner->token == G_TOKEN_SYMBOL)
{
/* A new pseudo-class was starting, but the state was already
* parsed, so nothing is supposed to go after that.
*/
return G_TOKEN_LEFT_CURLY;
css_provider_pop_scope (css_provider);
}
return G_TOKEN_NONE;
......@@ -1652,20 +1691,14 @@ gtk_css_provider_get_default (void)
"@tooltip_bg_color: #eee1b3; \n"
"@tooltip_fg_color: #000; \n"
"\n"
"*, GtkTreeView > GtkButton {\n"
"*,\n"
"GtkTreeView > GtkButton {\n"
" background-color: @bg_color;\n"
" foreground-color: @fg_color;\n"
" text-color: @text_color; \n"
" base-color: @base_color; \n"
"}\n"
"\n"
"*:active {\n"
" background-color: #c4c2bd;\n"
" foreground-color: #000000;\n"
" text-color: #c4c2bd; \n"
" base-color: #9c9a94; \n"
"}\n"
"\n"
"*:prelight {\n"
" background-color: #eeebe7;\n"
" foreground-color: #000000;\n"
......@@ -1701,6 +1734,13 @@ gtk_css_provider_get_default (void)
"GtkToggleButton:prelight {\n"
" text-color: #000; \n"
"}\n"
"\n"
".button:active {\n"
" background-color: #c4c2bd;\n"
" foreground-color: #000000;\n"
" text-color: #c4c2bd; \n"
" base-color: #9c9a94; \n"
"}\n"
"\n";
provider = gtk_css_provider_new ();
......
......@@ -343,7 +343,7 @@ rebuild_properties (GtkStyleContext *context)
}
}
gtk_style_set_get (priv->store, GTK_STATE_NORMAL,
gtk_style_set_get (priv->store, 0,
"engine", &priv->theming_engine,
NULL);
}
......@@ -488,14 +488,13 @@ gtk_style_context_remove_provider (GtkStyleContext *context,
void
gtk_style_context_get_property (GtkStyleContext *context,
const gchar *property,
GtkStateType state,
GtkStateFlags state,
GValue *value)
{
GtkStyleContextPrivate *priv;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
g_return_if_fail (property != NULL);
g_return_if_fail (state < GTK_STATE_LAST);
g_return_if_fail (value != NULL);
priv = context->priv;
......@@ -504,13 +503,12 @@ gtk_style_context_get_property (GtkStyleContext *context,
void
gtk_style_context_get_valist (GtkStyleContext *context,
GtkStateType state,
GtkStateFlags state,
va_list args)
{
GtkStyleContextPrivate *priv;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
g_return_if_fail (state < GTK_STATE_LAST);
priv = context->priv;
gtk_style_set_get_valist (priv->store, state, args);
......@@ -518,14 +516,13 @@ gtk_style_context_get_valist (GtkStyleContext *context,
void
gtk_style_context_get (GtkStyleContext *context,
GtkStateType state,
GtkStateFlags state,
...)
{
GtkStyleContextPrivate *priv;
va_list args;
g_return_if_fail (GTK_IS_STYLE_CONTEXT (context));
g_return_if_fail (state < GTK_STATE_LAST);
priv = context->priv;
......
......@@ -61,13 +61,13 @@ void gtk_style_context_restore (GtkStyleContext *context);
void gtk_style_context_get_property (GtkStyleContext *context,
const gchar *property,
GtkStateType state,
GtkStateFlags state,
GValue *value);
void gtk_style_context_get_valist (GtkStyleContext *context,
GtkStateType state,
GtkStateFlags state,
va_list args);
void gtk_style_context_get (GtkStyleContext *context,
GtkStateType state,
GtkStateFlags state,
...) G_GNUC_NULL_TERMINATED;
void gtk_style_context_set_state (GtkStyleContext *context,
......
......@@ -33,6 +33,7 @@
typedef struct GtkStyleSetPrivate GtkStyleSetPrivate;
typedef struct PropertyData PropertyData;
typedef struct PropertyNode PropertyNode;
typedef struct ValueData ValueData;
struct PropertyNode
{
......@@ -42,10 +43,15 @@ struct PropertyNode
GtkStylePropertyParser parse_func;
};
struct ValueData
{
GtkStateFlags state;
GValue value;
};
struct PropertyData
{
GValue default_value;
GValue values[GTK_STATE_LAST];
GArray *values;
};
struct GtkStyleSetPrivate
......@@ -97,6 +103,7 @@ property_data_new (void)
PropertyData *data;
data = g_slice_new0 (PropertyData);
data->values = g_array_new (FALSE, FALSE, sizeof (ValueData));
return data;
}
......@@ -104,17 +111,138 @@ property_data_new (void)
static void
property_data_free (PropertyData *data)
{
gint i;
guint i;
for (i = 0; i <= GTK_STATE_INSENSITIVE; i++)
for (i = 0; i < data->values->len; i++)
{
if (G_IS_VALUE (&data->values[i]))
g_value_unset (&data->values[i]);
ValueData *value_data;
value_data = &g_array_index (data->values, ValueData, i);
if (G_IS_VALUE (&value_data->value))
g_value_unset (&value_data->value);
}
g_slice_free (PropertyData, data);
}
static gboolean
property_data_find_position (PropertyData *data,
GtkStateFlags state,
guint *pos)
{
gint min, max, mid;
gboolean found = FALSE;
guint position;
if (pos)
*pos = 0;
if (data->values->len == 0)
return FALSE;
/* Find position for the given state, or the position where
* it would be if not found, the array is ordered by the
* state flags.
*/
min = 0;
max = data->values->len - 1;
do
{
ValueData *value_data;
mid = (min + max) / 2;
value_data = &g_array_index (data->values, ValueData, mid);
if (value_data->state == state)
{
found = TRUE;
position = mid;
}
else if (value_data->state < state)
position = min = mid + 1;
else
{
max = mid - 1;
position = mid;
}
}
while (!found && min <= max);
if (pos)
*pos = position;
return found;
}
static GValue *
property_data_get_value (PropertyData *data,
GtkStateFlags state)
{
ValueData *val_data;
guint pos;
if (!property_data_find_position (data, state, &pos))
{
ValueData new = { 0 };
//val_data = &g_array_index (data->values, ValueData, pos);
new.state = state;
g_array_insert_val (data->values, pos, new);
}
val_data = &g_array_index (data->values, ValueData, pos);
return &val_data->value;
}
static GValue *
property_data_match_state (PropertyData *data,
GtkStateFlags state)
{
guint pos;
gint i;
if (property_data_find_position (data, state, &pos))
{
ValueData *val_data;
/* Exact match */
val_data = &g_array_index (data->values, ValueData, pos);
return &val_data->value;
}
if (pos >= data->values->len)
pos = data->values->len - 1;
/* No exact match, go downwards the list to find
* the closest match to the given state flags, as
* a side effect, there is an implicit precedence
* of higher flags over the smaller ones.
*/
for (i = pos; i >= 0; i--)
{
ValueData *val_data;
val_data = &g_array_index (data->values, ValueData, i);
/* Check whether any of the requested
* flags are set, and no other flags are.
*
* Also, no flags acts as a wildcard, such
* value should be always in the first position
* in the array (if present) anyways.
*/
if (val_data->state == 0 ||
((val_data->state & state) != 0 &&
(val_data->state & ~state) == 0))
return &val_data->value;
}
return NULL;
}
static void
gtk_style_set_init (GtkStyleSet *set)
{
......@@ -331,12 +459,11 @@ gtk_style_set_lookup_color (GtkStyleSet *set,
return g_hash_table_lookup (priv->color_map, name);
}
static void
set_property_internal (GtkStyleSet *set,
const gchar *property,
gboolean is_default,
GtkStateType state,
const GValue *value)
void
gtk_style_set_set_property (GtkStyleSet *set,
const gchar *property,
GtkStateFlags state,
const GValue *value)
{
GtkStyleSetPrivate *priv;
PropertyNode *node;
......@@ -344,6 +471,10 @@ set_property_internal (GtkStyleSet *set,
GType value_type;
GValue *val;
g_return_if_fail (GTK_IS_STYLE_SET (set));
g_return_if_fail (property != NULL);
g_return_if_fail (value != NULL);
value_type = G_VALUE_TYPE (value);
node = property_node_lookup (g_quark_try_string (property));
......@@ -359,7 +490,7 @@ set_property_internal (GtkStyleSet *set,
g_return_if_fail (value_type == GDK_TYPE_COLOR || value_type == GTK_TYPE_SYMBOLIC_COLOR);
}
else
g_return_if_fail (node->property_type == G_VALUE_TYPE (value));
g_return_if_fail (node->property_type == value_type);
priv = set->priv;
prop = g_hash_table_lookup (priv->properties,
......@@ -373,10 +504,7 @@ set_property_internal (GtkStyleSet *set,
prop);
}
if (is_default)
val = &prop->default_value;
else
val = &prop->values[state];
val = property_data_get_value (prop, state);
if (G_VALUE_TYPE (val) == value_type)
g_value_reset (val);
......@@ -392,41 +520,14 @@ set_property_internal (GtkStyleSet *set,
}
void
gtk_style_set_set_default (GtkStyleSet *set,
const gchar *property,
const GValue *value)
{
g_return_if_fail (GTK_IS_STYLE_SET (set));
g_return_if_fail (property != NULL);
g_return_if_fail (value != NULL);
set_property_internal (set, property, TRUE, GTK_STATE_NORMAL, value);
}
void
gtk_style_set_set_property (GtkStyleSet *set,
const gchar *property,
GtkStateType state,
const GValue *value)
{
g_return_if_fail (GTK_IS_STYLE_SET (set));
g_return_if_fail (property != NULL);
g_return_if_fail (state < GTK_STATE_LAST);
g_return_if_fail (value != NULL);
set_property_internal (set, property, FALSE, state, value);
}
void
gtk_style_set_set_valist (GtkStyleSet *set,
GtkStateType state,
va_list args)
gtk_style_set_set_valist (GtkStyleSet *set,
GtkStateFlags state,
va_list args)
{
GtkStyleSetPrivate *priv;
const gchar *property_name;
g_return_if_fail (GTK_IS_STYLE_SET (set));
g_return_if_fail (state < GTK_STATE_LAST);
priv = set->priv;
property_name = va_arg (args, const gchar *);
......@@ -436,6 +537,7 @@ gtk_style_set_set_valist (GtkStyleSet *set,
PropertyNode *node;
PropertyData *prop;
gchar *error = NULL;
GValue *val;
node = property_node_lookup (g_quark_try_string (property_name));
......@@ -456,14 +558,19 @@ gtk_style_set_set_valist (GtkStyleSet *set,
prop);
}
g_value_init (&prop->values[state], node->property_type);
G_VALUE_COLLECT (&prop->values[state], args, 0, &error);
val = property_data_get_value (prop, state);
if (G_IS_VALUE (val))
g_value_unset (val);
g_value_init (val, node->property_type);
G_VALUE_COLLECT (val, args, 0, &error);
if (error)
{
g_warning ("Could not set style property \"%s\": %s", property_name, error);
g_value_unset (&prop->values[state]);
g_free (error);
g_value_unset (val);
g_free (error);
break;
}
......@@ -472,14 +579,13 @@ gtk_style_set_set_valist (GtkStyleSet *set,
}
void
gtk_style_set_set (GtkStyleSet *set,
GtkStateType state,
gtk_style_set_set (GtkStyleSet *set,
GtkStateFlags state,
...)
{
va_list args;
g_return_if_fail (GTK_IS_STYLE_SET (set));
g_return_if_fail (state < GTK_STATE_LAST);
va_start (args, state);
gtk_style_set_set_valist (set, state, args);
......@@ -505,10 +611,10 @@ resolve_color (GtkStyleSet *set,
}
gboolean
gtk_style_set_get_property (GtkStyleSet *set,
const gchar *property,
GtkStateType state,
GValue *value)
gtk_style_set_get_property (GtkStyleSet *set,
const gchar *property,
GtkStateFlags state,
GValue *value)
{
GtkStyleSetPrivate *priv;
PropertyNode *node;
......@@ -517,7 +623,6 @@ gtk_style_set_get_property (GtkStyleSet *set,
g_return_val_if_fail (GTK_IS_STYLE_SET (set), FALSE);
g_return_val_if_fail (property != NULL, FALSE);
g_return_val_if_fail (state < GTK_STATE_LAST, FALSE);
g_return_val_if_fail (value != NULL, FALSE);
node = property_node_lookup (g_quark_try_string (property));
......@@ -537,11 +642,9 @@ gtk_style_set_get_property (GtkStyleSet *set,
g_value_init (value, node->property_type);
if (G_IS_VALUE (&prop->values[state]))
val = &prop->values[state];
else if (G_IS_VALUE (&prop->default_value))
val = &prop->default_value;
else
val = property_data_match_state (prop, state);
if (!val && G_IS_VALUE (&node->default_value))
val = &node->default_value;
g_return_val_if_fail (G_IS_VALUE (val), FALSE);
......@@ -560,15 +663,14 @@ gtk_style_set_get_property (GtkStyleSet *set,
}
void
gtk_style_set_get_valist (GtkStyleSet *set,
GtkStateType state,
va_list args)
gtk_style_set_get_valist (GtkStyleSet *set,
GtkStateFlags state,
va_list args)
{
GtkStyleSetPrivate *priv;
const gchar *property_name;
g_return_if_fail (GTK_IS_STYLE_SET (set));
g_return_if_fail (state < GTK_STATE_LAST);
priv = set->priv;
property_name = va_arg (args, const gchar *);
......@@ -604,14 +706,9 @@ gtk_style_set_get_valist (GtkStyleSet *set,
GValue *val = NULL;
if (prop)
{
if (G_IS_VALUE (&prop->values[state]))
val = &prop->values[state];
else if (G_IS_VALUE (&prop->default_value))
val = &prop->default_value;
}
val = property_data_match_state (prop, state);
if (!val)
if (!val && G_IS_VALUE (&node->default_value))
val = &node->default_value;
if (G_VALUE_TYPE (val) == GTK_TYPE_SYMBOLIC_COLOR)
......@@ -637,14 +734,13 @@ gtk_style_set_get_valist (GtkStyleSet *set,
}
void
gtk_style_set_get (GtkStyleSet *set,
GtkStateType state,
gtk_style_set_get (GtkStyleSet *set,
GtkStateFlags state,
...)
{
va_list args;
g_return_if_fail (GTK_IS_STYLE_SET (set));
g_return_if_fail (state < GTK_STATE_LAST);
va_start (args, state);
gtk_style_set_get_valist (set, state, args);
......@@ -652,17 +748,17 @@ gtk_style_set_get (GtkStyleSet *set,
}
void
gtk_style_set_unset_property (GtkStyleSet *set,
const gchar *property,
GtkStateType state)
gtk_style_set_unset_property (GtkStyleSet *set,
const gchar *property,
GtkStateFlags state)
{
GtkStyleSetPrivate *priv;
PropertyNode *node;
PropertyData *prop;
guint pos;
g_return_if_fail (GTK_IS_STYLE_SET (set));
g_return_if_fail (property != NULL);
g_return_if_fail (state < GTK_STATE_LAST);
node = property_node_lookup (g_quark_try_string (property));
......@@ -679,7 +775,17 @@ gtk_style_set_unset_property (GtkStyleSet *set,
if (!prop)
return;
g_value_unset (&prop->values[state]);
if (property_data_find_position (prop, state, &pos))
{
ValueData *data;
data = &g_array_index (prop->values, ValueData, pos);
if (G_IS_VALUE (&data->value))