Compare commits

..

20 Commits

Author SHA1 Message Date
Matthias Clasen 16c3d4b236 Add gsk vulkan tests
Add a testsuite called gsk-compare-vulkan to run
the gsk renderer tests with the Vulkan renderer.

The current stats:

Ok:                 184
Expected Fail:      0
Fail:               204
Unexpected Pass:    0
Skipped:            2
Timeout:            0

For now, we mark all the tests as failing to
avoid ci breakage. To run the tests locally,
you can do:

meson test -C_build --suite gsk-compare-vulkan
2023-05-07 07:42:20 -04:00
Matthias Clasen df93875c0c Merge branch 'matthiasc/for-main' into 'main'
rendernodeparser: Handle shader nodes better

See merge request GNOME/gtk!5930
2023-05-07 00:58:05 +00:00
Matthias Clasen 5a156e6b5f rendernodeparser: Handle shader nodes better
Avoid criticals when editing shader nodes in
the node editor.
2023-05-06 14:33:45 -04:00
Matthias Clasen 0e488b3dfe Merge branch 'headless-test-logging' into 'main'
ci: Improve headless test logging

See merge request GNOME/gtk!5929
2023-05-06 13:28:06 +00:00
Matthias Clasen 8495e0e412 Add a test for quick key events 2023-05-06 09:09:13 -04:00
Matthias Clasen c9b0ca0de7 ci: Improve headless test logging 2023-05-06 09:02:25 -04:00
Benjamin Otte 2a950dec71 Merge branch 'wip/otte/update-texture' into 'main'
Add texture update regions

See merge request GNOME/gtk!5880
2023-05-06 00:59:25 +00:00
Matthias Clasen d6c80d4f35 Merge branch 'tiled-states' into 'main'
Fix a corner-case in window states

Closes #5809

See merge request GNOME/gtk!5926
2023-05-05 23:58:08 +00:00
Matthias Clasen e41cc99474 Merge branch 'wip/kabus/column-id-leak' into 'main'
gtk/columnviewcolumn: Fix id leak

See merge request GNOME/gtk!5927
2023-05-05 23:55:34 +00:00
Matthias Clasen 61fe5ac684 Handle the opposite case too
Just in case.
2023-05-05 19:40:42 -04:00
Khalid Abu Shawarib 1cf3f492b8 gtk/columnviewcolumn: Fix id leak
Add a free that was missing in commit 3e2b962a
2023-05-05 22:18:16 +00:00
Matthias Clasen 54fed96f8c Fix a corner-case in window states
Remove detailed tiled states when not tiled.

Fixes: #5809
2023-05-05 16:47:43 -04:00
Matthias Clasen e2d659d5c2 Merge branch 'matthiasc/for-main' into 'main'
ci: Bump timeouts for headless tests

See merge request GNOME/gtk!5925
2023-05-05 20:34:39 +00:00
Matthias Clasen 8ad1189b0b ci: Bump timeouts for headless tests 2023-05-05 16:21:54 -04:00
Matthias Clasen b5b7e1f2b4 Merge branch 'matthiasc/for-main' into 'main'
Add a masked variation to gsk tests

See merge request GNOME/gtk!5924
2023-05-05 20:12:12 +00:00
Matthias Clasen e56a539363 Add a masked variation to gsk tests
This improves test coverage for mask nodes.
2023-05-05 15:05:08 -04:00
Benjamin Otte 97aff588d5 TEST TEST TEST
Add some random updates to the GL Area, so that funky testing can be
done with the GLArea and Gears gtk-demo.
2023-05-02 00:30:58 +02:00
Benjamin Otte e4040adbe7 rendernode: Implement texture diffing for scale nodes 2023-05-02 00:30:58 +02:00
Benjamin Otte 6506a3bc9c texturebuilder: Add ::udpate-region and ::update-texture 2023-05-02 00:30:58 +02:00
Benjamin Otte 1883035d34 texture: Add gdk_texture_diff()
... and use it in rendernodes.

Setting up textures for diffing is done via gdk_texture_set_diff() which
should only be used during texture construction.

