Compare commits

...

12 Commits

Author SHA1 Message Date
Matthias Clasen
e867944a5a Add a css style test for currentColor 2015-12-29 07:47:58 -05:00
Matthias Clasen
20eaea2b2d Add a css style test for inherit and initial 2015-12-29 07:47:58 -05:00
Matthias Clasen
79f383ab19 Add a css style test for :first/last/only-child 2015-12-29 07:47:58 -05:00
Matthias Clasen
ff9e589402 Add a css style test for font inheritance 2015-12-29 07:47:58 -05:00
Matthias Clasen
054e21afae Add a test framework for CSS styles
This uses the same function for dumping CSS nodes and styles
as the CSS node test. It can be used to test aspects of inheritance
and matching, as well as initial values.

No actual tests yet.
2015-12-29 07:46:31 -05:00
Matthias Clasen
9af17de76b Add CSS node tests for levelbars 2015-12-29 07:46:31 -05:00
Matthias Clasen
0f95ff74b8 Add CSS node test for progressbars 2015-12-29 07:46:30 -05:00
Matthias Clasen
fdd984f55c Add a CSS node test for buttons 2015-12-29 07:46:30 -05:00
Matthias Clasen
e13894396d Add a CSS node test for entries 2015-12-29 07:46:30 -05:00
Matthias Clasen
2fc7ecc3df Add a CSS node test for notebooks 2015-12-29 07:46:30 -05:00
Matthias Clasen
a3aeef3760 Add a test framework for CSS nodes
No actual tests yet.
2015-12-29 07:46:30 -05:00
Matthias Clasen
1535e22344 Add a function to dump CSS nodes and styles
Add a gtk_style_context_to_string function that can serialize
a CSS node or tree of nodes, optionally including CSS properties
as well.

This will be useful in writing tests.
2015-12-29 07:46:30 -05:00
35 changed files with 1605 additions and 2 deletions

View File

@@ -1894,6 +1894,8 @@ testsuite/a11y/Makefile
testsuite/a11y/state/Makefile
testsuite/css/Makefile
testsuite/css/parser/Makefile
testsuite/css/nodes/Makefile
testsuite/css/style/Makefile
testsuite/gdk/Makefile
testsuite/gtk/Makefile
testsuite/reftests/Makefile

View File

@@ -6244,6 +6244,8 @@ gtk_style_context_set_frame_clock
gtk_style_context_set_state
gtk_style_context_set_scale
gtk_style_context_get_scale
GtkStyleContextPrintFlags
gtk_style_context_to_string
<SUBSECTION>
GtkBorder

View File

@@ -25,6 +25,8 @@
#include "gtkmarshalers.h"
#include "gtksettingsprivate.h"
#include "gtktypebuiltins.h"
#include "gtkcssstylepropertyprivate.h"
#include "gtkcsssectionprivate.h"
/*
* CSS nodes are the backbone of the GtkStyleContext implementation and
@@ -1510,7 +1512,7 @@ GtkStyleProviderPrivate *
gtk_css_node_get_style_provider (GtkCssNode *cssnode)
{
GtkStyleProviderPrivate *result;
result = gtk_css_node_get_style_provider_or_null (cssnode);
if (result)
return result;
@@ -1520,3 +1522,162 @@ gtk_css_node_get_style_provider (GtkCssNode *cssnode)
return GTK_STYLE_PROVIDER_PRIVATE (_gtk_settings_get_style_cascade (gtk_settings_get_default (), 1));
}
static void
append_id (GtkCssNode *cssnode,
GString *string)
{
const char *id;
id = gtk_css_node_get_id (cssnode);
if (id)
{
g_string_append (string, " id=");
g_string_append (string, id);
}
}
static void
append_visible (GtkCssNode *cssnode,
GString *string)
{
g_string_append_printf (string, " visible=%d", gtk_css_node_get_visible (cssnode));
}
static void
append_state (GtkCssNode *cssnode,
GString *string)
{
GtkStateFlags state;
state = gtk_css_node_get_state (cssnode);
if (state)
{
GFlagsClass *fclass;
gint i;
gboolean first = TRUE;
g_string_append (string, " state=");
fclass = g_type_class_ref (GTK_TYPE_STATE_FLAGS);
for (i = 0; i < fclass->n_values; i++)
{
if (state & fclass->values[i].value)
{
if (first)
first = FALSE;
else
g_string_append_c (string, '|');
g_string_append (string, fclass->values[i].value_nick);
}
}
g_type_class_unref (fclass);
}
}
static void
append_classes (GtkCssNode *cssnode,
GString *string)
{
const GQuark *classes;
guint n_classes;
classes = gtk_css_node_list_classes (cssnode, &n_classes);
if (n_classes > 0)
{
int i;
g_string_append (string, " classes=");
for (i = 0; i < n_classes; i++)
{
if (i > 0)
g_string_append_c (string, ',');
g_string_append (string, g_quark_to_string (classes[i]));
}
}
}
static void
append_style (GtkCssNode *cssnode,
GtkStyleContextPrintFlags flags,
GString *string,
guint indent)
{
int i;
GtkCssStyle *style;
if (!(flags & GTK_STYLE_CONTEXT_PRINT_SHOW_STYLE))
return;
style = gtk_css_node_get_style (cssnode);
for (i = 0; i < _gtk_css_style_property_get_n_properties (); i++)
{
GtkCssStyleProperty *prop;
GtkCssValue *value;
GtkCssSection *section;
const char *name;
prop = _gtk_css_style_property_lookup_by_id (i);
name = _gtk_style_property_get_name (GTK_STYLE_PROPERTY (prop));
value = gtk_css_style_get_value (style, i);
if (!(flags & GTK_STYLE_CONTEXT_PRINT_SHOW_INITIAL))
{
GtkCssValue *initial, *computed;
GtkCssNode *parent_node;
GtkCssStyle *parent_style;
parent_node = gtk_css_node_get_parent (cssnode);
parent_style = parent_node ? gtk_css_node_get_style (parent_node) : NULL;
initial = _gtk_css_style_property_get_initial_value (prop);
computed = _gtk_css_value_compute (initial,
i,
gtk_css_node_get_style_provider (cssnode),
style,
parent_style);
if (_gtk_css_value_equal (value, computed))
continue;
}
g_string_append_printf (string, "%*s%s: ", indent, "", name);
_gtk_css_value_print (value, string);
section = gtk_css_style_get_section (style, i);
if (section)
{
g_string_append (string, " (");
_gtk_css_section_print (section, string);
g_string_append (string, ")");
}
g_string_append_c (string, '\n');
}
}
void
gtk_css_node_print (GtkCssNode *cssnode,
GtkStyleContextPrintFlags flags,
GString *string,
guint indent)
{
GtkCssNode *node;
g_string_append_printf (string, "%*s", indent, "");
if (gtk_css_node_get_name (cssnode))
g_string_append (string, gtk_css_node_get_name (cssnode));
else
g_string_append (string, g_type_name (gtk_css_node_get_widget_type (cssnode)));
append_id (cssnode, string);
append_visible (cssnode, string);
append_state (cssnode, string);
append_classes (cssnode, string);
g_string_append_c (string, '\n');
append_style (cssnode, flags, string, indent + 2);
if (flags & GTK_STYLE_CONTEXT_PRINT_RECURSE)
{
for (node = gtk_css_node_get_first_child (cssnode); node; node = gtk_css_node_get_next_sibling (node))
gtk_css_node_print (node, flags, string, indent + 2);
}
}

View File

@@ -171,6 +171,11 @@ GtkWidgetPath * gtk_css_node_create_widget_path (GtkCssNode *
const GtkWidgetPath * gtk_css_node_get_widget_path (GtkCssNode *cssnode);
GtkStyleProviderPrivate *gtk_css_node_get_style_provider(GtkCssNode *cssnode);
void gtk_css_node_print (GtkCssNode *cssnode,
GtkStyleContextPrintFlags flags,
GString *string,
guint indent);
G_END_DECLS
#endif /* __GTK_CSS_NODE_PRIVATE_H__ */

