Merge branch 'test-coverage' into 'main'

node-editor: Make the help more helpful

See merge request GNOME/gtk!4874
This commit is contained in:
Matthias Clasen 2022-07-15 22:34:02 +00:00
commit 63c61340ac
43 changed files with 1244 additions and 62 deletions

View File

@ -13,6 +13,8 @@ Each node has its own `<node-name>` and supports a custom set of properties, eac
When serializing and the value of a property equals the default value, this value will not be serialized. Serialization aims to produce an output as small as possible.
To embed newlines in strings, use \A. To break a long string into multiple lines, escape the newline with a \.
# Nodes
### container
@ -135,6 +137,23 @@ Creates a node like `gsk_cross_fade_node_new()` with the given properties.
Creates a node like `gsk_debug_node_new()` with the given properties.
### glshader
| property | syntax | default | printed |
| ---------- | ------------------ | ---------------------- | ----------- |
| bounds | `<rect>` | 50 | always |
| sourcecode | `<string>` | "" | always |
| args | `<uniform values>` | none | non-default |
| child1 | `<node>` | none | non-default |
| child2 | `<node>` | none | non-default |
| child3 | `<node>` | none | non-default |
| child4 | `<node>` | none | non-default |
Creates a GLShader node. The `sourcecode` must be a GLSL fragment shader.
The `args` must match the uniforms of simple types declared in that shader,
in order and comma-separated. The `child` properties must match the sampler
uniforms in the shader.
### inset-shadow
| property | syntax | default | printed |
@ -286,20 +305,3 @@ representation for this texture is `url("data:image/png;base64,iVBORw0KGgoAAAANS
| transform| `<transform>` | none | non-default |
Creates a node like `gsk_transform_node_new()` with the given properties.
### glshader
| property | syntax | default | printed |
| ---------- | ------------------ | ---------------------- | ----------- |
| bounds | `<rect>` | 50 | always |
| sourcecode | `<string>` | "" | always |
| args | `<uniform values>` | none | non-default |
| child1 | `<node>` | none | non-default |
| child2 | `<node>` | none | non-default |
| child3 | `<node>` | none | non-default |
| child4 | `<node>` | none | non-default |
Creates a GLShader node. The `sourcecode` must be a GLSL fragment shader.
The `args` must match the uniforms of simple types declared in that shader,
in order and comma-separated. The `child` properties must match the sampler
uniforms in the shader.

View File

@ -162,6 +162,7 @@ uniform_type_from_glsl (const char *str)
return GSK_GL_UNIFORM_TYPE_NONE;
}
#ifdef G_ENABLE_DEBUG
static const char *
uniform_type_name (GskGLUniformType type)
{
@ -194,6 +195,7 @@ uniform_type_name (GskGLUniformType type)
return NULL;
}
}
#endif
static int
uniform_type_size (GskGLUniformType type)
@ -397,6 +399,7 @@ gsk_gl_shader_constructed (GObject *object)
shader->n_textures = max_texture_seen;
#ifdef G_ENABLE_DEBUG
if (GSK_DEBUG_CHECK(SHADERS))
{
GString *s;
@ -414,6 +417,7 @@ gsk_gl_shader_constructed (GObject *object)
s->str);
g_string_free (s, TRUE);
}
#endif
}
#define SPACE_RE "[ \\t]+" // Don't use \s, we don't want to match newlines
@ -631,6 +635,7 @@ gsk_gl_shader_get_uniform_name (GskGLShader *shader,
int idx)
{
g_return_val_if_fail (GSK_IS_GL_SHADER (shader), NULL);
g_return_val_if_fail (0 <= idx && idx < shader->uniforms->len, NULL);
return g_array_index (shader->uniforms, GskGLUniform, idx).name;
}
@ -675,6 +680,7 @@ gsk_gl_shader_get_uniform_type (GskGLShader *shader,
int idx)
{
g_return_val_if_fail (GSK_IS_GL_SHADER (shader), 0);
g_return_val_if_fail (0 <= idx && idx < shader->uniforms->len, 0);
return g_array_index (shader->uniforms, GskGLUniform, idx).type;
}
@ -693,6 +699,7 @@ gsk_gl_shader_get_uniform_offset (GskGLShader *shader,
int idx)
{
g_return_val_if_fail (GSK_IS_GL_SHADER (shader), 0);
g_return_val_if_fail (0 <= idx && idx < shader->uniforms->len, 0);
return g_array_index (shader->uniforms, GskGLUniform, idx).offset;
}

View File

@ -15,23 +15,3 @@ gsk_ensure_resources (void)
g_once (&register_resources_once, register_resources, NULL);
}
int
pango_glyph_string_num_glyphs (PangoGlyphString *glyphs)
{
int i, count;
count = 0;
for (i = 0; i < glyphs->num_glyphs; i++)
{
PangoGlyphInfo *gi = &glyphs->glyphs[i];
if (gi->glyph != PANGO_GLYPH_EMPTY)
{
if (!(gi->glyph & PANGO_GLYPH_UNKNOWN_FLAG))
count++;
}
}
return count;
}

View File

@ -8,8 +8,6 @@ G_BEGIN_DECLS
void gsk_ensure_resources (void);
int pango_glyph_string_num_glyphs (PangoGlyphString *glyphs) G_GNUC_PURE;
typedef struct _GskVulkanRender GskVulkanRender;
typedef struct _GskVulkanRenderPass GskVulkanRenderPass;

View File

@ -982,7 +982,7 @@ parse_color_node (GtkCssParser *parser)
{ "color", parse_color, NULL, &color },
};
parse_declarations (parser, declarations, G_N_ELEMENTS(declarations));
parse_declarations (parser, declarations, G_N_ELEMENTS (declarations));
return gsk_color_node_new (&color, &bounds);
}
@ -1003,7 +1003,7 @@ parse_linear_gradient_node_internal (GtkCssParser *parser,
};
GskRenderNode *result;
parse_declarations (parser, declarations, G_N_ELEMENTS(declarations));
parse_declarations (parser, declarations, G_N_ELEMENTS (declarations));
if (stops == NULL)
{
GskColorStop from = { 0.0, GDK_RGBA("AAFF00") };
@ -1058,7 +1058,7 @@ parse_radial_gradient_node_internal (GtkCssParser *parser,
};
GskRenderNode *result;
parse_declarations (parser, declarations, G_N_ELEMENTS(declarations));
parse_declarations (parser, declarations, G_N_ELEMENTS (declarations));
if (stops == NULL)
{
GskColorStop from = { 0.0, GDK_RGBA("AAFF00") };
@ -1108,7 +1108,7 @@ parse_conic_gradient_node (GtkCssParser *parser)
};
GskRenderNode *result;
parse_declarations (parser, declarations, G_N_ELEMENTS(declarations));
parse_declarations (parser, declarations, G_N_ELEMENTS (declarations));
if (stops == NULL)
{
GskColorStop from = { 0.0, GDK_RGBA("AAFF00") };
@ -1142,7 +1142,7 @@ parse_inset_shadow_node (GtkCssParser *parser)
{ "blur", parse_double, NULL, &blur }
};
parse_declarations (parser, declarations, G_N_ELEMENTS(declarations));
parse_declarations (parser, declarations, G_N_ELEMENTS (declarations));
return gsk_inset_shadow_node_new (&outline, &color, dx, dy, spread, blur);
}
@ -1325,7 +1325,7 @@ parse_glshader_node (GtkCssParser *parser)
GBytes *args = NULL;
int len, i;
parse_declarations (parser, declarations, G_N_ELEMENTS(declarations));
parse_declarations (parser, declarations, G_N_ELEMENTS (declarations));
for (len = 0; len < 4; len++)
{
@ -1362,7 +1362,7 @@ parse_border_node (GtkCssParser *parser)
{ "colors", parse_colors4, NULL, &colors }
};
parse_declarations (parser, declarations, G_N_ELEMENTS(declarations));
parse_declarations (parser, declarations, G_N_ELEMENTS (declarations));
return gsk_border_node_new (&outline, widths, colors);
}
@ -1378,7 +1378,7 @@ parse_texture_node (GtkCssParser *parser)
};
GskRenderNode *node;
parse_declarations (parser, declarations, G_N_ELEMENTS(declarations));
parse_declarations (parser, declarations, G_N_ELEMENTS (declarations));
if (texture == NULL)
texture = create_default_texture ();
@ -1402,7 +1402,7 @@ parse_cairo_node (GtkCssParser *parser)
};
GskRenderNode *node;
parse_declarations (parser, declarations, G_N_ELEMENTS(declarations));
parse_declarations (parser, declarations, G_N_ELEMENTS (declarations));
node = gsk_cairo_node_new (&bounds);
@ -1447,7 +1447,7 @@ parse_outset_shadow_node (GtkCssParser *parser)
{ "blur", parse_double, NULL, &blur }
};
parse_declarations (parser, declarations, G_N_ELEMENTS(declarations));
parse_declarations (parser, declarations, G_N_ELEMENTS (declarations));
return gsk_outset_shadow_node_new (&outline, &color, dx, dy, spread, blur);
}
@ -1463,7 +1463,7 @@ parse_transform_node (GtkCssParser *parser)
};
GskRenderNode *result;
parse_declarations (parser, declarations, G_N_ELEMENTS(declarations));
parse_declarations (parser, declarations, G_N_ELEMENTS (declarations));
if (child == NULL)
child = create_default_render_node ();
@ -1490,7 +1490,7 @@ parse_opacity_node (GtkCssParser *parser)
};
GskRenderNode *result;
parse_declarations (parser, declarations, G_N_ELEMENTS(declarations));
parse_declarations (parser, declarations, G_N_ELEMENTS (declarations));
if (child == NULL)
child = create_default_render_node ();
@ -1517,7 +1517,7 @@ parse_color_matrix_node (GtkCssParser *parser)
graphene_vec4_init (&offset, 0, 0, 0, 0);
parse_declarations (parser, declarations, G_N_ELEMENTS(declarations));
parse_declarations (parser, declarations, G_N_ELEMENTS (declarations));
if (child == NULL)
child = create_default_render_node ();
@ -1544,7 +1544,7 @@ parse_cross_fade_node (GtkCssParser *parser)
};
GskRenderNode *result;
parse_declarations (parser, declarations, G_N_ELEMENTS(declarations));
parse_declarations (parser, declarations, G_N_ELEMENTS (declarations));
if (start == NULL)
start = gsk_color_node_new (&GDK_RGBA("AAFF00"), &GRAPHENE_RECT_INIT (0, 0, 50, 50));
if (end == NULL)
@ -1571,7 +1571,7 @@ parse_blend_node (GtkCssParser *parser)
};
GskRenderNode *result;
parse_declarations (parser, declarations, G_N_ELEMENTS(declarations));
parse_declarations (parser, declarations, G_N_ELEMENTS (declarations));
if (bottom == NULL)
bottom = gsk_color_node_new (&GDK_RGBA("AAFF00"), &GRAPHENE_RECT_INIT (0, 0, 50, 50));
if (top == NULL)
@ -1599,7 +1599,7 @@ parse_repeat_node (GtkCssParser *parser)
GskRenderNode *result;
guint parse_result;
parse_result = parse_declarations (parser, declarations, G_N_ELEMENTS(declarations));
parse_result = parse_declarations (parser, declarations, G_N_ELEMENTS (declarations));
if (child == NULL)
child = create_default_render_node ();
@ -1663,7 +1663,7 @@ parse_text_node (GtkCssParser *parser)
};
GskRenderNode *result;
parse_declarations (parser, declarations, G_N_ELEMENTS(declarations));
parse_declarations (parser, declarations, G_N_ELEMENTS (declarations));
if (font == NULL)
{
@ -1721,7 +1721,7 @@ parse_blur_node (GtkCssParser *parser)
};
GskRenderNode *result;
parse_declarations (parser, declarations, G_N_ELEMENTS(declarations));
parse_declarations (parser, declarations, G_N_ELEMENTS (declarations));
if (child == NULL)
child = create_default_render_node ();
@ -1743,7 +1743,7 @@ parse_clip_node (GtkCssParser *parser)
};
GskRenderNode *result;
parse_declarations (parser, declarations, G_N_ELEMENTS(declarations));
parse_declarations (parser, declarations, G_N_ELEMENTS (declarations));
if (child == NULL)
child = create_default_render_node ();
@ -1768,7 +1768,7 @@ parse_rounded_clip_node (GtkCssParser *parser)
};
GskRenderNode *result;
parse_declarations (parser, declarations, G_N_ELEMENTS(declarations));
parse_declarations (parser, declarations, G_N_ELEMENTS (declarations));
if (child == NULL)
child = create_default_render_node ();
@ -1790,7 +1790,7 @@ parse_shadow_node (GtkCssParser *parser)
};
GskRenderNode *result;
parse_declarations (parser, declarations, G_N_ELEMENTS(declarations));
parse_declarations (parser, declarations, G_N_ELEMENTS (declarations));
if (child == NULL)
child = create_default_render_node ();
@ -1819,7 +1819,7 @@ parse_debug_node (GtkCssParser *parser)
};
GskRenderNode *result;
parse_declarations (parser, declarations, G_N_ELEMENTS(declarations));
parse_declarations (parser, declarations, G_N_ELEMENTS (declarations));
if (child == NULL)
child = create_default_render_node ();

View File

@ -25,6 +25,7 @@ test_can_diff_basic (void)
{
GskRenderNode *container1, *container2;
GskRenderNode *color1, *color2;
GskRenderNode *debug1, *debug2;
color1 = gsk_color_node_new (&(GdkRGBA){0, 1, 0, 1 }, &GRAPHENE_RECT_INIT (0, 0, 10, 10));
color2 = gsk_color_node_new (&(GdkRGBA){1, 1, 0, 1 }, &GRAPHENE_RECT_INIT (0, 0, 10, 10));
@ -32,10 +33,15 @@ test_can_diff_basic (void)
container1 = gsk_container_node_new (&color1, 1);
container2 = gsk_container_node_new (&color2, 1);
debug1 = gsk_debug_node_new (color1, g_strdup ("Debug node!"));
debug2 = gsk_debug_node_new (color2, g_strdup ("Debug node!"));
/* We can diff two color nodes */
g_assert_true (gsk_render_node_can_diff (color1, color2));
/* We can diff two container nodes */
g_assert_true (gsk_render_node_can_diff (container1, container2));
/* We can diff two debug nodes */
g_assert_true (gsk_render_node_can_diff (debug1, debug2));
/* We can diff container nodes against anything else */
g_assert_true (gsk_render_node_can_diff (container1, color2));
g_assert_true (gsk_render_node_can_diff (color1, container2));
@ -45,6 +51,9 @@ test_can_diff_basic (void)
gsk_render_node_unref (container1);
gsk_render_node_unref (container2);
gsk_render_node_unref (debug1);
gsk_render_node_unref (debug2);
}
static void

View File

@ -129,6 +129,8 @@ node_parser_tests = [
'blend.node',
'border.node',
'color.node',
'conic-gradient.node',
'conic-gradient.ref.node',
'crash1.errors',
'crash1.node',
'crash1.ref.node',
@ -141,6 +143,9 @@ node_parser_tests = [
'crash4.node',
'crash4.ref.node',
'debug.node',
'debug-fail.node',
'debug-fail.ref.node',
'debug-fail.errors',
'empty-blend.node',
'empty-blend.ref.node',
'empty-blur.node',
@ -181,9 +186,33 @@ node_parser_tests = [
'empty-texture.ref.node',
'empty-transform.node',
'empty-transform.ref.node',
'glshader.node',
'glshader.ref.node',
'glshader.errors',
'gradient-fail.node',
'gradient-fail.ref.node',
'gradient-fail.errors',
'radial-gradient.node',
'radial-gradient.ref.node',
'repeating-linear-gradient.node',
'repeating-linear-gradient.ref.node',
'repeating-radial-gradient.node',
'repeating-radial-gradient.ref.node',
'rounded-rect.node',
'shadow.node',
'shadow-fail.node',
'shadow-fail.ref.node',
'shadow-fail.errors',
'testswitch.node',
'text-fail.node',
'text-fail.ref.node',
'text-fail.errors',
'texture-fail.node',
'texture-fail.ref.node',
'texture-fail.ref.errors',
'transform-fail.node',
'transform-fail.ref.node',
'transform-fail.errors',
'widgetfactory.node',
]
@ -205,7 +234,6 @@ foreach test : node_parser_tests
endforeach
tests = [
['rounded-rect'],
['transform'],
['shader'],
]
@ -242,6 +270,8 @@ endforeach
internal_tests = [
[ 'diff' ],
[ 'half-float' ],
['rounded-rect'],
['misc'],
]
foreach t : internal_tests

96
testsuite/gsk/misc.c Normal file
View File

@ -0,0 +1,96 @@
#include <gtk/gtk.h>
#include "gsk/gskrendernodeprivate.h"
static void
test_rendernode_gvalue (void)
{
GValue value = G_VALUE_INIT;
GskRenderNode *node, *node2;
g_assert_false (GSK_VALUE_HOLDS_RENDER_NODE (&value));
g_value_init (&value, GSK_TYPE_RENDER_NODE);
g_assert_true (GSK_VALUE_HOLDS_RENDER_NODE (&value));
node = gsk_value_get_render_node (&value);
g_assert_null (node);
node = gsk_color_node_new (&(GdkRGBA){0,1,1,1}, &GRAPHENE_RECT_INIT (0, 0, 50, 50));
gsk_value_set_render_node (&value, node);
node2 = gsk_value_dup_render_node (&value);
g_assert_true (node == node2);
g_value_reset (&value);
gsk_value_take_render_node (&value, node);
g_value_unset (&value);
}
static void
test_bordernode_uniform (void)
{
GskRenderNode *node;
GskRoundedRect rect;
GdkRGBA colors[4] = {
{ 0, 0, 0, 1 },
{ 0, 0, 0, 1 },
{ 0, 0, 0, 1 },
{ 0, 0, 0, 1 },
};
gsk_rounded_rect_init (&rect,
&GRAPHENE_RECT_INIT (0, 0, 50, 50),
&GRAPHENE_SIZE_INIT (10, 10),
&GRAPHENE_SIZE_INIT (10, 10),
&GRAPHENE_SIZE_INIT (10, 10),
&GRAPHENE_SIZE_INIT (10, 10));
node = gsk_border_node_new (&rect, (const float[]){ 1, 1, 1, 1}, colors);
g_assert_true (gsk_border_node_get_uniform (node));
g_assert_true (gsk_border_node_get_uniform_color (node));
gsk_render_node_unref (node);
node = gsk_border_node_new (&rect, (const float[]){ 1, 2, 3, 4}, colors);
g_assert_false (gsk_border_node_get_uniform (node));
g_assert_true (gsk_border_node_get_uniform_color (node));
gsk_render_node_unref (node);
}
#define DEG_TO_RAD(x) ((x) * (G_PI / 180.f))
static void
test_conic_gradient_angle (void)
{
GskRenderNode *node;
GskColorStop stops[] = {
{ 0.f, (GdkRGBA) { 0, 0, 0, 1} },
{ 1.f, (GdkRGBA) { 1, 0, 1, 1} },
};
node = gsk_conic_gradient_node_new (&GRAPHENE_RECT_INIT (0, 0, 50, 50),
&GRAPHENE_POINT_INIT (10, 20),
33.f,
stops,
G_N_ELEMENTS (stops));
g_assert_cmpfloat_with_epsilon (gsk_conic_gradient_node_get_angle (node), DEG_TO_RAD (90.f - 33.f), 0.001);
gsk_render_node_unref (node);
}
int
main (int argc, char *argv[])
{
(g_test_init) (&argc, &argv, NULL);
gtk_init ();
g_test_add_func ("/rendernode/gvalue", test_rendernode_gvalue);
g_test_add_func ("/rendernode/border/uniform", test_bordernode_uniform);
g_test_add_func ("/rendernode/conic-gradient/angle", test_conic_gradient_angle);
return g_test_run ();
}

View File

@ -0,0 +1,6 @@
conic-gradient {
bounds: 0 0 50 50;
center: 20 30;
rotation: 25;
stops: 0 #444, 0.2 #0F0, 1 #F0A;
}

View File

@ -0,0 +1,6 @@
conic-gradient {
bounds: 0 0 50 50;
center: 20 30;
rotation: 25;
stops: 0 rgb(68,68,68), 0.2 rgb(0,255,0), 1 rgb(255,0,170);
}

View File

@ -0,0 +1,2 @@
<data>:5:10-11: error: GTK_CSS_PARSER_WARNING_SYNTAX
<data>:6:8-9: error: GTK_CSS_PARSER_WARNING_SYNTAX

View File

@ -0,0 +1,8 @@
debug {
message: "I'm a debug node.";
child: container {
}
message: "With repeating message and child.";
child: container {
}
}

View File

@ -0,0 +1,5 @@
debug {
message: "With repeating message and child.";
child: container {
}
}

View File

@ -0,0 +1 @@
<data>:10:43-47: error: GTK_CSS_PARSER_ERROR_SYNTAX

View File

@ -0,0 +1,11 @@
glshader {
bounds: 0 0 50 50;
sourcecode: "uniform vec3 iResolution;\A\
uniform vec4 another;\A\
uniform vec2 point;\A\
uniform int iii;\A\
uniform uint uuu;\A\
uniform bool bbb;\A\
uniform float num;";
args: 10 20 30, 1 2 3 4, -1 -2, 0, 100, true, 3.1415;
}

View File

@ -0,0 +1,11 @@
glshader {
bounds: 0 0 50 50;
sourcecode: "uniform vec3 iResolution;\A\
uniform vec4 another;\A\
uniform vec2 point;\A\
uniform int iii;\A\
uniform uint uuu;\A\
uniform bool bbb;\A\
uniform float num;";
args: 10 20 30, 1 2 3 4, -1 -2, 0, 100, 0, 0;
}

View File

@ -0,0 +1 @@
<data>:3:8-9: error: GTK_CSS_PARSER_WARNING_SYNTAX

View File

@ -0,0 +1,4 @@
repeating-linear-gradient {
stops: 0 #FF0, 0.25 #F0A, 1 #0FF;
stops: 0 #FF0, 0.25 #F0A, 1 #0FF;
}

View File

@ -0,0 +1,6 @@
repeating-linear-gradient {
bounds: 0 0 50 50;
start: 0 0;
end: 0 50;
stops: 0 rgb(255,255,0), 0.25 rgb(255,0,170), 1 rgb(0,255,255);
}

View File

@ -0,0 +1,9 @@
radial-gradient {
bounds: 0 0 50 50;
center: 20 20;
hradius: 10;
vradius: 20;
start: 0.25;
end: 0.75;
stops: 0 #FF0, 0.5 #ABC, 1 #F0F;
}

View File

@ -0,0 +1,9 @@
radial-gradient {
bounds: 0 0 50 50;
center: 20 20;
hradius: 10;
vradius: 20;
start: 0.25;
end: 0.75;
stops: 0 rgb(255,255,0), 0.5 rgb(170,187,204), 1 rgb(255,0,255);
}

View File

@ -0,0 +1,6 @@
repeating-linear-gradient {
bounds: 0 0 50 50;
start: 50 0;
end: 25 25;
stops: 0 #FF0, 0.25 #F0A, 1 #0FF;
}

View File

@ -0,0 +1,6 @@
repeating-linear-gradient {
bounds: 0 0 50 50;
start: 50 0;
end: 25 25;
stops: 0 rgb(255,255,0), 0.25 rgb(255,0,170), 1 rgb(0,255,255);
}

View File

@ -0,0 +1,9 @@
repeating-radial-gradient {
bounds: 0 0 50 50;
center: 20 30;
hradius: 30;
vradius: 20;
start: 0.25;
end: 0.75;
stops: 0 #F0F, 1 #0F0;
}

View File

@ -0,0 +1,9 @@
repeating-radial-gradient {
bounds: 0 0 50 50;
center: 20 30;
hradius: 30;
vradius: 20;
start: 0.25;
end: 0.75;
stops: 0 rgb(255,0,255), 1 rgb(0,255,0);
}

View File

@ -0,0 +1,9 @@
<data>:2:11-13: error: GTK_CSS_PARSER_ERROR_SYNTAX
<data>:2:11-13: error: GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE
<data>:2:13-14: error: GTK_CSS_PARSER_ERROR_SYNTAX
<data>:2:13-14: error: GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE
<data>:3:9-10: error: GTK_CSS_PARSER_WARNING_SYNTAX
<data>:3:11-13: error: GTK_CSS_PARSER_ERROR_SYNTAX
<data>:3:11-13: error: GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE
<data>:3:13-14: error: GTK_CSS_PARSER_ERROR_SYNTAX
<data>:3:13-14: error: GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE

View File

@ -0,0 +1,4 @@
shadow {
shadows: 22;
shadows: 22;
}

View File

@ -0,0 +1,7 @@
shadow {
shadows: rgb(0,0,0) 22 0, rgb(0,0,0) 22 0;
child: color {
bounds: 0 0 50 50;
color: rgb(255,0,204);
}
}

View File

@ -0,0 +1,3 @@
<data>:4:7-8: error: GTK_CSS_PARSER_WARNING_SYNTAX
<data>:6:9-10: error: GTK_CSS_PARSER_WARNING_SYNTAX
<data>:8:1-2: error: GTK_CSS_PARSER_ERROR_UNKNOWN_VALUE

View File

@ -0,0 +1,8 @@
text {
color: rgb(50,50,50);
font: "";
font: "";
glyphs: "N";
glyphs: "N";
offset: 0 32.0186;
}

View File

@ -0,0 +1,4 @@
color {
bounds: 0 0 50 50;
color: rgb(255,0,204);
}

View File

@ -0,0 +1 @@
<data>:2:12-14: error: GTK_CSS_PARSER_ERROR_SYNTAX

View File

@ -0,0 +1,3 @@
texture {
texture: 22;
}

View File

@ -0,0 +1,6 @@
texture {
bounds: 0 0 50 50;
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAKUlEQVQYlWP8z3DmPwMaYGQwYUQX\
Y0IXwAUGUCGGoxkYGBiweXAoeAYAz44F3e3U1xUAAAAASUVORK5CYII=\
");
}

View File

@ -0,0 +1 @@
<data>:2:14-16: error: GTK_CSS_PARSER_ERROR_SYNTAX

View File

@ -0,0 +1,3 @@
transform {
transform: 22;
}

View File

@ -0,0 +1,6 @@
transform {
child: color {
bounds: 0 0 50 50;
color: rgb(255,0,204);
}
}

View File

@ -20,6 +20,7 @@
#include "config.h"
#include <gtk/gtk.h>
#include <gsk/gskroundedrectprivate.h>
static void
test_contains_rect (void)
@ -114,6 +115,51 @@ test_contains_point (void)
g_assert_true (gsk_rounded_rect_contains_point (&rect, &GRAPHENE_POINT_INIT (10, 95)));
}
static void
test_is_circular (void)
{
GskRoundedRect rect;
gsk_rounded_rect_init (&rect,
&GRAPHENE_RECT_INIT (0, 0, 100, 100),
&GRAPHENE_SIZE_INIT (0, 0),
&GRAPHENE_SIZE_INIT (10, 10),
&GRAPHENE_SIZE_INIT (10, 20),
&GRAPHENE_SIZE_INIT (20, 10));
g_assert_false (gsk_rounded_rect_is_circular (&rect));
gsk_rounded_rect_init (&rect,
&GRAPHENE_RECT_INIT (0, 0, 100, 100),
&GRAPHENE_SIZE_INIT (0, 0),
&GRAPHENE_SIZE_INIT (10, 10),
&GRAPHENE_SIZE_INIT (20, 20),
&GRAPHENE_SIZE_INIT (30, 30));
g_assert_true (gsk_rounded_rect_is_circular (&rect));
}
static void
test_to_float (void)
{
GskRoundedRect rect;
float flt[12];
gsk_rounded_rect_init (&rect,
&GRAPHENE_RECT_INIT (0, 11, 22, 33),
&GRAPHENE_SIZE_INIT (4, 5),
&GRAPHENE_SIZE_INIT (6, 7),
&GRAPHENE_SIZE_INIT (8, 9),
&GRAPHENE_SIZE_INIT (10, 11));
gsk_rounded_rect_to_float (&rect, flt);
g_assert_true (flt[0] == 0. && flt[1] == 11. && flt[2] == 22. && flt[3] == 33.);
g_assert_true (flt[4] == 4. && flt[5] == 6.);
g_assert_true (flt[6] == 8. && flt[7] == 10.);
g_assert_true (flt[8] == 5. && flt[9] == 7.);
g_assert_true (flt[10] == 9. && flt[11] == 11.);
}
int
main (int argc,
char *argv[])
@ -123,6 +169,8 @@ main (int argc,
g_test_add_func ("/rounded-rect/contains-rect", test_contains_rect);
g_test_add_func ("/rounded-rect/intersects-rect", test_intersects_rect);
g_test_add_func ("/rounded-rect/contains-point", test_contains_point);
g_test_add_func ("/rounded-rect/is-circular", test_is_circular);
g_test_add_func ("/rounded-rect/to-float", test_to_float);
return g_test_run ();
}

View File

@ -76,6 +76,7 @@ test_create_simple (void)
{
GBytes *bytes;
GskGLShader *shader;
GBytes *source;
bytes = g_bytes_new_static (shader1, sizeof (shader1));
shader = gsk_gl_shader_new_from_bytes (bytes);
@ -100,19 +101,48 @@ test_create_simple (void)
g_assert_cmpstr (gsk_gl_shader_get_uniform_name (shader, 7), ==, "test5");
g_assert_cmpint (gsk_gl_shader_get_uniform_type (shader, 7), ==, GSK_GL_UNIFORM_TYPE_VEC4);
g_assert_cmpint (gsk_gl_shader_find_uniform_by_name (shader, "progress"), ==, 0);
g_assert_cmpint (gsk_gl_shader_find_uniform_by_name (shader, "dots"), ==, 1);
g_assert_cmpint (gsk_gl_shader_find_uniform_by_name (shader, "center"), ==, 2);
g_assert_cmpint (gsk_gl_shader_find_uniform_by_name (shader, "test1"), ==, 3);
g_assert_cmpint (gsk_gl_shader_find_uniform_by_name (shader, "test2"), ==, 4);
g_assert_cmpint (gsk_gl_shader_find_uniform_by_name (shader, "test3"), ==, 5);
g_assert_cmpint (gsk_gl_shader_find_uniform_by_name (shader, "test4"), ==, 6);
g_assert_cmpint (gsk_gl_shader_find_uniform_by_name (shader, "test5"), ==, 7);
g_assert_cmpint (gsk_gl_shader_find_uniform_by_name (shader, "nosucharg"), ==, -1);
g_assert_cmpint (gsk_gl_shader_get_uniform_offset (shader, 0), ==, 0);
g_assert_cmpint (gsk_gl_shader_get_uniform_offset (shader, 1), >, 0);
g_assert_cmpint (gsk_gl_shader_get_uniform_offset (shader, 2), >, 0);
g_assert_cmpint (gsk_gl_shader_get_uniform_offset (shader, 3), >, 0);
g_assert_cmpint (gsk_gl_shader_get_uniform_offset (shader, 4), >, 0);
g_assert_cmpint (gsk_gl_shader_get_uniform_offset (shader, 5), >, 0);
g_assert_cmpint (gsk_gl_shader_get_uniform_offset (shader, 6), >, 0);
g_assert_cmpint (gsk_gl_shader_get_uniform_offset (shader, 7), >, 0);
g_assert_null (gsk_gl_shader_get_resource (shader));
g_object_get (shader, "source", &source, NULL);
g_assert_true (g_bytes_equal (source, bytes));
g_object_unref (shader);
g_bytes_unref (bytes);
g_bytes_unref (source);
}
static void
test_create_data (void)
{
GBytes *bytes;
GBytes *bytes2;
GskGLShader *shader;
GskShaderArgsBuilder *builder;
GskShaderArgsBuilder *builder2;
graphene_vec2_t v2, vv2;
graphene_vec3_t v3, vv3;
graphene_vec4_t v4, vv4;
GskRenderNode *node;
GskRenderNode *children[2];
bytes = g_bytes_new_static (shader1, sizeof (shader1));
shader = gsk_gl_shader_new_from_bytes (bytes);
@ -150,6 +180,31 @@ test_create_data (void)
gsk_gl_shader_get_arg_vec4 (shader, bytes, 7, &vv4);
g_assert_true (graphene_vec4_equal (&v4, &vv4));
children[0] = gsk_color_node_new (&(GdkRGBA){0,0,0,1}, &GRAPHENE_RECT_INIT (0, 0, 50, 50));
children[1] = gsk_color_node_new (&(GdkRGBA){1,0,0,1}, &GRAPHENE_RECT_INIT (0, 0, 50, 50));
node = gsk_gl_shader_node_new (shader,
&GRAPHENE_RECT_INIT (0, 0, 50, 50),
bytes,
children,
2);
g_assert_true (gsk_gl_shader_node_get_shader (node) == shader);
g_assert_cmpuint (gsk_gl_shader_node_get_n_children (node), ==, 2);
g_assert_true (gsk_gl_shader_node_get_child (node, 0) == children[0]);
g_assert_true (gsk_gl_shader_node_get_child (node, 1) == children[1]);
gsk_render_node_unref (children[0]);
gsk_render_node_unref (children[1]);
gsk_render_node_unref (node);
builder2 = gsk_shader_args_builder_new (shader, bytes);
gsk_shader_args_builder_ref (builder2);
bytes2 = gsk_shader_args_builder_free_to_args (builder2);
gsk_shader_args_builder_unref (builder2);
g_assert_true (g_bytes_equal (bytes, bytes2));
g_bytes_unref (bytes2);
g_bytes_unref (bytes);
gsk_shader_args_builder_unref (builder);

View File

@ -655,6 +655,19 @@ test_to_2d (void)
g_assert_cmpfloat (yy, ==, 1);
g_assert_cmpfloat (dx, ==, 0.0);
g_assert_cmpfloat (dy, ==, 0.0);
transform = gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (10.0, 5.0));
transform = gsk_transform_rotate (transform, 33.0);
gsk_transform_to_2d (transform, &xx, &yx, &xy, &yy, &dx, &dy);
gsk_transform_unref (transform);
g_assert_cmpfloat (xx, ==, 0.838670552f);
g_assert_cmpfloat (yx, ==, 0.544639051f);
g_assert_cmpfloat (xy, ==, -0.544639051f);
g_assert_cmpfloat (yy, ==, 0.838670552f);
g_assert_cmpfloat (dx, ==, 10.f);
g_assert_cmpfloat (dy, ==, 5.f);
}
static void
@ -735,6 +748,101 @@ test_transform_point (void)
gsk_transform_unref (t2);
}
static void
test_skew_transform (void)
{
GskTransform *t1, *t2, *t3;
char *string;
gboolean res;
GskTransform *x;
t1 = gsk_transform_skew (NULL, 30, 60);
t2 = gsk_transform_skew (NULL, 0, 30);
t3 = gsk_transform_skew (NULL, 0, -30);
g_assert_true (gsk_transform_get_category (t1) == GSK_TRANSFORM_CATEGORY_2D);
g_assert_true (gsk_transform_get_category (t2) == GSK_TRANSFORM_CATEGORY_2D);
g_assert_false (gsk_transform_equal (t1, t2));
t2 = gsk_transform_invert (t2);
graphene_assert_fuzzy_transform_equal (t2, t3, EPSILON);
string = gsk_transform_to_string (t1);
res = gsk_transform_parse (string, &x);
g_assert_true (res);
g_assert_true (gsk_transform_equal (t1, x));
gsk_transform_unref (t1);
gsk_transform_unref (t2);
gsk_transform_unref (t3);
g_free (string);
gsk_transform_unref (x);
}
static void
test_perspective_transform (void)
{
GskTransform *t1, *t2;
t1 = gsk_transform_perspective (NULL, 1000);
t2 = gsk_transform_perspective (NULL, 300);
g_assert_true (gsk_transform_get_category (t1) == GSK_TRANSFORM_CATEGORY_ANY);
g_assert_true (gsk_transform_get_category (t2) == GSK_TRANSFORM_CATEGORY_ANY);
g_assert_false (gsk_transform_equal (t1, t2));
t2 = gsk_transform_perspective (t2, 700);
g_assert_true (gsk_transform_equal (t1, t2));
gsk_transform_unref (t1);
gsk_transform_unref (t2);
}
static void
test_rotate_transform (void)
{
GskTransform *t1, *t2, *t3;
t1 = gsk_transform_rotate (NULL, 60);
t2 = gsk_transform_rotate (NULL, 20);
g_assert_true (gsk_transform_get_category (t1) == GSK_TRANSFORM_CATEGORY_2D);
g_assert_true (gsk_transform_get_category (t2) == GSK_TRANSFORM_CATEGORY_2D);
g_assert_false (gsk_transform_equal (t1, t2));
t2 = gsk_transform_rotate (t2, 40);
g_assert_true (gsk_transform_equal (t1, t2));
t1 = gsk_transform_invert (t1);
t3 = gsk_transform_rotate (NULL, -60);
g_assert_true (gsk_transform_equal (t1, t3));
gsk_transform_unref (t1);
gsk_transform_unref (t2);
gsk_transform_unref (t3);
}
static void
test_rotate3d_transform (void)
{
GskTransform *t1, *t2;
graphene_vec3_t vec;
t1 = gsk_transform_rotate_3d (NULL, 60, graphene_vec3_init (&vec, 1, 2, 3));
t2 = gsk_transform_rotate_3d (NULL, -60, graphene_vec3_init (&vec, 1, 2, 3));
g_assert_true (gsk_transform_get_category (t1) == GSK_TRANSFORM_CATEGORY_3D);
g_assert_true (gsk_transform_get_category (t2) == GSK_TRANSFORM_CATEGORY_3D);
g_assert_false (gsk_transform_equal (t1, t2));
t2 = gsk_transform_invert (t2);
g_assert_true (gsk_transform_equal (t1, t2));
gsk_transform_unref (t1);
gsk_transform_unref (t2);
}
int
main (int argc,
char *argv[])
@ -753,6 +861,10 @@ main (int argc,
g_test_add_func ("/transform/point", test_transform_point);
g_test_add_func ("/transform/to-2d", test_to_2d);
g_test_add_func ("/transform/to-2d-components", test_to_2d_components);
g_test_add_func ("/transform/skew", test_skew_transform);
g_test_add_func ("/transform/perspective", test_perspective_transform);
g_test_add_func ("/transform/rotate", test_rotate_transform);
g_test_add_func ("/transform/rotate3d", test_rotate3d_transform);
return g_test_run ();
}

View File

@ -0,0 +1,126 @@
/*
* Copyright (C) 2022, Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <locale.h>
#include <gtk/gtk.h>
static GQuark changes_quark;
static void
items_changed_cb (GListModel *model,
guint position,
guint removed,
guint added)
{
GString *changes;
g_assert_true (removed != 0 || added != 0);
changes = g_object_get_qdata (G_OBJECT (model), changes_quark);
if (changes->len)
g_string_append (changes, ", ");
if (removed == 1 && added == 0)
{
g_string_append_printf (changes, "-%u", position);
}
else if (removed == 0 && added == 1)
{
g_string_append_printf (changes, "+%u", position);
}
else
{
g_string_append_printf (changes, "%u", position);
if (removed > 0)
g_string_append_printf (changes, "-%u", removed);
if (added > 0)
g_string_append_printf (changes, "+%u", added);
}
}
#define assert_changes(model, expected) G_STMT_START{ \
GString *changes = g_object_get_qdata (G_OBJECT (model), changes_quark); \
if (!g_str_equal (changes->str, expected)) \
g_assertion_message_cmpstr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
#model " == " #expected, changes->str, "==", expected); \
g_string_set_size (changes, 0); \
}G_STMT_END
static void
free_changes (gpointer data)
{
GString *s = data;
g_string_free (s, TRUE);
}
static void
test_list_list_model (void)
{
GtkWidget *box;
GListModel *model;
GtkWidget *a, *b;
GObject *item;
guint n_items;
box = g_object_ref_sink (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0));
model = gtk_widget_observe_children (box);
g_assert_true (g_list_model_get_item_type (model) == G_TYPE_OBJECT);
g_assert_true (g_list_model_get_n_items (model) == 0);
g_assert_true (g_list_model_get_item (model, 0) == NULL);
g_object_set_qdata_full (G_OBJECT (model), changes_quark, g_string_new (""), free_changes);
g_signal_connect (model, "items-changed", G_CALLBACK (items_changed_cb), NULL);
a = gtk_label_new ("a");
b = gtk_label_new ("b");
gtk_box_append (GTK_BOX (box), a);
gtk_box_append (GTK_BOX (box), b);
item = g_list_model_get_item (model, 0);
g_assert_true (GTK_WIDGET (item) == a);
g_object_unref (item);
item = g_list_model_get_item (model, 1);
g_assert_true (GTK_WIDGET (item) == b);
g_object_unref (item);
assert_changes (model, "+0, +1");
g_object_get (model, "n-items", &n_items, NULL);
g_assert_true (n_items == 2);
g_object_unref (model);
g_object_unref (box);
}
int
main (int argc, char *argv[])
{
(g_test_init) (&argc, &argv, NULL);
gtk_init ();
setlocale (LC_ALL, "C");
changes_quark = g_quark_from_static_string ("What did I see? Can I believe what I saw?");
g_test_add_func ("/listlistmodel/change", test_list_list_model);
return g_test_run ();
}

View File

@ -54,9 +54,11 @@ tests = [
{ 'name': 'icontheme' },
{ 'name': 'label' },
{ 'name': 'listbox' },
{ 'name': 'listlistmodel' },
{ 'name': 'main' },
{ 'name': 'maplistmodel' },
{ 'name': 'multiselection' },
{ 'name': 'noselection' },
{ 'name': 'notify' },
{ 'name': 'no-gtk-init' },
{ 'name': 'object' },

553
testsuite/gtk/noselection.c Normal file
View File

@ -0,0 +1,553 @@
/*
* Copyright (C) 2022, Red Hat, Inc.
* Authors: Matthias Clasen <mclasen@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <locale.h>
#include <gtk/gtk.h>
static GQuark number_quark;
static GQuark changes_quark;
static GQuark selection_quark;
static guint
get (GListModel *model,
guint position)
{
guint number;
GObject *object = g_list_model_get_item (model, position);
g_assert_nonnull (object);
number = GPOINTER_TO_UINT (g_object_get_qdata (object, number_quark));
g_object_unref (object);
return number;
}
static char *
model_to_string (GListModel *model)
{
GString *string = g_string_new (NULL);
guint i;
for (i = 0; i < g_list_model_get_n_items (model); i++)
{
if (i > 0)
g_string_append (string, " ");
g_string_append_printf (string, "%u", get (model, i));
}
return g_string_free (string, FALSE);
}
static char *
selection_to_string (GListModel *model)
{
GString *string = g_string_new (NULL);
guint i;
for (i = 0; i < g_list_model_get_n_items (model); i++)
{
if (!gtk_selection_model_is_selected (GTK_SELECTION_MODEL (model), i))
continue;
if (string->len > 0)
g_string_append (string, " ");
g_string_append_printf (string, "%u", get (model, i));
}
return g_string_free (string, FALSE);
}
static GListStore *
new_store (guint start,
guint end,
guint step);
static GObject *
make_object (guint number)
{
GObject *object;
/* 0 cannot be differentiated from NULL, so don't use it */
g_assert_cmpint (number, !=, 0);
object = g_object_new (G_TYPE_OBJECT, NULL);
g_object_set_qdata (object, number_quark, GUINT_TO_POINTER (number));
return object;
}
static void
splice (GListStore *store,
guint pos,
guint removed,
guint *numbers,
guint added)
{
GObject **objects = g_newa (GObject *, added);
guint i;
for (i = 0; i < added; i++)
objects[i] = make_object (numbers[i]);
g_list_store_splice (store, pos, removed, (gpointer *) objects, added);
for (i = 0; i < added; i++)
g_object_unref (objects[i]);
}
static void
add (GListStore *store,
guint number)
{
GObject *object = make_object (number);
g_list_store_append (store, object);
g_object_unref (object);
}
static void
insert (GListStore *store,
guint position,
guint number)
{
GObject *object = make_object (number);
g_list_store_insert (store, position, object);
g_object_unref (object);
}
#define assert_model(model, expected) G_STMT_START{ \
char *s = model_to_string (G_LIST_MODEL (model)); \
if (!g_str_equal (s, expected)) \
g_assertion_message_cmpstr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
#model " == " #expected, s, "==", expected); \
g_free (s); \
}G_STMT_END
#define ignore_changes(model) G_STMT_START{ \
GString *changes = g_object_get_qdata (G_OBJECT (model), changes_quark); \
g_string_set_size (changes, 0); \
}G_STMT_END
#define assert_changes(model, expected) G_STMT_START{ \
GString *changes = g_object_get_qdata (G_OBJECT (model), changes_quark); \
if (!g_str_equal (changes->str, expected)) \
g_assertion_message_cmpstr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
#model " == " #expected, changes->str, "==", expected); \
g_string_set_size (changes, 0); \
}G_STMT_END
#define assert_selection(model, expected) G_STMT_START{ \
char *s = selection_to_string (G_LIST_MODEL (model)); \
if (!g_str_equal (s, expected)) \
g_assertion_message_cmpstr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
#model " == " #expected, s, "==", expected); \
g_free (s); \
}G_STMT_END
#define assert_selection_changes(model, expected) G_STMT_START{ \
GString *changes = g_object_get_qdata (G_OBJECT (model), selection_quark); \
if (!g_str_equal (changes->str, expected)) \
g_assertion_message_cmpstr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
#model " == " #expected, changes->str, "==", expected); \
g_string_set_size (changes, 0); \
}G_STMT_END
#define ignore_selection_changes(model) G_STMT_START{ \
GString *changes = g_object_get_qdata (G_OBJECT (model), selection_quark); \
g_string_set_size (changes, 0); \
}G_STMT_END
static GListStore *
new_empty_store (void)
{
return g_list_store_new (G_TYPE_OBJECT);
}
static GListStore *
new_store (guint start,
guint end,
guint step)
{
GListStore *store = new_empty_store ();
guint i;
for (i = start; i <= end; i += step)
add (store, i);
return store;
}
static void
items_changed (GListModel *model,
guint position,
guint removed,
guint added,
GString *changes)
{
g_assert_true (removed != 0 || added != 0);
if (changes->len)
g_string_append (changes, ", ");
if (removed == 1 && added == 0)
{
g_string_append_printf (changes, "-%u", position);
}
else if (removed == 0 && added == 1)
{
g_string_append_printf (changes, "+%u", position);
}
else
{
g_string_append_printf (changes, "%u", position);
if (removed > 0)
g_string_append_printf (changes, "-%u", removed);
if (added > 0)
g_string_append_printf (changes, "+%u", added);
}
}
static void
notify_n_items (GObject *object,
GParamSpec *pspec,
GString *changes)
{
g_string_append_c (changes, '*');
}
static void
selection_changed (GListModel *model,
guint position,
guint n_items,
GString *changes)
{
if (changes->len)
g_string_append (changes, ", ");
g_string_append_printf (changes, "%u:%u", position, n_items);
}
static void
free_changes (gpointer data)
{
GString *changes = data;
/* all changes must have been checked via assert_changes() before */
g_assert_cmpstr (changes->str, ==, "");
g_string_free (changes, TRUE);
}
static GtkSelectionModel *
new_model (GListStore *store, gboolean autoselect, gboolean can_unselect)
{
GtkSelectionModel *result;
GString *changes;
result = GTK_SELECTION_MODEL (gtk_no_selection_new (g_object_ref (G_LIST_MODEL (store))));
changes = g_string_new ("");
g_object_set_qdata_full (G_OBJECT(result), changes_quark, changes, free_changes);
g_signal_connect (result, "items-changed", G_CALLBACK (items_changed), changes);
g_signal_connect (result, "notify::n-items", G_CALLBACK (notify_n_items), changes);
changes = g_string_new ("");
g_object_set_qdata_full (G_OBJECT(result), selection_quark, changes, free_changes);
g_signal_connect (result, "selection-changed", G_CALLBACK (selection_changed), changes);
return result;
}
static void
test_create (void)
{
GtkSelectionModel *selection;
GListStore *store;
if (glib_check_version (2, 59, 0) != NULL)
{
g_test_skip ("g_list_store_get_item() has overflow issues before GLIB 2.59.0");
return;
}
store = new_store (1, 5, 2);
selection = new_model (store, FALSE, FALSE);
assert_model (selection, "1 3 5");
assert_changes (selection, "");
assert_selection (selection, "");
assert_selection_changes (selection, "");
g_object_unref (store);
assert_model (selection, "1 3 5");
assert_changes (selection, "");
assert_selection (selection, "");
assert_selection_changes (selection, "");
g_object_unref (selection);
}
static void
test_create_empty (void)
{
GtkSingleSelection *selection;
selection = gtk_single_selection_new (NULL);
g_assert_cmpint (g_list_model_get_n_items (G_LIST_MODEL (selection)), ==, 0);
g_object_unref (selection);
}
static void
test_changes (void)
{
GtkSelectionModel *selection;
GListStore *store;
if (glib_check_version (2, 58, 0) != NULL)
{
g_test_skip ("g_list_store_splice() is broken before GLIB 2.58.0");
return;
}
store = new_store (1, 5, 1);
selection = new_model (store, FALSE, FALSE);
assert_model (selection, "1 2 3 4 5");
assert_changes (selection, "");
assert_selection (selection, "");
assert_selection_changes (selection, "");
g_list_store_remove (store, 3);
assert_model (selection, "1 2 3 5");
assert_changes (selection, "-3*");
assert_selection (selection, "");
assert_selection_changes (selection, "");
insert (store, 3, 99);
assert_model (selection, "1 2 3 99 5");
assert_changes (selection, "+3*");
assert_selection (selection, "");
assert_selection_changes (selection, "");
splice (store, 3, 2, (guint[]) { 97 }, 1);
assert_model (selection, "1 2 3 97");
assert_changes (selection, "3-2+1*");
assert_selection (selection, "");
assert_selection_changes (selection, "");
g_object_unref (selection);
g_object_unref (store);
}
static void
test_selection (void)
{
GtkSelectionModel *selection;
GListStore *store;
gboolean ret;
if (glib_check_version (2, 59, 0) != NULL)
{
g_test_skip ("g_list_store_get_item() has overflow issues before GLIB 2.59.0");
return;
}
store = new_store (1, 5, 1);
selection = new_model (store, TRUE, FALSE);
assert_selection (selection, "");
assert_selection_changes (selection, "");
ret = gtk_selection_model_select_item (selection, 3, FALSE);
g_assert_false (ret);
assert_selection (selection, "");
assert_selection_changes (selection, "");
ret = gtk_selection_model_unselect_item (selection, 3);
g_assert_false (ret);
assert_selection (selection, "");
assert_selection_changes (selection, "");
ret = gtk_selection_model_select_item (selection, 1, FALSE);
g_assert_false (ret);
assert_selection (selection, "");
assert_selection_changes (selection, "");
ret = gtk_selection_model_select_range (selection, 3, 2, FALSE);
g_assert_false (ret);
assert_selection (selection, "");
assert_selection_changes (selection, "");
ret = gtk_selection_model_unselect_range (selection, 4, 2);
g_assert_false (ret);
assert_selection (selection, "");
assert_selection_changes (selection, "");
ret = gtk_selection_model_select_all (selection);
g_assert_false (ret);
assert_selection (selection, "");
assert_selection_changes (selection, "");
ret = gtk_selection_model_unselect_all (selection);
g_assert_false (ret);
assert_selection (selection, "");
assert_selection_changes (selection, "");
g_object_unref (store);
g_object_unref (selection);
}
static void
check_get_selection (GtkSelectionModel *selection)
{
GtkBitset *set;
guint i, n_items;
set = gtk_selection_model_get_selection (selection);
n_items = g_list_model_get_n_items (G_LIST_MODEL (selection));
if (n_items == 0)
{
g_assert_true (gtk_bitset_is_empty (set));
}
else
{
for (i = 0; i < n_items; i++)
{
g_assert_cmpint (gtk_bitset_contains (set, i), ==, gtk_selection_model_is_selected (selection, i));
}
/* check that out-of-range has no bits set */
g_assert_cmpint (gtk_bitset_get_maximum (set), <, g_list_model_get_n_items (G_LIST_MODEL (selection)));
}
gtk_bitset_unref (set);
}
static void
test_query_range (void)
{
GtkSelectionModel *selection;
GListStore *store;
store = new_store (1, 5, 1);
selection = new_model (store, TRUE, TRUE);
check_get_selection (selection);
gtk_selection_model_unselect_item (selection, 0);
check_get_selection (selection);
gtk_selection_model_select_item (selection, 2, TRUE);
check_get_selection (selection);
gtk_selection_model_select_item (selection, 4, TRUE);
check_get_selection (selection);
ignore_selection_changes (selection);
g_object_unref (store);
g_object_unref (selection);
}
static void
test_set_model (void)
{
GtkSelectionModel *selection;
GListStore *store;
GListModel *m1, *m2;
store = new_store (1, 5, 1);
m1 = G_LIST_MODEL (store);
m2 = G_LIST_MODEL (gtk_slice_list_model_new (g_object_ref (m1), 0, 3));
selection = new_model (store, TRUE, TRUE);
assert_selection (selection, "");
assert_selection_changes (selection, "");
/* we retain the selected item across model changes */
gtk_no_selection_set_model (GTK_NO_SELECTION (selection), m2);
assert_changes (selection, "0-5+3*");
assert_selection (selection, "");
assert_selection_changes (selection, "");
gtk_no_selection_set_model (GTK_NO_SELECTION (selection), m1);
assert_changes (selection, "0-3+5*");
assert_selection (selection, "");
assert_selection_changes (selection, "");
gtk_no_selection_set_model (GTK_NO_SELECTION (selection), m2);
assert_changes (selection, "0-5+3*");
assert_selection (selection, "");
assert_selection_changes (selection, "");
/* we retain no selected item across model changes */
gtk_no_selection_set_model (GTK_NO_SELECTION (selection), m1);
assert_changes (selection, "0-3+5*");
assert_selection (selection, "");
assert_selection_changes (selection, "");
gtk_no_selection_set_model (GTK_NO_SELECTION (selection), m1);
assert_changes (selection, "");
assert_selection (selection, "");
assert_selection_changes (selection, "");
g_object_unref (m2);
g_object_unref (m1);
g_object_unref (selection);
}
static void
test_empty (void)
{
GtkNoSelection *selection;
GListStore *store;
selection = gtk_no_selection_new (NULL);
g_assert_cmpuint (g_list_model_get_n_items (G_LIST_MODEL (selection)), ==, 0);
g_assert_null (g_list_model_get_item (G_LIST_MODEL (selection), 11));
g_assert_true (g_list_model_get_item_type (G_LIST_MODEL (selection)) == G_TYPE_OBJECT);
g_assert_null (gtk_no_selection_get_model (GTK_NO_SELECTION (selection)));
store = g_list_store_new (G_TYPE_OBJECT);
gtk_no_selection_set_model (selection, G_LIST_MODEL (store));
g_object_unref (store);
g_assert_cmpuint (g_list_model_get_n_items (G_LIST_MODEL (selection)), ==, 0);
g_assert_null (g_list_model_get_item (G_LIST_MODEL (selection), 11));
g_object_unref (selection);
}
int
main (int argc, char *argv[])
{
(g_test_init) (&argc, &argv, NULL);
setlocale (LC_ALL, "C");
number_quark = g_quark_from_static_string ("Hell and fire was spawned to be released.");
changes_quark = g_quark_from_static_string ("What did I see? Can I believe what I saw?");
selection_quark = g_quark_from_static_string ("Mana mana, badibidibi");
g_test_add_func ("/noselection/create", test_create);
g_test_add_func ("/noselection/create-empty", test_create_empty);
g_test_add_func ("/noselection/selection", test_selection);
g_test_add_func ("/noselection/query-range", test_query_range);
g_test_add_func ("/noselection/changes", test_changes);
g_test_add_func ("/noselection/set-model", test_set_model);
g_test_add_func ("/noselection/empty", test_empty);
return g_test_run ();
}