Note that the pointers to next/previous are allowed to dangle if one of
the textures is finalized, but that's fine because we always check both
textures' links to each other before we consider the pointer valid.
2023-05-01 22:24:14 +02:00
18 changed files with 578 additions and 122 deletions
+1
View File
@@ -70,6 +70,7 @@ style-check-diff:
- "${CI_PROJECT_DIR}/_build/testsuite/tools/output/*/*"
- "${CI_PROJECT_DIR}/_build/testsuite/gsk/compare/*/*/*.png"
- "${CI_PROJECT_DIR}/_build/testsuite/css/output/*/*.syscap"
- "${CI_PROJECT_DIR}/_build/testsuite/headless/*/*.log"
- "${CI_PROJECT_DIR}/_build_hello/meson-logs"
cache:
key: "$CI_JOB_NAME"
+17
View File
@@ -338,6 +338,7 @@ gdk_gl_texture_new_from_builder (GdkGLTextureBuilder *builder,
gpointer data)
{
GdkGLTexture *self;
GdkTexture *update_texture;
self = g_object_new (GDK_TYPE_GL_TEXTURE,
"width", gdk_gl_texture_builder_get_width (builder),
@@ -353,6 +354,22 @@ gdk_gl_texture_new_from_builder (GdkGLTextureBuilder *builder,
self->destroy = destroy;
self->data = data;
update_texture = gdk_gl_texture_builder_get_update_texture (builder);
if (update_texture)
{
cairo_region_t *update_region = gdk_gl_texture_builder_get_update_region (builder);
if (update_region)
{
update_region = cairo_region_copy (update_region);
cairo_region_intersect_rectangle (update_region,
&(cairo_rectangle_int_t) {
0, 0,
update_texture->width, update_texture->height
});
gdk_texture_set_diff (GDK_TEXTURE (self), update_texture, update_region);
}
}
return GDK_TEXTURE (self);
}
+147
View File
@@ -25,6 +25,8 @@
#include "gdkglcontext.h"
#include "gdkgltextureprivate.h"
#include <cairo-gobject.h>
struct _GdkGLTextureBuilder
{
GObject parent_instance;
@@ -36,6 +38,9 @@ struct _GdkGLTextureBuilder
GdkMemoryFormat format;
gboolean has_mipmap;
gpointer sync;
GdkTexture *update_texture;
cairo_region_t *update_region;
};
struct _GdkGLTextureBuilderClass
@@ -70,6 +75,8 @@ enum
PROP_HEIGHT,
PROP_ID,
PROP_SYNC,
PROP_UPDATE_REGION,
PROP_UPDATE_TEXTURE,
PROP_WIDTH,
N_PROPS
@@ -86,6 +93,9 @@ gdk_gl_texture_builder_dispose (GObject *object)
g_clear_object (&self->context);
g_clear_object (&self->update_texture);
g_clear_pointer (&self->update_region, cairo_region_destroy);
G_OBJECT_CLASS (gdk_gl_texture_builder_parent_class)->dispose (object);
}
@@ -123,6 +133,14 @@ gdk_gl_texture_builder_get_property (GObject *object,
g_value_set_pointer (value, self->sync);
break;
case PROP_UPDATE_REGION:
g_value_set_boxed (value, self->update_region);
break;
case PROP_UPDATE_TEXTURE:
g_value_set_object (value, self->update_texture);
break;
case PROP_WIDTH:
g_value_set_int (value, self->width);
break;
@@ -167,6 +185,14 @@ gdk_gl_texture_builder_set_property (GObject *object,
gdk_gl_texture_builder_set_sync (self, g_value_get_pointer (value));
break;
case PROP_UPDATE_REGION:
gdk_gl_texture_builder_set_update_region (self, g_value_get_boxed (value));
break;
case PROP_UPDATE_TEXTURE:
gdk_gl_texture_builder_set_update_texture (self, g_value_get_object (value));
break;
case PROP_WIDTH:
gdk_gl_texture_builder_set_width (self, g_value_get_int (value));
break;
@@ -260,6 +286,30 @@ gdk_gl_texture_builder_class_init (GdkGLTextureBuilderClass *klass)
g_param_spec_pointer ("sync", NULL, NULL,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* GdkGLTextureBuilder:update-region: (attributes org.gdk.Property.get=gdk_gl_texture_builder_get_update_region org.gdk.Property.set=gdk_gl_texture_builder_set_update_region)
*
* The update region for [property@Gdk.GLTextureBuilder:update-texture].
*
* Since: 4.12
*/
properties[PROP_UPDATE_REGION] =
g_param_spec_boxed ("update-region", NULL, NULL,
CAIRO_GOBJECT_TYPE_REGION,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* GdkGLTextureBuilder:update-texture: (attributes org.gdk.Property.get=gdk_gl_texture_builder_get_update_texture org.gdk.Property.set=gdk_gl_texture_builder_set_update_texture)
*
* The texture [property@Gdk.GLTextureBuilder:update-region] is an update for.
*
* Since: 4.12
*/
properties[PROP_UPDATE_TEXTURE] =
g_param_spec_object ("update-texture", NULL, NULL,
GDK_TYPE_TEXTURE,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* GdkGLTextureBuilder:width: (attributes org.gdk.Property.get=gdk_gl_texture_builder_get_width org.gdk.Property.set=gdk_gl_texture_builder_set_width)
*
@@ -271,6 +321,7 @@ gdk_gl_texture_builder_class_init (GdkGLTextureBuilderClass *klass)
g_param_spec_int ("width", NULL, NULL,
G_MININT, G_MAXINT, 0,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class, N_PROPS, properties);
}
@@ -613,6 +664,102 @@ gdk_gl_texture_builder_set_format (GdkGLTextureBuilder *self,
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FORMAT]);
}
/**
* gdk_gl_texture_builder_get_update_texture: (attributes org.gdk.Method.get_property=update_texture)
* @self: a `GdkGLTextureBuilder`
*
* Gets the texture previously set via gdk_gl_texture_builder_set_update_texture() or
* %NULL if none was set.
*
* Returns: (transfer none) (nullable): The texture
*
* Since: 4.12
*/
GdkTexture *
gdk_gl_texture_builder_get_update_texture (GdkGLTextureBuilder *self)
{
g_return_val_if_fail (GDK_IS_GL_TEXTURE_BUILDER (self), NULL);
return self->update_texture;
}
/**
* gdk_gl_texture_builder_set_update_texture: (attributes org.gdk.Method.set_property=update_texture)
* @self: a `GdkGLTextureBuilder`
* @texture: (nullable): the texture to update
*
* Sets the texture to be updated by this texture. See
* [method@Gdk.GLTextureBuilder.set_update_region] for an explanation.
*
* Since: 4.12
*/
void
gdk_gl_texture_builder_set_update_texture (GdkGLTextureBuilder *self,
GdkTexture *texture)
{
g_return_if_fail (GDK_IS_GL_TEXTURE_BUILDER (self));
g_return_if_fail (texture == NULL || GDK_IS_TEXTURE (texture));
if (!g_set_object (&self->update_texture, texture))
return;
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_UPDATE_TEXTURE]);
}
/**
* gdk_gl_texture_builder_get_update_region: (attributes org.gdk.Method.get_property=update_region)
* @self: a `GdkGLTextureBuilder`
*
* Gets the region previously set via gdk_gl_texture_builder_set_update_region() or
* %NULL if none was set.
*
* Returns: (transfer none) (nullable): The region
*
* Since: 4.12
*/
cairo_region_t *
gdk_gl_texture_builder_get_update_region (GdkGLTextureBuilder *self)
{
g_return_val_if_fail (GDK_IS_GL_TEXTURE_BUILDER (self), NULL);
return self->update_region;
}
/**
* gdk_gl_texture_builder_set_update_region: (attributes org.gdk.Method.set_property=update_region)
* @self: a `GdkGLTextureBuilder`
* @region: (nullable): the region to update
*
* Sets the region to be updated by this texture. Together with
* [property@Gdk.GLTextureBuilder:update-texture] this describes an
* update of a previous texture.
*
* When rendering animations of large textures, it is possible that
* consecutive textures are only updating contents in parts of the texture.
* It is then possible to describe this update via these two properties,
* so that GTK can avoid rerendering parts that did not change.
*
* An example would be a screen recording where only the mouse pointer moves.
*
* Since: 4.12
*/
void
gdk_gl_texture_builder_set_update_region (GdkGLTextureBuilder *self,
cairo_region_t *region)
{
g_return_if_fail (GDK_IS_GL_TEXTURE_BUILDER (self));
if (self->update_region == region)
return;
g_clear_pointer (&self->update_region, cairo_region_destroy);
if (region)
self->update_region = cairo_region_reference (region);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_UPDATE_REGION]);
}
/**
* gdk_gl_texture_builder_build:
* @self: a `GdkGLTextureBuilder`
+12
View File
@@ -78,6 +78,18 @@ GDK_AVAILABLE_IN_4_12
void gdk_gl_texture_builder_set_sync (GdkGLTextureBuilder *self,
gpointer sync);
GDK_AVAILABLE_IN_4_12
GdkTexture * gdk_gl_texture_builder_get_update_texture (GdkGLTextureBuilder *self) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_12
void gdk_gl_texture_builder_set_update_texture (GdkGLTextureBuilder *self,
GdkTexture *texture);
GDK_AVAILABLE_IN_4_12
cairo_region_t * gdk_gl_texture_builder_get_update_region (GdkGLTextureBuilder *self) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_12
void gdk_gl_texture_builder_set_update_region (GdkGLTextureBuilder *self,
cairo_region_t *region);
GDK_AVAILABLE_IN_4_12
GdkTexture * gdk_gl_texture_builder_build (GdkGLTextureBuilder *self,
GDestroyNotify destroy,
+43 -1
View File
@@ -282,6 +282,8 @@ gdk_texture_dispose (GObject *object)
{
GdkTexture *self = GDK_TEXTURE (object);
g_clear_pointer (&self->diff_to_previous, cairo_region_destroy);
gdk_texture_clear_render_data (self);
G_OBJECT_CLASS (gdk_texture_parent_class)->dispose (object);
@@ -671,7 +673,47 @@ gdk_texture_do_download (GdkTexture *texture,
guchar *data,
gsize stride)
{
GDK_TEXTURE_GET_CLASS (texture)->download (texture, format, data,stride);
GDK_TEXTURE_GET_CLASS (texture)->download (texture, format, data, stride);
}
void
gdk_texture_diff (GdkTexture *self,
GdkTexture *other,
cairo_region_t *region)
{
if (self == other)
return;
if (self->previous_texture == other &&
g_atomic_pointer_get (&other->next_texture) == self)
{
cairo_region_union (region, self->diff_to_previous);
}
else if (other->previous_texture == self &&
g_atomic_pointer_get (&self->next_texture) == other)
{
cairo_region_union (region, other->diff_to_previous);
}
else
{
cairo_region_union_rectangle (region,
&(cairo_rectangle_int_t) {
0,
0,
MAX (self->width, other->width),
MAX (self->height, other->height)
});
}
}
void
gdk_texture_set_diff (GdkTexture *self,
GdkTexture *previous,
cairo_region_t *diff)
{
self->previous_texture = previous;
self->diff_to_previous = diff;
g_atomic_pointer_set (&previous->next_texture, self);
}
cairo_surface_t *
+14
View File
@@ -21,6 +21,12 @@ struct _GdkTexture
gpointer render_key;
gpointer render_data;
GDestroyNotify render_notify;
/* for diffing swapchain-like textures.
* Links are only valid if both textures agree on them */
gpointer next_texture; /* atomic, no reference, may be invalid pointer */
gpointer previous_texture; /* no reference, may be invalid pointer */
cairo_region_t *diff_to_previous;
};
struct _GdkTextureClass {
@@ -42,6 +48,14 @@ void gdk_texture_do_download (GdkTexture
GdkMemoryFormat format,
guchar *data,
gsize stride);
void gdk_texture_diff (GdkTexture *self,
GdkTexture *other,
cairo_region_t *region);
void gdk_texture_set_diff (GdkTexture *self,
GdkTexture *previous,
cairo_region_t *diff);
gboolean gdk_texture_set_render_data (GdkTexture *self,
gpointer key,
gpointer data,
+39 -7
View File
@@ -1650,12 +1650,28 @@ gsk_texture_node_diff (GskRenderNode *node1,
{
GskTextureNode *self1 = (GskTextureNode *) node1;
GskTextureNode *self2 = (GskTextureNode *) node2;
cairo_region_t *sub;
if (graphene_rect_equal (&node1->bounds, &node2->bounds) &&
self1->texture == self2->texture)
if (!graphene_rect_equal (&node1->bounds, &node2->bounds) ||
gdk_texture_get_width (self1->texture) != gdk_texture_get_width (self2->texture) ||
gdk_texture_get_height (self1->texture) != gdk_texture_get_height (self2->texture))
{
gsk_render_node_diff_impossible (node1, node2, region);
return;
}
if (self1->texture == self2->texture)
return;
gsk_render_node_diff_impossible (node1, node2, region);
sub = cairo_region_create ();
gdk_texture_diff (self1->texture, self2->texture, sub);
region_union_region_affine (region,
sub,
node1->bounds.size.width / gdk_texture_get_width (self1->texture),
node1->bounds.size.height / gdk_texture_get_height (self1->texture),
node1->bounds.origin.x,
node1->bounds.origin.y);
cairo_region_destroy (sub);
}
static void
@@ -1828,13 +1844,29 @@ gsk_texture_scale_node_diff (GskRenderNode *node1,
{
GskTextureScaleNode *self1 = (GskTextureScaleNode *) node1;
GskTextureScaleNode *self2 = (GskTextureScaleNode *) node2;
cairo_region_t *sub;
if (graphene_rect_equal (&node1->bounds, &node2->bounds) &&
self1->texture == self2->texture &&
self1->filter == self2->filter)
if (!graphene_rect_equal (&node1->bounds, &node2->bounds) ||
self1->filter != self2->filter ||
gdk_texture_get_width (self1->texture) != gdk_texture_get_width (self2->texture) ||
gdk_texture_get_height (self1->texture) != gdk_texture_get_height (self2->texture))
{
gsk_render_node_diff_impossible (node1, node2, region);
return;
}
if (self1->texture == self2->texture)
return;
gsk_render_node_diff_impossible (node1, node2, region);
sub = cairo_region_create ();
gdk_texture_diff (self1->texture, self2->texture, sub);
region_union_region_affine (region,
sub,
node1->bounds.size.width / gdk_texture_get_width (self1->texture),
node1->bounds.size.height / gdk_texture_get_height (self1->texture),
node1->bounds.origin.x,
node1->bounds.origin.y);
cairo_region_destroy (sub);
}
static void
+39 -3
View File
@@ -1371,7 +1371,10 @@ parse_shader (GtkCssParser *parser,
GskGLShader *shader;
if (!parse_string (parser, context, &sourcecode))
return FALSE;
{
gtk_css_parser_error_value (parser, "Not a string");
return FALSE;
}
bytes = g_bytes_new_take (sourcecode, strlen (sourcecode));
shader = gsk_gl_shader_new_from_bytes (bytes);
@@ -1500,6 +1503,29 @@ parse_shader_args (GtkCssParser *parser,
return TRUE;
}
static const char default_glsl[] =
"void\n"
"mainImage(out vec4 fragColor,\n"
" in vec2 fragCoord,\n"
" in vec2 resolution,\n"
" in vec2 uv)\n"
"{\n"
" fragColor = vec4(1.0, 105.0/255.0, 180.0/255.0, 1.0);\n"
"}";
static GskGLShader *
get_default_glshader (void)
{
GBytes *bytes;
GskGLShader *shader;
bytes = g_bytes_new (default_glsl, strlen (default_glsl) + 1);
shader = gsk_gl_shader_new_from_bytes (bytes);
g_bytes_unref (bytes);
return shader;
}
static GskRenderNode *
parse_glshader_node (GtkCssParser *parser,
Context *context)
@@ -1520,6 +1546,7 @@ parse_glshader_node (GtkCssParser *parser,
{ "child4", parse_node, clear_node, &child[3] },
};
GskGLShader *shader;
GskShaderArgsBuilder *builder;
GskRenderNode *node;
GBytes *args = NULL;
int len, i;
@@ -1532,8 +1559,17 @@ parse_glshader_node (GtkCssParser *parser,
break;
}
shader = shader_info.shader;
args = gsk_shader_args_builder_free_to_args (shader_info.args);
if (shader_info.shader)
shader = shader_info.shader;
else
shader = get_default_glshader ();
if (shader_info.args)
builder = shader_info.args;
else
builder = gsk_shader_args_builder_new (shader, NULL);
args = gsk_shader_args_builder_free_to_args (builder);
node = gsk_gl_shader_node_new (shader, &bounds, args, child, len);
+1
View File
@@ -119,6 +119,7 @@ gtk_column_view_column_dispose (GObject *object)
g_clear_object (&self->sorter);
g_clear_pointer (&self->title, g_free);
g_clear_object (&self->menu);
g_clear_pointer (&self->id, g_free);
G_OBJECT_CLASS (gtk_column_view_column_parent_class)->dispose (object);
}
+15
View File
@@ -770,6 +770,20 @@ gtk_gl_area_snapshot (GtkWidget *widget,
texture = priv->texture;
priv->texture = NULL;
if (priv->textures)
gdk_gl_texture_builder_set_update_texture (texture->builder, ((Texture *) priv->textures->data)->holder);
{
cairo_region_t *region = cairo_region_create ();
cairo_region_union_rectangle (region, &(cairo_rectangle_int_t) { 0, 0, 300, 300 });
cairo_region_union_rectangle (region, &(cairo_rectangle_int_t) { 0, 600, 300, 300 });
cairo_region_union_rectangle (region, &(cairo_rectangle_int_t) { 300, 300, 300, 300 });
cairo_region_union_rectangle (region, &(cairo_rectangle_int_t) { 600, 0, 300, 300 });
cairo_region_union_rectangle (region, &(cairo_rectangle_int_t) { 600, 600, 300, 300 });
gdk_gl_texture_builder_set_update_region (texture->builder, region);
cairo_region_destroy (region);
}
priv->textures = g_list_prepend (priv->textures, texture);
if (gdk_gl_context_has_sync (priv->context))
@@ -781,6 +795,7 @@ gtk_gl_area_snapshot (GtkWidget *widget,
release_texture,
texture);
gdk_gl_texture_builder_set_update_texture (texture->builder, NULL);
/* Our texture is rendered by OpenGL, so it is upside down,
* compared to what GSK expects, so flip it back.
*/
+7
View File
@@ -4466,6 +4466,11 @@ update_window_style_classes (GtkWindow *window)
if (!priv->edge_constraints)
{
gtk_widget_remove_css_class (widget, "tiled-top");
gtk_widget_remove_css_class (widget, "tiled-right");
gtk_widget_remove_css_class (widget, "tiled-bottom");
gtk_widget_remove_css_class (widget, "tiled-left");
if (priv->tiled)
gtk_widget_add_css_class (widget, "tiled");
else
@@ -4473,6 +4478,8 @@ update_window_style_classes (GtkWindow *window)
}
else
{
gtk_widget_remove_css_class (widget, "tiled");
if (edge_constraints & GDK_TOPLEVEL_STATE_TOP_TILED)
gtk_widget_add_css_class (widget, "tiled-top");
else
+71 -1
View File
@@ -8,6 +8,7 @@ static char *arg_output_dir = NULL;
static gboolean flip = FALSE;
static gboolean rotate = FALSE;
static gboolean repeat = FALSE;
static gboolean mask = FALSE;
static const char *
get_output_dir (void)
@@ -156,7 +157,8 @@ static const GOptionEntry options[] = {
{ "output", 0, 0, G_OPTION_ARG_FILENAME, &arg_output_dir, "Directory to save image files to", "DIR" },
{ "flip", 0, 0, G_OPTION_ARG_NONE, &flip, "Do flipped test", NULL },
{ "rotate", 0, 0, G_OPTION_ARG_NONE, &rotate, "Do rotated test", NULL },
{ "repeat", 0, 0, G_OPTION_ARG_NONE, &repeat, "Do repeat test", NULL },
{ "repeat", 0, 0, G_OPTION_ARG_NONE, &repeat, "Do repeated test", NULL },
{ "mask", 0, 0, G_OPTION_ARG_NONE, &mask, "Do masked test", NULL },
{ NULL }
};
@@ -186,6 +188,28 @@ load_node_file (const char *node_file)
return node;
}
static GdkPixbuf *
apply_mask_to_pixbuf (GdkPixbuf *pixbuf)
{
GdkPixbuf *copy;
copy = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0);
for (unsigned int j = 0; j < gdk_pixbuf_get_height (copy); j++)
{
guint8 *row = gdk_pixbuf_get_pixels (copy) + j * gdk_pixbuf_get_rowstride (copy);
for (unsigned int i = 0; i < gdk_pixbuf_get_width (copy); i++)
{
guint8 *p = row + i * 4;
if ((i < 25 && j >= 25) || (i >= 25 && j < 25))
{
p[0] = p[1] = p[2] = p[3] = 0;
}
}
}
return copy;
}
/*
* Non-option arguments:
* 1) .node file to compare
@@ -408,6 +432,52 @@ main (int argc, char **argv)
gsk_render_node_unref (node2);
}
if (mask)
{
GskRenderNode *node2;
GdkPixbuf *pixbuf, *pixbuf2;
graphene_rect_t bounds;
GskRenderNode *mask_node;
GskRenderNode *nodes[2];
gsk_render_node_get_bounds (node, &bounds);
nodes[0] = gsk_color_node_new (&(GdkRGBA){ 0, 0, 0, 1},
&GRAPHENE_RECT_INIT (bounds.origin.x, bounds.origin.y, 25, 25));
nodes[1] = gsk_color_node_new (&(GdkRGBA){ 0, 0, 0, 1},
&GRAPHENE_RECT_INIT (bounds.origin.x + 25, bounds.origin.y + 25, bounds.size.width - 25, bounds.size.height - 25));
mask_node = gsk_container_node_new (nodes, G_N_ELEMENTS (nodes));
node2 = gsk_mask_node_new (node, mask_node, GSK_MASK_MODE_ALPHA);
gsk_render_node_unref (mask_node);
gsk_render_node_unref (nodes[0]);
gsk_render_node_unref (nodes[1]);
rendered_texture = gsk_renderer_render_texture (renderer, node2, NULL);
save_image (rendered_texture, node_file, "-masked.out.png");
pixbuf = gdk_pixbuf_new_from_file (png_file, &error);
pixbuf2 = apply_mask_to_pixbuf (pixbuf);
reference_texture = gdk_texture_new_for_pixbuf (pixbuf2);
g_object_unref (pixbuf2);
g_object_unref (pixbuf);
save_image (reference_texture, node_file, "-masked.ref.png");
diff_texture = reftest_compare_textures (rendered_texture, reference_texture);
if (diff_texture)
{
save_node (node2, node_file, "-masked.node");
save_image (diff_texture, node_file, "-masked.diff.png");
g_object_unref (diff_texture);
success = FALSE;
}
g_clear_object (&rendered_texture);
g_clear_object (&reference_texture);
gsk_render_node_unref (node2);
}
gsk_render_node_unref (node);
return success ? 0 : 1;
+19 -2
View File
@@ -101,6 +101,7 @@ informative_render_tests = [
renderers = [
{ 'name': 'gl' },
{ 'name': 'vulkan' },
{ 'name': 'broadway', 'exclude_term': '-3d' },
{ 'name': 'cairo', 'exclude_term': '-3d' },
]
@@ -131,7 +132,7 @@ foreach renderer : renderers
'gsk-compare-' + renderer_name,
]
if compare_xfails.contains(testname)
if compare_xfails.contains(testname) or renderer_name == 'vulkan'
suites += 'failing'
endif
@@ -140,7 +141,8 @@ foreach renderer : renderers
endif
if ((exclude_term == '' or not testname.contains(exclude_term)) and
(renderer_name != 'broadway' or broadway_enabled))
(renderer_name != 'broadway' or broadway_enabled) and
(renderer_name != 'vulkan' or have_vulkan))
test(renderer_name + ' ' + testname, compare_render,
args: [
'--output', join_paths(meson.current_build_dir(), 'compare', renderer_name),
@@ -200,6 +202,21 @@ foreach renderer : renderers
],
suite: suites + [ 'gsk-compare-rotated-' + renderer_name ],
)
test(renderer_name + ' ' + testname + ' masked', compare_render,
args: [
'--mask',
'--output', join_paths(meson.current_build_dir(), 'compare', renderer_name),
join_paths(meson.current_source_dir(), 'compare', testname + '.node'),
join_paths(meson.current_source_dir(), 'compare', testname + '.png'),
],
env: [
'GSK_RENDERER=' + renderer_name,
'GTK_A11Y=test',
'G_TEST_SRCDIR=@0@'.format(meson.current_source_dir()),
'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir())
],
suite: suites + [ 'gsk-compare-masked-' + renderer_name ],
)
endif
endforeach
endforeach
+82 -63
View File
@@ -24,12 +24,17 @@ loop = None
def quit_cb(loop):
loop.quit()
print('timed out while waiting')
def wait(millis):
global loop
before = GLib.get_monotonic_time()
loop = GLib.MainLoop()
GLib.timeout_add(millis, quit_cb, loop)
loop.run()
if verbose:
time = (GLib.get_monotonic_time() - before) / 1000
print(f'waited for {time} milliseconds')
display = None
window = None
@@ -42,10 +47,10 @@ def key_pressed_cb (controller, keyval, keycode, state):
if verbose:
print(f'got key press: {keyval}, state {state}')
assert expected_change != None, "Unexpected key press"
assert expected_change['type'] == 'press', "Key press event expected"
assert keyval == expected_change['keyval'], "Unexpected keyval in key press event"
assert state == expected_change['state'], "Unexpected state in key press event"
assert expected_change != None, 'Unexpected key press'
assert expected_change['type'] == 'press', 'Key press event expected'
assert keyval == expected_change['keyval'], 'Unexpected keyval in key press event'
assert state == expected_change['state'], 'Unexpected state in key press event'
expected_change = None
loop.quit()
@@ -56,10 +61,10 @@ def key_released_cb (controller, keyval, keycode, state):
if verbose:
print(f'got key release: {keyval}, state {state}')
assert expected_change != None, "Unexpected key release"
assert expected_change['type'] == 'release', "Key release event expected"
assert keyval == expected_change['keyval'], "Unexpected keyval in key release event"
assert state == expected_change['state'], "Unexpected state in key release event"
assert expected_change != None, 'Unexpected key release'
assert expected_change['type'] == 'release', 'Key release event expected'
assert keyval == expected_change['keyval'], 'Unexpected keyval in key release event'
assert state == expected_change['state'], 'Unexpected state in key release event'
expected_change = None
loop.quit()
@@ -71,9 +76,9 @@ def motion_cb (controller, x, y):
if verbose:
print(f'got motion: {x}, {y}')
if expected_change != None:
assert expected_change['type'] == 'motion', "Motion event expected"
assert x == expected_change['x'], "Unexpected x coord in motion event"
assert y == expected_change['y'], "Unexpected y coord in motion event"
assert expected_change['type'] == 'motion', 'Motion event expected'
assert x == expected_change['x'], 'Unexpected x coord in motion event'
assert y == expected_change['y'], 'Unexpected y coord in motion event'
expected_change = None
loop.quit()
@@ -83,10 +88,10 @@ def enter_cb (controller, x, y):
if verbose:
print(f'got enter: {x}, {y}')
assert expected_change != None, "Unexpected enter"
assert expected_change['type'] == 'enter', "Enter event expected"
assert x == expected_change['x'], "Unexpected x coord in enter event"
assert y == expected_change['y'], "Unexpected y coord in enter event"
assert expected_change != None, 'Unexpected enter'
assert expected_change['type'] == 'enter', 'Enter event expected'
assert x == expected_change['x'], 'Unexpected x coord in enter event'
assert y == expected_change['y'], 'Unexpected y coord in enter event'
expected_change = None
loop.quit()
@@ -97,11 +102,11 @@ def pressed_cb(controller, n, x, y):
if verbose:
print(f'got pressed')
assert expected_change != None, "Unexpected event"
assert expected_change['type'] == 'press', "Button press expected"
assert expected_change['button'] == controller.get_current_button(), "Unexpected button pressed"
assert x == expected_change['x'], "Unexpected x coord in motion event"
assert y == expected_change['y'], "Unexpected y coord in motion event"
assert expected_change != None, 'Unexpected event'
assert expected_change['type'] == 'press', 'Button press expected'
assert expected_change['button'] == controller.get_current_button(), 'Unexpected button pressed'
assert x == expected_change['x'], 'Unexpected x coord in motion event'
assert y == expected_change['y'], 'Unexpected y coord in motion event'
expected_change = None
loop.quit()
@@ -112,8 +117,8 @@ def released_cb(controller, n, x, y):
if verbose:
print(f'got released')
assert expected_change != None, "Unexpected event"
assert expected_change['type'] == 'release', "Button release expected"
assert expected_change != None, 'Unexpected event'
assert expected_change['type'] == 'release', 'Button release expected'
expected_change = None
loop.quit()
@@ -126,7 +131,7 @@ def expect_key_press(keyval, state, timeout):
'state' : state
}
wait(timeout)
assert expected_change == None, "Expected event did not happen"
assert expected_change == None, 'Expected event did not happen'
def expect_key_release(keyval, state, timeout):
global expected_change
@@ -136,7 +141,7 @@ def expect_key_release(keyval, state, timeout):
'state' : state
}
wait(timeout)
assert expected_change == None, "Expected event did not happen"
assert expected_change == None, 'Expected event did not happen'
def expect_motion(x, y, timeout):
global expected_change
@@ -146,7 +151,7 @@ def expect_motion(x, y, timeout):
'y' : y
}
wait(timeout)
assert expected_change == None, "Expected event did not happen"
assert expected_change == None, 'Expected event did not happen'
def expect_enter(x, y, timeout):
global expected_change
@@ -156,7 +161,7 @@ def expect_enter(x, y, timeout):
'y' : y
}
wait(timeout)
assert expected_change == None, "Expected event did not happen"
assert expected_change == None, 'Expected event did not happen'
def expect_button_press(button, x, y, timeout):
global expected_change
@@ -167,7 +172,7 @@ def expect_button_press(button, x, y, timeout):
'y' : y
}
wait(timeout)
assert expected_change == None, "Button press did not arrive"
assert expected_change == None, 'Button press did not arrive'
def expect_button_release(button, x, y, timeout):
global expected_change
@@ -178,7 +183,7 @@ def expect_button_release(button, x, y, timeout):
'y' : y
}
wait(timeout)
assert expected_change == None, "Button release did not arrive"
assert expected_change == None, 'Button release did not arrive'
def got_active(object, pspec):
global loop
@@ -219,11 +224,11 @@ def launch_observer():
window.maximize()
window.present()
wait(500)
wait(2000)
assert window.is_active(), "Observer not active"
assert window.get_width() == 1024, "Window not maximized"
assert window.get_height() == 768, "Window not maximized"
assert window.is_active(), 'Observer not active'
assert window.get_width() == 1024, 'Window not maximized'
assert window.get_height() == 768, 'Window not maximized'
# we need to wait out the map animation, or pointer coords will be off
wait(1000)
@@ -264,7 +269,7 @@ def stop_observer():
window = None
def expect_entry_text(text):
assert text == entry.get_text(), "Unexpected entry text: " + entry.get_text()
assert text == entry.get_text(), 'Unexpected entry text: ' + entry.get_text()
def key_press(keyval):
if verbose:
@@ -299,6 +304,9 @@ def pointer_move(x, y):
def basic_keyboard_tests():
try:
if verbose:
print('Starting basic keyboard tests')
launch_observer()
key_press(Gdk.KEY_a)
@@ -321,7 +329,7 @@ def basic_keyboard_tests():
stop_observer()
except AssertionError as e:
print("Error in basic_keyboard_tests: {0}".format(e))
print(f'Error in basic_keyboard_tests: {e}')
terminate()
def quick_typing_test():
@@ -338,15 +346,18 @@ def quick_typing_test():
key_release(Gdk.KEY_t)
wait(100)
expect_entry_text("Test")
expect_entry_text('Test')
stop_observer()
except AssertionError as e:
print("Error in quick_typing_test: {0}".format(e))
print(f'Error in quick_typing_test: {e}')
terminate()
def basic_pointer_tests():
try:
if verbose:
print('Starting basic pointer tests')
pointer_move(-100.0, -100.0)
launch_observer()
@@ -368,7 +379,7 @@ def basic_pointer_tests():
stop_observer()
except AssertionError as e:
print("Error in basic_pointer_tests: {0}".format(e))
print(f'Error in basic_pointer_tests: {e}')
terminate()
ds_window = None
@@ -379,9 +390,9 @@ def drag_begin(controller, drag):
global loop
if verbose:
print(f'got drag begin')
assert expected_change != None, "Unexpected drag begin"
assert expected_change['type'] == 'drag', "Drag begin expected"
print('got drag begin')
assert expected_change != None, 'Unexpected drag begin'
assert expected_change['type'] == 'drag', 'Drag begin expected'
expected_change = None
loop.quit()
@@ -415,11 +426,11 @@ def launch_drag_source(value):
ds_window.maximize()
ds_window.present()
wait(500)
wait(2000)
assert ds_window.is_active(), "drag source not active"
assert ds_window.get_width() == 1024, "Window not maximized"
assert ds_window.get_height() == 768, "Window not maximized"
assert ds_window.is_active(), 'drag source not active'
assert ds_window.get_width() == 1024, 'Window not maximized'
assert ds_window.get_height() == 768, 'Window not maximized'
# we need to wait out the map animation, or pointer coords will be off
wait(1000)
@@ -437,9 +448,9 @@ def do_drop(controller, value, x, y):
if verbose:
print(f'got drop {value}')
assert expected_change != None, "Unexpected drop begin"
assert expected_change['type'] == 'drop', "Drop expected"
assert expected_change['value'] == value, "Unexpected value dropped"
assert expected_change != None, 'Unexpected drop begin'
assert expected_change['type'] == 'drop', 'Drop expected'
assert expected_change['value'] == value, 'Unexpected value dropped'
expected_change = None
loop.quit()
@@ -465,11 +476,11 @@ def launch_drop_target():
dt_window.maximize()
dt_window.present()
wait(500)
wait(2000)
assert dt_window.is_active(), "drop target not active"
assert dt_window.get_width() == 1024, "Window not maximized"
assert dt_window.get_height() == 768, "Window not maximized"
assert dt_window.is_active(), 'drop target not active'
assert dt_window.get_width() == 1024, 'Window not maximized'
assert dt_window.get_height() == 768, 'Window not maximized'
# we need to wait out the map animation, or pointer coords will be off
wait(1000)
@@ -485,7 +496,7 @@ def expect_drag(timeout):
'type' : 'drag',
}
wait(timeout)
assert expected_change == None, "DND operation not started"
assert expected_change == None, 'DND operation not started'
def expect_drop(value, timeout):
global expected_change
@@ -494,10 +505,13 @@ def expect_drop(value, timeout):
'value' : value
}
wait(timeout)
assert expected_change == None, "Drop has not happened"
assert expected_change == None, 'Drop has not happened'
def dnd_tests():
try:
if verbose:
print('Starting dnd tests')
pointer_move(-100, -100)
launch_drag_source('abc')
@@ -511,7 +525,7 @@ def dnd_tests():
wait(150)
pointer_move(120, 150)
expect_drag(timeout=1000)
expect_drag(timeout=2000)
launch_drop_target()
wait(100);
@@ -521,12 +535,18 @@ def dnd_tests():
stop_drop_target()
stop_drag_source()
except AssertionError as e:
print("Error in dnd_tests: {0}".format(e))
print(f'Error in dnd_tests: {e}')
terminate()
def session_closed_cb():
print('Session closed')
def run_commands():
basic_keyboard_tests()
basic_pointer_tests()
dnd_tests()
quick_typing_test()
def mutter_appeared(name):
global remote_desktop
global session
@@ -534,13 +554,13 @@ def mutter_appeared(name):
global done
if verbose:
print("mutter appeared on the bus")
print('mutter appeared on the bus')
remote_desktop = bus.get('org.gnome.Mutter.RemoteDesktop',
'/org/gnome/Mutter/RemoteDesktop')
device_types = remote_desktop.Get('org.gnome.Mutter.RemoteDesktop', 'SupportedDeviceTypes')
assert device_types & 1 == 1, "No keyboard"
assert device_types & 2 == 2, "No pointer"
assert device_types & 1 == 1, 'No keyboard'
assert device_types & 2 == 2, 'No pointer'
screen_cast = bus.get('org.gnome.Mutter.ScreenCast',
'/org/gnome/Mutter/ScreenCast')
@@ -560,20 +580,19 @@ def mutter_appeared(name):
key_release(Gdk.KEY_Control_L)
pointer_move(-100, -100)
basic_keyboard_tests()
basic_pointer_tests()
dnd_tests()
quick_typing_test()
run_commands()
session.Stop()
if verbose:
print('Done running commands, exiting...')
done = True
def mutter_vanished():
global done
if remote_desktop != None:
if verbose:
print("mutter left the bus")
print('mutter left the bus')
done = True
bus = SessionBus()
+40 -29
View File
@@ -26,6 +26,9 @@ def terminate():
def stream_added_closure(name):
def stream_added(node_id):
if verbose:
print('pipewire stream added')
monitor = monitors[name];
freq = monitor['freq'];
@@ -36,7 +39,7 @@ def stream_added_closure(name):
# Use gstreamer out-of-process, since the gst gl support gets
# itself into a twist with its wayland connection when monitors
# disappear
pipeline_desc = f'gst-launch-1.0 --verbose pipewiresrc path={node_id} ! video/x-raw,max-framerate={freq}/1,width={width},height={height} ! videoconvert ! glimagesink'
pipeline_desc = f'gst-launch-1.0 pipewiresrc path={node_id} ! video/x-raw,max-framerate={freq}/1,width={width},height={height} ! videoconvert ! glimagesink' # >& gstreamer-monitor.log'
if verbose:
print(f'launching {pipeline_desc}')
monitor['pipeline'] = subprocess.Popen([pipeline_desc], shell=True)
@@ -49,11 +52,11 @@ def add_monitor(name, width, height, scale, freq):
session_path = screen_cast.CreateSession({})
session = bus.get('org.gnome.Mutter.ScreenCast', session_path)
monitors[name] = {
"session": session,
"width": width,
"height": height,
"scale": scale,
"freq": freq
'session': session,
'width': width,
'height': height,
'scale': scale,
'freq': freq
}
stream_path = session.RecordVirtual({})
stream = bus.get('org.gnome.Mutter.ScreenCast', stream_path)
@@ -70,7 +73,7 @@ def remove_monitor(name):
session = monitor['session']
session.Stop()
except KeyError:
print("failed to remove monitor")
print('failed to remove monitor')
monitors[name] = None
expected_change = None
@@ -78,23 +81,28 @@ loop = None
def quit_cb(loop):
loop.quit()
print('timed out while waiting')
def wait(millis):
global loop
before = GLib.get_monotonic_time()
loop = GLib.MainLoop()
GLib.timeout_add(millis, quit_cb, loop)
loop.run()
if verbose:
time = (GLib.get_monotonic_time() - before) / 1000
print(f'waited for {time} milliseconds')
def monitors_changed(monitors, position, removed, added):
global expected_change
assert expected_change != None, "No change expected"
assert position == expected_change['position'], "Unexpected position in monitors-changed"
assert removed == expected_change['removed'], "Unexpected removed in monitors-changed"
assert added == expected_change['added'], "Unexpected added in monitors-changed"
assert expected_change != None, 'No change expected'
assert position == expected_change['position'], 'Unexpected position in monitors-changed'
assert removed == expected_change['removed'], 'Unexpected removed in monitors-changed'
assert added == expected_change['added'], 'Unexpected added in monitors-changed'
if verbose:
print('got expected change')
print('got expected monitors-changed signal')
expected_change = None
loop.quit()
@@ -110,7 +118,7 @@ def launch_observer():
print('launch observer')
monitor_model = display.get_monitors()
assert monitor_model.get_n_items() == 0, "Unexpected initial monitors"
assert monitor_model.get_n_items() == 0, 'Unexpected initial monitors'
monitor_model.connect('items-changed', monitors_changed)
def expect_monitors_changed(position, removed, added, timeout):
@@ -121,7 +129,7 @@ def expect_monitors_changed(position, removed, added, timeout):
'added' : added
}
wait(timeout)
assert expected_change == None, "Expected change did not happen"
assert expected_change == None, 'Expected change did not happen'
def got_connector(monitor, pspec):
loop.quit()
@@ -130,15 +138,18 @@ def expect_monitor(position, width, height, scale, freq):
assert monitor_model.get_n_items() > position, f'Monitor {position} not present'
monitor = monitor_model.get_item(position)
if monitor.get_connector() == None:
if verbose:
print('waiting for connector')
handler = monitor.connect('notify::connector', got_connector)
wait(500)
monitor.disconnect(handler)
assert monitor.is_valid(), "Monitor is not valid"
assert monitor.get_connector() != None, 'Monitor has no connector'
assert monitor.is_valid(), 'Monitor is not valid'
geometry = monitor.get_geometry()
assert geometry.width == width, "Unexpected monitor width"
assert geometry.height == height, "Unexpected monitor height"
assert monitor.get_scale_factor() == scale, "Unexpected scale factor"
assert monitor.get_refresh_rate() == freq, "Unexpected monitor frequency"
assert geometry.width == width, 'Unexpected monitor width'
assert geometry.height == height, 'Unexpected monitor height'
assert monitor.get_scale_factor() == scale, 'Unexpected scale factor'
assert monitor.get_refresh_rate() == freq, 'Unexpected monitor frequency'
if verbose:
print(f'monitor {position}: {geometry.width}x{geometry.height} frequency {monitor.get_refresh_rate()} scale {monitor.get_scale_factor()} model \'{monitor.get_model()}\' connector \'{monitor.get_connector()}\'')
@@ -146,41 +157,41 @@ def run_commands():
try:
launch_observer()
add_monitor("0", width=100, height=100, scale=1, freq=60)
expect_monitors_changed(0, 0, 1, 5000)
add_monitor('0', width=100, height=100, scale=1, freq=60)
expect_monitors_changed(0, 0, 1, 10000)
expect_monitor (position=0, width=100, height=100, scale=1, freq=60000)
add_monitor("1", width=1024, height=768, scale=1, freq=144)
expect_monitors_changed(1, 0, 1, 5000)
add_monitor('1', width=1024, height=768, scale=1, freq=144)
expect_monitors_changed(1, 0, 1, 10000)
expect_monitor (position=1, width=1024, height=768, scale=1, freq=144000)
remove_monitor("0")
remove_monitor('0')
expect_monitors_changed(0, 1, 0, 11000) # mutter takes 10 seconds to remove it
remove_monitor("1")
remove_monitor('1')
expect_monitors_changed(0, 1, 0, 11000)
except AssertionError as e:
print("Error: {0}".format(e))
print(f'Error: {e}')
terminate()
def mutter_appeared(name):
global screen_cast
global done
if verbose:
print("mutter appeared on the bus")
print('mutter appeared on the bus')
screen_cast = bus.get('org.gnome.Mutter.ScreenCast',
'/org/gnome/Mutter/ScreenCast')
run_commands()
if verbose:
print ("Done running commands, exiting...")
print ('Done running commands, exiting...')
done = True
def mutter_vanished():
global done
if screen_cast != None:
if verbose:
print("mutter left the bus")
print('mutter left the bus')
done = True
bus = SessionBus()
+1
View File
@@ -5,6 +5,7 @@ env.prepend('GI_TYPELIB_PATH',
)
env.prepend('LD_PRELOAD', project_build_root / 'gtk' / 'libgtk-4.so')
env.prepend('MESON_CURRENT_SOURCE_DIR', meson.current_source_dir())
env.prepend('MESON_CURRENT_BUILD_DIR', meson.current_build_dir())
test('monitor',
find_program('run-headless-monitor-tests.sh', dirs: meson.current_source_dir()),
+21 -12
View File
@@ -1,26 +1,35 @@
#! /bin/sh
srcdir=${MESON_CURRENT_SOURCE_DIR:-./testsuite/headless}
builddir=${MESON_CURRENT_BUILD_DIR:-.}
outputdir=${builddir}/input
dbus-run-session sh <<EOF
mkdir -p ${outputdir}
export XDG_RUNTIME_DIR="$(mktemp -p $(pwd) -d xdg-runtime-XXXXXX)"
pipewire &
pipewire_pid=\$!
wireplumber &
wireplumber_pid=\$!
sleep 1
#echo DBUS_SESSION_BUS_ADDRESS=\$DBUS_SESSION_BUS_ADDRESS
#echo WAYLAND_DISPLAY=gtk-test
export GTK_A11Y=none
export GIO_USE_VFS=local
mutter --headless --virtual-monitor 1024x768 --no-x11 --wayland-display gtk-test2 >&mutter2.log &
dbus-run-session sh 2>${outputdir}/dbus-stderr.log <<EOF
export XDG_RUNTIME_DIR="$(mktemp -p $(pwd) -d xdg-runtime-XXXXXX)"
pipewire >&${outputdir}/pipewire.log &
pipewire_pid=\$!
sleep 2
wireplumber >&${outputdir}/wireplumber.log &
wireplumber_pid=\$!
sleep 2
#echo DBUS_SESSION_BUS_ADDRESS=\$DBUS_SESSION_BUS_ADDRESS
#echo WAYLAND_DISPLAY=gtk-test
mutter --headless --virtual-monitor 1024x768 --no-x11 --wayland-display gtk-test2 >&${outputdir}/mutter.log &
mutter_pid=\$!
sleep 2
export WAYLAND_DISPLAY=gtk-test2
export GDK_BACKEND=wayland
@@ -1,19 +1,24 @@
#! /bin/sh
srcdir=${MESON_CURRENT_SOURCE_DIR:-./testsuite/headless}
builddir=${MESON_CURRENT_BUILD_DIR:-.}
outputdir=${builddir}/monitor
mkdir -p ${outputdir}
export GTK_A11Y=none
export GIO_USE_VFS=local
dbus-run-session sh <<EOF
dbus-run-session sh 2>${outputdir}/dbus-stderr.log <<EOF
export XDG_RUNTIME_DIR="$(mktemp -p $(pwd) -d xdg-runtime-XXXXXX)"
pipewire &
pipewire >&${outputdir}/pipewire.log &
pipewire_pid=\$!
sleep 2
wireplumber &
wireplumber >&${outputdir}/wireplumber.log &
wireplumber_pid=\$!
sleep 2
@@ -22,7 +27,7 @@ sleep 2
export MUTTER_DEBUG=screen-cast
mutter --headless --no-x11 --wayland-display gtk-test &
mutter --headless --no-x11 --wayland-display gtk-test >&${outputdir}/mutter.log &
mutter_pid=\$!
sleep 2