View File

@@ -3219,3 +3219,48 @@ _gtk_style_context_is_background_opaque (GtkStyleContext *context)
corner_value_is_right_angle (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_BOTTOM_RIGHT_RADIUS)) &&
corner_value_is_right_angle (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_BOTTOM_LEFT_RADIUS)));
}
/**
* GtkStyleContextPrintFlags:
* @GTK_STYLE_CONTEXT_PRINT_RECURSE: Print the entire tree of
* CSS nodes starting at the style context's node
* @GTK_STYLE_CONTEXT_PRINT_SHOW_STYLE: Show the values of the
* CSS properties for each node
* @GTK_STYLE_CONTEXT_PRINT_SHOW_INITIAL: Show the values of the
* CSS properties even if they match the initial value. By default,
* values are only shown if they are different from the initial
* value.
*
* Flags that modify the behavior of gtk_style_context_to_string().
*/
/**
* gtk_style_context_to_string:
* @context: a #GtkStyleContext
* @flags: Flags that determine what to print
*
* Converts the style context into a string representation.
*
* The string representation always includes information about
* the name, state, id, visibility and style classes of the CSS
* node that is backing @context. Depending on the flags, more
* information may be included.
*
* Returns: a newly allocated string representing @context
*
* Since: 3.20
*/
char *
gtk_style_context_to_string (GtkStyleContext *context,
GtkStyleContextPrintFlags flags)
{
GString *string;
g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
string = g_string_new ("");
gtk_css_node_print (context->priv->cssnode, flags, string, 0);
return g_string_free (string, FALSE);
}

View File

@@ -1208,6 +1208,17 @@ void gtk_draw_insertion_cursor (GtkWidget *widget,
GtkTextDirection direction,
gboolean draw_arrow);
typedef enum {
GTK_STYLE_CONTEXT_PRINT_NONE = 0,
GTK_STYLE_CONTEXT_PRINT_RECURSE = 1 << 0,
GTK_STYLE_CONTEXT_PRINT_SHOW_STYLE = 1 << 1,
GTK_STYLE_CONTEXT_PRINT_SHOW_INITIAL = 1 << 2
} GtkStyleContextPrintFlags;
GDK_AVAILABLE_IN_3_20
char * gtk_style_context_to_string (GtkStyleContext *context,
GtkStyleContextPrintFlags flags);
G_END_DECLS
#endif /* __GTK_STYLE_CONTEXT_H__ */

View File

@@ -2,7 +2,7 @@ include $(top_srcdir)/Makefile.decl
NULL =
SUBDIRS = parser
SUBDIRS = parser nodes style
check_PROGRAMS = $(TEST_PROGS)
test_in_files =

View File

