Compare commits

...

3 Commits

Author SHA1 Message Date
Matthias Clasen
9e281fb2b5 Add another css change testcase
This one tests selectors similar to the ones we are using
for linked buttons and entries, involving siblings and
:first-child/:last-child.
2020-01-18 16:30:28 -05:00
Matthias Clasen
ccda2a094f change tests: Update expected results
These are the expected changes: A widget which does
not meet the conditions of a complex selector due
to its parents is no longer marked with various
parent- flags.
2020-01-18 16:30:28 -05:00
Matthias Clasen
79afff410a Make change computation more precise
Don't ignore parent name, id, class when matching for change.
This reduces the amount of parent-state in our change flags.
The price we pay for this is that we need to treat parent-name,
parent-id and parent-class as radical change now. But since
they are less frequent than parent-state changes, it is still
a win.

When we meet a sibling or adjacent selector while collecting change
flags, we want to 'always match', since just the right sibling might
appear in the node tree. Calling gtk_css_selector_foreach does not
achieve that, since it won't match if there is no sibling in the
current tree. To fix this, pretend that there is one, and continue
matching.
2020-01-18 16:30:28 -05:00
7 changed files with 148 additions and 38 deletions

View File

@@ -86,7 +86,14 @@
/* When these change we do a full restyling. Otherwise we try to figure out
* if we need to change things. */
#define GTK_CSS_RADICAL_CHANGE (GTK_CSS_CHANGE_ID | GTK_CSS_CHANGE_NAME | GTK_CSS_CHANGE_CLASS | GTK_CSS_CHANGE_SOURCE | GTK_CSS_CHANGE_PARENT_STYLE)
#define GTK_CSS_RADICAL_CHANGE (GTK_CSS_CHANGE_ID | \
GTK_CSS_CHANGE_NAME | \
GTK_CSS_CHANGE_CLASS | \
GTK_CSS_CHANGE_PARENT_ID | \
GTK_CSS_CHANGE_PARENT_NAME | \
GTK_CSS_CHANGE_PARENT_CLASS | \
GTK_CSS_CHANGE_SOURCE | \
GTK_CSS_CHANGE_PARENT_STYLE)
/* When these change, we need to recompute the change flags for the new style
* since they may have changed.

View File

@@ -316,7 +316,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_DESCENDANT = {
gtk_css_selector_default_hash_one,
gtk_css_selector_default_compare_one,
FALSE,
TRUE
FALSE
};
/* CHILD */
@@ -358,7 +358,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_CHILD = {
gtk_css_selector_default_hash_one,
gtk_css_selector_default_compare_one,
FALSE,
TRUE
FALSE
};
/* SIBLING */
@@ -405,7 +405,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_SIBLING = {
gtk_css_selector_default_hash_one,
gtk_css_selector_default_compare_one,
FALSE,
TRUE
FALSE,
};
/* ADJACENT */
@@ -447,7 +447,7 @@ static const GtkCssSelectorClass GTK_CSS_SELECTOR_ADJACENT = {
gtk_css_selector_default_hash_one,
gtk_css_selector_default_compare_one,
FALSE,
TRUE
FALSE,
};
/* SIMPLE SELECTOR DEFINE */
@@ -1901,67 +1901,104 @@ gtk_css_selector_match_for_change (const GtkCssSelector *selector,
that change != 0 on any match. */
#define GTK_CSS_CHANGE_GOT_MATCH GTK_CSS_CHANGE_RESERVED_BIT
static GtkCssChange
gtk_css_selector_tree_collect_change (const GtkCssSelectorTree *tree)
static void
print_sel (const char *format, const GtkCssSelector *selector)
{
GString *s = g_string_new ("");
selector->class->print (selector, s);
g_print (format, s->str);
g_string_free (s, TRUE);
}
static gboolean gtk_css_selector_tree_change_foreach (const GtkCssSelector *selector,
const GtkCssMatcher *matcher,
gpointer res);
/* Handle the case that a new sibling with just the right properties might appear.
* This is done by collecting the sibling selector and all following simple selectors,
* before resuming matching.
*/
static GtkCssChange
gtk_css_selector_tree_change_for_sibling (const GtkCssSelector *selector,
const GtkCssMatcher *matcher,
gboolean skip_first)
{
const GtkCssSelectorTree *tree = (const GtkCssSelectorTree *) selector;
GtkCssChange change = 0;
const GtkCssSelectorTree *prev;
for (prev = gtk_css_selector_tree_get_previous (tree);
prev != NULL;
prev = gtk_css_selector_tree_get_sibling (prev))
change |= gtk_css_selector_tree_collect_change (prev);
change = tree->selector.class->get_change (&tree->selector, change);
if (skip_first || tree->selector.class->is_simple)
{
const GtkCssSelectorTree *prev;
for (prev = gtk_css_selector_tree_get_previous (tree);
prev;
prev = gtk_css_selector_tree_get_sibling (prev))
change |= gtk_css_selector_tree_change_for_sibling (prev, matcher, FALSE);
change = selector->class->get_change (selector, change);
}
else
{
gtk_css_selector_tree_change_foreach (selector, matcher, &change);
}
return change;
}
static GtkCssChange
gtk_css_selector_tree_get_change (const GtkCssSelectorTree *tree,
const GtkCssMatcher *matcher)
static gboolean
gtk_css_selector_tree_change_foreach (const GtkCssSelector *selector,
const GtkCssMatcher *matcher,
gpointer res)
{
GtkCssChange change = 0;
const GtkCssSelectorTree *tree = (const GtkCssSelectorTree *) selector;
const GtkCssSelectorTree *prev;
GtkCssChange *ret = res;
GtkCssChange change = 0;
if (!gtk_css_selector_match_for_change (&tree->selector, matcher))
return 0;
return FALSE;
if (!tree->selector.class->is_simple)
return gtk_css_selector_tree_collect_change (tree) | GTK_CSS_CHANGE_GOT_MATCH;
// print_sel ("match at %s\n", selector);
for (prev = gtk_css_selector_tree_get_previous (tree);
prev != NULL;
prev = gtk_css_selector_tree_get_sibling (prev))
change |= gtk_css_selector_tree_get_change (prev, matcher);
{
GtkCssChange change2 = 0;
if (prev->selector.class == &GTK_CSS_SELECTOR_SIBLING ||
prev->selector.class == &GTK_CSS_SELECTOR_ADJACENT)
change2 = gtk_css_selector_tree_change_for_sibling (&prev->selector, matcher, TRUE);
else
gtk_css_selector_foreach (&prev->selector, matcher, gtk_css_selector_tree_change_foreach, &change2);
change |= change2;
}
if (change || gtk_css_selector_tree_get_matches (tree))
change = tree->selector.class->get_change (&tree->selector, change & ~GTK_CSS_CHANGE_GOT_MATCH) | GTK_CSS_CHANGE_GOT_MATCH;
{
*ret |= tree->selector.class->get_change (&tree->selector, change & ~GTK_CSS_CHANGE_GOT_MATCH) | GTK_CSS_CHANGE_GOT_MATCH;
}
return change;
}
gboolean
_gtk_css_selector_tree_is_empty (const GtkCssSelectorTree *tree)
{
return tree == NULL;
return FALSE;
}
GtkCssChange
_gtk_css_selector_tree_get_change_all (const GtkCssSelectorTree *tree,
const GtkCssMatcher *matcher)
{
GtkCssChange change;
GtkCssChange change = 0;
change = 0;
/* no need to foreach here because we abort for non-simple selectors */
for (; tree != NULL;
tree = gtk_css_selector_tree_get_sibling (tree))
change |= gtk_css_selector_tree_get_change (tree, matcher);
gtk_css_selector_foreach (&tree->selector, matcher, gtk_css_selector_tree_change_foreach, &change);
/* Never return reserved bit set */
return change & ~GTK_CSS_CHANGE_RESERVED_BIT;
return change & ~GTK_CSS_CHANGE_GOT_MATCH;
}
gboolean
_gtk_css_selector_tree_is_empty (const GtkCssSelectorTree *tree)
{
return tree == NULL;
}
#ifdef PRINT_TREE

View File

@@ -25,6 +25,7 @@ test_data = [
'test3.css', 'test3.ui', 'test3.nodes',
'test4.css', 'test4.ui', 'test4.nodes',
'test5.css', 'test5.ui', 'test5.nodes',
'test6.css', 'test6.ui', 'test6.nodes',
]
if get_option('install-tests')

View File

@@ -1,9 +1,9 @@
window.background:dir(ltr)
decoration:dir(ltr)
grid.horizontal:dir(ltr)
label:dir(ltr) name|sibling-name|parent-name|parent-sibling-name
label:dir(ltr) name|sibling-name
box.horizontal:dir(ltr)
label:dir(ltr) name|sibling-name|parent-name|parent-sibling-name
label:dir(ltr) name|sibling-name
button:dir(ltr)
box.horizontal:dir(ltr)
checkbutton:dir(ltr)

View File

@@ -0,0 +1,19 @@
/* a simplified version of some of the things we do for linked buttons and entries */
box:not(.vertical).linked > button:not(:first-child) {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
box:not(.vertical).linked > button:not(:last-child) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
box:not(.vetical).linked > *:disabled ~ entry:disabled {
border-left-color: red;
}
box:not(.vetical).linked > entry:focus + button {
border-left-color: blue;
}

View File

@@ -0,0 +1,12 @@
window.background:dir(ltr)
decoration:dir(ltr)
box.horizontal.linked:dir(ltr)
button:dir(ltr) name|first-child|last-child|parent-class|parent-name
button:dir(ltr) name|first-child|last-child|sibling-name|sibling-state|parent-class|parent-name
button:dir(ltr) name|first-child|last-child|sibling-name|sibling-state|parent-class|parent-name
box.horizontal.linked:dir(ltr)
entry:dir(ltr)
text:dir(ltr)
undershoot.left:dir(ltr)
undershoot.right:dir(ltr)
button:dir(ltr) name|first-child|last-child|sibling-name|sibling-state|parent-class|parent-name

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
<object class="GtkWindow" id="window1">
<property name="can_focus">False</property>
<property name="type">popup</property>
<child>
<object class="GtkBox">
<style><class name="linked"/></style>
<child>
<object class="GtkButton"/>
</child>
<child>
<object class="GtkButton"/>
</child>
<child>
<object class="GtkButton"/>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<style><class name="linked"/></style>
<child>
<object class="GtkEntry"/>
</child>
<child>
<object class="GtkButton"/>
</child>
</object>
</child>
</object>
</interface>