Skip to content
Commits on Source (19)
42.3
====
* wayland: Fix rotation transform [Robert; !1055]
* Fix dma-buf screencast regression [Jonas; !2462]
* Fix monitor mirroring in some cases [Jonas; !2492]
* Fixed crash [Jonas; !2364]
* Plugged leak [Michel; !2469]
Contributors:
Michel Dänzer, Robert Mader, Jonas Ådahl
42.2
====
* Don't use direct scanout for transparent windows [Sebastian; !2409]
......
mutter (42.3-0ubuntu1) jammy; urgency=medium
* New upstream release (LP: #1981724)
* Drop patches applied in new release
-- Jeremy Bicha <jbicha@ubuntu.com> Thu, 14 Jul 2022 17:46:27 +0200
mutter (42.2-0ubuntu1) jammy; urgency=medium
* New upstream release (LP: #1976381)
......
From: =?utf-8?q?Jonas_=C3=85dahl?= <jadahl@gmail.com>
Date: Wed, 6 Apr 2022 10:04:05 +0200
Subject: selection: Return an error if trying to transfer from NULL source
Origin: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2364
---
src/core/meta-selection.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/src/core/meta-selection.c b/src/core/meta-selection.c
index 76c3420..411db49 100644
--- a/src/core/meta-selection.c
+++ b/src/core/meta-selection.c
@@ -438,6 +438,13 @@ meta_selection_transfer_async (MetaSelection *selection,
task = g_task_new (selection, cancellable, callback, user_data);
g_task_set_source_tag (task, meta_selection_transfer_async);
+ if (!selection->owners[selection_type])
+ {
+ g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+ "Tried to transfer from NULL selection source");
+ return;
+ }
+
transfer_request = transfer_request_new (output, selection_type, size,
cancellable);
x11-selection-Unset-selection-ownership-on-shutdown.patch
tests-test-client-Add-clipboard-set-command.patch
wayland-Add-getter-for-XWayland-manager-object.patch
xwayland-Only-warn-on-X-IO-errors-when-X11-is-mandatory.patch
xwayland-Add-API-to-send-signal-to-the-Xwayland-process.patch
selection-Return-an-error-if-trying-to-transfer-from-NULL.patch
x11-input-selection-stream-Handle-Xwayland-going-away.patch
tests-async-waiter-Keep-track-of-X11-display-it-was-creat.patch
tests-Check-that-X11-selections-handle-Xwayland-disappear.patch
theme-use-gtk_render_icon_suface-to-paint-button-icon.patch
theme-load-icons-as-Gtk-does-with-fallback-and-RTL-suppor.patch
meson-add-back-default_driver-option.patch
......
From: =?utf-8?q?Jonas_=C3=85dahl?= <jadahl@gmail.com>
Date: Tue, 5 Apr 2022 23:48:07 +0200
Subject: tests: Check that X11 selections handle Xwayland disappearing
It works by using an X11 client to set the clipboard content, using a
mimetype that on purpose is not handled by the clipboard manager. The
test then makes sure we don't crash when trying to transfer data from
the old X11 selection source.
Origin: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2364
---
src/tests/meson.build | 7 ++
src/tests/xwayland-tests.c | 190 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 197 insertions(+)
create mode 100644 src/tests/xwayland-tests.c
diff --git a/src/tests/meson.build b/src/tests/meson.build
index a197032..3e89ade 100644
--- a/src/tests/meson.build
+++ b/src/tests/meson.build
@@ -276,6 +276,13 @@ if have_native_tests
wayland_test_utils,
],
},
+ {
+ 'name': 'xwayland',
+ 'suite': 'wayland',
+ 'sources': [
+ 'xwayland-tests.c',
+ ],
+ },
]
foreach test_case: test_cases
diff --git a/src/tests/xwayland-tests.c b/src/tests/xwayland-tests.c
new file mode 100644
index 0000000..9cdce37
--- /dev/null
+++ b/src/tests/xwayland-tests.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2022 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+
+#include "meta/meta-selection.h"
+#include "meta-test/meta-context-test.h"
+#include "tests/meta-test-utils.h"
+#include "wayland/meta-wayland.h"
+#include "wayland/meta-xwayland.h"
+#include "x11/meta-x11-display-private.h"
+
+static MetaContext *test_context;
+
+static void
+test_client_do_check (MetaTestClient *test_client,
+ ...)
+{
+ g_autoptr (GError) error = NULL;
+ va_list vap;
+ gboolean retval;
+
+ va_start (vap, test_client);
+ retval = meta_test_client_dov (test_client, &error, vap);
+ va_end (vap);
+
+ if (!retval)
+ g_error ("Failed to process test client command: %s", error->message);
+}
+
+static void
+test_client_wait_check (MetaTestClient *test_client)
+{
+ g_autoptr (GError) error = NULL;
+
+ if (!meta_test_client_wait (test_client, &error))
+ g_error ("Failed to wait for test client: %s", error->message);
+}
+
+static void
+transfer_ready_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GMainLoop *loop = user_data;
+ g_autoptr (GError) error = NULL;
+
+ if (!meta_selection_transfer_finish (META_SELECTION (source_object), res,
+ &error))
+ g_warning ("Failed to transfer: %s", error->message);
+
+ g_main_loop_quit (loop);
+}
+
+static gboolean
+tests_alarm_filter (MetaX11Display *x11_display,
+ XSyncAlarmNotifyEvent *event,
+ gpointer user_data)
+{
+ MetaTestClient *test_client = user_data;
+ return meta_test_client_process_x11_event (test_client,
+ x11_display, event);
+}
+
+static void
+ensure_xwayland (MetaContext *context)
+{
+ MetaDisplay *display = meta_context_get_display (test_context);
+
+ if (meta_display_get_x11_display (display))
+ return;
+
+ while (!meta_display_get_x11_display (display))
+ g_main_context_iteration (NULL, TRUE);
+}
+
+static void
+meta_test_xwayland_restart_selection (void)
+{
+ MetaWaylandCompositor *wayland_compositor =
+ meta_context_get_wayland_compositor (test_context);
+ MetaXWaylandManager *xwayland_manager =
+ meta_wayland_compositor_get_xwayland_manager (wayland_compositor);
+ MetaDisplay *display = meta_context_get_display (test_context);
+ MetaSelection *selection = meta_display_get_selection (display);
+ MetaX11Display *x11_display;
+ MetaTestClient *test_client;
+ static int client_count = 0;
+ g_autofree char *client_name = NULL;
+ g_autoptr (GError) error = NULL;
+ g_autoptr (GMainLoop) loop = NULL;
+ g_autoptr (GOutputStream) output = NULL;
+ const char *window_name = "clipboard-window";
+
+ client_name = g_strdup_printf ("test_client_%d", client_count++);
+ test_client = meta_test_client_new (test_context,
+ client_name, META_WINDOW_CLIENT_TYPE_X11,
+ &error);
+ if (!test_client)
+ g_error ("Failed to launch test client: %s", error->message);
+
+ ensure_xwayland (test_context);
+ x11_display = meta_display_get_x11_display (display);
+ meta_x11_display_set_alarm_filter (x11_display,
+ tests_alarm_filter,
+ test_client);
+
+ test_client_do_check (test_client,
+ "create", window_name,
+ NULL);
+ test_client_do_check (test_client,
+ "clipboard-set", "application/mutter-test", "hello",
+ NULL);
+ test_client_wait_check (test_client);
+
+ g_test_expect_message ("libmutter", G_LOG_LEVEL_WARNING,
+ "*Connection to xwayland lost*");
+ g_test_expect_message ("libmutter", G_LOG_LEVEL_WARNING,
+ "X Wayland crashed*; attempting to recover");
+
+ if (!meta_xwayland_signal (xwayland_manager, SIGKILL, &error))
+ g_error ("Failed to signal SIGSEGV to Xwayland");
+
+ while (meta_display_get_x11_display (display))
+ g_main_context_iteration (NULL, TRUE);
+
+ g_test_assert_expected_messages ();
+
+ loop = g_main_loop_new (NULL, FALSE);
+ output = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
+
+ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
+ "*Tried to transfer from NULL selection source");
+ meta_selection_transfer_async (selection,
+ META_SELECTION_CLIPBOARD,
+ "text/plain",
+ -1,
+ output,
+ NULL,
+ transfer_ready_cb,
+ loop);
+
+ g_main_loop_run (loop);
+
+ g_test_assert_expected_messages ();
+
+ meta_test_client_destroy (test_client);
+}
+
+static void
+init_tests (void)
+{
+ g_test_add_func ("/backends/xwayland/restart/selection",
+ meta_test_xwayland_restart_selection);
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ g_autoptr (MetaContext) context = NULL;
+ g_autoptr (GError) error = NULL;
+
+ context = test_context =
+ meta_create_test_context (META_CONTEXT_TEST_TYPE_HEADLESS,
+ META_CONTEXT_TEST_FLAG_TEST_CLIENT);
+ g_assert (meta_context_configure (context, &argc, &argv, NULL));
+
+ init_tests ();
+
+ return meta_context_test_run_tests (META_CONTEXT_TEST (context),
+ META_TEST_RUN_FLAG_NONE);
+}
From: =?utf-8?q?Jonas_=C3=85dahl?= <jadahl@gmail.com>
Date: Wed, 6 Apr 2022 10:30:59 +0200
Subject: tests/async-waiter: Keep track of X11 display it was created with
The Xwayland server can go away at any time; when this happen we might
have a test client running, and for it to tear down more nicely, make
sure to avoid trying to clean up X11 resources on the old X11 display.
Origin: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2364
---
src/tests/meta-test-utils.c | 55 ++++++++++++++++++++++++++++++++-------------
src/tests/meta-test-utils.h | 4 ++--
src/tests/test-runner.c | 2 +-
3 files changed, 42 insertions(+), 19 deletions(-)
diff --git a/src/tests/meta-test-utils.c b/src/tests/meta-test-utils.c
index 261d2c4..626317b 100644
--- a/src/tests/meta-test-utils.c
+++ b/src/tests/meta-test-utils.c
@@ -50,7 +50,10 @@ struct _MetaTestClient
MetaAsyncWaiter *waiter;
};
-struct _MetaAsyncWaiter {
+struct _MetaAsyncWaiter
+{
+ MetaX11Display *x11_display;
+
XSyncCounter counter;
int counter_value;
XSyncAlarm alarm;
@@ -91,15 +94,18 @@ meta_ensure_test_client_path (int argc,
}
MetaAsyncWaiter *
-meta_async_waiter_new (void)
+meta_async_waiter_new (MetaX11Display *x11_display)
{
- MetaAsyncWaiter *waiter = g_new0 (MetaAsyncWaiter, 1);
-
- MetaDisplay *display = meta_get_display ();
- Display *xdisplay = display->x11_display->xdisplay;
+ Display *xdisplay = meta_x11_display_get_xdisplay (x11_display);
+ MetaAsyncWaiter *waiter;
XSyncValue value;
XSyncAlarmAttributes attr;
+ waiter = g_new0 (MetaAsyncWaiter, 1);
+
+ waiter->x11_display = x11_display;
+ g_object_add_weak_pointer (G_OBJECT (x11_display),
+ (gpointer *) &waiter->x11_display);
waiter->counter_value = 0;
XSyncIntToValue (&value, waiter->counter_value);
@@ -136,11 +142,19 @@ meta_async_waiter_new (void)
void
meta_async_waiter_destroy (MetaAsyncWaiter *waiter)
{
- MetaDisplay *display = meta_get_display ();
- Display *xdisplay = display->x11_display->xdisplay;
+ MetaX11Display *x11_display;
- XSyncDestroyAlarm (xdisplay, waiter->alarm);
- XSyncDestroyCounter (xdisplay, waiter->counter);
+ x11_display = waiter->x11_display;
+ if (x11_display)
+ {
+ Display *xdisplay = meta_x11_display_get_xdisplay (x11_display);
+
+ XSyncDestroyAlarm (xdisplay, waiter->alarm);
+ XSyncDestroyCounter (xdisplay, waiter->counter);
+
+ g_object_remove_weak_pointer (G_OBJECT (x11_display),
+ (gpointer *) &waiter->x11_display);
+ }
g_main_loop_unref (waiter->loop);
}
@@ -165,13 +179,17 @@ meta_async_waiter_wait (MetaAsyncWaiter *waiter,
void
meta_async_waiter_set_and_wait (MetaAsyncWaiter *waiter)
{
- MetaDisplay *display = meta_get_display ();
- Display *xdisplay = display->x11_display->xdisplay;
- int wait_value = meta_async_waiter_next_value (waiter);
+ Display *xdisplay;
+ int wait_value;
+
+ g_return_if_fail (waiter->x11_display);
+
+ wait_value = meta_async_waiter_next_value (waiter);
XSyncValue sync_value;
XSyncIntToValue (&sync_value, wait_value);
+ xdisplay = meta_x11_display_get_xdisplay (waiter->x11_display);
XSyncSetCounter (xdisplay, waiter->counter, sync_value);
meta_async_waiter_wait (waiter, wait_value);
}
@@ -181,6 +199,7 @@ meta_async_waiter_process_x11_event (MetaAsyncWaiter *waiter,
MetaX11Display *x11_display,
XSyncAlarmNotifyEvent *event)
{
+ g_assert (x11_display == waiter->x11_display);
if (event->alarm != waiter->alarm)
return FALSE;
@@ -520,9 +539,11 @@ meta_test_client_new (MetaContext *context,
if (client->type == META_WINDOW_CLIENT_TYPE_X11)
{
- MetaDisplay *display = meta_get_display ();
+ MetaDisplay *display = meta_context_get_display (context);
+ MetaX11Display *x11_display;
- if (!display->x11_display)
+ x11_display = meta_display_get_x11_display (display);
+ if (!x11_display)
{
GThread *thread;
@@ -532,8 +553,10 @@ meta_test_client_new (MetaContext *context,
meta_context_test_wait_for_x11_display (META_CONTEXT_TEST (context));
g_thread_join (thread);
}
+ x11_display = meta_display_get_x11_display (display);
+ g_assert_nonnull (x11_display);
- client->waiter = meta_async_waiter_new ();
+ client->waiter = meta_async_waiter_new (x11_display);
}
return client;
diff --git a/src/tests/meta-test-utils.h b/src/tests/meta-test-utils.h
index fe0bde7..0ecd08c 100644
--- a/src/tests/meta-test-utils.h
+++ b/src/tests/meta-test-utils.h
@@ -50,14 +50,14 @@ typedef struct _MetaTestClient MetaTestClient;
META_EXPORT
gboolean meta_async_waiter_process_x11_event (MetaAsyncWaiter *waiter,
- MetaX11Display *display,
+ MetaX11Display *x11_display,
XSyncAlarmNotifyEvent *event);
META_EXPORT
void meta_async_waiter_set_and_wait (MetaAsyncWaiter *waiter);
META_EXPORT
-MetaAsyncWaiter * meta_async_waiter_new (void);
+MetaAsyncWaiter * meta_async_waiter_new (MetaX11Display *x11_display);
META_EXPORT
void meta_async_waiter_destroy (MetaAsyncWaiter *waiter);
diff --git a/src/tests/test-runner.c b/src/tests/test-runner.c
index 1386df0..c691ef6 100644
--- a/src/tests/test-runner.c
+++ b/src/tests/test-runner.c
@@ -73,7 +73,7 @@ on_x11_display_opened (MetaDisplay *display,
{
meta_x11_display_set_alarm_filter (display->x11_display,
test_case_alarm_filter, test);
- test->waiter = meta_async_waiter_new ();
+ test->waiter = meta_async_waiter_new (display->x11_display);
}
static TestCase *
From: =?utf-8?q?Jonas_=C3=85dahl?= <jadahl@gmail.com>
Date: Tue, 5 Apr 2022 23:42:55 +0200
Subject: tests/test-client: Add clipboard-set command
To be used for clipboard testing.
Origin: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2364
---
src/tests/test-client.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
src/tests/test-runner.c | 12 ++++++++++++
2 files changed, 59 insertions(+)
diff --git a/src/tests/test-client.c b/src/tests/test-client.c
index 0007d61..7e4235f 100644
--- a/src/tests/test-client.c
+++ b/src/tests/test-client.c
@@ -260,6 +260,22 @@ calculate_titlebar_height (GtkWindow *window)
return gtk_widget_get_allocated_height (titlebar);
}
+static void
+text_get_func (GtkClipboard *clipboard,
+ GtkSelectionData *selection_data,
+ unsigned int info,
+ gpointer data)
+{
+ gtk_selection_data_set_text (selection_data, data, -1);
+}
+
+static void
+text_clear_func (GtkClipboard *clipboard,
+ gpointer data)
+{
+ g_free (data);
+}
+
static void
process_line (const char *line)
{
@@ -845,6 +861,37 @@ process_line (const char *line)
sync_after_lines = -1;
}
+ else if (strcmp (argv[0], "clipboard-set") == 0)
+ {
+ GdkDisplay *display = gdk_display_get_default ();
+ GtkClipboard *clipboard;
+ GdkAtom atom;
+ GtkTargetList *target_list;
+ GtkTargetEntry *targets;
+ int n_targets;
+
+ if (argc != 3)
+ {
+ g_print ("usage: clipboard-set <mimetype> <text>\n");
+ goto out;
+ }
+
+ clipboard = gtk_clipboard_get_for_display (display,
+ GDK_SELECTION_CLIPBOARD);
+
+ atom = gdk_atom_intern (argv[1], FALSE);
+ target_list = gtk_target_list_new (NULL, 0);
+ gtk_target_list_add (target_list, atom, 0, 0);
+
+ targets = gtk_target_table_new_from_list (target_list, &n_targets);
+ gtk_target_list_unref (target_list);
+
+ gtk_clipboard_set_with_data (clipboard,
+ targets, n_targets,
+ text_get_func, text_clear_func,
+ g_strdup (argv[2]));
+ gtk_target_table_free (targets, n_targets);
+ }
else
{
g_print ("Unknown command %s\n", argv[0]);
diff --git a/src/tests/test-runner.c b/src/tests/test-runner.c
index 6a2e5a2..1386df0 100644
--- a/src/tests/test-runner.c
+++ b/src/tests/test-runner.c
@@ -973,6 +973,18 @@ test_case_do (TestCase *test,
if (!meta_test_client_do (client, error, argv[0], NULL))
return FALSE;
}
+ else if (strcmp (argv[0], "clipboard-set") == 0)
+ {
+ if (argc != 4)
+ BAD_COMMAND("usage: %s <client-id> <mimetype> <text>", argv[0]);
+
+ MetaTestClient *client = test_case_lookup_client (test, argv[1], error);
+ if (!client)
+ return FALSE;
+
+ if (!meta_test_client_do (client, error, argv[0], argv[2], argv[3], NULL))
+ return FALSE;
+ }
else
{
BAD_COMMAND("Unknown command %s", argv[0]);
From: =?utf-8?q?Jonas_=C3=85dahl?= <jadahl@gmail.com>
Date: Tue, 5 Apr 2022 23:43:38 +0200
Subject: wayland: Add getter for XWayland manager object
Origin: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2364
(cherry picked from commit e1033951ef687839245d94fb58393af9a66d9ce0)
---
src/wayland/meta-wayland-private.h | 4 ++--
src/wayland/meta-wayland-types.h | 2 ++
src/wayland/meta-wayland.c | 6 ++++++
src/wayland/meta-wayland.h | 3 +++
4 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/src/wayland/meta-wayland-private.h b/src/wayland/meta-wayland-private.h
index 613dc21..67510d5 100644
--- a/src/wayland/meta-wayland-private.h
+++ b/src/wayland/meta-wayland-private.h
@@ -52,7 +52,7 @@ typedef struct
char *name;
} MetaXWaylandConnection;
-typedef struct
+struct _MetaXWaylandManager
{
MetaXWaylandConnection private_connection;
MetaXWaylandConnection public_connection;
@@ -73,7 +73,7 @@ typedef struct
gboolean has_xrandr;
int rr_event_base;
int rr_error_base;
-} MetaXWaylandManager;
+};
struct _MetaWaylandCompositor
{
diff --git a/src/wayland/meta-wayland-types.h b/src/wayland/meta-wayland-types.h
index b2c8615..541636e 100644
--- a/src/wayland/meta-wayland-types.h
+++ b/src/wayland/meta-wayland-types.h
@@ -65,4 +65,6 @@ typedef struct _MetaWaylandActivation MetaWaylandActivation;
typedef struct _MetaWaylandDmaBufManager MetaWaylandDmaBufManager;
+typedef struct _MetaXWaylandManager MetaXWaylandManager;
+
#endif
diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c
index 856b819..14d0cff 100644
--- a/src/wayland/meta-wayland.c
+++ b/src/wayland/meta-wayland.c
@@ -820,3 +820,9 @@ meta_wayland_compositor_is_egl_display_bound (MetaWaylandCompositor *compositor)
return priv->is_wayland_egl_display_bound;
}
+
+MetaXWaylandManager *
+meta_wayland_compositor_get_xwayland_manager (MetaWaylandCompositor *compositor)
+{
+ return &compositor->xwayland_manager;
+}
diff --git a/src/wayland/meta-wayland.h b/src/wayland/meta-wayland.h
index bee2ef4..6528a02 100644
--- a/src/wayland/meta-wayland.h
+++ b/src/wayland/meta-wayland.h
@@ -94,5 +94,8 @@ void meta_wayland_compositor_notify_surface_id (MetaWaylandCo
int id,
MetaWaylandSurface *surface);
+META_EXPORT_TEST
+MetaXWaylandManager * meta_wayland_compositor_get_xwayland_manager (MetaWaylandCompositor *compositor);
+
#endif
From: =?utf-8?q?Jonas_=C3=85dahl?= <jadahl@gmail.com>
Date: Wed, 6 Apr 2022 10:05:35 +0200
Subject: x11/input-selection-stream: Handle Xwayland going away
Xwayland can disappear at any time, for example during a new_async() or
read_async() call. When we eventually finalize the stream, the X11
display it was created for is gone, thus can't clean up the X11
resources. Handle this by making the MetaX11Display pointer a weak
pointer, and ignore cleaning up if it disappeared. This is fine since
the X11 server it created those resources one is gone already.
Origin: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2364
---
src/x11/meta-x11-selection-input-stream.c | 25 +++++++++++++++++++++----
1 file changed, 21 insertions(+), 4 deletions(-)
diff --git a/src/x11/meta-x11-selection-input-stream.c b/src/x11/meta-x11-selection-input-stream.c
index 9747fa5..fead368 100644
--- a/src/x11/meta-x11-selection-input-stream.c
+++ b/src/x11/meta-x11-selection-input-stream.c
@@ -270,9 +270,14 @@ meta_x11_selection_input_stream_dispose (GObject *object)
META_X11_SELECTION_INPUT_STREAM (object);
MetaX11SelectionInputStreamPrivate *priv =
meta_x11_selection_input_stream_get_instance_private (stream);
+ MetaX11Display *x11_display;
- priv->x11_display->selection.input_streams =
- g_list_remove (priv->x11_display->selection.input_streams, stream);
+ x11_display = priv->x11_display;
+ if (x11_display)
+ {
+ x11_display->selection.input_streams =
+ g_list_remove (x11_display->selection.input_streams, stream);
+ }
G_OBJECT_CLASS (meta_x11_selection_input_stream_parent_class)->dispose (object);
}
@@ -284,11 +289,20 @@ meta_x11_selection_input_stream_finalize (GObject *object)
META_X11_SELECTION_INPUT_STREAM (object);
MetaX11SelectionInputStreamPrivate *priv =
meta_x11_selection_input_stream_get_instance_private (stream);
- Display *xdisplay = priv->x11_display->xdisplay;
+ MetaX11Display *x11_display;
g_async_queue_unref (priv->chunks);
- XDestroyWindow (xdisplay, priv->window);
+ x11_display = priv->x11_display;
+ if (x11_display)
+ {
+ Display *xdisplay = meta_x11_display_get_xdisplay (x11_display);
+
+ XDestroyWindow (xdisplay, priv->window);
+
+ g_object_remove_weak_pointer (G_OBJECT (x11_display),
+ (gpointer *) &priv->x11_display);
+ }
G_OBJECT_CLASS (meta_x11_selection_input_stream_parent_class)->finalize (object);
}
@@ -522,6 +536,9 @@ meta_x11_selection_input_stream_new_async (MetaX11Display *x11_display,
attributes.override_redirect = True;
priv->x11_display = x11_display;
+ g_object_add_weak_pointer (G_OBJECT (x11_display),
+ (gpointer *) &priv->x11_display);
+
x11_display->selection.input_streams =
g_list_prepend (x11_display->selection.input_streams, stream);
priv->xselection = XInternAtom (x11_display->xdisplay, selection, False);
From: =?utf-8?q?Jonas_=C3=85dahl?= <jadahl@gmail.com>
Date: Tue, 5 Apr 2022 22:11:20 +0200
Subject: x11/selection: Unset selection ownership on shutdown
This makes sure we don't accidentally try to paste from past Xwayland
connection instances.
Origin: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2364
---
src/x11/meta-x11-selection.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/src/x11/meta-x11-selection.c b/src/x11/meta-x11-selection.c
index e389f22..cf50e63 100644
--- a/src/x11/meta-x11-selection.c
+++ b/src/x11/meta-x11-selection.c
@@ -524,16 +524,24 @@ meta_x11_selection_init (MetaX11Display *x11_display)
void
meta_x11_selection_shutdown (MetaX11Display *x11_display)
{
- MetaDisplay *display = meta_get_display ();
+ MetaDisplay *display = meta_x11_display_get_display (x11_display);
+ MetaSelection *selection = meta_display_get_selection (display);
guint i;
- g_signal_handlers_disconnect_by_func (meta_display_get_selection (display),
+ g_signal_handlers_disconnect_by_func (selection,
notify_selection_owner,
x11_display);
for (i = 0; i < META_N_SELECTION_TYPES; i++)
{
- g_clear_object (&x11_display->selection.owners[i]);
+ MetaSelectionSource *owner;
+
+ owner = x11_display->selection.owners[i];
+ if (owner)
+ {
+ meta_selection_unset_owner (selection, i, owner);
+ g_clear_object (&x11_display->selection.owners[i]);
+ }
if (x11_display->selection.cancellables[i])
{
g_cancellable_cancel (x11_display->selection.cancellables[i]);
From: =?utf-8?q?Jonas_=C3=85dahl?= <jadahl@gmail.com>
Date: Tue, 5 Apr 2022 23:46:42 +0200
Subject: xwayland: Add API to send signal to the Xwayland process
Will be used for test cases to fake-crash the Xwayland process.
Origin: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2364
---
src/wayland/meta-xwayland.c | 16 ++++++++++++++++
src/wayland/meta-xwayland.h | 5 +++++
2 files changed, 21 insertions(+)
diff --git a/src/wayland/meta-xwayland.c b/src/wayland/meta-xwayland.c
index 06f059f..a21cc9b 100644
--- a/src/wayland/meta-xwayland.c
+++ b/src/wayland/meta-xwayland.c
@@ -1276,3 +1276,19 @@ meta_xwayland_handle_xevent (XEvent *event)
return FALSE;
}
+
+gboolean
+meta_xwayland_signal (MetaXWaylandManager *manager,
+ int signum,
+ GError **error)
+{
+ if (!manager->proc)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Can't send signal, Xwayland not running");
+ return FALSE;
+ }
+
+ g_subprocess_send_signal (manager->proc, signum);
+ return TRUE;
+}
diff --git a/src/wayland/meta-xwayland.h b/src/wayland/meta-xwayland.h
index dac9c68..cbe27b1 100644
--- a/src/wayland/meta-xwayland.h
+++ b/src/wayland/meta-xwayland.h
@@ -50,4 +50,9 @@ void
meta_xwayland_associate_window_with_surface (MetaWindow *window,
MetaWaylandSurface *surface);
+META_EXPORT_TEST
+gboolean meta_xwayland_signal (MetaXWaylandManager *manager,
+ int signum,
+ GError **error);
+
#endif /* META_XWAYLAND_H */
From: =?utf-8?q?Jonas_=C3=85dahl?= <jadahl@gmail.com>
Date: Tue, 5 Apr 2022 23:45:51 +0200
Subject: xwayland: Only warn on X IO errors when X11 is mandatory
This avoids warnings when we're just slightly unlucky when Xwayland went
away due to inactivity.
Origin: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2364
---
src/wayland/meta-wayland-private.h | 2 ++
src/wayland/meta-xwayland.c | 12 +++++++++++-
2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/src/wayland/meta-wayland-private.h b/src/wayland/meta-wayland-private.h
index 67510d5..ecef32f 100644
--- a/src/wayland/meta-wayland-private.h
+++ b/src/wayland/meta-wayland-private.h
@@ -54,6 +54,8 @@ typedef struct
struct _MetaXWaylandManager
{
+ MetaWaylandCompositor *compositor;
+
MetaXWaylandConnection private_connection;
MetaXWaylandConnection public_connection;
diff --git a/src/wayland/meta-xwayland.c b/src/wayland/meta-xwayland.c
index dc96b60..06f059f 100644
--- a/src/wayland/meta-xwayland.c
+++ b/src/wayland/meta-xwayland.c
@@ -478,7 +478,16 @@ static void
x_io_error_exit (Display *display,
void *data)
{
- g_warning ("Xwayland just died, attempting to recover");
+ MetaXWaylandManager *manager = data;
+ MetaX11DisplayPolicy x11_display_policy;
+
+ x11_display_policy =
+ meta_context_get_x11_display_policy (manager->compositor->context);
+
+ if (x11_display_policy == META_X11_DISPLAY_POLICY_MANDATORY)
+ g_warning ("X Wayland crashed (X IO error)");
+ else
+ meta_topic (META_DEBUG_WAYLAND, "Xwayland disappeared during a Xlib call");
}
static void
@@ -1033,6 +1042,7 @@ meta_xwayland_init (MetaXWaylandManager *manager,
manager->public_connection.name,
manager->private_connection.name);
+ manager->compositor = compositor;
manager->wayland_display = wl_display;
policy = meta_context_get_x11_display_policy (context);
project('mutter', 'c',
version: '42.2',
version: '42.3',
meson_version: '>= 0.55.0',
license: 'GPLv2+'
)
......
......@@ -55,6 +55,7 @@ typedef struct _MetaCrtcModeInfo
int height;
float refresh_rate;
int64_t vblank_duration_us;
uint32_t pixel_clock_khz;
MetaCrtcModeFlag flags;
} MetaCrtcModeInfo;
......
......@@ -552,13 +552,13 @@ meta_screen_cast_monitor_stream_src_record_to_framebuffer (MetaScreenCastStreamS
{
MetaScreenCastMonitorStreamSrc *monitor_src =
META_SCREEN_CAST_MONITOR_STREAM_SRC (src);
MetaBackend *backend = get_backend (monitor_src);
MetaRenderer *renderer = meta_backend_get_renderer (backend);
MetaScreenCastStream *stream = meta_screen_cast_stream_src_get_stream (src);
ClutterStage *stage = get_stage (monitor_src);
MetaMonitor *monitor;
MetaLogicalMonitor *logical_monitor;
MetaRectangle logical_monitor_layout;
GList *l;
float view_scale;
ClutterPaintFlag paint_flags = CLUTTER_PAINT_FLAG_CLEAR;
monitor = get_monitor (monitor_src);
logical_monitor = meta_monitor_get_logical_monitor (monitor);
......@@ -569,44 +569,22 @@ meta_screen_cast_monitor_stream_src_record_to_framebuffer (MetaScreenCastStreamS
else
view_scale = 1.0;
for (l = meta_renderer_get_views (renderer); l; l = l->next)
switch (meta_screen_cast_stream_get_cursor_mode (stream))
{
ClutterStageView *view = CLUTTER_STAGE_VIEW (l->data);
CoglFramebuffer *view_framebuffer;
CoglScanout *scanout;
MetaRectangle view_layout;
int x, y;
clutter_stage_view_get_layout (view, &view_layout);
if (!meta_rectangle_overlap (&logical_monitor_layout, &view_layout))
continue;
x = (int) roundf ((view_layout.x - logical_monitor_layout.x) * view_scale);
y = (int) roundf ((view_layout.y - logical_monitor_layout.y) * view_scale);
case META_SCREEN_CAST_CURSOR_MODE_METADATA:
case META_SCREEN_CAST_CURSOR_MODE_HIDDEN:
paint_flags |= CLUTTER_PAINT_FLAG_NO_CURSORS;
break;
case META_SCREEN_CAST_CURSOR_MODE_EMBEDDED:
paint_flags |= CLUTTER_PAINT_FLAG_FORCE_CURSORS;
break;
}
scanout = clutter_stage_view_peek_scanout (view);
if (scanout)
{
if (!cogl_scanout_blit_to_framebuffer (scanout,
framebuffer,
x, y,
error))
return FALSE;
}
else
{
view_framebuffer = clutter_stage_view_get_framebuffer (view);
if (!cogl_blit_framebuffer (view_framebuffer,
clutter_stage_paint_to_framebuffer (stage,
framebuffer,
0, 0,
x, y,
cogl_framebuffer_get_width (view_framebuffer),
cogl_framebuffer_get_height (view_framebuffer),
error))
return FALSE;
}
}
&logical_monitor_layout,
view_scale,
paint_flags);
cogl_framebuffer_flush (framebuffer);
......
......@@ -57,6 +57,7 @@ meta_crtc_mode_kms_new (MetaKmsMode *kms_mode,
meta_calculate_drm_mode_refresh_rate (drm_mode);
crtc_mode_info->vblank_duration_us =
meta_calculate_drm_mode_vblank_duration_us (drm_mode);
crtc_mode_info->pixel_clock_khz = drm_mode->clock;
crtc_mode_name = g_strndup (drm_mode->name, DRM_DISPLAY_MODE_LEN);
mode_kms = g_object_new (META_TYPE_CRTC_MODE_KMS,
......
......@@ -178,7 +178,7 @@ add_common_modes (MetaOutputInfo *output_info,
unsigned max_hdisplay = 0;
unsigned max_vdisplay = 0;
float max_refresh_rate = 0.0;
float max_bandwidth = 0.0;
uint32_t max_pixel_clock = 0;
MetaKmsDevice *kms_device;
MetaKmsModeFlag flag_filter;
GList *l;
......@@ -187,14 +187,11 @@ add_common_modes (MetaOutputInfo *output_info,
{
const MetaCrtcModeInfo *crtc_mode_info =
meta_crtc_mode_get_info (output_info->modes[i]);
float bandwidth;
bandwidth = crtc_mode_info->refresh_rate * crtc_mode_info->width *
crtc_mode_info->height;
max_hdisplay = MAX (max_hdisplay, crtc_mode_info->width);
max_vdisplay = MAX (max_vdisplay, crtc_mode_info->height);
max_refresh_rate = MAX (max_refresh_rate, crtc_mode_info->refresh_rate);
max_bandwidth = MAX (max_bandwidth, bandwidth);
max_pixel_clock = MAX (max_pixel_clock, crtc_mode_info->pixel_clock_khz);
}
max_refresh_rate = MAX (max_refresh_rate, 60.0);
......@@ -213,7 +210,6 @@ add_common_modes (MetaOutputInfo *output_info,
{
MetaKmsMode *fallback_mode = l->data;
const drmModeModeInfo *drm_mode;
float bandwidth;
float refresh_rate;
gboolean is_duplicate = FALSE;
......@@ -222,11 +218,10 @@ add_common_modes (MetaOutputInfo *output_info,
drm_mode = meta_kms_mode_get_drm_mode (fallback_mode);
refresh_rate = meta_calculate_drm_mode_refresh_rate (drm_mode);
bandwidth = refresh_rate * drm_mode->hdisplay * drm_mode->vdisplay;
if (drm_mode->hdisplay > max_hdisplay ||
drm_mode->vdisplay > max_vdisplay ||
refresh_rate > max_refresh_rate ||
bandwidth > max_bandwidth)
drm_mode->clock > max_pixel_clock)
continue;
for (i = 0; i < output_info->n_modes; i++)
......
......@@ -438,6 +438,13 @@ meta_selection_transfer_async (MetaSelection *selection,
task = g_task_new (selection, cancellable, callback, user_data);
g_task_set_source_tag (task, meta_selection_transfer_async);
if (!selection->owners[selection_type])
{
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
"Tried to transfer from NULL selection source");
return;
}
transfer_request = transfer_request_new (output, selection_type, size,
cancellable);
......
......@@ -295,6 +295,13 @@ if have_native_tests
wayland_test_utils,
],
},
{
'name': 'xwayland',
'suite': 'wayland',
'sources': [
'xwayland-tests.c',
],
},
]
foreach test_case: test_cases
......
......@@ -50,7 +50,10 @@ struct _MetaTestClient
MetaAsyncWaiter *waiter;
};
struct _MetaAsyncWaiter {
struct _MetaAsyncWaiter
{
MetaX11Display *x11_display;
XSyncCounter counter;
int counter_value;
XSyncAlarm alarm;
......@@ -91,15 +94,18 @@ meta_ensure_test_client_path (int argc,
}
MetaAsyncWaiter *
meta_async_waiter_new (void)
meta_async_waiter_new (MetaX11Display *x11_display)
{
MetaAsyncWaiter *waiter = g_new0 (MetaAsyncWaiter, 1);
MetaDisplay *display = meta_get_display ();
Display *xdisplay = display->x11_display->xdisplay;
Display *xdisplay = meta_x11_display_get_xdisplay (x11_display);
MetaAsyncWaiter *waiter;
XSyncValue value;
XSyncAlarmAttributes attr;
waiter = g_new0 (MetaAsyncWaiter, 1);
waiter->x11_display = x11_display;
g_object_add_weak_pointer (G_OBJECT (x11_display),
(gpointer *) &waiter->x11_display);
waiter->counter_value = 0;
XSyncIntToValue (&value, waiter->counter_value);
......@@ -136,11 +142,19 @@ meta_async_waiter_new (void)
void
meta_async_waiter_destroy (MetaAsyncWaiter *waiter)
{
MetaDisplay *display = meta_get_display ();
Display *xdisplay = display->x11_display->xdisplay;
MetaX11Display *x11_display;
XSyncDestroyAlarm (xdisplay, waiter->alarm);
XSyncDestroyCounter (xdisplay, waiter->counter);
x11_display = waiter->x11_display;
if (x11_display)
{
Display *xdisplay = meta_x11_display_get_xdisplay (x11_display);
XSyncDestroyAlarm (xdisplay, waiter->alarm);
XSyncDestroyCounter (xdisplay, waiter->counter);
g_object_remove_weak_pointer (G_OBJECT (x11_display),
(gpointer *) &waiter->x11_display);
}
g_main_loop_unref (waiter->loop);
}
......@@ -165,13 +179,17 @@ meta_async_waiter_wait (MetaAsyncWaiter *waiter,
void
meta_async_waiter_set_and_wait (MetaAsyncWaiter *waiter)
{
MetaDisplay *display = meta_get_display ();
Display *xdisplay = display->x11_display->xdisplay;
int wait_value = meta_async_waiter_next_value (waiter);
Display *xdisplay;
int wait_value;
g_return_if_fail (waiter->x11_display);
wait_value = meta_async_waiter_next_value (waiter);
XSyncValue sync_value;
XSyncIntToValue (&sync_value, wait_value);
xdisplay = meta_x11_display_get_xdisplay (waiter->x11_display);
XSyncSetCounter (xdisplay, waiter->counter, sync_value);
meta_async_waiter_wait (waiter, wait_value);
}
......@@ -181,6 +199,7 @@ meta_async_waiter_process_x11_event (MetaAsyncWaiter *waiter,
MetaX11Display *x11_display,
XSyncAlarmNotifyEvent *event)
{
g_assert (x11_display == waiter->x11_display);
if (event->alarm != waiter->alarm)
return FALSE;
......@@ -520,9 +539,11 @@ meta_test_client_new (MetaContext *context,
if (client->type == META_WINDOW_CLIENT_TYPE_X11)
{
MetaDisplay *display = meta_get_display ();
MetaDisplay *display = meta_context_get_display (context);
MetaX11Display *x11_display;
if (!display->x11_display)
x11_display = meta_display_get_x11_display (display);
if (!x11_display)
{
GThread *thread;
......@@ -532,8 +553,10 @@ meta_test_client_new (MetaContext *context,
meta_context_test_wait_for_x11_display (META_CONTEXT_TEST (context));
g_thread_join (thread);
}
x11_display = meta_display_get_x11_display (display);
g_assert_nonnull (x11_display);
client->waiter = meta_async_waiter_new ();
client->waiter = meta_async_waiter_new (x11_display);
}
return client;
......