@@ -0,0 +1,60 @@
include $(top_srcdir)/Makefile.decl
NULL =
CLEANFILES =
TEST_PROGS += test-css-nodes
test_in_files = test-css-nodes.test.in
check_PROGRAMS = $(TEST_PROGS)
test_css_nodes_CFLAGS = \
-I$(top_srcdir) \
-I$(top_builddir)/gdk \
-I$(top_srcdir)/gdk \
$(GTK_DEBUG_FLAGS) \
$(GTK_DEP_CFLAGS)
test_css_nodes_LDADD = \
$(top_builddir)/gdk/libgdk-3.la \
$(top_builddir)/gtk/libgtk-3.la \
$(GTK_DEP_LIBS)
test_css_nodes_SOURCES = \
test-css-nodes.c
test_data = \
buttons.ui buttons.nodes \
entries.ui entries.nodes \
levelbar.ui levelbar.nodes \
notebook.ui notebook.nodes \
progressbar.ui progressbar.nodes \
$(NULL)
EXTRA_DIST += $(test_in_files) $(test_data)
if BUILDOPT_INSTALL_TESTS
insttestdir=$(libexecdir)/installed-tests/$(PACKAGE)/css/nodes
insttest_PROGRAMS = $(TEST_PROGS)
insttest_DATA = $(test_data)
substitutions = \
-e s,@libexecdir\@,$(libexecdir),g \
$(NULL)
test_files = $(test_in_files:.test.in=.test)
$(test_files): %.test: %.test.in
$(AM_V_GEN) sed $(substitutions) $< > $@.tmp && mv $@.tmp $@
EXTRA_DIST += $(test_files)
CLEANFILES += $(test_files)
testmetadir = $(datadir)/installed-tests/$(PACKAGE)/css/nodes
testmeta_DATA = $(test_files)
endif
-include $(top_srcdir)/git.mk

View File

@@ -0,0 +1,28 @@
window visible=0 state=dir-ltr classes=background
decoration visible=1 state=dir-ltr
grid visible=1 state=dir-ltr classes=horizontal
button visible=1 state=dir-ltr|checked classes=text-button,toggle
label visible=1 state=dir-ltr
checkbutton visible=1 state=dir-ltr classes=text-button
check visible=1 state=dir-ltr
label visible=1 state=dir-ltr
radiobutton visible=1 state=dir-ltr|checked classes=text-button
radio visible=1 state=dir-ltr|checked
label visible=1 state=dir-ltr
radiobutton visible=1 state=dir-ltr classes=text-button
radio visible=1 state=dir-ltr
label visible=1 state=dir-ltr
switch visible=1 state=active|dir-ltr
slider visible=1 classes=slider
switch visible=1 state=dir-ltr
slider visible=1 classes=slider
button visible=1 state=dir-ltr classes=text-button
label visible=1 state=dir-ltr
button visible=1 state=dir-ltr classes=image-button
GtkAlignment visible=1 state=dir-ltr
box visible=1 state=dir-ltr classes=horizontal
image visible=1 state=dir-ltr
button visible=1 state=dir-ltr classes=image-button
GtkAlignment visible=1 state=dir-ltr
box visible=1 state=dir-ltr classes=horizontal
image visible=1 state=dir-ltr

View File

@@ -0,0 +1,147 @@
<?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="GtkGrid" id="grid1">
<property name="visible">True</property>
<child>
<object class="GtkToggleButton" id="button1">
<property name="label" translatable="yes">Hello World!</property>
<property name="visible">True</property>
<property name="active">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="button2">
<property name="label" translatable="yes">Hello World!</property>
<property name="visible">True</property>
<property name="active">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="button3">
<property name="label" translatable="yes">Hello World!</property>
<property name="visible">True</property>
<property name="active">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="button4">
<property name="label" translatable="yes">Hello World!</property>
<property name="visible">True</property>
<property name="active">True</property>
<property name="group">button3</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
<packing>
<property name="left_attach">3</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkSwitch" id="button5">
<property name="visible">True</property>
<property name="active">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
<packing>
<property name="left_attach">4</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkSwitch" id="button6">
<property name="visible">True</property>
<property name="active">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<child internal-child="accessible">
<object class="AtkObject" id="button6-accessible">
<property name="accessible-name">Test switch</property>
</object>
</child>
</object>
<packing>
<property name="left_attach">5</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button7">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="label">Text Button</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button8">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="image">image8</property>
<property name="halign">center</property>
<property name="valign">center</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button9">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="image">image9</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="top_attach">1</property>
</packing>
</child>
</object>
</child>
</object>
<object class="GtkImage" id="image8">
<property name="visible">True</property>
<property name="icon-name">edit-find-replace</property>
<property name="icon-size">1</property>
</object>
<object class="GtkImage" id="image9">
<property name="visible">True</property>
<property name="icon-name">window-close-symbolic</property>
<property name="use-fallback">True</property>
<property name="icon-size">1</property>
</object>
</interface>

View File

@@ -0,0 +1,16 @@
window visible=0 state=dir-ltr classes=background
decoration visible=1 state=dir-ltr
box visible=0 state=dir-ltr classes=horizontal
label visible=1 state=dir-ltr
label visible=1 state=dir-ltr
label visible=1 state=dir-ltr
entry visible=1 state=dir-ltr
progress visible=1 state=dir-ltr
entry visible=1 state=dir-ltr
entry visible=1 state=dir-ltr
image visible=1 state=dir-ltr classes=left
image visible=1 state=dir-ltr classes=right
spinbutton visible=1 state=dir-ltr classes=horizontal
entry visible=1 state=dir-ltr
button visible=1 state=dir-ltr classes=down
button visible=1 state=dir-ltr classes=up

