Compare commits
1 Commits
quick-keyb
...
add-mutter
Author | SHA1 | Date | |
---|---|---|---|
|
f228e13b91 |
@@ -26,7 +26,7 @@ variables:
|
||||
BACKEND_FLAGS: "-Dx11-backend=true -Dwayland-backend=true -Dbroadway-backend=true"
|
||||
FEATURE_FLAGS: "-Dvulkan=enabled -Dcloudproviders=enabled -Ddemos=false -Dbuild-examples=false -Dbuild-tests=false -Dbuild-testsuite=true"
|
||||
MESON_TEST_TIMEOUT_MULTIPLIER: 3
|
||||
FEDORA_IMAGE: "registry.gitlab.gnome.org/gnome/gtk/fedora:v46"
|
||||
FEDORA_IMAGE: "registry.gitlab.gnome.org/gnome/gtk/fedora:v43"
|
||||
|
||||
workflow:
|
||||
rules:
|
||||
@@ -57,9 +57,15 @@ style-check-diff:
|
||||
reports:
|
||||
junit:
|
||||
- "${CI_PROJECT_DIR}/_build/report-x11.xml"
|
||||
- "${CI_PROJECT_DIR}/_build/report-x11_unstable.xml"
|
||||
- "${CI_PROJECT_DIR}/_build/report-wayland.xml"
|
||||
- "${CI_PROJECT_DIR}/_build/report-wayland_unstable.xml"
|
||||
- "${CI_PROJECT_DIR}/_build/report-wayland_gles.xml"
|
||||
- "${CI_PROJECT_DIR}/_build/report-wayland_gles_unstable.xml"
|
||||
- "${CI_PROJECT_DIR}/_build/report-wayland_smalltexture.xml"
|
||||
- "${CI_PROJECT_DIR}/_build/report-wayland_smalltexture_unstable.xml"
|
||||
- "${CI_PROJECT_DIR}/_build/report-broadway.xml"
|
||||
- "${CI_PROJECT_DIR}/_build/report-broadway_unstable.xml"
|
||||
name: "gtk-${CI_COMMIT_REF_NAME}"
|
||||
paths:
|
||||
- "${CI_PROJECT_DIR}/_build/meson-logs"
|
||||
@@ -85,6 +91,7 @@ fedora-x86_64:
|
||||
script:
|
||||
- .gitlab-ci/show-info-linux.sh
|
||||
- export PATH="$HOME/.local/bin:$PATH"
|
||||
- pip3 install --user meson~=0.64
|
||||
- meson subprojects download
|
||||
- meson subprojects update --reset
|
||||
- mkdir _install
|
||||
@@ -102,6 +109,7 @@ fedora-x86_64:
|
||||
- .gitlab-ci/run-tests.sh _build x11
|
||||
- .gitlab-ci/run-tests.sh _build wayland
|
||||
- .gitlab-ci/run-tests.sh _build wayland_gles
|
||||
- .gitlab-ci/run-tests.sh _build wayland_smalltexture
|
||||
- .gitlab-ci/run-tests.sh _build broadway
|
||||
|
||||
release-build:
|
||||
@@ -113,6 +121,7 @@ release-build:
|
||||
script:
|
||||
- .gitlab-ci/show-info-linux.sh
|
||||
- export PATH="$HOME/.local/bin:$PATH"
|
||||
- pip3 install --user meson~=0.64
|
||||
- meson subprojects download
|
||||
- meson subprojects update --reset
|
||||
- meson setup
|
||||
@@ -143,11 +152,23 @@ fedora-mingw64:
|
||||
script:
|
||||
- .gitlab-ci/show-info-linux.sh
|
||||
- export PATH="$HOME/.local/bin:$PATH"
|
||||
- pip3 install --user meson~=1.0
|
||||
- pip3 install --user meson~=0.64
|
||||
- meson subprojects download
|
||||
- meson subprojects update --reset
|
||||
- meson -Dintrospection=disabled -Dgraphene:introspection=disabled _build
|
||||
- meson compile -C _build
|
||||
# Test that mingw64-meson still fails. If it has stopped failing, the CI
|
||||
# will fail and now you should remove the hack that follows this.
|
||||
- FAILED=false
|
||||
- mingw64-meson --version || FAILED=true
|
||||
- test $FAILED = false && echo "mingw64-meson works now, remove the hack" && exit 1
|
||||
# HACK: Running mingw64-meson directly fails on the CI with:
|
||||
# /usr/bin/mingw64-meson: line 92: fg: no job control
|
||||
# Because rpm is not evaluating %__meson and it gets interpreted as a job
|
||||
# specifier. So we fix that and run it ourselves.
|
||||
- rpm --eval "%{mingw64_meson}" > mingw64-meson.sh
|
||||
- sed -i -e 's/%__meson/meson/' mingw64-meson.sh
|
||||
- chmod +x mingw64-meson.sh
|
||||
- ./mingw64-meson.sh -Dintrospection=disabled -Dgraphene:introspection=disabled _build
|
||||
- ninja -C _build
|
||||
|
||||
.mingw-defaults:
|
||||
stage: build
|
||||
@@ -189,7 +210,7 @@ macos:
|
||||
needs: []
|
||||
before_script:
|
||||
- bash .gitlab-ci/show-info-osx.sh
|
||||
- pip3 install --user meson~=1.0
|
||||
- pip3 install --user meson~=0.64
|
||||
- pip3 install --user ninja
|
||||
- export PATH=/Users/gitlabrunner/Library/Python/3.7/bin:$PATH
|
||||
- export MESON_FORCE_BACKTRACE=1
|
||||
@@ -347,6 +368,7 @@ static-scan:
|
||||
EXTRA_MESON_FLAGS: "--buildtype=debug"
|
||||
script:
|
||||
- export PATH="$HOME/.local/bin:$PATH"
|
||||
- pip3 install --user meson~=0.64
|
||||
- meson setup
|
||||
${COMMON_MESON_FLAGS}
|
||||
${EXTRA_MESON_FLAGS}
|
||||
@@ -368,6 +390,7 @@ asan-build:
|
||||
variables:
|
||||
script:
|
||||
- export PATH="$HOME/.local/bin:$PATH"
|
||||
- pip3 install --user meson~=0.64
|
||||
- CC=clang meson setup --buildtype=debugoptimized -Db_sanitize=address -Db_lundef=false -Dintrospection=disabled -Df16c=disabled _build
|
||||
- ninja -C _build
|
||||
- .gitlab-ci/run-tests.sh _build wayland
|
||||
@@ -382,6 +405,7 @@ reference:
|
||||
needs: []
|
||||
script:
|
||||
- export PATH="$HOME/.local/bin:$PATH"
|
||||
- pip3 install --user meson~=0.64
|
||||
- meson setup
|
||||
${COMMON_MESON_FLAGS}
|
||||
--buildtype=release
|
||||
|
@@ -32,6 +32,7 @@ RUN dnf -y install \
|
||||
glib2-static \
|
||||
glibc-devel \
|
||||
glibc-headers \
|
||||
gnome-desktop-testing \
|
||||
gnupg2 \
|
||||
gobject-introspection-devel \
|
||||
graphene-devel \
|
||||
@@ -72,14 +73,11 @@ RUN dnf -y install \
|
||||
mesa-dri-drivers \
|
||||
mesa-libEGL-devel \
|
||||
mesa-libGLES-devel \
|
||||
meson \
|
||||
mutter \
|
||||
ninja-build \
|
||||
pango-devel \
|
||||
pcre-devel \
|
||||
pcre-static \
|
||||
pipewire \
|
||||
pipewire-gstreamer \
|
||||
python3 \
|
||||
python3-docutils \
|
||||
python3-gobject \
|
||||
@@ -99,7 +97,6 @@ RUN dnf -y install \
|
||||
weston \
|
||||
weston-libs \
|
||||
which \
|
||||
wireplumber \
|
||||
xorg-x11-server-Xvfb \
|
||||
&& dnf clean all
|
||||
|
||||
|
@@ -138,8 +138,7 @@ if [ $run == 1 ]; then
|
||||
echo -e "\e[1;32mRUNNING\e[0m: ${base} as ${TAG}"
|
||||
${CMD} run \
|
||||
--rm \
|
||||
--userns=keep-id \
|
||||
--volume "$(pwd)/..:/home/user/app:rw,z" \
|
||||
--volume "$(pwd)/..:/home/user/app" \
|
||||
--workdir "/home/user/app" \
|
||||
--tty \
|
||||
--interactive "${TAG}" \
|
||||
|
@@ -6,7 +6,6 @@ set +e
|
||||
srcdir=$( pwd )
|
||||
builddir=$1
|
||||
backend=$2
|
||||
multiplier=${MESON_TEST_TIMEOUT_MULTIPLIER:-1}
|
||||
|
||||
# Ignore memory leaks lower in dependencies
|
||||
export LSAN_OPTIONS=suppressions=$srcdir/lsan.supp:print_suppressions=0:verbosity=1:log_threads=1
|
||||
@@ -16,8 +15,7 @@ case "${backend}" in
|
||||
x11)
|
||||
xvfb-run -a -s "-screen 0 1024x768x24 -noreset" \
|
||||
meson test -C ${builddir} \
|
||||
--quiet \
|
||||
--timeout-multiplier "${multiplier}" \
|
||||
--timeout-multiplier "${MESON_TEST_TIMEOUT_MULTIPLIER}" \
|
||||
--print-errorlogs \
|
||||
--setup=${backend} \
|
||||
--suite=gtk \
|
||||
@@ -28,6 +26,14 @@ case "${backend}" in
|
||||
# Store the exit code for the CI run, but always
|
||||
# generate the reports
|
||||
exit_code=$?
|
||||
|
||||
xvfb-run -a -s "-screen 0 1024x768x24 -noreset" \
|
||||
meson test -C ${builddir} \
|
||||
--timeout-multiplier "${MESON_TEST_TIMEOUT_MULTIPLIER}" \
|
||||
--print-errorlogs \
|
||||
--setup=${backend}_unstable \
|
||||
--suite=flaky \
|
||||
--suite=failing || true
|
||||
;;
|
||||
|
||||
wayland*)
|
||||
@@ -38,8 +44,7 @@ case "${backend}" in
|
||||
export WAYLAND_DISPLAY=wayland-5
|
||||
|
||||
meson test -C ${builddir} \
|
||||
--quiet \
|
||||
--timeout-multiplier "${multiplier}" \
|
||||
--timeout-multiplier "${MESON_TEST_TIMEOUT_MULTIPLIER}" \
|
||||
--print-errorlogs \
|
||||
--setup=${backend} \
|
||||
--suite=gtk \
|
||||
@@ -49,6 +54,13 @@ case "${backend}" in
|
||||
--no-suite=gsk-compare-broadway
|
||||
exit_code=$?
|
||||
|
||||
meson test -C ${builddir} \
|
||||
--timeout-multiplier "${MESON_TEST_TIMEOUT_MULTIPLIER}" \
|
||||
--print-errorlogs \
|
||||
--setup=${backend}_unstable \
|
||||
--suite=flaky \
|
||||
--suite=failing || true
|
||||
|
||||
kill ${compositor}
|
||||
;;
|
||||
|
||||
@@ -60,8 +72,7 @@ case "${backend}" in
|
||||
export BROADWAY_DISPLAY=:5
|
||||
|
||||
meson test -C ${builddir} \
|
||||
--quiet \
|
||||
--timeout-multiplier "${multiplier}" \
|
||||
--timeout-multiplier "${MESON_TEST_TIMEOUT_MULTIPLIER}" \
|
||||
--print-errorlogs \
|
||||
--setup=${backend} \
|
||||
--suite=gtk \
|
||||
@@ -72,6 +83,13 @@ case "${backend}" in
|
||||
# don't let Broadway failures fail the run, for now
|
||||
exit_code=0
|
||||
|
||||
meson test -C ${builddir} \
|
||||
--timeout-multiplier "${MESON_TEST_TIMEOUT_MULTIPLIER}" \
|
||||
--print-errorlogs \
|
||||
--setup=${backend}_unstable \
|
||||
--suite=flaky \
|
||||
--suite=failing || true
|
||||
|
||||
kill ${server}
|
||||
;;
|
||||
|
||||
@@ -84,19 +102,20 @@ esac
|
||||
|
||||
cd ${builddir}
|
||||
|
||||
$srcdir/.gitlab-ci/meson-junit-report.py \
|
||||
for suffix in "" "_unstable"; do
|
||||
$srcdir/.gitlab-ci/meson-junit-report.py \
|
||||
--project-name=gtk \
|
||||
--backend="${backend}" \
|
||||
--backend="${backend}${suffix}" \
|
||||
--job-id="${CI_JOB_NAME}" \
|
||||
--output="report-${backend}.xml" \
|
||||
"meson-logs/testlog-${backend}.json"
|
||||
|
||||
$srcdir/.gitlab-ci/meson-html-report.py \
|
||||
--output="report-${backend}${suffix}.xml" \
|
||||
"meson-logs/testlog-${backend}${suffix}.json"
|
||||
$srcdir/.gitlab-ci/meson-html-report.py \
|
||||
--project-name=gtk \
|
||||
--backend="${backend}" \
|
||||
--backend="${backend}${suffix}" \
|
||||
--job-id="${CI_JOB_NAME}" \
|
||||
--reftest-output-dir="testsuite/reftests/output/${backend}" \
|
||||
--output="report-${backend}.html" \
|
||||
"meson-logs/testlog-${backend}.json"
|
||||
--reftest-output-dir="testsuite/reftests/output/${backend}${suffix}" \
|
||||
--output="report-${backend}${suffix}.html" \
|
||||
"meson-logs/testlog-${backend}${suffix}.json"
|
||||
done
|
||||
|
||||
exit $exit_code
|
||||
|
@@ -64,7 +64,6 @@ struct _NodeEditorWindow
|
||||
GListStore *renderers;
|
||||
GskRenderNode *node;
|
||||
|
||||
GFile *file;
|
||||
GFileMonitor *file_monitor;
|
||||
|
||||
GArray *errors;
|
||||
@@ -545,14 +544,12 @@ node_editor_window_load (NodeEditorWindow *self,
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
g_clear_object (&self->file);
|
||||
g_clear_object (&self->file_monitor);
|
||||
|
||||
if (!load_file_contents (self, file))
|
||||
return FALSE;
|
||||
|
||||
self->file = g_object_ref (file);
|
||||
self->file_monitor = g_file_monitor_file (self->file, G_FILE_MONITOR_NONE, NULL, &error);
|
||||
self->file_monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, &error);
|
||||
|
||||
if (error)
|
||||
{
|
||||
@@ -589,21 +586,13 @@ static void
|
||||
show_open_filechooser (NodeEditorWindow *self)
|
||||
{
|
||||
GtkFileDialog *dialog;
|
||||
GFile *cwd;
|
||||
|
||||
dialog = gtk_file_dialog_new ();
|
||||
gtk_file_dialog_set_title (dialog, "Open node file");
|
||||
if (self->file)
|
||||
{
|
||||
gtk_file_dialog_set_initial_file (dialog, self->file);
|
||||
}
|
||||
else
|
||||
{
|
||||
GFile *cwd;
|
||||
cwd = g_file_new_for_path (".");
|
||||
gtk_file_dialog_set_initial_folder (dialog, cwd);
|
||||
g_object_unref (cwd);
|
||||
}
|
||||
|
||||
cwd = g_file_new_for_path (".");
|
||||
gtk_file_dialog_set_initial_folder (dialog, cwd);
|
||||
g_object_unref (cwd);
|
||||
gtk_file_dialog_open (dialog, GTK_WINDOW (self),
|
||||
NULL, open_response_cb, self);
|
||||
g_object_unref (dialog);
|
||||
@@ -661,21 +650,14 @@ save_cb (GtkWidget *button,
|
||||
NodeEditorWindow *self)
|
||||
{
|
||||
GtkFileDialog *dialog;
|
||||
GFile *cwd;
|
||||
|
||||
dialog = gtk_file_dialog_new ();
|
||||
gtk_file_dialog_set_title (dialog, "Save node");
|
||||
if (self->file)
|
||||
{
|
||||
gtk_file_dialog_set_initial_file (dialog, self->file);
|
||||
}
|
||||
else
|
||||
{
|
||||
GFile *cwd = g_file_new_for_path (".");
|
||||
gtk_file_dialog_set_initial_folder (dialog, cwd);
|
||||
gtk_file_dialog_set_initial_name (dialog, "demo.node");
|
||||
g_object_unref (cwd);
|
||||
}
|
||||
|
||||
cwd = g_file_new_for_path (".");
|
||||
gtk_file_dialog_set_initial_folder (dialog, cwd);
|
||||
gtk_file_dialog_set_initial_name (dialog, "demo.node");
|
||||
g_object_unref (cwd);
|
||||
gtk_file_dialog_save (dialog,
|
||||
GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (button))),
|
||||
NULL,
|
||||
@@ -1109,8 +1091,6 @@ node_editor_window_finalize (GObject *object)
|
||||
|
||||
g_clear_pointer (&self->node, gsk_render_node_unref);
|
||||
g_clear_object (&self->renderers);
|
||||
g_clear_object (&self->file_monitor);
|
||||
g_clear_object (&self->file);
|
||||
|
||||
G_OBJECT_CLASS (node_editor_window_parent_class)->finalize (object);
|
||||
}
|
||||
|
@@ -78,7 +78,6 @@ gsk_gl_attachment_state_bind_texture (GskGLAttachmentState *self,
|
||||
target == GL_TEXTURE_2D ||
|
||||
target == GL_TEXTURE_3D);
|
||||
g_assert (texture >= GL_TEXTURE0 && texture <= GL_TEXTURE16);
|
||||
g_assert (texture - GL_TEXTURE0 < G_N_ELEMENTS (self->textures));
|
||||
|
||||
attach = &self->textures[texture - GL_TEXTURE0];
|
||||
|
||||
|
@@ -73,13 +73,11 @@ struct _GskGLBindFramebuffer
|
||||
|
||||
G_STATIC_ASSERT (sizeof (GskGLBindFramebuffer) == 4);
|
||||
|
||||
/* Increase if shaders add more textures */
|
||||
#define GSK_GL_MAX_TEXTURES_PER_PROGRAM 4
|
||||
|
||||
struct _GskGLAttachmentState
|
||||
{
|
||||
GskGLBindFramebuffer fbo;
|
||||
GskGLBindTexture textures[GSK_GL_MAX_TEXTURES_PER_PROGRAM];
|
||||
/* Increase if shaders add more textures */
|
||||
GskGLBindTexture textures[4];
|
||||
guint n_changed;
|
||||
};
|
||||
|
||||
|
@@ -1028,8 +1028,8 @@ gsk_gl_command_queue_execute (GskGLCommandQueue *self,
|
||||
G_GNUC_UNUSED unsigned int n_programs = 0;
|
||||
guint vao_id;
|
||||
guint vbo_id;
|
||||
int textures[GSK_GL_MAX_TEXTURES_PER_PROGRAM];
|
||||
int samplers[GSK_GL_MAX_TEXTURES_PER_PROGRAM];
|
||||
int textures[4];
|
||||
int samplers[4];
|
||||
int framebuffer = -1;
|
||||
int next_batch_index;
|
||||
int active = -1;
|
||||
@@ -1161,8 +1161,6 @@ gsk_gl_command_queue_execute (GskGLCommandQueue *self,
|
||||
if G_UNLIKELY (batch->draw.bind_count > 0)
|
||||
{
|
||||
const GskGLCommandBind *bind = &self->batch_binds.items[batch->draw.bind_offset];
|
||||
|
||||
g_assert (bind->texture < G_N_ELEMENTS (textures));
|
||||
for (guint i = 0; i < batch->draw.bind_count; i++)
|
||||
{
|
||||
if (textures[bind->texture] != bind->id)
|
||||
|
@@ -1121,21 +1121,19 @@ gsk_gl_driver_lookup_shader (GskGLDriver *self,
|
||||
}
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
void
|
||||
gsk_gl_driver_save_texture_to_png (GskGLDriver *driver,
|
||||
int texture_id,
|
||||
int width,
|
||||
int height,
|
||||
const char *filename)
|
||||
static void
|
||||
write_atlas_to_png (GskGLDriver *driver,
|
||||
GskGLTextureAtlas *atlas,
|
||||
const char *filename)
|
||||
{
|
||||
GdkGLTextureBuilder *builder;
|
||||
GdkTexture *texture;
|
||||
|
||||
builder = gdk_gl_texture_builder_new ();
|
||||
gdk_gl_texture_builder_set_context (builder, gsk_gl_driver_get_context (driver));
|
||||
gdk_gl_texture_builder_set_id (builder, texture_id);
|
||||
gdk_gl_texture_builder_set_width (builder, width);
|
||||
gdk_gl_texture_builder_set_height (builder, height);
|
||||
gdk_gl_texture_builder_set_id (builder, atlas->texture_id);
|
||||
gdk_gl_texture_builder_set_width (builder, atlas->width);
|
||||
gdk_gl_texture_builder_set_height (builder, atlas->height);
|
||||
|
||||
texture = gdk_gl_texture_builder_build (builder, NULL, NULL);
|
||||
gdk_texture_save_to_png (texture, filename);
|
||||
@@ -1170,7 +1168,7 @@ gsk_gl_driver_save_atlases_to_png (GskGLDriver *self,
|
||||
G_DIR_SEPARATOR_S,
|
||||
(int)self->current_frame_id,
|
||||
atlas->texture_id);
|
||||
gsk_gl_driver_save_texture_to_png (self, atlas->texture_id, atlas->width, atlas->height, filename);
|
||||
write_atlas_to_png (self, atlas, filename);
|
||||
g_free (filename);
|
||||
}
|
||||
|
||||
|
@@ -176,13 +176,8 @@ GskGLProgram * gsk_gl_driver_lookup_shader (GskGLDriver *s
|
||||
GError **error);
|
||||
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
void gsk_gl_driver_save_texture_to_png (GskGLDriver *self,
|
||||
int texture_id,
|
||||
int width,
|
||||
int height,
|
||||
const char *filename);
|
||||
void gsk_gl_driver_save_atlases_to_png (GskGLDriver *self,
|
||||
const char *filename);
|
||||
const char *directory);
|
||||
#endif
|
||||
|
||||
static inline GskGLTexture *
|
||||
|
@@ -1750,13 +1750,22 @@ gsk_gl_render_job_visit_rounded_clip_node (GskGLRenderJob *job,
|
||||
|
||||
if (job->clip->len <= 1)
|
||||
need_offscreen = FALSE;
|
||||
else if (gsk_rounded_rect_contains_rect (&job->current_clip->rect, &transformed_clip.bounds))
|
||||
else if (rounded_inner_rect_contains_rect (&job->current_clip->rect, &transformed_clip.bounds))
|
||||
need_offscreen = FALSE;
|
||||
else
|
||||
need_offscreen = TRUE;
|
||||
|
||||
if (!need_offscreen)
|
||||
{
|
||||
/* If the new clip entirely contains the current clip, the intersection is simply
|
||||
* the current clip, so we can ignore the new one.
|
||||
*/
|
||||
if (rounded_inner_rect_contains_rect (&transformed_clip, &job->current_clip->rect.bounds))
|
||||
{
|
||||
gsk_gl_render_job_visit_node (job, child);
|
||||
return;
|
||||
}
|
||||
|
||||
gsk_gl_render_job_push_clip (job, &transformed_clip);
|
||||
gsk_gl_render_job_visit_node (job, child);
|
||||
gsk_gl_render_job_pop_clip (job);
|
||||
@@ -2824,7 +2833,7 @@ gsk_gl_render_job_visit_cross_fade_node (GskGLRenderJob *job,
|
||||
offscreen_end.reset_clip = TRUE;
|
||||
offscreen_end.bounds = &node->bounds;
|
||||
|
||||
gsk_gl_render_job_set_modelview (job, gsk_transform_scale (NULL, fabs (job->scale_x), fabs (job->scale_y)));
|
||||
gsk_gl_render_job_set_modelview (job, NULL);
|
||||
|
||||
if (!gsk_gl_render_job_visit_node_with_offscreen (job, start_node, &offscreen_start))
|
||||
{
|
||||
@@ -3243,7 +3252,7 @@ gsk_gl_render_job_visit_blend_node (GskGLRenderJob *job,
|
||||
bottom_offscreen.force_offscreen = TRUE;
|
||||
bottom_offscreen.reset_clip = TRUE;
|
||||
|
||||
gsk_gl_render_job_set_modelview (job, gsk_transform_scale (NULL, fabs (job->scale_x), fabs (job->scale_y)));
|
||||
gsk_gl_render_job_set_modelview (job, NULL);
|
||||
|
||||
/* TODO: We create 2 textures here as big as the blend node, but both the
|
||||
* start and the end node might be a lot smaller than that. */
|
||||
@@ -3312,7 +3321,7 @@ gsk_gl_render_job_visit_mask_node (GskGLRenderJob *job,
|
||||
mask_offscreen.reset_clip = TRUE;
|
||||
mask_offscreen.do_not_cache = TRUE;
|
||||
|
||||
gsk_gl_render_job_set_modelview (job, gsk_transform_scale (NULL, fabs (job->scale_x), fabs (job->scale_y)));
|
||||
gsk_gl_render_job_set_modelview (job, NULL);
|
||||
|
||||
/* TODO: We create 2 textures here as big as the mask node, but both
|
||||
* nodes might be a lot smaller than that.
|
||||
|
@@ -871,7 +871,7 @@ create_ascii_glyphs (PangoFont *font)
|
||||
if (!pango_coverage_get (coverage, i))
|
||||
break;
|
||||
}
|
||||
g_object_unref (coverage);
|
||||
pango_coverage_unref (coverage);
|
||||
if (i < MAX_ASCII_GLYPH)
|
||||
return NULL;
|
||||
|
||||
|
@@ -164,7 +164,7 @@ gskenum_h = gsk_enums[1]
|
||||
gskresources = gnome.compile_resources('gskresources',
|
||||
gsk_resources_xml,
|
||||
dependencies: gsk_private_vulkan_compiled_shaders_deps,
|
||||
source_dir: [meson.current_build_dir(), meson.current_source_dir()],
|
||||
source_dir: meson.current_source_dir(),
|
||||
c_name: '_gsk',
|
||||
extra_args: [ '--manual-register', ],
|
||||
)
|
||||
|
@@ -1012,8 +1012,9 @@ gsk_vulkan_render_pass_get_node_as_texture (GskVulkanRenderPass *self,
|
||||
GskVulkanRender *render,
|
||||
GskVulkanUploader *uploader,
|
||||
GskRenderNode *node,
|
||||
const graphene_rect_t *bounds,
|
||||
GskVulkanClip *current_clip,
|
||||
graphene_rect_t *tex_bounds)
|
||||
graphene_rect_t *tex_rect)
|
||||
{
|
||||
GskVulkanImage *result;
|
||||
cairo_surface_t *surface;
|
||||
@@ -1022,12 +1023,16 @@ gsk_vulkan_render_pass_get_node_as_texture (GskVulkanRenderPass *self,
|
||||
switch ((guint) gsk_render_node_get_node_type (node))
|
||||
{
|
||||
case GSK_TEXTURE_NODE:
|
||||
result = gsk_vulkan_renderer_ref_texture_image (GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
|
||||
gsk_texture_node_get_texture (node),
|
||||
uploader);
|
||||
gsk_vulkan_render_add_cleanup_image (render, result);
|
||||
*tex_bounds = node->bounds;
|
||||
return result;
|
||||
if (graphene_rect_equal (bounds, &node->bounds))
|
||||
{
|
||||
result = gsk_vulkan_renderer_ref_texture_image (GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
|
||||
gsk_texture_node_get_texture (node),
|
||||
uploader);
|
||||
gsk_vulkan_render_add_cleanup_image (render, result);
|
||||
*tex_rect = GRAPHENE_RECT_INIT(0, 0, 1, 1);
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_CAIRO_NODE:
|
||||
/* We're using recording surfaces, so drawing them to an image
|
||||
@@ -1045,9 +1050,9 @@ gsk_vulkan_render_pass_get_node_as_texture (GskVulkanRenderPass *self,
|
||||
graphene_rect_t clipped;
|
||||
|
||||
if (current_clip)
|
||||
graphene_rect_intersection (¤t_clip->rect.bounds, &node->bounds, &clipped);
|
||||
graphene_rect_intersection (¤t_clip->rect.bounds, bounds, &clipped);
|
||||
else
|
||||
clipped = node->bounds;
|
||||
clipped = *bounds;
|
||||
|
||||
if (clipped.size.width == 0 || clipped.size.height == 0)
|
||||
return NULL;
|
||||
@@ -1106,30 +1111,33 @@ gsk_vulkan_render_pass_get_node_as_texture (GskVulkanRenderPass *self,
|
||||
/* assuming the unclipped bounds should go to texture coordinates 0..1,
|
||||
* calculate the coordinates for the clipped texture size
|
||||
*/
|
||||
*tex_bounds = clipped;
|
||||
tex_rect->origin.x = (bounds->origin.x - clipped.origin.x)/clipped.size.width;
|
||||
tex_rect->origin.y = (bounds->origin.y - clipped.origin.y)/clipped.size.height;
|
||||
tex_rect->size.width = bounds->size.width/clipped.size.width;
|
||||
tex_rect->size.height = bounds->size.height/clipped.size.height;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
GSK_RENDERER_DEBUG (gsk_vulkan_render_get_renderer (render), FALLBACK, "Node as texture not implemented for this case. Using %gx%g fallback surface",
|
||||
ceil (node->bounds.size.width),
|
||||
ceil (node->bounds.size.height));
|
||||
ceil (bounds->size.width),
|
||||
ceil (bounds->size.height));
|
||||
#ifdef G_ENABLE_DEBUG
|
||||
{
|
||||
GskProfiler *profiler = gsk_renderer_get_profiler (gsk_vulkan_render_get_renderer (render));
|
||||
gsk_profiler_counter_add (profiler,
|
||||
self->fallback_pixels,
|
||||
ceil (node->bounds.size.width) * ceil (node->bounds.size.height));
|
||||
ceil (bounds->size.width) * ceil (bounds->size.height));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* XXX: We could intersect bounds with clip bounds here */
|
||||
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
|
||||
ceil (node->bounds.size.width),
|
||||
ceil (node->bounds.size.height));
|
||||
ceil (bounds->size.width),
|
||||
ceil (bounds->size.height));
|
||||
cr = cairo_create (surface);
|
||||
cairo_translate (cr, -node->bounds.origin.x, -node->bounds.origin.y);
|
||||
cairo_translate (cr, -bounds->origin.x, -bounds->origin.y);
|
||||
|
||||
gsk_render_node_draw (node, cr);
|
||||
|
||||
@@ -1145,7 +1153,10 @@ gsk_vulkan_render_pass_get_node_as_texture (GskVulkanRenderPass *self,
|
||||
|
||||
gsk_vulkan_render_add_cleanup_image (render, result);
|
||||
|
||||
*tex_bounds = node->bounds;
|
||||
tex_rect->origin.x = (node->bounds.origin.x - bounds->origin.x)/bounds->size.width;
|
||||
tex_rect->origin.y = (node->bounds.origin.y - bounds->origin.y)/bounds->size.height;
|
||||
tex_rect->size.width = node->bounds.size.width/bounds->size.width;
|
||||
tex_rect->size.height = node->bounds.size.height/bounds->size.height;
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -1239,18 +1250,6 @@ gsk_vulkan_render_pass_upload_fallback (GskVulkanRenderPass *self,
|
||||
gsk_vulkan_render_add_cleanup_image (render, op->source);
|
||||
}
|
||||
|
||||
static void
|
||||
get_tex_rect (graphene_rect_t *tex_coords,
|
||||
const graphene_rect_t *rect,
|
||||
const graphene_rect_t *tex)
|
||||
{
|
||||
graphene_rect_init (tex_coords,
|
||||
(rect->origin.x - tex->origin.x) / tex->size.width,
|
||||
(rect->origin.y - tex->origin.y) / tex->size.height,
|
||||
rect->size.width / tex->size.width,
|
||||
rect->size.height / tex->size.height);
|
||||
}
|
||||
|
||||
void
|
||||
gsk_vulkan_render_pass_upload (GskVulkanRenderPass *self,
|
||||
GskVulkanRender *render,
|
||||
@@ -1295,61 +1294,63 @@ gsk_vulkan_render_pass_upload (GskVulkanRenderPass *self,
|
||||
case GSK_VULKAN_OP_OPACITY:
|
||||
{
|
||||
GskRenderNode *child = gsk_opacity_node_get_child (op->render.node);
|
||||
graphene_rect_t tex_bounds;
|
||||
|
||||
op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
|
||||
render,
|
||||
uploader,
|
||||
child,
|
||||
&child->bounds,
|
||||
clip,
|
||||
&tex_bounds);
|
||||
get_tex_rect (&op->render.source_rect, &op->render.node->bounds, &tex_bounds);
|
||||
&op->render.source_rect);
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_VULKAN_OP_REPEAT:
|
||||
{
|
||||
GskRenderNode *child = gsk_repeat_node_get_child (op->render.node);
|
||||
const graphene_rect_t *bounds = &op->render.node->bounds;
|
||||
const graphene_rect_t *child_bounds = gsk_repeat_node_get_child_bounds (op->render.node);
|
||||
graphene_rect_t tex_bounds;
|
||||
|
||||
op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
|
||||
render,
|
||||
uploader,
|
||||
child,
|
||||
child_bounds,
|
||||
NULL,
|
||||
&tex_bounds);
|
||||
get_tex_rect (&op->render.source_rect, child_bounds, &tex_bounds);
|
||||
&op->render.source_rect);
|
||||
|
||||
op->render.source_rect.origin.x = (bounds->origin.x - child_bounds->origin.x)/child_bounds->size.width;
|
||||
op->render.source_rect.origin.y = (bounds->origin.y - child_bounds->origin.y)/child_bounds->size.height;
|
||||
op->render.source_rect.size.width = bounds->size.width / child_bounds->size.width;
|
||||
op->render.source_rect.size.height = bounds->size.height / child_bounds->size.height;
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_VULKAN_OP_BLUR:
|
||||
{
|
||||
GskRenderNode *child = gsk_blur_node_get_child (op->render.node);
|
||||
graphene_rect_t tex_bounds;
|
||||
|
||||
op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
|
||||
render,
|
||||
uploader,
|
||||
child,
|
||||
&child->bounds,
|
||||
clip,
|
||||
&tex_bounds);
|
||||
get_tex_rect (&op->render.source_rect, &op->render.node->bounds, &tex_bounds);
|
||||
&op->render.source_rect);
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_VULKAN_OP_COLOR_MATRIX:
|
||||
{
|
||||
GskRenderNode *child = gsk_color_matrix_node_get_child (op->render.node);
|
||||
graphene_rect_t tex_bounds;
|
||||
|
||||
op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
|
||||
render,
|
||||
uploader,
|
||||
child,
|
||||
&child->bounds,
|
||||
clip,
|
||||
&tex_bounds);
|
||||
get_tex_rect (&op->render.source_rect, &op->render.node->bounds, &tex_bounds);
|
||||
&op->render.source_rect);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1357,23 +1358,31 @@ gsk_vulkan_render_pass_upload (GskVulkanRenderPass *self,
|
||||
{
|
||||
GskRenderNode *start = gsk_cross_fade_node_get_start_child (op->render.node);
|
||||
GskRenderNode *end = gsk_cross_fade_node_get_end_child (op->render.node);
|
||||
graphene_rect_t tex_bounds;
|
||||
const graphene_rect_t *bounds = &op->render.node->bounds;
|
||||
|
||||
op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
|
||||
render,
|
||||
uploader,
|
||||
start,
|
||||
&start->bounds,
|
||||
clip,
|
||||
&tex_bounds);
|
||||
get_tex_rect (&op->render.source_rect, &op->render.node->bounds, &tex_bounds);
|
||||
&op->render.source_rect);
|
||||
op->render.source_rect.origin.x = (bounds->origin.x - start->bounds.origin.x)/start->bounds.size.width;
|
||||
op->render.source_rect.origin.y = (bounds->origin.y - start->bounds.origin.y)/start->bounds.size.height;
|
||||
op->render.source_rect.size.width = bounds->size.width / start->bounds.size.width;
|
||||
op->render.source_rect.size.height = bounds->size.height / start->bounds.size.height;
|
||||
|
||||
op->render.source2 = gsk_vulkan_render_pass_get_node_as_texture (self,
|
||||
render,
|
||||
uploader,
|
||||
end,
|
||||
&end->bounds,
|
||||
clip,
|
||||
&tex_bounds);
|
||||
get_tex_rect (&op->render.source2_rect, &op->render.node->bounds, &tex_bounds);
|
||||
&op->render.source2_rect);
|
||||
op->render.source2_rect.origin.x = (bounds->origin.x - end->bounds.origin.x)/end->bounds.size.width;
|
||||
op->render.source2_rect.origin.y = (bounds->origin.y - end->bounds.origin.y)/end->bounds.size.height;
|
||||
op->render.source2_rect.size.width = bounds->size.width / end->bounds.size.width;
|
||||
op->render.source2_rect.size.height = bounds->size.height / end->bounds.size.height;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1381,23 +1390,31 @@ gsk_vulkan_render_pass_upload (GskVulkanRenderPass *self,
|
||||
{
|
||||
GskRenderNode *top = gsk_blend_node_get_top_child (op->render.node);
|
||||
GskRenderNode *bottom = gsk_blend_node_get_bottom_child (op->render.node);
|
||||
graphene_rect_t tex_bounds;
|
||||
const graphene_rect_t *bounds = &op->render.node->bounds;
|
||||
|
||||
op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
|
||||
render,
|
||||
uploader,
|
||||
top,
|
||||
&top->bounds,
|
||||
clip,
|
||||
&tex_bounds);
|
||||
get_tex_rect (&op->render.source_rect, &op->render.node->bounds, &tex_bounds);
|
||||
&op->render.source_rect);
|
||||
op->render.source_rect.origin.x = (bounds->origin.x - top->bounds.origin.x)/top->bounds.size.width;
|
||||
op->render.source_rect.origin.y = (bounds->origin.y - top->bounds.origin.y)/top->bounds.size.height;
|
||||
op->render.source_rect.size.width = bounds->size.width / top->bounds.size.width;
|
||||
op->render.source_rect.size.height = bounds->size.height / top->bounds.size.height;
|
||||
|
||||
op->render.source2 = gsk_vulkan_render_pass_get_node_as_texture (self,
|
||||
render,
|
||||
uploader,
|
||||
bottom,
|
||||
&bottom->bounds,
|
||||
clip,
|
||||
&tex_bounds);
|
||||
get_tex_rect (&op->render.source2_rect, &op->render.node->bounds, &tex_bounds);
|
||||
&op->render.source2_rect);
|
||||
op->render.source2_rect.origin.x = (bounds->origin.x - bottom->bounds.origin.x)/bottom->bounds.size.width;
|
||||
op->render.source2_rect.origin.y = (bounds->origin.y - bottom->bounds.origin.y)/bottom->bounds.size.height;
|
||||
op->render.source2_rect.size.width = bounds->size.width / bottom->bounds.size.width;
|
||||
op->render.source2_rect.size.height = bounds->size.height / bottom->bounds.size.height;
|
||||
}
|
||||
break;
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -227,7 +227,7 @@ gtk_application_impl_quartz_active_window_changed (GtkApplicationImpl *impl,
|
||||
* Without this, we might hold on to a reference of the window
|
||||
* preventing it from getting disposed.
|
||||
*/
|
||||
if (window != NULL && !g_object_get_data (G_OBJECT (window), "quartz-muxer-unmap"))
|
||||
if (window != NULL && !g_object_get_data (G_OBJECT (window), "quartz-muxer-umap"))
|
||||
{
|
||||
gulong handler_id = g_signal_connect_object (window,
|
||||
"unmap",
|
||||
|
@@ -102,10 +102,10 @@ gtk_css_filter_clear (GtkCssFilter *filter)
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_css_filter_init_identity (GtkCssFilter *filter,
|
||||
const GtkCssFilter *other)
|
||||
gtk_css_filter_init_identity (GtkCssFilter *filter,
|
||||
GtkCssFilterType type)
|
||||
{
|
||||
switch (other->type)
|
||||
switch (type)
|
||||
{
|
||||
case GTK_CSS_FILTER_BRIGHTNESS:
|
||||
filter->brightness.value = _gtk_css_number_value_new (1, GTK_CSS_NUMBER);
|
||||
@@ -135,7 +135,7 @@ gtk_css_filter_init_identity (GtkCssFilter *filter,
|
||||
filter->blur.value = _gtk_css_number_value_new (0, GTK_CSS_PX);
|
||||
break;
|
||||
case GTK_CSS_FILTER_DROP_SHADOW:
|
||||
filter->drop_shadow.value = gtk_css_shadow_value_new_filter (other->drop_shadow.value);
|
||||
filter->drop_shadow.value = gtk_css_shadow_value_new_filter ();
|
||||
break;
|
||||
case GTK_CSS_FILTER_NONE:
|
||||
default:
|
||||
@@ -143,7 +143,7 @@ gtk_css_filter_init_identity (GtkCssFilter *filter,
|
||||
break;
|
||||
}
|
||||
|
||||
filter->type = other->type;
|
||||
filter->type = type;
|
||||
}
|
||||
|
||||
#define R 0.2126
|
||||
@@ -464,7 +464,7 @@ gtk_css_value_filter_equal (const GtkCssValue *value1,
|
||||
{
|
||||
GtkCssFilter filter;
|
||||
|
||||
gtk_css_filter_init_identity (&filter, &larger->filters[i]);
|
||||
gtk_css_filter_init_identity (&filter, larger->filters[i].type);
|
||||
|
||||
if (!gtk_css_filter_equal (&larger->filters[i], &filter))
|
||||
{
|
||||
@@ -588,7 +588,7 @@ gtk_css_value_filter_transition (GtkCssValue *start,
|
||||
{
|
||||
GtkCssFilter filter;
|
||||
|
||||
gtk_css_filter_init_identity (&filter, &start->filters[i]);
|
||||
gtk_css_filter_init_identity (&filter, start->filters[i].type);
|
||||
gtk_css_filter_transition (&result->filters[i],
|
||||
&start->filters[i],
|
||||
&filter,
|
||||
@@ -600,7 +600,7 @@ gtk_css_value_filter_transition (GtkCssValue *start,
|
||||
{
|
||||
GtkCssFilter filter;
|
||||
|
||||
gtk_css_filter_init_identity (&filter, &end->filters[i]);
|
||||
gtk_css_filter_init_identity (&filter, end->filters[i].type);
|
||||
gtk_css_filter_transition (&result->filters[i],
|
||||
&filter,
|
||||
&end->filters[i],
|
||||
|
@@ -331,7 +331,7 @@ gtk_css_shadow_value_new (ShadowValue *shadows,
|
||||
}
|
||||
|
||||
GtkCssValue *
|
||||
gtk_css_shadow_value_new_filter (const GtkCssValue *other)
|
||||
gtk_css_shadow_value_new_filter (void)
|
||||
{
|
||||
ShadowValue value;
|
||||
|
||||
@@ -340,7 +340,7 @@ gtk_css_shadow_value_new_filter (const GtkCssValue *other)
|
||||
value.voffset = _gtk_css_number_value_new (0, GTK_CSS_NUMBER);
|
||||
value.radius = _gtk_css_number_value_new (0, GTK_CSS_NUMBER);
|
||||
value.spread = _gtk_css_number_value_new (0, GTK_CSS_NUMBER);
|
||||
value.color = gtk_css_value_ref (other->shadows[0].color);
|
||||
value.color = _gtk_css_color_value_new_current_color ();
|
||||
|
||||
return gtk_css_shadow_value_new (&value, 1, TRUE);
|
||||
}
|
||||
|
@@ -34,7 +34,7 @@
|
||||
G_BEGIN_DECLS
|
||||
|
||||
GtkCssValue * gtk_css_shadow_value_new_none (void);
|
||||
GtkCssValue * gtk_css_shadow_value_new_filter (const GtkCssValue *other);
|
||||
GtkCssValue * gtk_css_shadow_value_new_filter (void);
|
||||
|
||||
GtkCssValue * gtk_css_shadow_value_parse (GtkCssParser *parser,
|
||||
gboolean box_shadow_mode);
|
||||
|
@@ -637,10 +637,8 @@ gtk_init_check (void)
|
||||
* applications. It will initialize everything needed to operate the
|
||||
* toolkit.
|
||||
*
|
||||
* If you are using `GtkApplication`, you usually don't have to call this
|
||||
* function; the `GApplication::startup` handler does it for you. Though,
|
||||
* if you are using GApplication methods that will be invoked before `startup`,
|
||||
* such as `local_command_line`, you may need to initialize stuff explicitly.
|
||||
* If you are using `GtkApplication`, you don't have to call this
|
||||
* function; the `GApplication::startup` handler does it for you.
|
||||
*
|
||||
* This function will terminate your program if it was unable to
|
||||
* initialize the windowing system for some reason. If you want
|
||||
|
@@ -387,8 +387,7 @@ cairo_dep = dependency('cairo', version: cairo_req,
|
||||
default_options: ['zlib=enabled', 'tests=disabled'])
|
||||
cairogobj_dep = dependency('cairo-gobject', version: cairo_req)
|
||||
pango_dep = dependency('pango', version: pango_req)
|
||||
fribidi_dep = dependency('fribidi', version: fribidi_req,
|
||||
default_options: ['docs=false'])
|
||||
fribidi_dep = dependency('fribidi', version: fribidi_req)
|
||||
harfbuzz_dep = dependency('harfbuzz', version: harfbuzz_req,
|
||||
default_options: ['coretext=enabled'])
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
directory = fribidi
|
||||
url = https://github.com/fribidi/fribidi.git
|
||||
push-url = git@github.com:fribidi/fribidi.git
|
||||
revision = master
|
||||
revision = v1.0.12
|
||||
depth = 1
|
||||
|
||||
[provide]
|
||||
|
@@ -2,7 +2,6 @@
|
||||
directory = pango
|
||||
url = https://gitlab.gnome.org/GNOME/pango.git
|
||||
push-url = ssh://git@ssh.gitlab.gnome.org:GNOME/pango.git
|
||||
# needs to be main, because we build the nightly docs from the subproject
|
||||
revision = main
|
||||
depth = 1
|
||||
|
||||
|
@@ -37,7 +37,6 @@ test_rectangle_intersect (void)
|
||||
|
||||
/* non-empty, non-intersecting rectangles */
|
||||
res = gdk_rectangle_intersect (&e, &f, &f);
|
||||
g_assert_false (res);
|
||||
g_assert_cmpint (f.width, ==, 0);
|
||||
g_assert_cmpint (f.height, ==, 0);
|
||||
|
||||
|
@@ -114,8 +114,7 @@ compare_xfails = [
|
||||
|
||||
compare_xfails_small_texture = [
|
||||
'big-checkerboard',
|
||||
'big-checkerboard-scaled-down',
|
||||
'big-checkerboard-scaled-down2'
|
||||
'big-checkerboard-scaled-down'
|
||||
]
|
||||
|
||||
foreach renderer : renderers
|
||||
@@ -136,7 +135,7 @@ foreach renderer : renderers
|
||||
endif
|
||||
|
||||
if compare_xfails_small_texture.contains(testname)
|
||||
suites += 'wayland_gles_failing'
|
||||
suites += 'wayland_smalltexture_failing'
|
||||
endif
|
||||
|
||||
if ((exclude_term == '' or not testname.contains(exclude_term)) and
|
||||
|
@@ -104,6 +104,9 @@ tests = [
|
||||
{ 'name': 'revealer-size' },
|
||||
{ 'name': 'widgetorder' },
|
||||
{ 'name': 'widget-refcount' },
|
||||
# This test was disabled for long enough that it no longer compiles
|
||||
#{ 'name': 'window',
|
||||
# 'suites': ['failing'] },
|
||||
]
|
||||
|
||||
# Tests that test private apis and therefore are linked against libgtk-4.a
|
||||
|
248
testsuite/gtk/window.c
Normal file
248
testsuite/gtk/window.c
Normal file
@@ -0,0 +1,248 @@
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
#include <gdk/x11/gdkx.h>
|
||||
#include <X11/Xatom.h>
|
||||
#endif
|
||||
|
||||
static gboolean interactive = FALSE;
|
||||
|
||||
static gboolean
|
||||
stop_main (gpointer data)
|
||||
{
|
||||
gboolean *done = data;
|
||||
|
||||
*done = TRUE;
|
||||
|
||||
g_main_context_wakeup (NULL);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
on_draw (GtkDrawingArea *da,
|
||||
cairo_t *cr,
|
||||
int width,
|
||||
int height,
|
||||
gpointer data)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; 20 * i < width; i++)
|
||||
{
|
||||
for (j = 0; 20 * j < height; j++)
|
||||
{
|
||||
if ((i + j) % 2 == 1)
|
||||
cairo_set_source_rgb (cr, 1., 1., 1.);
|
||||
else
|
||||
cairo_set_source_rgb (cr, 0., 0., 0.);
|
||||
|
||||
cairo_rectangle (cr, 20. * i, 20. *j, 20., 20.);
|
||||
cairo_fill (cr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
on_keypress (GtkEventControllerKey *key,
|
||||
guint keyval,
|
||||
guint keycode,
|
||||
GdkModifierType state,
|
||||
gpointer data)
|
||||
{
|
||||
gboolean *done = data;
|
||||
|
||||
*done = TRUE;
|
||||
|
||||
g_main_context_wakeup (NULL);
|
||||
|
||||
return GDK_EVENT_PROPAGATE;
|
||||
}
|
||||
|
||||
static void
|
||||
test_default_size (void)
|
||||
{
|
||||
GtkWidget *window;
|
||||
GtkWidget *da;
|
||||
int w, h;
|
||||
gboolean done;
|
||||
|
||||
window = gtk_window_new ();
|
||||
if (interactive)
|
||||
{
|
||||
GtkEventController *controller = gtk_event_controller_key_new ();
|
||||
g_signal_connect (controller, "key-pressed", G_CALLBACK (on_keypress), &done);
|
||||
gtk_widget_add_controller (window, controller);
|
||||
}
|
||||
|
||||
da = gtk_drawing_area_new ();
|
||||
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (da), on_draw, NULL, NULL);
|
||||
gtk_window_set_child (GTK_WINDOW (window), da);
|
||||
|
||||
/* check that default size is unset initially */
|
||||
gtk_window_get_default_size (GTK_WINDOW (window), &w, &h);
|
||||
g_assert_cmpint (w, ==, -1);
|
||||
g_assert_cmpint (h, ==, -1);
|
||||
|
||||
/* check that setting default size before realize works */
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 300, 300);
|
||||
|
||||
gtk_window_get_default_size (GTK_WINDOW (window), &w, &h);
|
||||
g_assert_cmpint (w, ==, 300);
|
||||
g_assert_cmpint (h, ==, 300);
|
||||
|
||||
/* check that the window size is also reported accordingly */
|
||||
gtk_window_get_size (GTK_WINDOW (window), &w, &h);
|
||||
g_assert_cmpint (w, ==, 300);
|
||||
g_assert_cmpint (h, ==, 300);
|
||||
|
||||
gtk_window_present (GTK_WINDOW (window));
|
||||
|
||||
done = FALSE;
|
||||
if (!interactive)
|
||||
g_timeout_add (200, stop_main, &done);
|
||||
while (!done)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
|
||||
/* check that the window and its content actually gets the right size */
|
||||
gtk_window_get_size (GTK_WINDOW (window), &w, &h);
|
||||
g_assert_cmpint (w, ==, 300);
|
||||
g_assert_cmpint (h, ==, 300);
|
||||
|
||||
g_assert_cmpint (gtk_widget_get_allocated_width (da), ==, 300);
|
||||
g_assert_cmpint (gtk_widget_get_allocated_height (da), ==, 300);
|
||||
|
||||
/* check that setting default size after the fact does not change
|
||||
* window size
|
||||
*/
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 100, 600);
|
||||
gtk_window_get_default_size (GTK_WINDOW (window), &w, &h);
|
||||
g_assert_cmpint (w, ==, 100);
|
||||
g_assert_cmpint (h, ==, 600);
|
||||
|
||||
done = FALSE;
|
||||
if (!interactive)
|
||||
g_timeout_add (200, stop_main, &done);
|
||||
while (!done)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
|
||||
gtk_window_get_size (GTK_WINDOW (window), &w, &h);
|
||||
g_assert_cmpint (w, ==, 300);
|
||||
g_assert_cmpint (h, ==, 300);
|
||||
|
||||
/* check that even hide/show does not pull in the new default */
|
||||
gtk_widget_set_visible (window, FALSE);
|
||||
gtk_widget_set_visible (window, TRUE);
|
||||
|
||||
done = FALSE;
|
||||
if (!interactive)
|
||||
g_timeout_add (200, stop_main, &done);
|
||||
while (!done)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
|
||||
gtk_window_get_size (GTK_WINDOW (window), &w, &h);
|
||||
g_assert_cmpint (w, ==, 300);
|
||||
g_assert_cmpint (h, ==, 300);
|
||||
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
}
|
||||
|
||||
static void
|
||||
test_resize_popup (void)
|
||||
{
|
||||
GtkWidget *window;
|
||||
int w, h;
|
||||
gboolean done;
|
||||
|
||||
/* testcase for the dnd window */
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 1, 1);
|
||||
gtk_window_get_size (GTK_WINDOW (window), &w, &h);
|
||||
g_assert_cmpint (w, ==, 1);
|
||||
g_assert_cmpint (h, ==, 1);
|
||||
|
||||
gtk_window_present (GTK_WINDOW (window));
|
||||
|
||||
done = FALSE;
|
||||
if (!interactive)
|
||||
g_timeout_add (200, stop_main, &done);
|
||||
while (!done)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
|
||||
gtk_window_get_size (GTK_WINDOW (window), &w, &h);
|
||||
g_assert_cmpint (w, ==, 1);
|
||||
g_assert_cmpint (h, ==, 1);
|
||||
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
}
|
||||
|
||||
static void
|
||||
test_show_hide (void)
|
||||
{
|
||||
GtkWidget *window;
|
||||
int w, h, w1, h1;
|
||||
gboolean done;
|
||||
|
||||
/*http://bugzilla.gnome.org/show_bug.cgi?id=696882 */
|
||||
|
||||
/* test that hide/show does not affect the size */
|
||||
|
||||
window = gtk_window_new ();
|
||||
|
||||
gtk_window_present (GTK_WINDOW (window));
|
||||
|
||||
done = FALSE;
|
||||
if (!interactive)
|
||||
g_timeout_add (200, stop_main, &done);
|
||||
while (!done)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
|
||||
gtk_window_get_size (GTK_WINDOW (window), &w, &h);
|
||||
|
||||
gtk_widget_hide (window);
|
||||
|
||||
done = FALSE;
|
||||
if (!interactive)
|
||||
g_timeout_add (200, stop_main, &done);
|
||||
while (!done)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
|
||||
gtk_window_get_size (GTK_WINDOW (window), &w1, &h1);
|
||||
g_assert_cmpint (w, ==, w1);
|
||||
g_assert_cmpint (h, ==, h1);
|
||||
|
||||
gtk_window_present (GTK_WINDOW (window));
|
||||
|
||||
done = FALSE;
|
||||
if (!interactive)
|
||||
g_timeout_add (200, stop_main, &done);
|
||||
while (!done)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
|
||||
gtk_window_get_size (GTK_WINDOW (window), &w1, &h1);
|
||||
g_assert_cmpint (w, ==, w1);
|
||||
g_assert_cmpint (h, ==, h1);
|
||||
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
|
||||
gtk_test_init (&argc, &argv);
|
||||
|
||||
for (i = 0; i < argc; i++)
|
||||
{
|
||||
if (g_strcmp0 (argv[i], "--interactive") == 0)
|
||||
interactive = TRUE;
|
||||
}
|
||||
|
||||
g_test_add_func ("/window/default-size", test_default_size);
|
||||
g_test_add_func ("/window/resize-popup", test_resize_popup);
|
||||
g_test_add_func ("/window/show-hide", test_show_hide);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
@@ -1,586 +0,0 @@
|
||||
import sys
|
||||
import os
|
||||
import subprocess
|
||||
import gi
|
||||
|
||||
gi.require_version('Gdk', '4.0')
|
||||
gi.require_version('Gtk', '4.0')
|
||||
|
||||
from gi.repository import GLib, GObject, Gdk, Gtk
|
||||
from pydbus import SessionBus
|
||||
|
||||
verbose = True
|
||||
|
||||
remote_desktop = None
|
||||
screen_cast = None
|
||||
session = None
|
||||
stream_path = None
|
||||
done = False
|
||||
|
||||
def terminate():
|
||||
sys.exit(1)
|
||||
|
||||
loop = None
|
||||
|
||||
def quit_cb(loop):
|
||||
loop.quit()
|
||||
|
||||
def wait(millis):
|
||||
global loop
|
||||
loop = GLib.MainLoop()
|
||||
GLib.timeout_add(millis, quit_cb, loop)
|
||||
loop.run()
|
||||
|
||||
display = None
|
||||
window = None
|
||||
entry = None
|
||||
expected_change = None
|
||||
|
||||
def key_pressed_cb (controller, keyval, keycode, state):
|
||||
global expected_change
|
||||
global loop
|
||||
|
||||
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"
|
||||
|
||||
expected_change = None
|
||||
loop.quit()
|
||||
|
||||
def key_released_cb (controller, keyval, keycode, state):
|
||||
global expected_change
|
||||
global loop
|
||||
|
||||
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"
|
||||
|
||||
expected_change = None
|
||||
loop.quit()
|
||||
|
||||
def motion_cb (controller, x, y):
|
||||
global expected_change
|
||||
global loop
|
||||
|
||||
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"
|
||||
expected_change = None
|
||||
loop.quit()
|
||||
|
||||
def enter_cb (controller, x, y):
|
||||
global expected_change
|
||||
global loop
|
||||
|
||||
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"
|
||||
|
||||
expected_change = None
|
||||
loop.quit()
|
||||
|
||||
def pressed_cb(controller, n, x, y):
|
||||
global expected_change
|
||||
global loop
|
||||
|
||||
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"
|
||||
|
||||
expected_change = None
|
||||
loop.quit()
|
||||
|
||||
def released_cb(controller, n, x, y):
|
||||
global expected_change
|
||||
global loop
|
||||
|
||||
if verbose:
|
||||
print(f'got released')
|
||||
assert expected_change != None, "Unexpected event"
|
||||
assert expected_change['type'] == 'release', "Button release expected"
|
||||
|
||||
expected_change = None
|
||||
loop.quit()
|
||||
|
||||
def expect_key_press(keyval, state, timeout):
|
||||
global expected_change
|
||||
expected_change = {
|
||||
'type' : 'press',
|
||||
'keyval' : keyval,
|
||||
'state' : state
|
||||
}
|
||||
wait(timeout)
|
||||
assert expected_change == None, "Expected event did not happen"
|
||||
|
||||
def expect_key_release(keyval, state, timeout):
|
||||
global expected_change
|
||||
expected_change = {
|
||||
'type' : 'release',
|
||||
'keyval' : keyval,
|
||||
'state' : state
|
||||
}
|
||||
wait(timeout)
|
||||
assert expected_change == None, "Expected event did not happen"
|
||||
|
||||
def expect_motion(x, y, timeout):
|
||||
global expected_change
|
||||
expected_change = {
|
||||
'type' : 'motion',
|
||||
'x' : x,
|
||||
'y' : y
|
||||
}
|
||||
wait(timeout)
|
||||
assert expected_change == None, "Expected event did not happen"
|
||||
|
||||
def expect_enter(x, y, timeout):
|
||||
global expected_change
|
||||
expected_change = {
|
||||
'type' : 'enter',
|
||||
'x' : x,
|
||||
'y' : y
|
||||
}
|
||||
wait(timeout)
|
||||
assert expected_change == None, "Expected event did not happen"
|
||||
|
||||
def expect_button_press(button, x, y, timeout):
|
||||
global expected_change
|
||||
expected_change = {
|
||||
'type' : 'press',
|
||||
'button' : button,
|
||||
'x' : x,
|
||||
'y' : y
|
||||
}
|
||||
wait(timeout)
|
||||
assert expected_change == None, "Button press did not arrive"
|
||||
|
||||
def expect_button_release(button, x, y, timeout):
|
||||
global expected_change
|
||||
expected_change = {
|
||||
'type' : 'release',
|
||||
'button' : button,
|
||||
'x' : x,
|
||||
'y' : y
|
||||
}
|
||||
wait(timeout)
|
||||
assert expected_change == None, "Button release did not arrive"
|
||||
|
||||
def got_active(object, pspec):
|
||||
global loop
|
||||
object.disconnect_by_func(got_active)
|
||||
loop.quit()
|
||||
|
||||
def launch_observer():
|
||||
global display
|
||||
global window
|
||||
|
||||
if verbose:
|
||||
print('launch observer')
|
||||
|
||||
if display == None:
|
||||
display = Gdk.Display.open(os.getenv('WAYLAND_DISPLAY'))
|
||||
|
||||
window = Gtk.Window.new()
|
||||
|
||||
controller = Gtk.EventControllerKey.new()
|
||||
controller.set_propagation_phase(Gtk.PropagationPhase.CAPTURE)
|
||||
controller.connect('key-pressed', key_pressed_cb)
|
||||
controller.connect('key-released', key_released_cb)
|
||||
window.add_controller(controller)
|
||||
|
||||
controller = Gtk.EventControllerMotion.new()
|
||||
controller.set_propagation_phase(Gtk.PropagationPhase.CAPTURE)
|
||||
controller.connect('enter', enter_cb)
|
||||
controller.connect('motion', motion_cb)
|
||||
window.add_controller(controller)
|
||||
|
||||
controller = Gtk.GestureClick.new()
|
||||
controller.set_propagation_phase(Gtk.PropagationPhase.CAPTURE)
|
||||
controller.connect('pressed', pressed_cb)
|
||||
controller.connect('released', released_cb)
|
||||
window.add_controller(controller)
|
||||
|
||||
window.connect('notify::is-active', got_active)
|
||||
window.maximize()
|
||||
window.present()
|
||||
|
||||
wait(500)
|
||||
|
||||
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)
|
||||
|
||||
def launch_entry():
|
||||
global display
|
||||
global window
|
||||
global entry
|
||||
|
||||
if verbose:
|
||||
print('launch entry')
|
||||
|
||||
if display == None:
|
||||
display = Gdk.Display.open(os.getenv('WAYLAND_DISPLAY'))
|
||||
|
||||
window = Gtk.Window.new()
|
||||
|
||||
entry = Gtk.Entry.new()
|
||||
|
||||
window.set_child(entry)
|
||||
|
||||
window.connect('notify::is-active', got_active)
|
||||
window.maximize()
|
||||
window.present()
|
||||
|
||||
wait(500)
|
||||
|
||||
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)
|
||||
|
||||
def stop_observer():
|
||||
global window
|
||||
window.destroy()
|
||||
window = None
|
||||
|
||||
def expect_entry_text(text):
|
||||
assert text == entry.get_text(), "Unexpected entry text: " + entry.get_text()
|
||||
|
||||
def key_press(keyval):
|
||||
if verbose:
|
||||
print(f'press key {keyval}')
|
||||
session.NotifyKeyboardKeysym(keyval, True)
|
||||
|
||||
def key_release(keyval):
|
||||
if verbose:
|
||||
print(f'release key {keyval}')
|
||||
session.NotifyKeyboardKeysym(keyval, False)
|
||||
|
||||
buttons = {
|
||||
1 : 0x110,
|
||||
2 : 0x111,
|
||||
3 : 0x112
|
||||
}
|
||||
|
||||
def button_press(button):
|
||||
if verbose:
|
||||
print(f'press button {button}')
|
||||
session.NotifyPointerButton(buttons[button], True)
|
||||
|
||||
def button_release(button):
|
||||
if verbose:
|
||||
print(f'release button {button}')
|
||||
session.NotifyPointerButton(buttons[button], False)
|
||||
|
||||
def pointer_move(x, y):
|
||||
if verbose:
|
||||
print(f'pointer move {x} {y}')
|
||||
session.NotifyPointerMotionAbsolute(stream_path, x, y)
|
||||
|
||||
def basic_keyboard_tests():
|
||||
try:
|
||||
launch_observer()
|
||||
|
||||
key_press(Gdk.KEY_a)
|
||||
expect_key_press(keyval=Gdk.KEY_a, state=0, timeout=100)
|
||||
|
||||
key_release(Gdk.KEY_a)
|
||||
expect_key_release(keyval=Gdk.KEY_a, state=0, timeout=100)
|
||||
|
||||
key_press(Gdk.KEY_Control_L)
|
||||
expect_key_press(keyval=Gdk.KEY_Control_L, state=0, timeout=100)
|
||||
|
||||
key_press(Gdk.KEY_x)
|
||||
expect_key_press(keyval=Gdk.KEY_x, state=Gdk.ModifierType.CONTROL_MASK, timeout=100)
|
||||
|
||||
key_release(Gdk.KEY_Control_L)
|
||||
expect_key_release(keyval=Gdk.KEY_Control_L, state=Gdk.ModifierType.CONTROL_MASK, timeout=100)
|
||||
|
||||
key_release(Gdk.KEY_x)
|
||||
expect_key_release(keyval=Gdk.KEY_x, state=0, timeout=100)
|
||||
|
||||
stop_observer()
|
||||
except AssertionError as e:
|
||||
print("Error in basic_keyboard_tests: {0}".format(e))
|
||||
terminate()
|
||||
|
||||
def quick_typing_test():
|
||||
try:
|
||||
launch_entry()
|
||||
|
||||
key_press(Gdk.KEY_T)
|
||||
key_release(Gdk.KEY_T)
|
||||
key_press(Gdk.KEY_e)
|
||||
key_release(Gdk.KEY_e)
|
||||
key_press(Gdk.KEY_s)
|
||||
key_release(Gdk.KEY_s)
|
||||
key_press(Gdk.KEY_t)
|
||||
key_release(Gdk.KEY_t)
|
||||
|
||||
wait(100)
|
||||
expect_entry_text("Test")
|
||||
|
||||
stop_observer()
|
||||
except AssertionError as e:
|
||||
print("Error in quick_typing_test: {0}".format(e))
|
||||
terminate()
|
||||
|
||||
def basic_pointer_tests():
|
||||
try:
|
||||
pointer_move(-100.0, -100.0)
|
||||
launch_observer()
|
||||
|
||||
# observer window is maximized, so window coords == global coords
|
||||
pointer_move(500.0, 300.0)
|
||||
expect_enter(x=500, y=300, timeout=200)
|
||||
|
||||
pointer_move(400.0, 200.0)
|
||||
expect_motion(x=400, y=200, timeout=200)
|
||||
|
||||
button_press(1)
|
||||
expect_button_press(button=1, x=400, y=200, timeout=200)
|
||||
|
||||
pointer_move(220.0, 200.0)
|
||||
expect_motion(x=220, y=200, timeout=200)
|
||||
|
||||
button_release(1)
|
||||
expect_button_release(button=1, x=220, y=200, timeout=200)
|
||||
|
||||
stop_observer()
|
||||
except AssertionError as e:
|
||||
print("Error in basic_pointer_tests: {0}".format(e))
|
||||
terminate()
|
||||
|
||||
ds_window = None
|
||||
ds = None
|
||||
|
||||
def drag_begin(controller, drag):
|
||||
global expected_change
|
||||
global loop
|
||||
|
||||
if verbose:
|
||||
print(f'got drag begin')
|
||||
assert expected_change != None, "Unexpected drag begin"
|
||||
assert expected_change['type'] == 'drag', "Drag begin expected"
|
||||
|
||||
expected_change = None
|
||||
loop.quit()
|
||||
|
||||
def launch_drag_source(value):
|
||||
global display
|
||||
global ds_window
|
||||
global ds
|
||||
|
||||
if verbose:
|
||||
print('launch drag source')
|
||||
|
||||
if display == None:
|
||||
display = Gdk.Display.open(os.getenv('WAYLAND_DISPLAY'))
|
||||
|
||||
ds_window = Gtk.Window.new()
|
||||
ds_window.set_title('Drag Source')
|
||||
|
||||
ds = Gtk.DragSource.new()
|
||||
ds.set_content(Gdk.ContentProvider.new_for_value(value))
|
||||
ds_window.add_controller(ds)
|
||||
ds.connect('drag-begin', drag_begin)
|
||||
|
||||
controller = Gtk.GestureClick.new()
|
||||
controller.set_propagation_phase(Gtk.PropagationPhase.CAPTURE)
|
||||
controller.connect('pressed', pressed_cb)
|
||||
controller.connect('released', released_cb)
|
||||
ds_window.add_controller(controller)
|
||||
|
||||
ds_window.connect('notify::is-active', got_active)
|
||||
ds_window.maximize()
|
||||
ds_window.present()
|
||||
|
||||
wait(500)
|
||||
|
||||
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)
|
||||
|
||||
def stop_drag_source():
|
||||
global ds_window
|
||||
ds_window.destroy()
|
||||
ds_window = None
|
||||
|
||||
dt_window = None
|
||||
|
||||
def do_drop(controller, value, x, y):
|
||||
global expected_change
|
||||
global loop
|
||||
|
||||
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"
|
||||
|
||||
expected_change = None
|
||||
loop.quit()
|
||||
|
||||
def launch_drop_target():
|
||||
global display
|
||||
global dt_window
|
||||
|
||||
if verbose:
|
||||
print('launch drop target')
|
||||
|
||||
if display == None:
|
||||
display = Gdk.Display.open(os.getenv('WAYLAND_DISPLAY'))
|
||||
|
||||
dt_window = Gtk.Window.new()
|
||||
dt_window.set_title('Drop Target')
|
||||
|
||||
controller = Gtk.DropTarget.new(GObject.TYPE_STRING, Gdk.DragAction.COPY)
|
||||
dt_window.add_controller(controller)
|
||||
controller.connect('drop', do_drop)
|
||||
|
||||
dt_window.connect('notify::is-active', got_active)
|
||||
dt_window.maximize()
|
||||
dt_window.present()
|
||||
|
||||
wait(500)
|
||||
|
||||
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)
|
||||
|
||||
def stop_drop_target():
|
||||
global dt_window
|
||||
dt_window.destroy()
|
||||
dt_window = None
|
||||
|
||||
def expect_drag(timeout):
|
||||
global expected_change
|
||||
expected_change = {
|
||||
'type' : 'drag',
|
||||
}
|
||||
wait(timeout)
|
||||
assert expected_change == None, "DND operation not started"
|
||||
|
||||
def expect_drop(value, timeout):
|
||||
global expected_change
|
||||
expected_change = {
|
||||
'type' : 'drop',
|
||||
'value' : value
|
||||
}
|
||||
wait(timeout)
|
||||
assert expected_change == None, "Drop has not happened"
|
||||
|
||||
def dnd_tests():
|
||||
try:
|
||||
pointer_move(-100, -100)
|
||||
|
||||
launch_drag_source('abc')
|
||||
wait(100);
|
||||
|
||||
pointer_move(100, 100)
|
||||
wait(100);
|
||||
button_press(1)
|
||||
expect_button_press(button=1, x=100, y=100, timeout=300)
|
||||
# need to wait out the MIN_TIME_TO_DND
|
||||
wait(150)
|
||||
|
||||
pointer_move(120, 150)
|
||||
expect_drag(timeout=1000)
|
||||
|
||||
launch_drop_target()
|
||||
wait(100);
|
||||
button_release(1)
|
||||
expect_drop('abc', timeout=2000)
|
||||
|
||||
stop_drop_target()
|
||||
stop_drag_source()
|
||||
except AssertionError as e:
|
||||
print("Error in dnd_tests: {0}".format(e))
|
||||
terminate()
|
||||
|
||||
def session_closed_cb():
|
||||
print('Session closed')
|
||||
|
||||
def mutter_appeared(name):
|
||||
global remote_desktop
|
||||
global session
|
||||
global stream_path
|
||||
global done
|
||||
|
||||
if verbose:
|
||||
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"
|
||||
|
||||
screen_cast = bus.get('org.gnome.Mutter.ScreenCast',
|
||||
'/org/gnome/Mutter/ScreenCast')
|
||||
|
||||
session_path = remote_desktop.CreateSession()
|
||||
session = bus.get('org.gnome.Mutter.RemoteDesktop', session_path)
|
||||
session.onClosed = session_closed_cb
|
||||
|
||||
screen_cast_session_path = screen_cast.CreateSession({ 'remote-desktop-session-id' : GLib.Variant('s', session.SessionId)})
|
||||
screen_cast_session = bus.get('org.gnome.Mutter.ScreenCast', screen_cast_session_path)
|
||||
|
||||
stream_path = screen_cast_session.RecordMonitor('Meta-0', {})
|
||||
session.Start()
|
||||
|
||||
# work around lack of initial devices
|
||||
key_press(Gdk.KEY_Control_L)
|
||||
key_release(Gdk.KEY_Control_L)
|
||||
pointer_move(-100, -100)
|
||||
|
||||
basic_keyboard_tests()
|
||||
basic_pointer_tests()
|
||||
dnd_tests()
|
||||
quick_typing_test()
|
||||
|
||||
session.Stop()
|
||||
|
||||
done = True
|
||||
|
||||
def mutter_vanished():
|
||||
global done
|
||||
if remote_desktop != None:
|
||||
if verbose:
|
||||
print("mutter left the bus")
|
||||
done = True
|
||||
|
||||
bus = SessionBus()
|
||||
bus.watch_name('org.gnome.Mutter.RemoteDesktop', 0, mutter_appeared, mutter_vanished)
|
||||
|
||||
try:
|
||||
while not done:
|
||||
GLib.MainContext.default().iteration(True)
|
||||
except KeyboardInterrupt:
|
||||
print('Interrupted')
|
@@ -1,193 +0,0 @@
|
||||
import sys
|
||||
import os
|
||||
import subprocess
|
||||
import gi
|
||||
|
||||
gi.require_version('Gdk', '4.0')
|
||||
|
||||
from gi.repository import GLib, Gdk
|
||||
from pydbus import SessionBus
|
||||
|
||||
verbose = True
|
||||
|
||||
screen_cast = None
|
||||
monitors = {}
|
||||
waiting = False
|
||||
done = False
|
||||
monitor_model = None
|
||||
display = None
|
||||
|
||||
def terminate():
|
||||
for key in monitors:
|
||||
monitor = monitors[key];
|
||||
pipeline = monitor['pipeline'];
|
||||
pipeline.terminate()
|
||||
sys.exit(1)
|
||||
|
||||
def stream_added_closure(name):
|
||||
def stream_added(node_id):
|
||||
monitor = monitors[name];
|
||||
|
||||
freq = monitor['freq'];
|
||||
width = monitor['width'];
|
||||
height = monitor['height'];
|
||||
# FIXME scale = monitor['scale'];
|
||||
|
||||
# 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'
|
||||
if verbose:
|
||||
print(f'launching {pipeline_desc}')
|
||||
monitor['pipeline'] = subprocess.Popen([pipeline_desc], shell=True)
|
||||
|
||||
return stream_added
|
||||
|
||||
def add_monitor(name, width, height, scale, freq):
|
||||
if verbose:
|
||||
print(f'add monitor {name}: {width}x{height}, scale {scale}, frequency {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
|
||||
}
|
||||
stream_path = session.RecordVirtual({})
|
||||
stream = bus.get('org.gnome.Mutter.ScreenCast', stream_path)
|
||||
stream.onPipeWireStreamAdded = stream_added_closure(name)
|
||||
session.Start()
|
||||
|
||||
def remove_monitor(name):
|
||||
if verbose:
|
||||
print(f'remove monitor {name}')
|
||||
try:
|
||||
monitor = monitors[name];
|
||||
pipeline = monitor['pipeline']
|
||||
pipeline.kill()
|
||||
session = monitor['session']
|
||||
session.Stop()
|
||||
except KeyError:
|
||||
print("failed to remove monitor")
|
||||
monitors[name] = None
|
||||
|
||||
expected_change = None
|
||||
loop = None
|
||||
|
||||
def quit_cb(loop):
|
||||
loop.quit()
|
||||
|
||||
def wait(millis):
|
||||
global loop
|
||||
loop = GLib.MainLoop()
|
||||
GLib.timeout_add(millis, quit_cb, loop)
|
||||
loop.run()
|
||||
|
||||
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"
|
||||
|
||||
if verbose:
|
||||
print('got expected change')
|
||||
|
||||
expected_change = None
|
||||
loop.quit()
|
||||
|
||||
def launch_observer():
|
||||
global monitor_model
|
||||
global display
|
||||
|
||||
if display == None:
|
||||
display = Gdk.Display.open(os.getenv('WAYLAND_DISPLAY'))
|
||||
|
||||
if verbose:
|
||||
print('launch observer')
|
||||
|
||||
monitor_model = display.get_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):
|
||||
global expected_change
|
||||
expected_change = {
|
||||
'position' : position,
|
||||
'removed' : removed,
|
||||
'added' : added
|
||||
}
|
||||
wait(timeout)
|
||||
assert expected_change == None, "Expected change did not happen"
|
||||
|
||||
def got_connector(monitor, pspec):
|
||||
loop.quit()
|
||||
|
||||
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:
|
||||
handler = monitor.connect('notify::connector', got_connector)
|
||||
wait(500)
|
||||
monitor.disconnect(handler)
|
||||
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"
|
||||
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()}\'')
|
||||
|
||||
def run_commands():
|
||||
try:
|
||||
launch_observer()
|
||||
|
||||
add_monitor("0", width=100, height=100, scale=1, freq=60)
|
||||
expect_monitors_changed(0, 0, 1, 5000)
|
||||
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)
|
||||
expect_monitor (position=1, width=1024, height=768, scale=1, freq=144000)
|
||||
|
||||
remove_monitor("0")
|
||||
expect_monitors_changed(0, 1, 0, 11000) # mutter takes 10 seconds to remove it
|
||||
|
||||
remove_monitor("1")
|
||||
expect_monitors_changed(0, 1, 0, 11000)
|
||||
except AssertionError as e:
|
||||
print("Error: {0}".format(e))
|
||||
terminate()
|
||||
|
||||
def mutter_appeared(name):
|
||||
global screen_cast
|
||||
global done
|
||||
if verbose:
|
||||
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...")
|
||||
done = True
|
||||
|
||||
def mutter_vanished():
|
||||
global done
|
||||
if screen_cast != None:
|
||||
if verbose:
|
||||
print("mutter left the bus")
|
||||
done = True
|
||||
|
||||
bus = SessionBus()
|
||||
bus.watch_name('org.gnome.Mutter.ScreenCast', 0, mutter_appeared, mutter_vanished)
|
||||
|
||||
try:
|
||||
while not done:
|
||||
GLib.MainContext.default().iteration(True)
|
||||
except KeyboardInterrupt:
|
||||
print('Interrupted')
|
@@ -1,19 +0,0 @@
|
||||
env = environment()
|
||||
env.prepend('GI_TYPELIB_PATH',
|
||||
project_build_root / 'gtk',
|
||||
gi_dep.get_variable(pkgconfig: 'typelibdir'),
|
||||
)
|
||||
env.prepend('LD_PRELOAD', project_build_root / 'gtk' / 'libgtk-4.so')
|
||||
env.prepend('MESON_CURRENT_SOURCE_DIR', meson.current_source_dir())
|
||||
|
||||
test('monitor',
|
||||
find_program('run-headless-monitor-tests.sh', dirs: meson.current_source_dir()),
|
||||
suite: ['headless'],
|
||||
env: env,
|
||||
)
|
||||
|
||||
test('input',
|
||||
find_program('run-headless-input-tests.sh', dirs: meson.current_source_dir()),
|
||||
suite: ['headless'],
|
||||
env: env,
|
||||
)
|
@@ -1,36 +0,0 @@
|
||||
#! /bin/sh
|
||||
|
||||
srcdir=${MESON_CURRENT_SOURCE_DIR:-./testsuite/headless}
|
||||
|
||||
dbus-run-session sh <<EOF
|
||||
|
||||
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 &
|
||||
mutter_pid=\$!
|
||||
|
||||
export WAYLAND_DISPLAY=gtk-test2
|
||||
export GDK_BACKEND=wayland
|
||||
|
||||
python3 ${srcdir}/headless-input-tests.py
|
||||
status=\$?
|
||||
|
||||
kill \$mutter_pid
|
||||
kill \$wireplumber_pid
|
||||
kill \$pipewire_pid
|
||||
|
||||
exit \$status
|
||||
|
||||
EOF
|
@@ -1,42 +0,0 @@
|
||||
#! /bin/sh
|
||||
|
||||
srcdir=${MESON_CURRENT_SOURCE_DIR:-./testsuite/headless}
|
||||
|
||||
export GTK_A11Y=none
|
||||
export GIO_USE_VFS=local
|
||||
|
||||
dbus-run-session sh <<EOF
|
||||
|
||||
export XDG_RUNTIME_DIR="$(mktemp -p $(pwd) -d xdg-runtime-XXXXXX)"
|
||||
|
||||
pipewire &
|
||||
pipewire_pid=\$!
|
||||
sleep 2
|
||||
|
||||
wireplumber &
|
||||
wireplumber_pid=\$!
|
||||
sleep 2
|
||||
|
||||
# echo DBUS_SESSION_BUS_ADDRESS=\$DBUS_SESSION_BUS_ADDRESS
|
||||
# echo WAYLAND_DISPLAY=gtk-test
|
||||
|
||||
export MUTTER_DEBUG=screen-cast
|
||||
|
||||
mutter --headless --no-x11 --wayland-display gtk-test &
|
||||
mutter_pid=\$!
|
||||
|
||||
sleep 2
|
||||
|
||||
export WAYLAND_DISPLAY=gtk-test
|
||||
export GDK_BACKEND=wayland
|
||||
|
||||
python3 ${srcdir}/headless-monitor-tests.py
|
||||
status=\$?
|
||||
|
||||
kill \$mutter_pid
|
||||
kill \$wireplumber_pid
|
||||
kill \$pipewire_pid
|
||||
|
||||
exit \$status
|
||||
|
||||
EOF
|
@@ -20,10 +20,12 @@ setups = [
|
||||
'env': ['GDK_DEBUG=gl-gles,default-settings',
|
||||
'MESA_GLES_VERSION_OVERRIDE=2.0',
|
||||
'MESA_EXTENSION_OVERRIDE=-GL_OES_vertex_array_object',
|
||||
'GSK_MAX_TEXTURE_SIZE=1024',
|
||||
], },
|
||||
{ 'backend': 'win32', 'if': os_win32 },
|
||||
{ 'backend': 'broadway', 'if': broadway_enabled, },
|
||||
{ 'name': 'wayland_smalltexture',
|
||||
'backend': 'wayland', 'if': wayland_enabled,
|
||||
'env': ['GSK_MAX_TEXTURE_SIZE=1024'] },
|
||||
{ 'backend': 'win32', 'if': os_win32 },
|
||||
]
|
||||
|
||||
@@ -37,8 +39,8 @@ foreach setup : setups
|
||||
exclude += 'gsk-compare-broadway'
|
||||
endif
|
||||
|
||||
if name == 'wayland_gles'
|
||||
exclude += 'wayland_gles_failing'
|
||||
if name == 'wayland_smalltexture'
|
||||
exclude += 'wayland_smalltexture_failing'
|
||||
endif
|
||||
|
||||
env = common_env + [
|
||||
@@ -68,9 +70,7 @@ subdir('css')
|
||||
subdir('a11y')
|
||||
subdir('tools')
|
||||
subdir('reftests')
|
||||
|
||||
if build_gir
|
||||
subdir('introspection')
|
||||
endif
|
||||
if wayland_enabled
|
||||
subdir('headless')
|
||||
endif
|
||||
|
Reference in New Issue
Block a user