Locking windows on monitor
Resolves: https://issues.redhat.com/browse/RHEL-155379
This commit is contained in:
parent
d7457fe9e0
commit
91299a5f68
124
0001-window-Add-a-map-inhibit-API.patch
Normal file
124
0001-window-Add-a-map-inhibit-API.patch
Normal file
@ -0,0 +1,124 @@
|
||||
From 362fe3dd06395405160114d76b35099ba9e79e2d Mon Sep 17 00:00:00 2001
|
||||
From: Olivier Fourdan <ofourdan@redhat.com>
|
||||
Date: Tue, 30 Sep 2025 14:35:37 +0200
|
||||
Subject: [PATCH 1/7] window: Add a map inhibit API
|
||||
|
||||
A compositor (such as GNOME Kiosk) may need to prevent windows from
|
||||
showing on screen for various reasons, yet there is no appropriate API
|
||||
to tell mutter that a window that could be mapped on screen should not
|
||||
actually show up.
|
||||
|
||||
To solve that problem, add a new API that allows to caller to inhibit
|
||||
mapping windows.
|
||||
|
||||
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4692>
|
||||
(cherry picked from commit 6f77df353a48dc394e1921d29bfd1175ffd09575)
|
||||
---
|
||||
src/core/window.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
src/meta/window.h | 9 ++++++++
|
||||
2 files changed, 63 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/core/window.c b/src/core/window.c
|
||||
index 8f44f60d22..b7b62fbda5 100644
|
||||
--- a/src/core/window.c
|
||||
+++ b/src/core/window.c
|
||||
@@ -191,6 +191,8 @@ typedef struct _MetaWindowPrivate
|
||||
gboolean is_queued;
|
||||
guint idle_handle_id;
|
||||
} auto_maximize;
|
||||
+
|
||||
+ unsigned int mapped_inhibit_count;
|
||||
} MetaWindowPrivate;
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (MetaWindow, meta_window, G_TYPE_OBJECT,
|
||||
@@ -1757,6 +1759,7 @@ meta_window_showing_on_its_workspace (MetaWindow *window)
|
||||
gboolean showing;
|
||||
gboolean is_desktop_or_dock;
|
||||
MetaWorkspace *workspace_of_window;
|
||||
+ MetaWindowPrivate *priv = meta_window_get_instance_private (window);
|
||||
|
||||
showing = TRUE;
|
||||
|
||||
@@ -1764,7 +1767,11 @@ meta_window_showing_on_its_workspace (MetaWindow *window)
|
||||
if (window->minimized)
|
||||
showing = FALSE;
|
||||
|
||||
- /* 2. See if we're in "show desktop" mode */
|
||||
+ /* 2. See if mapping state is inhibited */
|
||||
+ if (priv->mapped_inhibit_count > 0)
|
||||
+ showing = FALSE;
|
||||
+
|
||||
+ /* 3. See if we're in "show desktop" mode */
|
||||
is_desktop_or_dock = FALSE;
|
||||
is_desktop_or_dock_foreach (window,
|
||||
&is_desktop_or_dock);
|
||||
@@ -8700,3 +8707,49 @@ meta_window_show_in_window_list (MetaWindow *window)
|
||||
window->skip_from_window_list = FALSE;
|
||||
meta_window_recalc_features (window);
|
||||
}
|
||||
+
|
||||
+/**
|
||||
+ * meta_window_inhibit_mapped
|
||||
+ * @window: A #MetaWindow
|
||||
+ *
|
||||
+ * Inhibits the mapped state of the window.
|
||||
+ */
|
||||
+void
|
||||
+meta_window_inhibit_mapped (MetaWindow *window)
|
||||
+{
|
||||
+ MetaWindowPrivate *priv = meta_window_get_instance_private (window);
|
||||
+
|
||||
+ if (++priv->mapped_inhibit_count == 1)
|
||||
+ meta_window_queue (window, META_QUEUE_CALC_SHOWING);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * meta_window_uninhibit_mapped
|
||||
+ * @window: A #MetaWindow
|
||||
+ *
|
||||
+ * Uninhibits the mapped state of the window.
|
||||
+ */
|
||||
+void
|
||||
+meta_window_uninhibit_mapped (MetaWindow *window)
|
||||
+{
|
||||
+ MetaWindowPrivate *priv = meta_window_get_instance_private (window);
|
||||
+
|
||||
+ g_return_if_fail (priv->mapped_inhibit_count > 0);
|
||||
+
|
||||
+ if (--priv->mapped_inhibit_count == 0)
|
||||
+ meta_window_queue (window, META_QUEUE_CALC_SHOWING);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * meta_window_is_mapped_inhibited
|
||||
+ * @window: A #MetaWindow
|
||||
+ *
|
||||
+ * Returns whether the mapped state of the window is inhibited.
|
||||
+ */
|
||||
+gboolean
|
||||
+meta_window_is_mapped_inhibited (MetaWindow *window)
|
||||
+{
|
||||
+ MetaWindowPrivate *priv = meta_window_get_instance_private (window);
|
||||
+
|
||||
+ return priv->mapped_inhibit_count > 0;
|
||||
+}
|
||||
diff --git a/src/meta/window.h b/src/meta/window.h
|
||||
index 9670987843..4f6390f0a1 100644
|
||||
--- a/src/meta/window.h
|
||||
+++ b/src/meta/window.h
|
||||
@@ -460,3 +460,12 @@ void meta_window_set_maximize_flags (MetaWindow *window,
|
||||
META_EXPORT
|
||||
void meta_window_set_unmaximize_flags (MetaWindow *window,
|
||||
MetaMaximizeFlags directions);
|
||||
+
|
||||
+META_EXPORT
|
||||
+void meta_window_inhibit_mapped (MetaWindow *window);
|
||||
+
|
||||
+META_EXPORT
|
||||
+void meta_window_uninhibit_mapped (MetaWindow *window);
|
||||
+
|
||||
+META_EXPORT
|
||||
+gboolean meta_window_is_mapped_inhibited (MetaWindow *window);
|
||||
--
|
||||
2.53.0
|
||||
|
||||
326
0002-tests-Add-tests-for-map-inhibit.patch
Normal file
326
0002-tests-Add-tests-for-map-inhibit.patch
Normal file
@ -0,0 +1,326 @@
|
||||
From faf8b0a563b4078a990337811e1c97b0de9f1971 Mon Sep 17 00:00:00 2001
|
||||
From: Olivier Fourdan <ofourdan@redhat.com>
|
||||
Date: Tue, 30 Sep 2025 17:48:51 +0200
|
||||
Subject: [PATCH 2/7] tests: Add tests for map inhibit
|
||||
|
||||
Test basic functionality of the API.
|
||||
|
||||
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4692>
|
||||
(cherry picked from commit 92b21b8c0119df74ccd1f01737b9be3ea9fa223a)
|
||||
---
|
||||
src/tests/meson.build | 8 +
|
||||
src/tests/window-mapped-inhibit-tests.c | 283 ++++++++++++++++++++++++
|
||||
2 files changed, 291 insertions(+)
|
||||
create mode 100644 src/tests/window-mapped-inhibit-tests.c
|
||||
|
||||
diff --git a/src/tests/meson.build b/src/tests/meson.build
|
||||
index 8c3773033f..8c824b5752 100644
|
||||
--- a/src/tests/meson.build
|
||||
+++ b/src/tests/meson.build
|
||||
@@ -955,6 +955,14 @@ wayland_test_cases = [
|
||||
wayland_test_utils,
|
||||
],
|
||||
},
|
||||
+ {
|
||||
+ 'name': 'window-mapped-inhibit',
|
||||
+ 'suite': 'wayland',
|
||||
+ 'sources': [
|
||||
+ 'window-mapped-inhibit-tests.c',
|
||||
+ wayland_test_utils,
|
||||
+ ],
|
||||
+ },
|
||||
{
|
||||
'name': 'viewport-tests',
|
||||
'suite': 'wayland',
|
||||
diff --git a/src/tests/window-mapped-inhibit-tests.c b/src/tests/window-mapped-inhibit-tests.c
|
||||
new file mode 100644
|
||||
index 0000000000..0b297e94ce
|
||||
--- /dev/null
|
||||
+++ b/src/tests/window-mapped-inhibit-tests.c
|
||||
@@ -0,0 +1,283 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2025 Red Hat Inc.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License as
|
||||
+ * published by the Free Software Foundation; either version 2 of the
|
||||
+ * License, or (at your option) any later version.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License
|
||||
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+#include "config.h"
|
||||
+
|
||||
+#include <glib.h>
|
||||
+
|
||||
+#include "core/window-private.h"
|
||||
+#include "meta-test/meta-context-test.h"
|
||||
+#include "tests/meta-test-utils.h"
|
||||
+#include "tests/meta-wayland-test-driver.h"
|
||||
+#include "tests/meta-wayland-test-utils.h"
|
||||
+#include "wayland/meta-wayland.h"
|
||||
+
|
||||
+static MetaContext *test_context;
|
||||
+static MetaWaylandTestDriver *test_driver;
|
||||
+static MetaVirtualMonitor *virtual_monitor;
|
||||
+
|
||||
+#define TEST_CLIENT_TITLE "window-mapped-inhibit-test-window"
|
||||
+
|
||||
+static void
|
||||
+wait_for_condition (gboolean (*condition_func) (gpointer),
|
||||
+ gpointer user_data)
|
||||
+{
|
||||
+ while (!condition_func (user_data))
|
||||
+ g_main_context_iteration (NULL, TRUE);
|
||||
+}
|
||||
+
|
||||
+static gboolean
|
||||
+window_is_not_hidden (gpointer user_data)
|
||||
+{
|
||||
+ MetaWindow *window = (MetaWindow *) user_data;
|
||||
+ return !meta_window_is_hidden (window);
|
||||
+}
|
||||
+
|
||||
+static gboolean
|
||||
+window_is_hidden (gpointer user_data)
|
||||
+{
|
||||
+ MetaWindow *window = (MetaWindow *) user_data;
|
||||
+ return meta_window_is_hidden (window);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+test_window_mapped_inhibit (MetaWindowClientType client_type)
|
||||
+{
|
||||
+ g_autoptr (GError) error = NULL;
|
||||
+ MetaTestClient *test_client;
|
||||
+ MetaWindow *window;
|
||||
+
|
||||
+ g_debug ("Starting window mapped inhibit test");
|
||||
+
|
||||
+ test_client = meta_test_client_new (test_context,
|
||||
+ TEST_CLIENT_TITLE,
|
||||
+ client_type,
|
||||
+ &error);
|
||||
+ g_assert_no_error (error);
|
||||
+
|
||||
+ meta_test_client_run (test_client,
|
||||
+ "create " TEST_CLIENT_TITLE " csd\n"
|
||||
+ "show " TEST_CLIENT_TITLE "\n");
|
||||
+
|
||||
+ /* Wait for the window to be created */
|
||||
+ while (!(window = meta_test_client_find_window (test_client,
|
||||
+ TEST_CLIENT_TITLE,
|
||||
+ NULL)))
|
||||
+ g_main_context_iteration (NULL, TRUE);
|
||||
+ g_object_add_weak_pointer (G_OBJECT (window), (gpointer *) &window);
|
||||
+
|
||||
+ /* Wait for the window to be properly shown */
|
||||
+ wait_for_condition (window_is_not_hidden, window);
|
||||
+
|
||||
+ /* Initially, the window should not be mapped inhibited */
|
||||
+ g_assert_false (meta_window_is_mapped_inhibited (window));
|
||||
+
|
||||
+ /* The window should be showing normally */
|
||||
+ g_assert_false (meta_window_is_hidden (window));
|
||||
+
|
||||
+ /* Inhibit the window mapping */
|
||||
+ meta_window_inhibit_mapped (window);
|
||||
+
|
||||
+ /* Now the window should be mapped inhibited */
|
||||
+ g_assert_true (meta_window_is_mapped_inhibited (window));
|
||||
+
|
||||
+ /* Wait for the window to be processed and hidden */
|
||||
+ wait_for_condition (window_is_hidden, window);
|
||||
+
|
||||
+ /* The window should now be hidden due to the inhibit */
|
||||
+ g_assert_true (meta_window_is_hidden (window));
|
||||
+
|
||||
+ /* Uninhibit the window mapping */
|
||||
+ meta_window_uninhibit_mapped (window);
|
||||
+
|
||||
+ /* The window should no longer be mapped inhibited */
|
||||
+ g_assert_false (meta_window_is_mapped_inhibited (window));
|
||||
+
|
||||
+ /* Wait for the window to be processed and shown again */
|
||||
+ wait_for_condition (window_is_not_hidden, window);
|
||||
+
|
||||
+ /* The window should be showing again */
|
||||
+ g_assert_false (meta_window_is_hidden (window));
|
||||
+
|
||||
+ g_debug ("Window mapped inhibit test passed");
|
||||
+
|
||||
+ meta_test_client_destroy (test_client);
|
||||
+
|
||||
+ /* Wait for the window to be removed */
|
||||
+ while (window)
|
||||
+ g_main_context_iteration (NULL, TRUE);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+test_window_mapped_inhibit_multiple (MetaWindowClientType client_type)
|
||||
+{
|
||||
+ g_autoptr (GError) error = NULL;
|
||||
+ MetaTestClient *test_client;
|
||||
+ MetaWindow *window;
|
||||
+
|
||||
+ g_debug ("Starting multiple window mapped inhibit test");
|
||||
+
|
||||
+ test_client = meta_test_client_new (test_context,
|
||||
+ TEST_CLIENT_TITLE,
|
||||
+ client_type,
|
||||
+ &error);
|
||||
+ g_assert_no_error (error);
|
||||
+
|
||||
+ meta_test_client_run (test_client,
|
||||
+ "create " TEST_CLIENT_TITLE " csd\n"
|
||||
+ "show " TEST_CLIENT_TITLE "\n");
|
||||
+
|
||||
+ /* Wait for the window to be created */
|
||||
+ while (!(window = meta_test_client_find_window (test_client,
|
||||
+ TEST_CLIENT_TITLE,
|
||||
+ NULL)))
|
||||
+ g_main_context_iteration (NULL, TRUE);
|
||||
+ g_object_add_weak_pointer (G_OBJECT (window), (gpointer *) &window);
|
||||
+
|
||||
+ /* Wait for the window to be properly shown */
|
||||
+ wait_for_condition (window_is_not_hidden, window);
|
||||
+
|
||||
+ /* Initially, the window should not be mapped inhibited */
|
||||
+ g_assert_false (meta_window_is_mapped_inhibited (window));
|
||||
+
|
||||
+ /* Inhibit the window mapping multiple times */
|
||||
+ meta_window_inhibit_mapped (window);
|
||||
+ g_assert_true (meta_window_is_mapped_inhibited (window));
|
||||
+ wait_for_condition (window_is_hidden, window);
|
||||
+
|
||||
+ meta_window_inhibit_mapped (window);
|
||||
+ g_assert_true (meta_window_is_mapped_inhibited (window));
|
||||
+ g_assert_true (meta_window_is_hidden (window));
|
||||
+
|
||||
+ meta_window_inhibit_mapped (window);
|
||||
+ g_assert_true (meta_window_is_mapped_inhibited (window));
|
||||
+ g_assert_true (meta_window_is_hidden (window));
|
||||
+
|
||||
+ /* Uninhibit once - should still be inhibited */
|
||||
+ meta_window_uninhibit_mapped (window);
|
||||
+ g_assert_true (meta_window_is_mapped_inhibited (window));
|
||||
+ g_assert_true (meta_window_is_hidden (window));
|
||||
+
|
||||
+ /* Uninhibit again - should still be inhibited */
|
||||
+ meta_window_uninhibit_mapped (window);
|
||||
+ g_assert_true (meta_window_is_mapped_inhibited (window));
|
||||
+ g_assert_true (meta_window_is_hidden (window));
|
||||
+
|
||||
+ /* Uninhibit the final time - should no longer be inhibited */
|
||||
+ meta_window_uninhibit_mapped (window);
|
||||
+ g_assert_false (meta_window_is_mapped_inhibited (window));
|
||||
+ wait_for_condition (window_is_not_hidden, window);
|
||||
+ g_assert_false (meta_window_is_hidden (window));
|
||||
+
|
||||
+ g_debug ("Multiple window mapped inhibit test passed");
|
||||
+
|
||||
+ meta_test_client_destroy (test_client);
|
||||
+
|
||||
+ /* Wait for the window to be removed */
|
||||
+ while (window)
|
||||
+ g_main_context_iteration (NULL, TRUE);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+test_window_mapped_inhibit_wayland (void)
|
||||
+{
|
||||
+ test_window_mapped_inhibit (META_WINDOW_CLIENT_TYPE_WAYLAND);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+test_window_mapped_inhibit_x11 (void)
|
||||
+{
|
||||
+#ifdef MUTTER_PRIVILEGED_TEST
|
||||
+ g_test_skip ("Running Xwayland in CI KVM doesn't work currently");
|
||||
+#else
|
||||
+ test_window_mapped_inhibit (META_WINDOW_CLIENT_TYPE_X11);
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+test_window_mapped_inhibit_multiple_wayland (void)
|
||||
+{
|
||||
+ test_window_mapped_inhibit_multiple (META_WINDOW_CLIENT_TYPE_WAYLAND);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+test_window_mapped_inhibit_multiple_x11 (void)
|
||||
+{
|
||||
+#ifdef MUTTER_PRIVILEGED_TEST
|
||||
+ g_test_skip ("Running Xwayland in CI KVM doesn't work currently");
|
||||
+#else
|
||||
+ test_window_mapped_inhibit_multiple (META_WINDOW_CLIENT_TYPE_X11);
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+on_before_tests (void)
|
||||
+{
|
||||
+ MetaWaylandCompositor *compositor =
|
||||
+ meta_context_get_wayland_compositor (test_context);
|
||||
+
|
||||
+ test_driver = meta_wayland_test_driver_new (compositor);
|
||||
+ virtual_monitor = meta_create_test_monitor (test_context,
|
||||
+ 400, 400, 60.0);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+on_after_tests (void)
|
||||
+{
|
||||
+ g_clear_object (&test_driver);
|
||||
+ g_clear_object (&virtual_monitor);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+init_tests (void)
|
||||
+{
|
||||
+ g_test_add_func ("/window/mapped-inhibit",
|
||||
+ test_window_mapped_inhibit_wayland);
|
||||
+ g_test_add_func ("/window/mapped-inhibit/x11",
|
||||
+ test_window_mapped_inhibit_x11);
|
||||
+ g_test_add_func ("/window/mapped-inhibit/multiple",
|
||||
+ test_window_mapped_inhibit_multiple_wayland);
|
||||
+ g_test_add_func ("/window/mapped-inhibit/multiple/x11",
|
||||
+ test_window_mapped_inhibit_multiple_x11);
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+main (int argc,
|
||||
+ char **argv)
|
||||
+{
|
||||
+ g_autoptr (MetaContext) context = NULL;
|
||||
+
|
||||
+ context = meta_create_test_context (META_CONTEXT_TEST_TYPE_HEADLESS,
|
||||
+#ifdef MUTTER_PRIVILEGED_TEST
|
||||
+ META_CONTEXT_TEST_FLAG_NO_X11 |
|
||||
+#endif
|
||||
+ META_CONTEXT_TEST_FLAG_TEST_CLIENT);
|
||||
+ g_assert_true (meta_context_configure (context, &argc, &argv, NULL));
|
||||
+
|
||||
+ test_context = context;
|
||||
+
|
||||
+ init_tests ();
|
||||
+
|
||||
+ g_signal_connect (context, "before-tests",
|
||||
+ G_CALLBACK (on_before_tests), NULL);
|
||||
+ g_signal_connect (context, "after-tests",
|
||||
+ G_CALLBACK (on_after_tests), NULL);
|
||||
+
|
||||
+ return meta_context_test_run_tests (META_CONTEXT_TEST (context),
|
||||
+ META_TEST_RUN_FLAG_CAN_SKIP);
|
||||
+}
|
||||
--
|
||||
2.53.0
|
||||
|
||||
40
0003-window-Add-MetaExternalConstraintFlags.patch
Normal file
40
0003-window-Add-MetaExternalConstraintFlags.patch
Normal file
@ -0,0 +1,40 @@
|
||||
From c2af2bec1618fbac784c61722b073a0cb4637067 Mon Sep 17 00:00:00 2001
|
||||
From: Olivier Fourdan <ofourdan@redhat.com>
|
||||
Date: Wed, 5 Nov 2025 17:05:25 +0100
|
||||
Subject: [PATCH 3/7] window: Add MetaExternalConstraintFlags
|
||||
|
||||
The plan is to allow plugins to implement their own constraint, while
|
||||
not exposing all of the internal MetaMoveResizeFlags.
|
||||
|
||||
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4692>
|
||||
(cherry picked from commit 3c9155a395c3c07f8aeb928a676e83bd82b7d30e)
|
||||
---
|
||||
src/meta/meta-enums.h | 15 +++++++++++++++
|
||||
1 file changed, 15 insertions(+)
|
||||
|
||||
diff --git a/src/meta/meta-enums.h b/src/meta/meta-enums.h
|
||||
index e0a2fc50ea..79294d7c15 100644
|
||||
--- a/src/meta/meta-enums.h
|
||||
+++ b/src/meta/meta-enums.h
|
||||
@@ -418,3 +418,18 @@ typedef enum
|
||||
META_A11Y_STICKY_KEYS_BEEP = 1 << 12,
|
||||
META_A11Y_FEATURE_STATE_CHANGE_BEEP = 1 << 13,
|
||||
} MetaKeyboardA11yFlags;
|
||||
+
|
||||
+/**
|
||||
+ * MetaMoveResizeFlags:
|
||||
+ * @META_EXTERNAL_CONSTRAINT_FLAGS_NONE: No operation
|
||||
+ * @META_EXTERNAL_CONSTRAINT_FLAGS_MOVE: Move operation
|
||||
+ * @META_EXTERNAL_CONSTRAINT_FLAGS_RESIZE: Resize operation
|
||||
+ *
|
||||
+ * Flags for external constraint operations.
|
||||
+ */
|
||||
+typedef enum _MetaExternalConstraintFlags
|
||||
+{
|
||||
+ META_EXTERNAL_CONSTRAINT_FLAGS_NONE = 0,
|
||||
+ META_EXTERNAL_CONSTRAINT_FLAGS_MOVE = 1 << 0,
|
||||
+ META_EXTERNAL_CONSTRAINT_FLAGS_RESIZE = 1 << 1,
|
||||
+} MetaExternalConstraintFlags;
|
||||
--
|
||||
2.53.0
|
||||
|
||||
212
0004-constraints-Add-external-constraints-interface.patch
Normal file
212
0004-constraints-Add-external-constraints-interface.patch
Normal file
@ -0,0 +1,212 @@
|
||||
From e0e3307984eaa4ac716ee6431b9d469d890e42be Mon Sep 17 00:00:00 2001
|
||||
From: Olivier Fourdan <ofourdan@redhat.com>
|
||||
Date: Fri, 14 Nov 2025 14:04:00 +0100
|
||||
Subject: [PATCH 4/7] constraints: Add external constraints interface
|
||||
|
||||
This adds a new type interface for constraints.
|
||||
|
||||
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4692>
|
||||
(cherry picked from commit 17b6a69868a38240a9e179239310dc55ae9202d5)
|
||||
---
|
||||
src/core/meta-external-constraint.c | 58 +++++++++++++++++++
|
||||
src/meson.build | 1 +
|
||||
src/meta/meson.build | 1 +
|
||||
src/meta/meta-external-constraint.h | 87 +++++++++++++++++++++++++++++
|
||||
src/meta/types.h | 1 +
|
||||
5 files changed, 148 insertions(+)
|
||||
create mode 100644 src/core/meta-external-constraint.c
|
||||
create mode 100644 src/meta/meta-external-constraint.h
|
||||
|
||||
diff --git a/src/core/meta-external-constraint.c b/src/core/meta-external-constraint.c
|
||||
new file mode 100644
|
||||
index 0000000000..bc84f8bf97
|
||||
--- /dev/null
|
||||
+++ b/src/core/meta-external-constraint.c
|
||||
@@ -0,0 +1,58 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2025 Red Hat, Inc.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License as
|
||||
+ * published by the Free Software Foundation; either version 2 of the
|
||||
+ * License, or (at your option) any later version.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License
|
||||
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
+ */
|
||||
+
|
||||
+#include "config.h"
|
||||
+
|
||||
+#include "meta/meta-external-constraint.h"
|
||||
+
|
||||
+G_DEFINE_INTERFACE (MetaExternalConstraint, meta_external_constraint, G_TYPE_OBJECT)
|
||||
+
|
||||
+static void
|
||||
+meta_external_constraint_default_init (MetaExternalConstraintInterface *iface)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * meta_external_constraint_constrain:
|
||||
+ * @constraint: a #MetaExternalConstraint
|
||||
+ * @window: the #MetaWindow being constrained
|
||||
+ * @info: a #MetaExternalConstraintInfo with constraint parameters
|
||||
+ *
|
||||
+ * Applies external constraints to a window's position and size.
|
||||
+ *
|
||||
+ * Returns: %TRUE if the constraint has fully constrained the window,
|
||||
+ %FALSE otherwise.
|
||||
+ */
|
||||
+gboolean
|
||||
+meta_external_constraint_constrain (MetaExternalConstraint *constraint,
|
||||
+ MetaWindow *window,
|
||||
+ MetaExternalConstraintInfo *info)
|
||||
+{
|
||||
+ MetaExternalConstraintInterface *iface;
|
||||
+
|
||||
+ g_return_val_if_fail (META_IS_EXTERNAL_CONSTRAINT (constraint), TRUE);
|
||||
+ g_return_val_if_fail (META_IS_WINDOW (window), TRUE);
|
||||
+ g_return_val_if_fail (info != NULL, TRUE);
|
||||
+ g_return_val_if_fail (info->new_rect != NULL, TRUE);
|
||||
+
|
||||
+ iface = META_EXTERNAL_CONSTRAINT_GET_IFACE (constraint);
|
||||
+
|
||||
+ if (iface->constrain)
|
||||
+ return iface->constrain (constraint, window, info);
|
||||
+
|
||||
+ return TRUE;
|
||||
+}
|
||||
diff --git a/src/meson.build b/src/meson.build
|
||||
index 508c3416da..744f941e6e 100644
|
||||
--- a/src/meson.build
|
||||
+++ b/src/meson.build
|
||||
@@ -360,6 +360,7 @@ mutter_sources = [
|
||||
'core/meta-context.c',
|
||||
'core/meta-debug-control.c',
|
||||
'core/meta-debug-control-private.h',
|
||||
+ 'core/meta-external-constraint.c',
|
||||
'core/meta-fraction.c',
|
||||
'core/meta-fraction.h',
|
||||
'core/meta-gesture-tracker.c',
|
||||
diff --git a/src/meta/meson.build b/src/meta/meson.build
|
||||
index bc42b56174..f34ace7439 100644
|
||||
--- a/src/meta/meson.build
|
||||
+++ b/src/meta/meson.build
|
||||
@@ -21,6 +21,7 @@ mutter_public_headers = [
|
||||
'meta-debug-control.h',
|
||||
'meta-dnd.h',
|
||||
'meta-enums.h',
|
||||
+ 'meta-external-constraint.h',
|
||||
'meta-idle-monitor.h',
|
||||
'meta-inhibit-shortcuts-dialog.h',
|
||||
'meta-launch-context.h',
|
||||
diff --git a/src/meta/meta-external-constraint.h b/src/meta/meta-external-constraint.h
|
||||
new file mode 100644
|
||||
index 0000000000..a2d5cd6176
|
||||
--- /dev/null
|
||||
+++ b/src/meta/meta-external-constraint.h
|
||||
@@ -0,0 +1,87 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2025 Red Hat, Inc.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License as
|
||||
+ * published by the Free Software Foundation; either version 2 of the
|
||||
+ * License, or (at your option) any later version.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License
|
||||
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
+ */
|
||||
+
|
||||
+#pragma once
|
||||
+
|
||||
+#include <glib-object.h>
|
||||
+
|
||||
+#include "meta/types.h"
|
||||
+#include "meta/window.h"
|
||||
+
|
||||
+G_BEGIN_DECLS
|
||||
+
|
||||
+#define META_TYPE_EXTERNAL_CONSTRAINT (meta_external_constraint_get_type ())
|
||||
+
|
||||
+META_EXPORT
|
||||
+G_DECLARE_INTERFACE (MetaExternalConstraint,
|
||||
+ meta_external_constraint,
|
||||
+ META,
|
||||
+ EXTERNAL_CONSTRAINT,
|
||||
+ GObject)
|
||||
+
|
||||
+/**
|
||||
+ * MetaExternalConstraintInfo:
|
||||
+ * @new_rect: (inout): the proposed new window rectangle
|
||||
+ * @flags: the constraint flags for this operation
|
||||
+ * @resize_gravity: the gravity for resizing
|
||||
+ *
|
||||
+ * Structure containing parameters for external window constraints.
|
||||
+ */
|
||||
+typedef struct _MetaExternalConstraintInfo MetaExternalConstraintInfo;
|
||||
+struct _MetaExternalConstraintInfo
|
||||
+{
|
||||
+ MtkRectangle *new_rect;
|
||||
+ MetaExternalConstraintFlags flags;
|
||||
+ MetaGravity resize_gravity;
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
+ * MetaExternalConstraintInterface:
|
||||
+ * @constrain: virtual function for applying external constraints
|
||||
+ *
|
||||
+ * Interface for objects that can apply external window constraints.
|
||||
+ */
|
||||
+struct _MetaExternalConstraintInterface
|
||||
+{
|
||||
+ GTypeInterface parent_iface;
|
||||
+
|
||||
+ /**
|
||||
+ * MetaExternalConstraintInterface::constrain:
|
||||
+ * @constraint: a #MetaExternalConstraint
|
||||
+ * @window: the #MetaWindow being constrained
|
||||
+ * @info: a #MetaExternalConstraintInfo with constraint parameters
|
||||
+ *
|
||||
+ * Virtual function called with other window constraints processing.
|
||||
+ * This allows external components to implement custom window positioning
|
||||
+ * and sizing constraints.
|
||||
+ *
|
||||
+ * The implementation can modify @info->new_rect to enforce its own constraints.
|
||||
+ *
|
||||
+ * Returns: %TRUE if the constraint has fully constrained the window,
|
||||
+ %FALSE otherwise.
|
||||
+ */
|
||||
+ gboolean (*constrain) (MetaExternalConstraint *constraint,
|
||||
+ MetaWindow *window,
|
||||
+ MetaExternalConstraintInfo *info);
|
||||
+};
|
||||
+
|
||||
+META_EXPORT
|
||||
+gboolean meta_external_constraint_constrain (MetaExternalConstraint *constraint,
|
||||
+ MetaWindow *window,
|
||||
+ MetaExternalConstraintInfo *info);
|
||||
+
|
||||
+G_END_DECLS
|
||||
diff --git a/src/meta/types.h b/src/meta/types.h
|
||||
index cf7432ec48..944043d854 100644
|
||||
--- a/src/meta/types.h
|
||||
+++ b/src/meta/types.h
|
||||
@@ -37,3 +37,4 @@ typedef struct _MetaWorkspaceManager MetaWorkspaceManager;
|
||||
typedef struct _MetaSelection MetaSelection;
|
||||
typedef struct _MetaDebugControl MetaDebugControl;
|
||||
typedef struct _MetaWindowConfig MetaWindowConfig;
|
||||
+typedef struct _MetaExternalConstraint MetaExternalConstraint;
|
||||
--
|
||||
2.53.0
|
||||
|
||||
176
0005-window-Add-external-constraints-support.patch
Normal file
176
0005-window-Add-external-constraints-support.patch
Normal file
@ -0,0 +1,176 @@
|
||||
From 80ff12ecbb492a6f87b0f22e47977b26b018f4d9 Mon Sep 17 00:00:00 2001
|
||||
From: Olivier Fourdan <ofourdan@redhat.com>
|
||||
Date: Fri, 14 Nov 2025 15:16:30 +0100
|
||||
Subject: [PATCH 5/7] window: Add external constraints support
|
||||
|
||||
This allows to keep a list of external constraints with the window.
|
||||
|
||||
The caller can add/remove constraint objects to each window.
|
||||
|
||||
This is preparation work for the following commit that will call into
|
||||
this to apply external window constraints along the rest of the
|
||||
constraints.
|
||||
|
||||
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4692>
|
||||
(cherry picked from commit 0eaf17634ecda569b519ab73cf79f21be1f631f2)
|
||||
---
|
||||
src/core/window-private.h | 5 +++
|
||||
src/core/window.c | 87 +++++++++++++++++++++++++++++++++++++++
|
||||
src/meta/window.h | 8 ++++
|
||||
3 files changed, 100 insertions(+)
|
||||
|
||||
diff --git a/src/core/window-private.h b/src/core/window-private.h
|
||||
index 01f6679ac3..e35bc66a82 100644
|
||||
--- a/src/core/window-private.h
|
||||
+++ b/src/core/window-private.h
|
||||
@@ -937,3 +937,8 @@ void meta_window_set_tag (MetaWindow *window,
|
||||
|
||||
META_EXPORT_TEST
|
||||
GPtrArray * meta_window_get_transient_children (MetaWindow *window);
|
||||
+
|
||||
+gboolean meta_window_apply_external_constraints (MetaWindow *window,
|
||||
+ MetaGravity resize_gravity,
|
||||
+ MtkRectangle *constrained_rect,
|
||||
+ MetaExternalConstraintFlags constraint_flags);
|
||||
diff --git a/src/core/window.c b/src/core/window.c
|
||||
index b7b62fbda5..5ea7c1bc2a 100644
|
||||
--- a/src/core/window.c
|
||||
+++ b/src/core/window.c
|
||||
@@ -80,6 +80,7 @@
|
||||
#include "core/workspace-private.h"
|
||||
#include "meta/meta-cursor-tracker.h"
|
||||
#include "meta/meta-enum-types.h"
|
||||
+#include "meta/meta-external-constraint.h"
|
||||
#include "meta/prefs.h"
|
||||
#include "meta/meta-window-config.h"
|
||||
|
||||
@@ -193,6 +194,8 @@ typedef struct _MetaWindowPrivate
|
||||
} auto_maximize;
|
||||
|
||||
unsigned int mapped_inhibit_count;
|
||||
+
|
||||
+ GHashTable *external_constraints;
|
||||
} MetaWindowPrivate;
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (MetaWindow, meta_window, G_TYPE_OBJECT,
|
||||
@@ -415,6 +418,8 @@ meta_window_finalize (GObject *object)
|
||||
g_free (window->placement.rule);
|
||||
g_free (window->tag);
|
||||
|
||||
+ g_clear_pointer (&priv->external_constraints, g_hash_table_destroy);
|
||||
+
|
||||
G_OBJECT_CLASS (meta_window_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
@@ -837,6 +842,8 @@ meta_window_init (MetaWindow *window)
|
||||
window->stamp = next_window_stamp++;
|
||||
meta_prefs_add_listener (prefs_changed_callback, window);
|
||||
window->is_alive = TRUE;
|
||||
+ priv->external_constraints =
|
||||
+ g_hash_table_new_full (NULL, NULL, g_object_unref, NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -8753,3 +8760,83 @@ meta_window_is_mapped_inhibited (MetaWindow *window)
|
||||
|
||||
return priv->mapped_inhibit_count > 0;
|
||||
}
|
||||
+
|
||||
+/**
|
||||
+ * meta_window_add_external_constraint:
|
||||
+ * @window: a #MetaWindow
|
||||
+ * @constraint: a #MetaExternalConstraint
|
||||
+ *
|
||||
+ * Adds an external constraint to the window.
|
||||
+ *
|
||||
+ * The constraint object is referenced by the window, so the caller should
|
||||
+ * release its own reference when no longer needed.
|
||||
+ */
|
||||
+void
|
||||
+meta_window_add_external_constraint (MetaWindow *window,
|
||||
+ MetaExternalConstraint *constraint)
|
||||
+{
|
||||
+ MetaWindowPrivate *priv;
|
||||
+
|
||||
+ g_return_if_fail (META_IS_WINDOW (window));
|
||||
+ g_return_if_fail (META_IS_EXTERNAL_CONSTRAINT (constraint));
|
||||
+
|
||||
+ priv = meta_window_get_instance_private (window);
|
||||
+ if (g_hash_table_contains (priv->external_constraints, constraint))
|
||||
+ {
|
||||
+ g_warning ("Not adding external window constraint, already present");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ g_hash_table_add (priv->external_constraints, g_object_ref (constraint));
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * meta_window_remove_external_constraint:
|
||||
+ * @window: a #MetaWindow
|
||||
+ * @constraint: a #MetaExternalConstraint
|
||||
+ *
|
||||
+ * Removes a previously added external constraint from the window.
|
||||
+ */
|
||||
+void
|
||||
+meta_window_remove_external_constraint (MetaWindow *window,
|
||||
+ MetaExternalConstraint *constraint)
|
||||
+{
|
||||
+ MetaWindowPrivate *priv;
|
||||
+
|
||||
+ g_return_if_fail (META_IS_WINDOW (window));
|
||||
+ g_return_if_fail (META_IS_EXTERNAL_CONSTRAINT (constraint));
|
||||
+
|
||||
+ priv = meta_window_get_instance_private (window);
|
||||
+ g_hash_table_remove (priv->external_constraints, constraint);
|
||||
+}
|
||||
+
|
||||
+gboolean
|
||||
+meta_window_apply_external_constraints (MetaWindow *window,
|
||||
+ MetaGravity resize_gravity,
|
||||
+ MtkRectangle *constrained_rect,
|
||||
+ MetaExternalConstraintFlags constraint_flags)
|
||||
+{
|
||||
+ MetaWindowPrivate *priv = meta_window_get_instance_private (window);
|
||||
+ GHashTableIter iter;
|
||||
+ gpointer constraint_ptr;
|
||||
+ gboolean constraint_satisfied = TRUE;
|
||||
+
|
||||
+ g_return_val_if_fail (META_IS_WINDOW (window), TRUE);
|
||||
+
|
||||
+ g_hash_table_iter_init (&iter, priv->external_constraints);
|
||||
+ while (g_hash_table_iter_next (&iter, &constraint_ptr, NULL))
|
||||
+ {
|
||||
+ MetaExternalConstraint *constraint = META_EXTERNAL_CONSTRAINT (constraint_ptr);
|
||||
+ MetaExternalConstraintInfo constraint_info = {
|
||||
+ .new_rect = constrained_rect,
|
||||
+ .flags = constraint_flags,
|
||||
+ .resize_gravity = resize_gravity,
|
||||
+ };
|
||||
+
|
||||
+ constraint_satisfied |= meta_external_constraint_constrain (constraint,
|
||||
+ window,
|
||||
+ &constraint_info);
|
||||
+ }
|
||||
+
|
||||
+ return constraint_satisfied;
|
||||
+}
|
||||
diff --git a/src/meta/window.h b/src/meta/window.h
|
||||
index 4f6390f0a1..a677122716 100644
|
||||
--- a/src/meta/window.h
|
||||
+++ b/src/meta/window.h
|
||||
@@ -469,3 +469,11 @@ void meta_window_uninhibit_mapped (MetaWindow *window);
|
||||
|
||||
META_EXPORT
|
||||
gboolean meta_window_is_mapped_inhibited (MetaWindow *window);
|
||||
+
|
||||
+META_EXPORT
|
||||
+void meta_window_add_external_constraint (MetaWindow *window,
|
||||
+ MetaExternalConstraint *constraint);
|
||||
+
|
||||
+META_EXPORT
|
||||
+void meta_window_remove_external_constraint (MetaWindow *window,
|
||||
+ MetaExternalConstraint *constraint);
|
||||
--
|
||||
2.53.0
|
||||
|
||||
103
0006-constraints-Apply-window-external-constraints.patch
Normal file
103
0006-constraints-Apply-window-external-constraints.patch
Normal file
@ -0,0 +1,103 @@
|
||||
From 9b0f9f6346c9ffa6422f34d1232dcb1905794828 Mon Sep 17 00:00:00 2001
|
||||
From: Olivier Fourdan <ofourdan@redhat.com>
|
||||
Date: Wed, 5 Nov 2025 17:11:47 +0100
|
||||
Subject: [PATCH 6/7] constraints: Apply window external constraints
|
||||
|
||||
Apply the window external constraints last, yet at the highest priority.
|
||||
|
||||
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4692>
|
||||
(cherry picked from commit d7f0f7a7a477bfd452614f5c35c78a5743f9cec4)
|
||||
---
|
||||
src/core/constraints.c | 48 +++++++++++++++++++++++++++++++++++++++++-
|
||||
1 file changed, 47 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/core/constraints.c b/src/core/constraints.c
|
||||
index fe4f6b3de3..bdea6b5c2b 100644
|
||||
--- a/src/core/constraints.c
|
||||
+++ b/src/core/constraints.c
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "core/meta-workspace-manager-private.h"
|
||||
#include "core/place.h"
|
||||
#include "core/workspace-private.h"
|
||||
+#include "meta/meta-external-constraint.h"
|
||||
#include "meta/prefs.h"
|
||||
|
||||
#ifdef HAVE_X11_CLIENT
|
||||
@@ -115,7 +116,8 @@ typedef enum
|
||||
PRIORITY_TITLEBAR_VISIBLE = 4,
|
||||
PRIORITY_PARTIALLY_VISIBLE_ON_WORKAREA = 4,
|
||||
PRIORITY_CUSTOM_RULE = 4,
|
||||
- PRIORITY_MAXIMUM = 4 /* Dummy value used for loop end = max(all priorities) */
|
||||
+ PRIORITY_EXTERNAL_CONSTRAINT = 5, /* External constraints - highest priority */
|
||||
+ PRIORITY_MAXIMUM = 5 /* Dummy value used for loop end = max(all priorities) */
|
||||
} ConstraintPriority;
|
||||
|
||||
typedef enum
|
||||
@@ -164,6 +166,10 @@ static gboolean do_screen_and_monitor_relative_constraints (MetaWindow *wind
|
||||
GList *region_spanning_rectangles,
|
||||
ConstraintInfo *info,
|
||||
gboolean check_only);
|
||||
+static gboolean constrain_external (MetaWindow *window,
|
||||
+ ConstraintInfo *info,
|
||||
+ ConstraintPriority priority,
|
||||
+ gboolean check_only);
|
||||
static gboolean constrain_custom_rule (MetaWindow *window,
|
||||
ConstraintInfo *info,
|
||||
ConstraintPriority priority,
|
||||
@@ -249,6 +255,7 @@ static const Constraint all_constraints[] = {
|
||||
{constrain_fully_onscreen, "constrain_fully_onscreen"},
|
||||
{constrain_titlebar_visible, "constrain_titlebar_visible"},
|
||||
{constrain_partially_onscreen, "constrain_partially_onscreen"},
|
||||
+ {constrain_external, "constrain_external"},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
@@ -877,6 +884,45 @@ is_custom_rule_satisfied (MtkRectangle *rect,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
+static MetaExternalConstraintFlags
|
||||
+get_external_constraint_flags (ConstraintInfo *info)
|
||||
+{
|
||||
+ MetaExternalConstraintFlags flags = META_EXTERNAL_CONSTRAINT_FLAGS_NONE;
|
||||
+
|
||||
+ if (info->flags & META_MOVE_RESIZE_MOVE_ACTION)
|
||||
+ flags |= META_EXTERNAL_CONSTRAINT_FLAGS_MOVE;
|
||||
+ if (info->flags & META_MOVE_RESIZE_RESIZE_ACTION)
|
||||
+ flags |= META_EXTERNAL_CONSTRAINT_FLAGS_RESIZE;
|
||||
+
|
||||
+ return flags;
|
||||
+}
|
||||
+
|
||||
+static gboolean
|
||||
+constrain_external (MetaWindow *window,
|
||||
+ ConstraintInfo *info,
|
||||
+ ConstraintPriority priority,
|
||||
+ gboolean check_only)
|
||||
+{
|
||||
+ MtkRectangle current_rect = info->current;
|
||||
+ gboolean constraint_satisfied;
|
||||
+
|
||||
+ if (priority > PRIORITY_EXTERNAL_CONSTRAINT)
|
||||
+ return TRUE;
|
||||
+
|
||||
+ constraint_satisfied =
|
||||
+ meta_window_apply_external_constraints (window,
|
||||
+ info->resize_gravity,
|
||||
+ ¤t_rect,
|
||||
+ get_external_constraint_flags (info));
|
||||
+
|
||||
+ if (check_only)
|
||||
+ return constraint_satisfied;
|
||||
+
|
||||
+ info->current = current_rect;
|
||||
+
|
||||
+ return constraint_satisfied;
|
||||
+}
|
||||
+
|
||||
static gboolean
|
||||
constrain_custom_rule (MetaWindow *window,
|
||||
ConstraintInfo *info,
|
||||
--
|
||||
2.53.0
|
||||
|
||||
564
0007-tests-Add-test-for-external-constraints.patch
Normal file
564
0007-tests-Add-test-for-external-constraints.patch
Normal file
@ -0,0 +1,564 @@
|
||||
From f4b835ff3c34dded177e51419a09da105089c085 Mon Sep 17 00:00:00 2001
|
||||
From: Olivier Fourdan <ofourdan@redhat.com>
|
||||
Date: Wed, 5 Nov 2025 17:19:33 +0100
|
||||
Subject: [PATCH 7/7] tests: Add test for external constraints
|
||||
|
||||
Test the new external constraints, by checking that the size and
|
||||
location set through external constraints get enforced on initial
|
||||
placement, moving, resizing, maximizing and fullscreening the window.
|
||||
|
||||
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4692>
|
||||
(cherry picked from commit aa803d6fe1f177eae5039913564499eeb2b31f55)
|
||||
---
|
||||
src/tests/external-constraint-tests.c | 519 ++++++++++++++++++++++++++
|
||||
src/tests/meson.build | 8 +
|
||||
2 files changed, 527 insertions(+)
|
||||
create mode 100644 src/tests/external-constraint-tests.c
|
||||
|
||||
diff --git a/src/tests/external-constraint-tests.c b/src/tests/external-constraint-tests.c
|
||||
new file mode 100644
|
||||
index 0000000000..46bf2461c4
|
||||
--- /dev/null
|
||||
+++ b/src/tests/external-constraint-tests.c
|
||||
@@ -0,0 +1,519 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2025 Red Hat, Inc.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License as
|
||||
+ * published by the Free Software Foundation; either version 2 of the
|
||||
+ * License, or (at your option) any later version.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License
|
||||
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
+ */
|
||||
+
|
||||
+#include "config.h"
|
||||
+
|
||||
+#include "backends/meta-virtual-monitor.h"
|
||||
+#include "compositor/meta-window-actor-private.h"
|
||||
+#include "core/window-private.h"
|
||||
+#include "meta/display.h"
|
||||
+#include "meta/meta-external-constraint.h"
|
||||
+#include "meta-test/meta-context-test.h"
|
||||
+#include "tests/meta-test-shell.h"
|
||||
+#include "tests/meta-test-utils.h"
|
||||
+#include "tests/meta-wayland-test-driver.h"
|
||||
+
|
||||
+#define TEST_CLIENT_TITLE "external-constraint-test-window"
|
||||
+
|
||||
+static MetaContext *test_context;
|
||||
+static MetaWaylandTestDriver *test_driver;
|
||||
+static MetaVirtualMonitor *virtual_monitor;
|
||||
+
|
||||
+/* Global state for constraint testing */
|
||||
+static struct {
|
||||
+ gboolean enabled;
|
||||
+ MtkRectangle target_rect;
|
||||
+ gboolean was_called;
|
||||
+ MetaWindow *expected_window;
|
||||
+} constraint_state;
|
||||
+
|
||||
+/* Define our test constraint type */
|
||||
+#define TEST_TYPE_CONSTRAINT (test_constraint_get_type ())
|
||||
+G_DECLARE_FINAL_TYPE (TestConstraint, test_constraint,
|
||||
+ TEST, CONSTRAINT, GObject)
|
||||
+
|
||||
+struct _TestConstraint
|
||||
+{
|
||||
+ GObject parent_instance;
|
||||
+};
|
||||
+
|
||||
+static void test_constraint_external_constraint_iface_init (MetaExternalConstraintInterface *iface);
|
||||
+
|
||||
+G_DEFINE_TYPE_WITH_CODE (TestConstraint, test_constraint, G_TYPE_OBJECT,
|
||||
+ G_IMPLEMENT_INTERFACE (META_TYPE_EXTERNAL_CONSTRAINT,
|
||||
+ test_constraint_external_constraint_iface_init))
|
||||
+
|
||||
+/* Our test constraint function */
|
||||
+static gboolean
|
||||
+test_constraint_constrain (MetaExternalConstraint *constraint,
|
||||
+ MetaWindow *window,
|
||||
+ MetaExternalConstraintInfo *info)
|
||||
+{
|
||||
+ if (!constraint_state.enabled)
|
||||
+ return FALSE;
|
||||
+
|
||||
+ /* Apply our test constraint */
|
||||
+ *info->new_rect = constraint_state.target_rect;
|
||||
+ constraint_state.was_called = TRUE;
|
||||
+ constraint_state.expected_window = window;
|
||||
+
|
||||
+ return TRUE; /* Skip other constraints */
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+test_constraint_external_constraint_iface_init (MetaExternalConstraintInterface *iface)
|
||||
+{
|
||||
+ iface->constrain = test_constraint_constrain;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+test_constraint_class_init (TestConstraintClass *klass)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+test_constraint_init (TestConstraint *constraint)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+on_effects_completed (MetaWindowActor *window_actor,
|
||||
+ gboolean *done)
|
||||
+{
|
||||
+ *done = TRUE;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+wait_for_window_added (MetaWindow *window)
|
||||
+{
|
||||
+ MetaWindowActor *window_actor;
|
||||
+ gboolean done = FALSE;
|
||||
+ gulong handler_id;
|
||||
+
|
||||
+ window_actor = meta_window_actor_from_window (window);
|
||||
+ handler_id = g_signal_connect (window_actor, "effects-completed",
|
||||
+ G_CALLBACK (on_effects_completed), &done);
|
||||
+
|
||||
+ while (!done)
|
||||
+ g_main_context_iteration (NULL, TRUE);
|
||||
+
|
||||
+ g_signal_handler_disconnect (window_actor, handler_id);
|
||||
+}
|
||||
+
|
||||
+/* Test: Basic external constraint on window creation */
|
||||
+static void
|
||||
+test_external_constraint_basic (void)
|
||||
+{
|
||||
+ g_autoptr (GError) error = NULL;
|
||||
+ MetaTestClient *test_client;
|
||||
+ MetaWindow *window = NULL;
|
||||
+ MtkRectangle frame_rect;
|
||||
+
|
||||
+ /* Configure constraint */
|
||||
+ constraint_state.enabled = TRUE;
|
||||
+ constraint_state.target_rect = (MtkRectangle) { 100, 150, 300, 200 };
|
||||
+ constraint_state.was_called = FALSE;
|
||||
+
|
||||
+ /* Create test window */
|
||||
+ test_client = meta_test_client_new (test_context,
|
||||
+ "external-constraint-test-client",
|
||||
+ META_WINDOW_CLIENT_TYPE_WAYLAND,
|
||||
+ &error);
|
||||
+ g_assert_nonnull (test_client);
|
||||
+ g_assert_no_error (error);
|
||||
+
|
||||
+ meta_test_client_run (test_client,
|
||||
+ "create " TEST_CLIENT_TITLE " csd\n"
|
||||
+ "show " TEST_CLIENT_TITLE "\n");
|
||||
+
|
||||
+ while (!(window = meta_test_client_find_window (test_client,
|
||||
+ TEST_CLIENT_TITLE,
|
||||
+ NULL)))
|
||||
+ g_main_context_iteration (NULL, TRUE);
|
||||
+
|
||||
+ g_object_add_weak_pointer (G_OBJECT (window), (gpointer *) &window);
|
||||
+ wait_for_window_added (window);
|
||||
+
|
||||
+ /* Verify constraint was called */
|
||||
+ g_assert_true (constraint_state.was_called);
|
||||
+ g_assert_true (constraint_state.expected_window == window);
|
||||
+
|
||||
+ /* Verify window position matches constraint */
|
||||
+ meta_window_get_frame_rect (window, &frame_rect);
|
||||
+
|
||||
+ g_assert_cmpint (frame_rect.x, ==, constraint_state.target_rect.x);
|
||||
+ g_assert_cmpint (frame_rect.y, ==, constraint_state.target_rect.y);
|
||||
+ g_assert_cmpint (frame_rect.width, ==, constraint_state.target_rect.width);
|
||||
+ g_assert_cmpint (frame_rect.height, ==, constraint_state.target_rect.height);
|
||||
+
|
||||
+ /* Cleanup */
|
||||
+ meta_test_client_destroy (test_client);
|
||||
+ while (window)
|
||||
+ g_main_context_iteration (NULL, TRUE);
|
||||
+
|
||||
+ constraint_state.enabled = FALSE;
|
||||
+ constraint_state.expected_window = NULL;
|
||||
+}
|
||||
+
|
||||
+/* Test: External constraint prevents window move */
|
||||
+static void
|
||||
+test_external_constraint_move (void)
|
||||
+{
|
||||
+ g_autoptr (GError) error = NULL;
|
||||
+ MetaTestClient *test_client;
|
||||
+ MetaWindow *window = NULL;
|
||||
+ MtkRectangle frame_rect;
|
||||
+
|
||||
+ /* Configure constraint to fixed position */
|
||||
+ constraint_state.enabled = TRUE;
|
||||
+ constraint_state.target_rect = (MtkRectangle) { 200, 100, 400, 300 };
|
||||
+ constraint_state.was_called = FALSE;
|
||||
+
|
||||
+ /* Create window */
|
||||
+ test_client = meta_test_client_new (test_context,
|
||||
+ "external-constraint-test-client",
|
||||
+ META_WINDOW_CLIENT_TYPE_WAYLAND,
|
||||
+ &error);
|
||||
+ g_assert_nonnull (test_client);
|
||||
+ g_assert_no_error (error);
|
||||
+
|
||||
+ meta_test_client_run (test_client,
|
||||
+ "create " TEST_CLIENT_TITLE " csd\n"
|
||||
+ "show " TEST_CLIENT_TITLE "\n");
|
||||
+
|
||||
+ while (!(window = meta_test_client_find_window (test_client,
|
||||
+ TEST_CLIENT_TITLE,
|
||||
+ NULL)))
|
||||
+ g_main_context_iteration (NULL, TRUE);
|
||||
+
|
||||
+ g_object_add_weak_pointer (G_OBJECT (window), (gpointer *) &window);
|
||||
+ wait_for_window_added (window);
|
||||
+
|
||||
+ /* Verify initial position */
|
||||
+ meta_window_get_frame_rect (window, &frame_rect);
|
||||
+
|
||||
+ /* Try to move window */
|
||||
+ constraint_state.was_called = FALSE;
|
||||
+
|
||||
+ meta_window_move_frame (window, TRUE, 500, 500);
|
||||
+
|
||||
+ while (g_main_context_pending (NULL))
|
||||
+ g_main_context_iteration (NULL, FALSE);
|
||||
+
|
||||
+ /* Verify constraint prevented the move */
|
||||
+ g_assert_true (constraint_state.was_called);
|
||||
+
|
||||
+ meta_window_get_frame_rect (window, &frame_rect);
|
||||
+
|
||||
+ g_assert_cmpint (frame_rect.x, ==, constraint_state.target_rect.x);
|
||||
+ g_assert_cmpint (frame_rect.y, ==, constraint_state.target_rect.y);
|
||||
+
|
||||
+ /* Cleanup */
|
||||
+ meta_test_client_destroy (test_client);
|
||||
+ while (window)
|
||||
+ g_main_context_iteration (NULL, TRUE);
|
||||
+
|
||||
+ constraint_state.enabled = FALSE;
|
||||
+ constraint_state.expected_window = NULL;
|
||||
+}
|
||||
+
|
||||
+/* Test: External constraint limits maximized window size */
|
||||
+static void
|
||||
+test_external_constraint_maximized (void)
|
||||
+{
|
||||
+ g_autoptr (GError) error = NULL;
|
||||
+ MetaTestClient *test_client;
|
||||
+ MetaWindow *window = NULL;
|
||||
+ MtkRectangle frame_rect;
|
||||
+
|
||||
+ /* Configure constraint to a smaller size than monitor */
|
||||
+ constraint_state.enabled = TRUE;
|
||||
+ constraint_state.target_rect = (MtkRectangle) { 50, 50, 400, 300 };
|
||||
+ constraint_state.was_called = FALSE;
|
||||
+
|
||||
+ /* Create window */
|
||||
+ test_client = meta_test_client_new (test_context,
|
||||
+ "external-constraint-test-client",
|
||||
+ META_WINDOW_CLIENT_TYPE_WAYLAND,
|
||||
+ &error);
|
||||
+ g_assert_nonnull (test_client);
|
||||
+ g_assert_no_error (error);
|
||||
+
|
||||
+ meta_test_client_run (test_client,
|
||||
+ "create " TEST_CLIENT_TITLE " csd\n"
|
||||
+ "show " TEST_CLIENT_TITLE "\n");
|
||||
+
|
||||
+ while (!(window = meta_test_client_find_window (test_client,
|
||||
+ TEST_CLIENT_TITLE,
|
||||
+ NULL)))
|
||||
+ g_main_context_iteration (NULL, TRUE);
|
||||
+
|
||||
+ g_object_add_weak_pointer (G_OBJECT (window), (gpointer *) &window);
|
||||
+ wait_for_window_added (window);
|
||||
+
|
||||
+ /* Maximize the window */
|
||||
+ constraint_state.was_called = FALSE;
|
||||
+ meta_window_maximize (window);
|
||||
+
|
||||
+ while (g_main_context_pending (NULL))
|
||||
+ g_main_context_iteration (NULL, FALSE);
|
||||
+
|
||||
+ /* Verify constraint was called during maximize */
|
||||
+ g_assert_true (constraint_state.was_called);
|
||||
+
|
||||
+ /* Verify maximized window respects constraint size */
|
||||
+ meta_window_get_frame_rect (window, &frame_rect);
|
||||
+
|
||||
+ g_assert_cmpint (frame_rect.x, ==, constraint_state.target_rect.x);
|
||||
+ g_assert_cmpint (frame_rect.y, ==, constraint_state.target_rect.y);
|
||||
+ g_assert_cmpint (frame_rect.width, ==, constraint_state.target_rect.width);
|
||||
+ g_assert_cmpint (frame_rect.height, ==, constraint_state.target_rect.height);
|
||||
+
|
||||
+ /* Cleanup */
|
||||
+ meta_test_client_destroy (test_client);
|
||||
+ while (window)
|
||||
+ g_main_context_iteration (NULL, TRUE);
|
||||
+
|
||||
+ constraint_state.enabled = FALSE;
|
||||
+ constraint_state.expected_window = NULL;
|
||||
+}
|
||||
+
|
||||
+/* Test: External constraint limits fullscreen window size */
|
||||
+static void
|
||||
+test_external_constraint_fullscreen (void)
|
||||
+{
|
||||
+ g_autoptr (GError) error = NULL;
|
||||
+ MetaTestClient *test_client;
|
||||
+ MetaWindow *window = NULL;
|
||||
+ MtkRectangle frame_rect;
|
||||
+
|
||||
+ /* Configure constraint to a smaller size than monitor */
|
||||
+ constraint_state.enabled = TRUE;
|
||||
+ constraint_state.target_rect = (MtkRectangle) { 100, 80, 500, 350 };
|
||||
+ constraint_state.was_called = FALSE;
|
||||
+
|
||||
+ /* Create window */
|
||||
+ test_client = meta_test_client_new (test_context,
|
||||
+ "external-constraint-test-client",
|
||||
+ META_WINDOW_CLIENT_TYPE_WAYLAND,
|
||||
+ &error);
|
||||
+ g_assert_nonnull (test_client);
|
||||
+ g_assert_no_error (error);
|
||||
+
|
||||
+ meta_test_client_run (test_client,
|
||||
+ "create " TEST_CLIENT_TITLE " csd\n"
|
||||
+ "show " TEST_CLIENT_TITLE "\n");
|
||||
+
|
||||
+ while (!(window = meta_test_client_find_window (test_client,
|
||||
+ TEST_CLIENT_TITLE,
|
||||
+ NULL)))
|
||||
+ g_main_context_iteration (NULL, TRUE);
|
||||
+
|
||||
+ g_object_add_weak_pointer (G_OBJECT (window), (gpointer *) &window);
|
||||
+ wait_for_window_added (window);
|
||||
+
|
||||
+ /* Make the window fullscreen */
|
||||
+ constraint_state.was_called = FALSE;
|
||||
+ meta_window_make_fullscreen (window);
|
||||
+
|
||||
+ while (g_main_context_pending (NULL))
|
||||
+ g_main_context_iteration (NULL, FALSE);
|
||||
+
|
||||
+ /* Verify constraint was called during fullscreen */
|
||||
+ g_assert_true (constraint_state.was_called);
|
||||
+
|
||||
+ /* Verify fullscreen window respects constraint size */
|
||||
+ meta_window_get_frame_rect (window, &frame_rect);
|
||||
+
|
||||
+ g_assert_cmpint (frame_rect.x, ==, constraint_state.target_rect.x);
|
||||
+ g_assert_cmpint (frame_rect.y, ==, constraint_state.target_rect.y);
|
||||
+ g_assert_cmpint (frame_rect.width, ==, constraint_state.target_rect.width);
|
||||
+ g_assert_cmpint (frame_rect.height, ==, constraint_state.target_rect.height);
|
||||
+
|
||||
+ /* Cleanup */
|
||||
+ meta_test_client_destroy (test_client);
|
||||
+ while (window)
|
||||
+ g_main_context_iteration (NULL, TRUE);
|
||||
+
|
||||
+ constraint_state.enabled = FALSE;
|
||||
+ constraint_state.expected_window = NULL;
|
||||
+}
|
||||
+
|
||||
+/* Test: External constraint applies on window resize */
|
||||
+static void
|
||||
+test_external_constraint_resize (void)
|
||||
+{
|
||||
+ g_autoptr (GError) error = NULL;
|
||||
+ MetaTestClient *test_client;
|
||||
+ MetaWindow *window = NULL;
|
||||
+ MtkRectangle frame_rect;
|
||||
+
|
||||
+ /* Configure constraint to limit window size */
|
||||
+ constraint_state.enabled = TRUE;
|
||||
+ constraint_state.target_rect = (MtkRectangle) { 150, 100, 350, 250 };
|
||||
+ constraint_state.was_called = FALSE;
|
||||
+
|
||||
+ /* Create window */
|
||||
+ test_client = meta_test_client_new (test_context,
|
||||
+ "external-constraint-test-client",
|
||||
+ META_WINDOW_CLIENT_TYPE_WAYLAND,
|
||||
+ &error);
|
||||
+ g_assert_nonnull (test_client);
|
||||
+ g_assert_no_error (error);
|
||||
+
|
||||
+ meta_test_client_run (test_client,
|
||||
+ "create " TEST_CLIENT_TITLE " csd\n"
|
||||
+ "show " TEST_CLIENT_TITLE "\n");
|
||||
+
|
||||
+ while (!(window = meta_test_client_find_window (test_client,
|
||||
+ TEST_CLIENT_TITLE,
|
||||
+ NULL)))
|
||||
+ g_main_context_iteration (NULL, TRUE);
|
||||
+
|
||||
+ g_object_add_weak_pointer (G_OBJECT (window), (gpointer *) &window);
|
||||
+ wait_for_window_added (window);
|
||||
+
|
||||
+ /* Verify initial constraint was applied */
|
||||
+ meta_window_get_frame_rect (window, &frame_rect);
|
||||
+ g_assert_cmpint (frame_rect.width, ==, constraint_state.target_rect.width);
|
||||
+ g_assert_cmpint (frame_rect.height, ==, constraint_state.target_rect.height);
|
||||
+
|
||||
+ /* Try to resize window to a larger size via the client */
|
||||
+ constraint_state.was_called = FALSE;
|
||||
+ meta_window_move_resize_frame (window, TRUE, 10, 10, 500, 400);
|
||||
+
|
||||
+ /* Wait for the resize to be processed */
|
||||
+ while (g_main_context_pending (NULL))
|
||||
+ g_main_context_iteration (NULL, FALSE);
|
||||
+
|
||||
+ /* Give it a bit more time to ensure all constraint processing completes */
|
||||
+ g_usleep (50000); /* 50ms */
|
||||
+
|
||||
+ while (g_main_context_pending (NULL))
|
||||
+ g_main_context_iteration (NULL, FALSE);
|
||||
+
|
||||
+ /* Verify constraint was called during client-initiated resize */
|
||||
+ g_assert_true (constraint_state.was_called);
|
||||
+
|
||||
+ /* Verify window size is constrained to our limit, not the requested 500x400 */
|
||||
+ meta_window_get_frame_rect (window, &frame_rect);
|
||||
+
|
||||
+ g_assert_cmpint (frame_rect.x, >=, constraint_state.target_rect.x);
|
||||
+ g_assert_cmpint (frame_rect.y, >=, constraint_state.target_rect.y);
|
||||
+ g_assert_cmpint (frame_rect.width, <=, constraint_state.target_rect.width);
|
||||
+ g_assert_cmpint (frame_rect.height, <=, constraint_state.target_rect.height);
|
||||
+
|
||||
+ /* Cleanup */
|
||||
+ meta_test_client_destroy (test_client);
|
||||
+ while (window)
|
||||
+ g_main_context_iteration (NULL, TRUE);
|
||||
+
|
||||
+ constraint_state.enabled = FALSE;
|
||||
+ constraint_state.expected_window = NULL;
|
||||
+}
|
||||
+
|
||||
+static MetaExternalConstraint *test_constraint = NULL;
|
||||
+
|
||||
+static void
|
||||
+on_window_created (MetaDisplay *display,
|
||||
+ MetaWindow *window,
|
||||
+ gpointer user_data)
|
||||
+{
|
||||
+ /* Add constraint to every newly created window */
|
||||
+ if (test_constraint)
|
||||
+ meta_window_add_external_constraint (window, test_constraint);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+on_before_tests (void)
|
||||
+{
|
||||
+ MetaWaylandCompositor *compositor;
|
||||
+ MetaDisplay *display;
|
||||
+
|
||||
+ /* Create our constraint */
|
||||
+ test_constraint = g_object_new (TEST_TYPE_CONSTRAINT, NULL);
|
||||
+
|
||||
+ /* Connect to window-created signal to add constraint to new windows */
|
||||
+ display = meta_context_get_display (test_context);
|
||||
+ g_signal_connect (display, "window-created",
|
||||
+ G_CALLBACK (on_window_created), NULL);
|
||||
+
|
||||
+ /* Setup test environment */
|
||||
+ compositor = meta_context_get_wayland_compositor (test_context);
|
||||
+ test_driver = meta_wayland_test_driver_new (compositor);
|
||||
+ virtual_monitor = meta_create_test_monitor (test_context, 640, 480, 60.0);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+on_after_tests (void)
|
||||
+{
|
||||
+ MetaDisplay *display;
|
||||
+
|
||||
+ /* Disconnect signal handler */
|
||||
+ display = meta_context_get_display (test_context);
|
||||
+ g_signal_handlers_disconnect_by_func (display,
|
||||
+ G_CALLBACK (on_window_created),
|
||||
+ NULL);
|
||||
+
|
||||
+ /* Cleanup constraint */
|
||||
+ g_clear_object (&test_constraint);
|
||||
+
|
||||
+ g_clear_object (&test_driver);
|
||||
+ g_clear_object (&virtual_monitor);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+init_tests (void)
|
||||
+{
|
||||
+ g_test_add_func ("/backends/external-constraints/basic",
|
||||
+ test_external_constraint_basic);
|
||||
+ g_test_add_func ("/backends/external-constraints/move",
|
||||
+ test_external_constraint_move);
|
||||
+ g_test_add_func ("/backends/external-constraints/resize",
|
||||
+ test_external_constraint_resize);
|
||||
+ g_test_add_func ("/backends/external-constraints/maximized",
|
||||
+ test_external_constraint_maximized);
|
||||
+ g_test_add_func ("/backends/external-constraints/fullscreen",
|
||||
+ test_external_constraint_fullscreen);
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+main (int argc,
|
||||
+ char **argv)
|
||||
+{
|
||||
+ g_autoptr (MetaContext) context = NULL;
|
||||
+ g_autoptr (GError) error = NULL;
|
||||
+
|
||||
+ context = meta_create_test_context (META_CONTEXT_TEST_TYPE_HEADLESS,
|
||||
+#ifdef MUTTER_PRIVILEGED_TEST
|
||||
+ META_CONTEXT_TEST_FLAG_NO_X11 |
|
||||
+#endif
|
||||
+ META_CONTEXT_TEST_FLAG_TEST_CLIENT);
|
||||
+ g_assert_true (meta_context_configure (context, &argc, &argv, NULL));
|
||||
+
|
||||
+ test_context = context;
|
||||
+
|
||||
+ init_tests ();
|
||||
+
|
||||
+ g_signal_connect (context, "before-tests",
|
||||
+ G_CALLBACK (on_before_tests), NULL);
|
||||
+ g_signal_connect (context, "after-tests",
|
||||
+ G_CALLBACK (on_after_tests), NULL);
|
||||
+
|
||||
+ return meta_context_test_run_tests (META_CONTEXT_TEST (context),
|
||||
+ META_TEST_RUN_FLAG_NONE);
|
||||
+}
|
||||
diff --git a/src/tests/meson.build b/src/tests/meson.build
|
||||
index 8c824b5752..9b1a1edf01 100644
|
||||
--- a/src/tests/meson.build
|
||||
+++ b/src/tests/meson.build
|
||||
@@ -955,6 +955,14 @@ wayland_test_cases = [
|
||||
wayland_test_utils,
|
||||
],
|
||||
},
|
||||
+ {
|
||||
+ 'name': 'external-constraint',
|
||||
+ 'suite': 'wayland',
|
||||
+ 'sources': [
|
||||
+ 'external-constraint-tests.c',
|
||||
+ wayland_test_utils,
|
||||
+ ],
|
||||
+ },
|
||||
{
|
||||
'name': 'window-mapped-inhibit',
|
||||
'suite': 'wayland',
|
||||
--
|
||||
2.53.0
|
||||
|
||||
10
mutter.spec
10
mutter.spec
@ -46,6 +46,16 @@ Patch: 0001-Revert-tests-monitor-backlight-Add-tests-for-the-sys.patch
|
||||
Patch: 0001-mtk-Take-explicit-reference-for-mtk_extrapolate_next.patch
|
||||
Patch: 0001-tests-test-runner-Do-a-client-roundtrip-after-popup-.patch
|
||||
|
||||
# Locking windows on monitor - https://issues.redhat.com/browse/RHEL-155377
|
||||
# https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4692
|
||||
Patch: 0001-window-Add-a-map-inhibit-API.patch
|
||||
Patch: 0002-tests-Add-tests-for-map-inhibit.patch
|
||||
Patch: 0003-window-Add-MetaExternalConstraintFlags.patch
|
||||
Patch: 0004-constraints-Add-external-constraints-interface.patch
|
||||
Patch: 0005-window-Add-external-constraints-support.patch
|
||||
Patch: 0006-constraints-Apply-window-external-constraints.patch
|
||||
Patch: 0007-tests-Add-test-for-external-constraints.patch
|
||||
|
||||
BuildRequires: pkgconfig(gobject-introspection-1.0) >= 1.41.0
|
||||
BuildRequires: pkgconfig(sm)
|
||||
BuildRequires: pkgconfig(libadwaita-1)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user