View File

@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
<object class="GtkAdjustment" id="adjustment1">
<property name="lower">0.5</property>
<property name="upper">99.5</property>
<property name="page-size">0</property>
<property name="value">45.5</property>
<property name="step-increment">0.5</property>
<property name="page-increment">5.0</property>
</object>
<object class="GtkWindow" id="window1">
<property name="can_focus">False</property>
<property name="type">popup</property>
<child>
<object class="GtkBox" id="box1">
<child>
<object class="GtkLabel" id="label1">
<property name="label">_entry:</property>
<property name="visible">True</property>
<property name="use-underline">True</property>
<property name="mnemonic-widget">entry1</property>
</object>
</child>
<child>
<object class="GtkLabel" id="label2">
<property name="label">_password entry:</property>
<property name="visible">True</property>
<property name="use-underline">True</property>
<property name="mnemonic-widget">entry2</property>
</object>
</child>
<child>
<object class="GtkLabel" id="label3">
<property name="label">_spinbutton:</property>
<property name="visible">True</property>
<property name="use-underline">True</property>
<property name="mnemonic-widget">spinbutton1</property>
</object>
</child>
<child>
<object class="GtkEntry" id="entry1">
<property name="text" translatable="yes">text</property>
<property name="visible">True</property>
<property name="progress-fraction">0.3</property>
</object>
</child>
<child>
<object class="GtkEntry" id="entry2">
<property name="text" translatable="yes">password text</property>
<property name="visible">True</property>
<property name="visibility">False</property>
<property name="invisible_char">*</property>
<property name="invisible_char_set">True</property>
</object>
</child>
<child>
<object class="GtkEntry" id="entry3">
<property name="text" translatable="yes">icons</property>
<property name="visible">True</property>
<property name="primary-icon-stock">stock1</property>
<property name="secondary-icon-stock">stock2</property>
</object>
</child>
<child>
<object class="GtkSpinButton" id="spinbutton1">
<property name="adjustment">adjustment1</property>
<property name="visible">True</property>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -0,0 +1,55 @@
window visible=0 state=dir-ltr classes=background
decoration visible=1 state=dir-ltr
box visible=1 state=dir-ltr classes=vertical
levelbar visible=1 state=dir-ltr classes=horizontal,continuous
trough visible=1 state=dir-ltr
block visible=1 state=dir-ltr classes=high,filled
block visible=1 state=dir-ltr classes=empty
levelbar visible=1 state=dir-ltr classes=horizontal,continuous
trough visible=1 state=dir-ltr
block visible=1 state=dir-ltr classes=empty
block visible=1 state=dir-ltr classes=high,filled
levelbar visible=1 state=dir-ltr classes=horizontal,continuous
trough visible=1 state=dir-ltr
block visible=1 state=dir-ltr classes=low,filled
block visible=1 state=dir-ltr classes=empty
levelbar visible=1 state=dir-ltr classes=horizontal,continuous
trough visible=1 state=dir-ltr
block visible=1 state=dir-ltr classes=full,filled
block visible=1 state=dir-ltr classes=empty
levelbar visible=1 state=dir-ltr classes=horizontal,discrete
trough visible=1 state=dir-ltr
block visible=1 state=dir-ltr classes=full,filled
block visible=1 state=dir-ltr classes=full,filled
block visible=1 state=dir-ltr classes=full,filled
block visible=1 state=dir-ltr classes=full,filled
block visible=1 state=dir-ltr classes=full,filled
block visible=1 state=dir-ltr classes=empty
block visible=1 state=dir-ltr classes=empty
block visible=1 state=dir-ltr classes=empty
block visible=1 state=dir-ltr classes=empty
block visible=1 state=dir-ltr classes=empty
levelbar visible=1 state=dir-ltr classes=horizontal,discrete
trough visible=1 state=dir-ltr
block visible=1 state=dir-ltr classes=full,filled
block visible=1 state=dir-ltr classes=full,filled
block visible=1 state=dir-ltr classes=empty
block visible=1 state=dir-ltr classes=empty
block visible=1 state=dir-ltr classes=empty
block visible=1 state=dir-ltr classes=empty
block visible=1 state=dir-ltr classes=empty
block visible=1 state=dir-ltr classes=empty
block visible=1 state=dir-ltr classes=empty
block visible=1 state=dir-ltr classes=empty
levelbar visible=1 state=dir-ltr classes=horizontal,discrete
trough visible=1 state=dir-ltr
block visible=1 state=dir-ltr classes=full,filled
block visible=1 state=dir-ltr classes=full,filled
block visible=1 state=dir-ltr classes=full,filled
block visible=1 state=dir-ltr classes=full,filled
block visible=1 state=dir-ltr classes=full,filled
block visible=1 state=dir-ltr classes=full,filled
block visible=1 state=dir-ltr classes=full,filled
block visible=1 state=dir-ltr classes=full,filled
block visible=1 state=dir-ltr classes=empty
block visible=1 state=dir-ltr classes=empty

View File

