diff --git a/SOURCES/0001-monitor-config-manager-Handle-multiple-builtin-panel.patch b/SOURCES/0001-monitor-config-manager-Handle-multiple-builtin-panel.patch new file mode 100644 index 0000000..73fcb7b --- /dev/null +++ b/SOURCES/0001-monitor-config-manager-Handle-multiple-builtin-panel.patch @@ -0,0 +1,211 @@ +From 19024a5b2eff02b22cdb3fc90142f522dd361996 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Fri, 27 Nov 2020 09:03:38 +0100 +Subject: [PATCH] monitor-config-manager: Handle multiple builtin panels + gracefully + +While multiple built-in panels isn't actually supported in any +meaningful manner, if we would ever end up with such a situation, e.g. +due to kernel bugs[0], we shouldn't crash when trying to set an +'external only' without any external monitors. + +While we could handle this with more degraded functionality (e.g. don't +support the 'switch' method of monitor configuration at all), handle it +by simply not trying to switch to external-only when there are no, +according to the kernel, external monitors available. This would e.g. +still allow betwene 'mirror-all', and 'linear' switches. + +The crash itself was disguised as an arbitrary X11 BadValue error, due +to mutter trying to resize the root window to 0x0, as the monitor +configuration that was applied consisted of zero logical monitors, thus +was effectively empty. + +[0] https://bugzilla.redhat.com/show_bug.cgi?id=1896904 + +Related: https://bugzilla.redhat.com/show_bug.cgi?id=1899260 +Part-of: +--- + src/backends/meta-monitor-config-manager.c | 3 + + src/tests/monitor-unit-tests.c | 145 +++++++++++++++++++++ + 2 files changed, 148 insertions(+) + +diff --git a/src/backends/meta-monitor-config-manager.c b/src/backends/meta-monitor-config-manager.c +index bc1a39db8..d62bad52d 100644 +--- a/src/backends/meta-monitor-config-manager.c ++++ b/src/backends/meta-monitor-config-manager.c +@@ -1157,6 +1157,9 @@ create_for_switch_config_external (MetaMonitorConfigManager *config_manager) + x += logical_monitor_config->layout.width; + } + ++ if (!logical_monitor_configs) ++ return NULL; ++ + return meta_monitors_config_new (monitor_manager, + logical_monitor_configs, + layout_mode, +diff --git a/src/tests/monitor-unit-tests.c b/src/tests/monitor-unit-tests.c +index f47544b03..725f84173 100644 +--- a/src/tests/monitor-unit-tests.c ++++ b/src/tests/monitor-unit-tests.c +@@ -3175,6 +3175,149 @@ meta_test_monitor_non_upright_panel (void) + check_monitor_configuration (&test_case); + } + ++static void ++meta_test_monitor_switch_external_without_external (void) ++{ ++ MonitorTestCase test_case = { ++ .setup = { ++ .modes = { ++ { ++ .width = 1024, ++ .height = 768, ++ .refresh_rate = 60.0 ++ } ++ }, ++ .n_modes = 1, ++ .outputs = { ++ { ++ .crtc = 0, ++ .modes = { 0 }, ++ .n_modes = 1, ++ .preferred_mode = 0, ++ .possible_crtcs = { 0 }, ++ .n_possible_crtcs = 1, ++ .width_mm = 222, ++ .height_mm = 125, ++ .is_laptop_panel = TRUE ++ }, ++ { ++ .crtc = 1, ++ .modes = { 0 }, ++ .n_modes = 1, ++ .preferred_mode = 0, ++ .possible_crtcs = { 1 }, ++ .n_possible_crtcs = 1, ++ .width_mm = 222, ++ .height_mm = 125, ++ .is_laptop_panel = TRUE ++ } ++ }, ++ .n_outputs = 2, ++ .crtcs = { ++ { ++ .current_mode = 0 ++ }, ++ { ++ .current_mode = 0 ++ } ++ }, ++ .n_crtcs = 2 ++ }, ++ ++ .expect = { ++ .monitors = { ++ { ++ .outputs = { 0 }, ++ .n_outputs = 1, ++ .modes = { ++ { ++ .width = 1024, ++ .height = 768, ++ .refresh_rate = 60.0, ++ .crtc_modes = { ++ { ++ .output = 0, ++ .crtc_mode = 0 ++ } ++ } ++ } ++ }, ++ .n_modes = 1, ++ .current_mode = 0, ++ .width_mm = 222, ++ .height_mm = 125 ++ }, ++ { ++ .outputs = { 1 }, ++ .n_outputs = 1, ++ .modes = { ++ { ++ .width = 1024, ++ .height = 768, ++ .refresh_rate = 60.0, ++ .crtc_modes = { ++ { ++ .output = 1, ++ .crtc_mode = 0 ++ } ++ } ++ } ++ }, ++ .n_modes = 1, ++ .current_mode = 0, ++ .width_mm = 222, ++ .height_mm = 125 ++ } ++ }, ++ .n_monitors = 2, ++ .logical_monitors = { ++ { ++ .monitors = { 0 }, ++ .n_monitors = 1, ++ .layout = { .x = 0, .y = 0, .width = 1024, .height = 768 }, ++ .scale = 1 ++ }, ++ { ++ .monitors = { 1 }, ++ .n_monitors = 1, ++ .layout = { .x = 1024, .y = 0, .width = 1024, .height = 768 }, ++ .scale = 1 ++ } ++ }, ++ .n_logical_monitors = 2, ++ .primary_logical_monitor = 0, ++ .n_outputs = 2, ++ .crtcs = { ++ { ++ .current_mode = 0, ++ }, ++ { ++ .current_mode = 0, ++ }, ++ }, ++ .n_crtcs = 2, ++ .n_tiled_monitors = 0, ++ .screen_width = 2048, ++ .screen_height = 768 ++ } ++ }; ++ MetaMonitorTestSetup *test_setup; ++ MetaBackend *backend = meta_get_backend (); ++ MetaMonitorManager *monitor_manager = ++ meta_backend_get_monitor_manager (backend); ++ ++ test_setup = create_monitor_test_setup (&test_case.setup, ++ MONITOR_TEST_FLAG_NO_STORED); ++ emulate_hotplug (test_setup); ++ check_monitor_configuration (&test_case); ++ ++ meta_monitor_manager_switch_config (monitor_manager, ++ META_MONITOR_SWITCH_CONFIG_EXTERNAL); ++ check_monitor_configuration (&test_case); ++ ++ check_monitor_test_clients_state (); ++} ++ + static void + meta_test_monitor_custom_vertical_config (void) + { +@@ -5969,6 +6112,8 @@ init_monitor_tests (void) + meta_test_monitor_preferred_non_first_mode); + add_monitor_test ("/backends/monitor/non-upright-panel", + meta_test_monitor_non_upright_panel); ++ add_monitor_test ("/backends/monitor/switch-external-without-external", ++ meta_test_monitor_switch_external_without_external); + + add_monitor_test ("/backends/monitor/custom/vertical-config", + meta_test_monitor_custom_vertical_config); +-- +2.29.2 + diff --git a/SOURCES/0001-xwayland-Don-t-spew-warnings-when-looking-for-X11-di.patch b/SOURCES/0001-xwayland-Don-t-spew-warnings-when-looking-for-X11-di.patch new file mode 100644 index 0000000..d5e0856 --- /dev/null +++ b/SOURCES/0001-xwayland-Don-t-spew-warnings-when-looking-for-X11-di.patch @@ -0,0 +1,304 @@ +From 1128c46af94e3928d5dc7fc77c44023faf01ab64 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Wed, 9 Dec 2020 11:23:37 +0100 +Subject: [PATCH 1/2] xwayland: Don't spew warnings when looking for X11 + displays + +It's not important, so only show it when doing MUTTER_DEBUG=wayland. +Instead report what display numbers were eventually found. +--- + src/wayland/meta-xwayland.c | 123 +++++++++++++++++++++++++++--------- + 1 file changed, 92 insertions(+), 31 deletions(-) + +diff --git a/src/wayland/meta-xwayland.c b/src/wayland/meta-xwayland.c +index 15c85df697..699d5561c7 100644 +--- a/src/wayland/meta-xwayland.c ++++ b/src/wayland/meta-xwayland.c +@@ -146,9 +146,10 @@ meta_xwayland_is_xwayland_surface (MetaWaylandSurface *surface) + } + + static gboolean +-try_display (int display, +- char **filename_out, +- int *fd_out) ++try_display (int display, ++ char **filename_out, ++ int *fd_out, ++ GError **error) + { + gboolean ret = FALSE; + char *filename; +@@ -164,11 +165,32 @@ try_display (int display, + char pid[11]; + char *end; + pid_t other; ++ int read_bytes; + + fd = open (filename, O_CLOEXEC, O_RDONLY); +- if (fd < 0 || read (fd, pid, 11) != 11) ++ if (fd < 0) + { +- g_warning ("can't read lock file %s: %m", filename); ++ g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), ++ "Failed to open lock file %s: %s", ++ filename, g_strerror (errno)); ++ goto out; ++ } ++ ++ read_bytes = read (fd, pid, 11); ++ if (read_bytes != 11) ++ { ++ if (read_bytes < 0) ++ { ++ g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), ++ "Failed to read lock file %s: %s", ++ filename, g_strerror (errno)); ++ } ++ else ++ { ++ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, ++ "Failed to read lock file %s", ++ filename); ++ } + goto out; + } + close (fd); +@@ -178,7 +200,8 @@ try_display (int display, + other = strtol (pid, &end, 0); + if (end != pid + 10) + { +- g_warning ("can't parse lock file %s", filename); ++ g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, ++ "Can't parse lock file %s", filename); + goto out; + } + +@@ -187,18 +210,23 @@ try_display (int display, + /* Process is dead. Try unlinking the lock file and trying again. */ + if (unlink (filename) < 0) + { +- g_warning ("failed to unlink stale lock file %s: %m", filename); ++ g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), ++ "Failed to unlink stale lock file %s: %m", filename); + goto out; + } + + goto again; + } + ++ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, ++ "Lock file %s already occupied", filename); + goto out; + } + else if (fd < 0) + { +- g_warning ("failed to create lock file %s: %m", filename); ++ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, ++ "Failed to create lock file %s: %s", ++ filename, g_strerror (errno)); + goto out; + } + +@@ -223,24 +251,34 @@ try_display (int display, + } + + static char * +-create_lock_file (int display, int *display_out) ++create_lock_file (int display, ++ int *display_out, ++ GError **error) + { ++ g_autoptr (GError) local_error = NULL; + char *filename; + int fd; +- + char pid[12]; + int size; + int number_of_tries = 0; + +- while (!try_display (display, &filename, &fd)) ++ while (!try_display (display, &filename, &fd, &local_error)) + { ++ meta_verbose ("Failed to open display %d: %s\n", ++ display, local_error->message); ++ g_clear_error (&local_error); ++ + display++; + number_of_tries++; + + /* If we can't get a display after 50 times, then something's wrong. Just + * abort in this case. */ + if (number_of_tries >= 50) +- return NULL; ++ { ++ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, ++ "Tried to bind 50 display numbers, giving up"); ++ return NULL; ++ } + } + + /* Subtle detail: we use the pid of the wayland compositor, not the xserver +@@ -248,11 +286,22 @@ create_lock_file (int display, int *display_out) + * it _would've_ written without either the NUL or the size clamping, hence + * the disparity in size. */ + size = snprintf (pid, 12, "%10d\n", getpid ()); ++ errno = 0; + if (size != 11 || write (fd, pid, 11) != 11) + { ++ if (errno != 0) ++ { ++ g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), ++ "Failed to write pid to lock file: %s", ++ g_strerror (errno)); ++ } ++ else ++ { ++ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, ++ "Failed to write pid to lock file"); ++ } + unlink (filename); + close (fd); +- g_warning ("failed to write pid to lock file %s", filename); + g_free (filename); + return NULL; + } +@@ -264,8 +313,8 @@ create_lock_file (int display, int *display_out) + } + + static int +-bind_to_abstract_socket (int display, +- gboolean *fatal) ++bind_to_abstract_socket (int display, ++ GError **error) + { + struct sockaddr_un addr; + socklen_t size, name_size; +@@ -274,8 +323,8 @@ bind_to_abstract_socket (int display, + fd = socket (PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (fd < 0) + { +- *fatal = TRUE; +- g_warning ("Failed to create socket: %m"); ++ g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), ++ "Failed to create socket: %s", g_strerror (errno)); + return -1; + } + +@@ -285,17 +334,18 @@ bind_to_abstract_socket (int display, + size = offsetof (struct sockaddr_un, sun_path) + name_size; + if (bind (fd, (struct sockaddr *) &addr, size) < 0) + { +- *fatal = errno != EADDRINUSE; +- g_warning ("failed to bind to @%s: %m", addr.sun_path + 1); ++ g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), ++ "Failed to bind to @%s: %s", ++ addr.sun_path + 1, g_strerror (errno)); + close (fd); + return -1; + } + + if (listen (fd, 1) < 0) + { +- *fatal = errno != EADDRINUSE; +- g_warning ("Failed to listen on abstract socket @%s: %m", +- addr.sun_path + 1); ++ g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), ++ "Failed to listen on abstract socket @%s: %s", ++ addr.sun_path + 1, g_strerror (errno)); + close (fd); + return -1; + } +@@ -304,7 +354,8 @@ bind_to_abstract_socket (int display, + } + + static int +-bind_to_unix_socket (int display) ++bind_to_unix_socket (int display, ++ GError **error) + { + struct sockaddr_un addr; + socklen_t size, name_size; +@@ -321,13 +372,18 @@ bind_to_unix_socket (int display) + unlink (addr.sun_path); + if (bind (fd, (struct sockaddr *) &addr, size) < 0) + { +- g_warning ("failed to bind to %s: %m\n", addr.sun_path); ++ g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), ++ "Failed to bind to %s: %s", ++ addr.sun_path, g_strerror (errno)); + close (fd); + return -1; + } + + if (listen (fd, 1) < 0) + { ++ g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), ++ "Failed to listen on %s: %s", ++ addr.sun_path, g_strerror (errno)); + unlink (addr.sun_path); + close (fd); + return -1; +@@ -385,7 +441,6 @@ choose_xdisplay (MetaXWaylandManager *manager) + { + int display = 0; + char *lock_file = NULL; +- gboolean fatal = FALSE; + + if (display_number_override != -1) + display = display_number_override; +@@ -394,33 +449,37 @@ choose_xdisplay (MetaXWaylandManager *manager) + + do + { +- lock_file = create_lock_file (display, &display); ++ g_autoptr (GError) error = NULL; ++ ++ lock_file = create_lock_file (display, &display, &error); + if (!lock_file) + { +- g_warning ("Failed to create an X lock file"); ++ g_warning ("Failed to create an X lock file: %s", error->message); + return FALSE; + } + +- manager->abstract_fd = bind_to_abstract_socket (display, &fatal); ++ manager->abstract_fd = bind_to_abstract_socket (display, &error); + if (manager->abstract_fd < 0) + { + unlink (lock_file); + +- if (!fatal) ++ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_ADDRESS_IN_USE)) + { ++ meta_verbose ("Failed to bind abstract socket: %s\n", error->message); + display++; + continue; + } + else + { +- g_warning ("Failed to bind abstract socket"); ++ g_warning ("Failed to bind abstract socket: %s", error->message); + return FALSE; + } + } + +- manager->unix_fd = bind_to_unix_socket (display); ++ manager->unix_fd = bind_to_unix_socket (display, &error); + if (manager->unix_fd < 0) + { ++ meta_verbose ("Failed to bind unix socket: %s\n", error->message); + unlink (lock_file); + close (manager->abstract_fd); + display++; +@@ -435,6 +494,8 @@ choose_xdisplay (MetaXWaylandManager *manager) + manager->display_name = g_strdup_printf (":%d", manager->display_index); + manager->lock_file = lock_file; + ++ g_message ("Using X11 display %s for Xwayland", manager->display_name); ++ + return TRUE; + } + +-- +2.28.0 + diff --git a/SOURCES/0002-xwayland-Make-sure-tmp-.X11-unix-exists.patch b/SOURCES/0002-xwayland-Make-sure-tmp-.X11-unix-exists.patch new file mode 100644 index 0000000..720c4de --- /dev/null +++ b/SOURCES/0002-xwayland-Make-sure-tmp-.X11-unix-exists.patch @@ -0,0 +1,82 @@ +From 04202ca080b49f9e71ccf837854fa03c9e572d54 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Wed, 9 Dec 2020 15:18:29 +0100 +Subject: [PATCH 2/2] xwayland: Make sure /tmp/.X11-unix/ exists + +When we're running under a polyinstantiated SELinux environment, we'll +likely start with an isolated and empty /tmp, meannig no /tmp/.X11-unix +directory to add things to. To make it possible to still function in +this kind of setup, make sure said directory exists. +--- + src/wayland/meta-xwayland.c | 29 +++++++++++++++++++++++++++-- + 1 file changed, 27 insertions(+), 2 deletions(-) + +diff --git a/src/wayland/meta-xwayland.c b/src/wayland/meta-xwayland.c +index 699d5561c7..f6f1010b12 100644 +--- a/src/wayland/meta-xwayland.c ++++ b/src/wayland/meta-xwayland.c +@@ -436,9 +436,27 @@ meta_xwayland_override_display_number (int number) + display_number_override = number; + } + ++static gboolean ++ensure_x11_unix_dir (GError **error) ++{ ++ if (mkdir ("/tmp/.X11-unix", 01777) != 0) ++ { ++ if (errno == EEXIST) ++ return TRUE; ++ ++ g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), ++ "Failed to create directory \"/tmp/.X11-unix\": %s", ++ g_strerror (errno)); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ + static gboolean + choose_xdisplay (MetaXWaylandManager *manager) + { ++ g_autoptr (GError) error = NULL; + int display = 0; + char *lock_file = NULL; + +@@ -447,10 +465,15 @@ choose_xdisplay (MetaXWaylandManager *manager) + else if (g_getenv ("RUNNING_UNDER_GDM")) + display = 1024; + +- do ++ if (!ensure_x11_unix_dir (error)) + { +- g_autoptr (GError) error = NULL; ++ g_warning ("Failed to ensure X11 socket directory: %s", ++ error->message); ++ return FALSE; ++ } + ++ do ++ { + lock_file = create_lock_file (display, &display, &error); + if (!lock_file) + { +@@ -466,6 +489,7 @@ choose_xdisplay (MetaXWaylandManager *manager) + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_ADDRESS_IN_USE)) + { + meta_verbose ("Failed to bind abstract socket: %s\n", error->message); ++ g_clear_error (error); + display++; + continue; + } +@@ -480,6 +504,7 @@ choose_xdisplay (MetaXWaylandManager *manager) + if (manager->unix_fd < 0) + { + meta_verbose ("Failed to bind unix socket: %s\n", error->message); ++ g_clear_error (error); + unlink (lock_file); + close (manager->abstract_fd); + display++; +-- +2.28.0 + diff --git a/SPECS/mutter.spec b/SPECS/mutter.spec index bca01b2..b631c48 100644 --- a/SPECS/mutter.spec +++ b/SPECS/mutter.spec @@ -8,7 +8,7 @@ Name: mutter Version: 3.32.2 -Release: 51%{?dist} +Release: 53%{?dist} Summary: Window and compositing manager based on Clutter License: GPLv2+ @@ -165,6 +165,13 @@ Patch504: shadow-buffer-tile-damage.patch # Add PING_TIMEOUT_DELAY to mutter MetaPreferences (#1886034) Patch505: 0001-display-Make-check-alive-timeout-configureable.patch +# Polyinstantiation (#1861769) +Patch506: 0001-xwayland-Don-t-spew-warnings-when-looking-for-X11-di.patch +Patch507: 0002-xwayland-Make-sure-tmp-.X11-unix-exists.patch + +# Mitigate nouveau misidentifying connectors (#1786496) +Patch508: 0001-monitor-config-manager-Handle-multiple-builtin-panel.patch + BuildRequires: chrpath BuildRequires: pango-devel BuildRequires: startup-notification-devel @@ -306,6 +313,16 @@ desktop-file-validate %{buildroot}/%{_datadir}/applications/%{name}.desktop %{_datadir}/mutter-%{mutter_api_version}/tests %changelog +* Thu Dec 17 2020 Jonas Ådahl - 3.32.2-53 +- Fix test case backport + Related: #1786496 + +* Thu Dec 17 2020 Jonas Ådahl - 3.32.2-52 +- Support polyinstantiation + Resolves: #1861769 +- Mitigate nouveau misidentifying connectors + Resolves: #1786496 + * Mon Dec 07 2020 Jonas Ådahl - 3.32.2-51 - Add PING_TIMEOUT_DELAY to mutter MetaPreferences Resolves: #1886034