@@ -0,0 +1,66 @@
<?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">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLevelBar">
<property name="visible">True</property>
<property name="value">0.5</property>
</object>
</child>
<child>
<object class="GtkLevelBar">
<property name="visible">True</property>
<property name="inverted">True</property>
<property name="value">0.5</property>
</object>
</child>
<child>
<object class="GtkLevelBar">
<property name="visible">True</property>
<property name="value">0.2</property>
</object>
</child>
<child>
<object class="GtkLevelBar">
<property name="visible">True</property>
<property name="value">0.8</property>
</object>
</child>
<child>
<object class="GtkLevelBar">
<property name="visible">True</property>
<property name="min-value">0</property>
<property name="max-value">10</property>
<property name="value">5</property>
<property name="mode">discrete</property>
</object>
</child>
<child>
<object class="GtkLevelBar">
<property name="visible">True</property>
<property name="min-value">0</property>
<property name="max-value">10</property>
<property name="value">2</property>
<property name="mode">discrete</property>
</object>
</child>
<child>
<object class="GtkLevelBar">
<property name="visible">True</property>
<property name="min-value">0</property>
<property name="max-value">10</property>
<property name="value">8</property>
<property name="mode">discrete</property>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -0,0 +1,15 @@
window visible=0 state=dir-ltr classes=background
decoration visible=1 state=dir-ltr
notebook visible=1 state=dir-ltr classes=frame
header visible=1 state=dir-ltr classes=top
button visible=1 state=dir-ltr classes=text-button
label visible=1 state=dir-ltr
tabs visible=1 state=dir-ltr
tab visible=1 state=active|dir-ltr
label visible=1 state=dir-ltr
tab visible=1 state=dir-ltr
label visible=1 state=dir-ltr
button visible=1 state=dir-ltr classes=text-button
label visible=1 state=dir-ltr
button visible=1 state=dir-ltr classes=text-button
label visible=1 state=dir-ltr

View File

@@ -0,0 +1,43 @@
<?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="GtkNotebook" id="notebook1">
<property name="visible">True</property>
<child>
<object class="GtkButton" id="page1">
<property name="label" translatable="yes">Yes</property>
<property name="visible">True</property>
</object>
</child>
<child type="tab">
<object class="GtkLabel" id="tab1">
<property name="label" translatable="yes">Tab 1</property>
<property name="visible">True</property>
</object>
</child>
<child>
<object class="GtkButton" id="page2">
<property name="label" translatable="yes">No</property>
<property name="visible">True</property>
</object>
</child>
<child type="tab">
<object class="GtkLabel" id="tab2">
<property name="label" translatable="yes">Tab 2</property>
<property name="visible">True</property>
</object>
</child>
<child type="action-start">
<object class="GtkButton" id="action">
<property name="label" translatable="yes">Action</property>
<property name="visible">True</property>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -0,0 +1,20 @@
window visible=0 state=dir-ltr classes=background
decoration visible=1 state=dir-ltr
box id=progressbars visible=1 state=dir-ltr classes=vertical
progressbar visible=1 state=dir-ltr classes=horizontal
text visible=1 state=dir-ltr
trough visible=1 state=dir-ltr
progress visible=1 state=dir-ltr classes=left
progressbar visible=1 state=dir-ltr classes=horizontal
trough visible=1 state=dir-ltr
progress visible=1 state=dir-ltr classes=left
progressbar visible=1 state=dir-ltr classes=horizontal
text visible=1 state=dir-ltr
trough visible=1 state=dir-ltr
progress visible=1 state=dir-ltr classes=left
progressbar visible=1 state=dir-ltr classes=horizontal
trough visible=1 state=dir-ltr
progress visible=1 state=dir-ltr classes=right
progressbar visible=1 state=dir-ltr classes=vertical
trough visible=1 state=dir-ltr
progress visible=1 state=dir-ltr classes=top

View File

@@ -0,0 +1,49 @@
<?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">
<property name="visible">True</property>
<property name="name">progressbars</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkProgressBar">
<property name="visible">True</property>
<property name="show-text">True</property>
<property name="fraction">0</property>
</object>
</child>
<child>
<object class="GtkProgressBar">
<property name="visible">True</property>
<property name="fraction">1</property>
</object>
</child>
<child>
<object class="GtkProgressBar">
<property name="visible">True</property>
<property name="show-text">True</property>
<property name="fraction">0.4</property>
</object>
</child>
<child>
<object class="GtkProgressBar">
<property name="visible">True</property>
<property name="inverted">True</property>
<property name="fraction">0.4</property>
</object>
</child>
<child>
<object class="GtkProgressBar">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="fraction">0.4</property>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -0,0 +1,265 @@
/*
* Copyright (C) 2015 Red Hat Inc.
*
* Author:
* Matthias Clasen <mclasen@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <glib/gstdio.h>
#include <gtk/gtk.h>
static char *
test_get_reference_file (const char *ui_file)
{
GString *file = g_string_new (NULL);
if (g_str_has_suffix (ui_file, ".ui"))
g_string_append_len (file, ui_file, strlen (ui_file) - 3);
else
g_string_append (file, ui_file);
g_string_append (file, ".nodes");
if (!g_file_test (file->str, G_FILE_TEST_EXISTS))
{
g_string_free (file, TRUE);
return g_strdup (ui_file);
}
return g_string_free (file, FALSE);
}
static char *
diff_with_file (const char *file1,
char *text,
gssize len,
GError **error)
{
const char *command[] = { "diff", "-u", file1, NULL, NULL };
char *diff, *tmpfile;
int fd;
diff = NULL;
if (len < 0)
len = strlen (text);
/* write the text buffer to a temporary file */
fd = g_file_open_tmp (NULL, &tmpfile, error);
if (fd < 0)
return NULL;
if (write (fd, text, len) != (int) len)
{
close (fd);
g_set_error (error,
G_FILE_ERROR, G_FILE_ERROR_FAILED,
"Could not write data to temporary file '%s'", tmpfile);
goto done;
}
close (fd);
command[3] = tmpfile;
/* run diff command */
g_spawn_sync (NULL,
(char **) command,
NULL,
G_SPAWN_SEARCH_PATH,
NULL, NULL,
&diff,
NULL, NULL,
error);
done:
g_unlink (tmpfile);
g_free (tmpfile);
return diff;
}
static void
load_ui_file (GFile *file, gboolean generate)
{
GtkBuilder *builder;
GtkWidget *window;
GtkStyleContext *context;
char *output, *diff;
char *ui_file, *reference_file;
GError *error = NULL;
ui_file = g_file_get_path (file);
builder = gtk_builder_new_from_file (ui_file);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window1"));
g_assert (window != NULL);
context = gtk_widget_get_style_context (window);
output = gtk_style_context_to_string (context, GTK_STYLE_CONTEXT_PRINT_RECURSE);
if (generate)
{
g_print ("%s", output);
goto out;
}
reference_file = test_get_reference_file (ui_file);
diff = diff_with_file (reference_file, output, -1, &error);
g_assert_no_error (error);
if (diff && diff[0])
{
g_test_message ("Resulting output doesn't match reference:\n%s", diff);
g_test_fail ();
}
g_free (reference_file);
g_free (diff);
out:
g_free (output);
g_free (ui_file);
}
static void
test_ui_file (GFile *file)
{
load_ui_file (file, FALSE);
}
static void
add_test_for_file (GFile *file)
{
char *path;
path = g_file_get_path (file);
g_test_add_vtable (path,
0,
g_object_ref (file),
NULL,
(GTestFixtureFunc) test_ui_file,
(GTestFixtureFunc) g_object_unref);
g_free (path);
}
static int
compare_files (gconstpointer a, gconstpointer b)
{
GFile *file1 = G_FILE (a);
GFile *file2 = G_FILE (b);
char *path1, *path2;
int result;
path1 = g_file_get_path (file1);
path2 = g_file_get_path (file2);
result = strcmp (path1, path2);
g_free (path1);
g_free (path2);
return result;
}
static void
add_tests_for_files_in_directory (GFile *dir)
{
GFileEnumerator *enumerator;
GFileInfo *info;
GList *files;
GError *error = NULL;
enumerator = g_file_enumerate_children (dir, G_FILE_ATTRIBUTE_STANDARD_NAME, 0, NULL, &error);
g_assert_no_error (error);
files = NULL;
while ((info = g_file_enumerator_next_file (enumerator, NULL, &error)))
{
const char *filename;
filename = g_file_info_get_name (info);
if (!g_str_has_suffix (filename, ".ui") ||
g_str_has_suffix (filename, ".nodes"))
{
g_object_unref (info);
continue;
}
files = g_list_prepend (files, g_file_get_child (dir, filename));
g_object_unref (info);
}
g_assert_no_error (error);
g_object_unref (enumerator);
files = g_list_sort (files, compare_files);
g_list_foreach (files, (GFunc) add_test_for_file, NULL);
g_list_free_full (files, g_object_unref);
}
int
main (int argc, char **argv)
{
g_setenv ("GTK_CSS_DEBUG", "1", TRUE);
gtk_test_init (&argc, &argv);
if (argc < 2)
{
const char *basedir;
GFile *dir;
basedir = g_test_get_dir (G_TEST_DIST);
dir = g_file_new_for_path (basedir);
add_tests_for_files_in_directory (dir);
g_object_unref (dir);
}
else if (strcmp (argv[1], "--generate") == 0)
{
if (argc >= 3)
{
GFile *file = g_file_new_for_commandline_arg (argv[2]);
load_ui_file (file, TRUE);
g_object_unref (file);
}
}
else
{
guint i;
for (i = 1; i < argc; i++)
{
GFile *file = g_file_new_for_commandline_arg (argv[i]);
add_test_for_file (file);
g_object_unref (file);
}
}
return g_test_run ();
}

View File

@@ -0,0 +1,3 @@
[Test]
Exec=/bin/sh -c "cd @libexecdir@/installed-tests/gtk+/css/nodes && @libexecdir@/installed-tests/gtk+/css/nodes/test-css-nodes
Type=session

View File

@@ -0,0 +1,59 @@
include $(top_srcdir)/Makefile.decl
NULL =
CLEANFILES =
TEST_PROGS += test-css-style
test_in_files = test-css-style.test.in
check_PROGRAMS = $(TEST_PROGS)
test_css_style_CFLAGS = \
-I$(top_srcdir) \
-I$(top_builddir)/gdk \
-I$(top_srcdir)/gdk \
$(GTK_DEBUG_FLAGS) \
$(GTK_DEP_CFLAGS)
test_css_style_LDADD = \
$(top_builddir)/gdk/libgdk-3.la \
$(top_builddir)/gtk/libgtk-3.la \
$(GTK_DEP_LIBS)
test_css_style_SOURCES = \
test-css-style.c
test_data = \
currentcolor.ui currentcolor.css currentcolor.nodes \
inherit.ui inherit.css inherit.nodes \
label.ui label.css label.nodes \
nth-child.ui nth-child.css nth-child.nodes \
$(NULL)
EXTRA_DIST += $(test_in_files) $(test_data)
if BUILDOPT_INSTALL_TESTS
insttestdir=$(libexecdir)/installed-tests/$(PACKAGE)/css/style
insttest_PROGRAMS = $(TEST_PROGS)
insttest_DATA = $(test_data)
substitutions = \
-e s,@libexecdir\@,$(libexecdir),g \
$(NULL)
test_files = $(test_in_files:.test.in=.test)
$(test_files): %.test: %.test.in
$(AM_V_GEN) sed $(substitutions) $< > $@.tmp && mv $@.tmp $@
EXTRA_DIST += $(test_files)
CLEANFILES += $(test_files)
testmetadir = $(datadir)/installed-tests/$(PACKAGE)/css/style
testmeta_DATA = $(test_files)
endif
-include $(top_srcdir)/git.mk

View File

@@ -0,0 +1,9 @@
@import "reset-to-defaults.css";
box {
color: red;
}
label {
background-color: currentColor;
}

View File

@@ -0,0 +1,7 @@
window visible=0 state=dir-ltr classes=background
decoration visible=1 state=dir-ltr
box visible=1 state=dir-ltr classes=horizontal
color: rgb(255,0,0) (currentcolor.css:4:12)
label visible=1 state=dir-ltr
color: rgb(255,0,0) (reset-to-defaults.css:2:12)
background-color: rgb(255,0,0) (currentcolor.css:8:32)

View File

@@ -0,0 +1,19 @@
<?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">
<property name="visible">True</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">Hello World!</property>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -0,0 +1,11 @@
@import "reset-to-defaults.css";
box {
color: red;
opacity: 0.5;
}
label#label1 {
color: initial;
opacity: inherit;
}

View File

@@ -0,0 +1,9 @@
window visible=0 state=dir-ltr classes=background
decoration visible=1 state=dir-ltr
box visible=1 state=dir-ltr classes=horizontal
color: rgb(255,0,0) (inherit.css:4:12)
opacity: 0.5 (inherit.css:5:14)
label id=label1 visible=1 state=dir-ltr
opacity: 0.5 (inherit.css:10:18)
label id=label2 visible=1 state=dir-ltr
color: rgb(255,0,0) (reset-to-defaults.css:2:12)

View File

@@ -0,0 +1,27 @@
<?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">
<property name="visible">True</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="name">label1</property>
<property name="label" translatable="yes">Hello World!</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="name">label2</property>
<property name="visible">True</property>
<property name="label" translatable="yes">Hello World!</property>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -0,0 +1,5 @@
@import "reset-to-defaults.css";
box {
font: "Comic Sans";
}

View File

@@ -0,0 +1,6 @@
window visible=0 state=dir-ltr classes=background
decoration visible=1 state=dir-ltr
box visible=1 state=dir-ltr classes=horizontal
font-family: "\"Comic Sans\"" (label.css:4:20)
label visible=1 state=dir-ltr
font-family: "\"Comic Sans\"" (reset-to-defaults.css:2:12)

View File

@@ -0,0 +1,19 @@
<?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">
<property name="visible">True</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">Hello World!</property>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -0,0 +1,14 @@
@import "reset-to-defaults.css";
label:first-child {
font-size: 20px;
}
label {
font-size: 30px;
}
label:last-child {
font-size: 40px;
}
label:only-child {
font-size: 50px;
}

View File

@@ -0,0 +1,13 @@
window visible=0 state=dir-ltr classes=background
decoration visible=1 state=dir-ltr
box visible=1 state=dir-ltr classes=horizontal
box visible=1 state=dir-ltr classes=horizontal
label visible=1 state=dir-ltr
font-size: 20px (nth-child.css:4:17)
label visible=1 state=dir-ltr
font-size: 30px (nth-child.css:7:17)
label visible=1 state=dir-ltr
font-size: 40px (nth-child.css:10:17)
box visible=1 state=dir-ltr classes=horizontal
label visible=1 state=dir-ltr
font-size: 50px (nth-child.css:13:17)

View File

@@ -0,0 +1,48 @@
<?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">
<property name="visible">True</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">Hello World!</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">Hello World!</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">Hello World!</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">Hello World!</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -0,0 +1,287 @@
/*
* Copyright (C) 2015 Red Hat Inc.
*
* Author:
* Matthias Clasen <mclasen@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <glib/gstdio.h>
#include <gtk/gtk.h>
/* There shall be no other styles */
#define GTK_STYLE_PROVIDER_PRIORITY_FORCE G_MAXUINT
char *
test_get_other_file (const char *ui_file, const char *extension)
{
GString *file = g_string_new (NULL);
if (g_str_has_suffix (ui_file, ".ui"))
g_string_append_len (file, ui_file, strlen (ui_file) - strlen (".ui"));
else
g_string_append (file, ui_file);
g_string_append (file, extension);
if (!g_file_test (file->str, G_FILE_TEST_EXISTS))
{
g_string_free (file, TRUE);
return NULL;
}
return g_string_free (file, FALSE);
}
static char *
diff_with_file (const char *file1,
char *text,
gssize len,
GError **error)
{
const char *command[] = { "diff", "-u", file1, NULL, NULL };
char *diff, *tmpfile;
int fd;
diff = NULL;
if (len < 0)
len = strlen (text);
/* write the text buffer to a temporary file */
fd = g_file_open_tmp (NULL, &tmpfile, error);
if (fd < 0)
return NULL;
if (write (fd, text, len) != (int) len)
{
close (fd);
g_set_error (error,
G_FILE_ERROR, G_FILE_ERROR_FAILED,
"Could not write data to temporary file '%s'", tmpfile);
goto done;
}
close (fd);
command[3] = tmpfile;
/* run diff command */
g_spawn_sync (NULL,
(char **) command,
NULL,
G_SPAWN_SEARCH_PATH,
NULL, NULL,
&diff,
NULL, NULL,
error);
done:
g_unlink (tmpfile);
g_free (tmpfile);
return diff;
}
static void
load_ui_file (GFile *file, gboolean generate)
{
GtkBuilder *builder;
GtkWidget *window;
GtkStyleContext *context;
char *output, *diff;
char *ui_file, *css_file, *reference_file;
GtkCssProvider *provider;
GError *error = NULL;
ui_file = g_file_get_path (file);
css_file = test_get_other_file (ui_file, ".css");
g_assert (css_file != NULL);
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_path (provider, css_file, &error);
g_assert_no_error (error);
gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
GTK_STYLE_PROVIDER (provider),
GTK_STYLE_PROVIDER_PRIORITY_FORCE);
builder = gtk_builder_new_from_file (ui_file);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window1"));
g_assert (window != NULL);
context = gtk_widget_get_style_context (window);
output = gtk_style_context_to_string (context, GTK_STYLE_CONTEXT_PRINT_RECURSE |
GTK_STYLE_CONTEXT_PRINT_SHOW_STYLE);
if (generate)
{
g_print ("%s", output);
goto out;
}
reference_file = test_get_other_file (ui_file, ".nodes");
diff = diff_with_file (reference_file, output, -1, &error);
g_assert_no_error (error);
if (diff && diff[0])
{
g_test_message ("Resulting output doesn't match reference:\n%s", diff);
g_test_fail ();
}
g_free (reference_file);
g_free (diff);
out:
gtk_style_context_remove_provider_for_screen (gdk_screen_get_default (),
GTK_STYLE_PROVIDER (provider));
g_object_unref (provider);
g_free (output);
g_free (ui_file);
g_free (css_file);
}
static void
test_ui_file (GFile *file)
{
load_ui_file (file, FALSE);
}
static void
add_test_for_file (GFile *file)
{
char *path;
path = g_file_get_path (file);
g_test_add_vtable (path,
0,
g_object_ref (file),
NULL,
(GTestFixtureFunc) test_ui_file,
(GTestFixtureFunc) g_object_unref);
g_free (path);
}
static int
compare_files (gconstpointer a, gconstpointer b)
{
GFile *file1 = G_FILE (a);
GFile *file2 = G_FILE (b);
char *path1, *path2;
int result;
path1 = g_file_get_path (file1);
path2 = g_file_get_path (file2);
result = strcmp (path1, path2);
g_free (path1);
g_free (path2);
return result;
}
static void
add_tests_for_files_in_directory (GFile *dir)
{
GFileEnumerator *enumerator;
GFileInfo *info;
GList *files;
GError *error = NULL;
enumerator = g_file_enumerate_children (dir, G_FILE_ATTRIBUTE_STANDARD_NAME, 0, NULL, &error);
g_assert_no_error (error);
files = NULL;
while ((info = g_file_enumerator_next_file (enumerator, NULL, &error)))
{
const char *filename;
filename = g_file_info_get_name (info);
if (!g_str_has_suffix (filename, ".ui") ||
g_str_has_suffix (filename, ".nodes"))
{
g_object_unref (info);
continue;
}
files = g_list_prepend (files, g_file_get_child (dir, filename));
g_object_unref (info);
}
g_assert_no_error (error);
g_object_unref (enumerator);
files = g_list_sort (files, compare_files);
g_list_foreach (files, (GFunc) add_test_for_file, NULL);
g_list_free_full (files, g_object_unref);
}
int
main (int argc, char **argv)
{
g_setenv ("GTK_CSS_DEBUG", "1", TRUE);
gtk_test_init (&argc, &argv);
g_object_set (gtk_settings_get_default (),
"gtk-font-name", "Sans",
NULL);
if (argc < 2)
{
const char *basedir;
GFile *dir;
basedir = g_test_get_dir (G_TEST_DIST);
dir = g_file_new_for_path (basedir);
add_tests_for_files_in_directory (dir);
g_object_unref (dir);
}
else if (strcmp (argv[1], "--generate") == 0)
{
if (argc >= 3)
{
GFile *file = g_file_new_for_commandline_arg (argv[2]);
load_ui_file (file, TRUE);
g_object_unref (file);
}
}
else
{
guint i;
for (i = 1; i < argc; i++)
{
GFile *file = g_file_new_for_commandline_arg (argv[i]);
add_test_for_file (file);
g_object_unref (file);
}
}
return g_test_run ();
}

View File

@@ -0,0 +1,3 @@
[Test]
Exec=/bin/sh -c "cd @libexecdir@/installed-tests/gtk+/css/style && @libexecdir@/installed-tests/gtk+/css/style/test-css-style
Type=session