2014-04-02 00:35:26 +00:00
|
|
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
|
|
|
|
2012-01-07 22:21:32 +00:00
|
|
|
/*
|
|
|
|
* X Wayland Support
|
|
|
|
*
|
|
|
|
* Copyright (C) 2013 Intel Corporation
|
|
|
|
*
|
|
|
|
* 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
|
2023-08-07 09:50:23 +00:00
|
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
2012-01-07 22:21:32 +00:00
|
|
|
*/
|
|
|
|
|
2014-04-02 00:35:26 +00:00
|
|
|
#include "config.h"
|
|
|
|
|
2018-07-10 08:36:24 +00:00
|
|
|
#include "wayland/meta-xwayland.h"
|
|
|
|
#include "wayland/meta-xwayland-private.h"
|
2012-01-07 22:21:32 +00:00
|
|
|
|
|
|
|
#include <errno.h>
|
2018-07-10 08:36:24 +00:00
|
|
|
#include <glib-unix.h>
|
|
|
|
#include <glib.h>
|
2023-01-25 20:33:18 +00:00
|
|
|
#include <glib/gstdio.h>
|
2012-01-07 22:21:32 +00:00
|
|
|
#include <sys/socket.h>
|
2020-12-09 14:04:56 +00:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/types.h>
|
2012-01-07 22:21:32 +00:00
|
|
|
#include <sys/un.h>
|
2019-06-20 10:11:29 +00:00
|
|
|
#if defined(HAVE_SYS_RANDOM)
|
2019-06-18 14:12:46 +00:00
|
|
|
#include <sys/random.h>
|
2019-06-20 10:11:29 +00:00
|
|
|
#elif defined(HAVE_LINUX_RANDOM)
|
|
|
|
#include <linux/random.h>
|
|
|
|
#endif
|
2019-06-18 14:12:46 +00:00
|
|
|
#include <unistd.h>
|
2020-11-11 12:17:14 +00:00
|
|
|
#include <X11/extensions/Xrandr.h>
|
xwayland: Mark our X11 connection terminatable
The connection to the Xserver for the X11 window manager part of mutter
even on Wayland may prevent the Xserver from shutting down.
Currently, what mutter does is to check the X11 clients still connected
to Xwayland using the XRes extension, with a list of X11 clients that
can be safely ignored (typically the GNOME XSettings daemon, the IBus
daemon, pulseaudio and even mutter window manager itself).
When there is just those known clients remaining, mutter would kill
Xwayland automatically.
But that's racy, because between the time mutter checks with Xwayland
the remaining clients and the time it actually kills the process, a new
X11 client might have come along and won't be able to connect to
Xwayland that mutter is just about to kill.
Because of that, the feature “autoclose-xwayland” is marked as an
experimental feature in mutter and not enabled by default.
Thankfully, the Xserver has all it takes to manage that already, and
is even capable of terminating itself once all X11 clients are gone (the
-terminate option on the command line).
With XFixes version 6, the X11 clients can declare themselves
"terminatable", so that the Xserver could simply ignore those X11
clients when checking the remaining clients and terminate itself
automatically.
Use that mechanism to declare mutter's own connection to the Xserver as
"terminatable" when Xwayland is started on demand so that it won't hold
Xwayland alive for the sole purpose of mutter itself.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1794>
2021-03-17 14:44:45 +00:00
|
|
|
#include <X11/extensions/Xfixes.h>
|
2019-06-18 14:12:46 +00:00
|
|
|
#include <X11/Xauth.h>
|
xwayland: Check X11 clients prior to terminate Xwayland
Currently, mutter checks for the presence of X11 windows to decide
whether or not Xwayland can be terminated, when Xwayland is started on
demand.
Unfortunately, not all X11 clients will map a window all the time, an
X11 client may keep the X11 connection opened after closing all its
windows. In that case, we may terminate Xwayland while there are some
X11 client connected still, and terminating Xwayland will also kill
those X11 clients.
To avoid that issue, check the X11 clients actually connected using the
XRes extension. The XRes extension provides the PID of the (local) X11
clients connected to the Xserver, so we need to match that against the
actual executable names, and compare with a list of known executables
that we can safely ignore, such as ibus-x11 or gsd-xsettings.
We also check against our own executable name, considering that the X11
window manager is also an X11 client connected to the Xserver.
Also, XRes returning the PID of local clients only is not a problem
considering that Xwayland does not listen to remote connections.
However, if the user spawns a client remotely on another system using
ssh tunneling (ssh -X), only clients which actually map a window will
be accounted for.
Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1537
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1671>
2021-01-18 09:22:01 +00:00
|
|
|
#include <X11/Xlib-xcb.h>
|
|
|
|
|
|
|
|
#include <xcb/res.h>
|
2012-01-07 22:21:32 +00:00
|
|
|
|
2020-11-11 12:17:14 +00:00
|
|
|
#include "backends/meta-monitor-manager-private.h"
|
2020-08-12 17:30:04 +00:00
|
|
|
#include "backends/meta-settings-private.h"
|
2018-07-10 08:36:24 +00:00
|
|
|
#include "meta/main.h"
|
2020-08-12 17:30:04 +00:00
|
|
|
#include "meta/meta-backend.h"
|
2024-01-03 14:43:36 +00:00
|
|
|
#include "mtk/mtk-x11.h"
|
2022-06-13 08:09:26 +00:00
|
|
|
#include "wayland/meta-xwayland-grab-keyboard.h"
|
2019-10-07 19:21:48 +00:00
|
|
|
#include "wayland/meta-xwayland-surface.h"
|
2019-05-24 19:09:32 +00:00
|
|
|
#include "x11/meta-x11-display-private.h"
|
2015-07-08 08:14:00 +00:00
|
|
|
|
2021-01-22 10:16:24 +00:00
|
|
|
#ifdef HAVE_XWAYLAND_LISTENFD
|
|
|
|
#define XWAYLAND_LISTENFD "-listenfd"
|
|
|
|
#else
|
|
|
|
#define XWAYLAND_LISTENFD "-listen"
|
|
|
|
#endif
|
|
|
|
|
2022-01-28 14:49:11 +00:00
|
|
|
#define TMP_UNIX_DIR "/tmp"
|
2021-03-18 09:22:50 +00:00
|
|
|
#define X11_TMP_UNIX_DIR "/tmp/.X11-unix"
|
|
|
|
#define X11_TMP_UNIX_PATH "/tmp/.X11-unix/X"
|
|
|
|
|
2018-11-12 10:29:44 +00:00
|
|
|
static int display_number_override = -1;
|
|
|
|
|
2019-05-24 19:36:50 +00:00
|
|
|
static void meta_xwayland_stop_xserver (MetaXWaylandManager *manager);
|
|
|
|
|
2020-11-11 12:17:14 +00:00
|
|
|
static void
|
2021-03-23 16:03:32 +00:00
|
|
|
meta_xwayland_set_primary_output (MetaX11Display *x11_display);
|
2020-11-11 12:17:14 +00:00
|
|
|
|
2022-05-30 21:48:44 +00:00
|
|
|
static MetaMonitorManager *
|
|
|
|
monitor_manager_from_x11_display (MetaX11Display *x11_display)
|
|
|
|
{
|
|
|
|
MetaDisplay *display = meta_x11_display_get_display (x11_display);
|
|
|
|
MetaContext *context = meta_display_get_context (display);
|
|
|
|
MetaBackend *backend = meta_context_get_backend (context);
|
|
|
|
|
|
|
|
return meta_backend_get_monitor_manager (backend);
|
|
|
|
}
|
|
|
|
|
2018-04-06 13:47:50 +00:00
|
|
|
void
|
|
|
|
meta_xwayland_associate_window_with_surface (MetaWindow *window,
|
|
|
|
MetaWaylandSurface *surface)
|
2013-08-12 08:06:13 +00:00
|
|
|
{
|
2014-04-02 14:19:39 +00:00
|
|
|
MetaDisplay *display = window->display;
|
2019-10-07 19:21:48 +00:00
|
|
|
MetaXwaylandSurface *xwayland_surface;
|
2023-11-02 13:29:12 +00:00
|
|
|
MetaContext *context = meta_display_get_context (display);
|
|
|
|
MetaWaylandCompositor *wayland_compositor =
|
|
|
|
meta_context_get_wayland_compositor (context);
|
2019-02-06 22:04:13 +00:00
|
|
|
|
2015-08-20 08:54:45 +00:00
|
|
|
if (!meta_wayland_surface_assign_role (surface,
|
2019-10-07 19:21:48 +00:00
|
|
|
META_TYPE_XWAYLAND_SURFACE,
|
2016-01-28 09:14:06 +00:00
|
|
|
NULL))
|
2015-08-20 08:54:45 +00:00
|
|
|
{
|
|
|
|
wl_resource_post_error (surface->resource,
|
|
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
|
|
"wl_surface@%d already has a different role",
|
|
|
|
wl_resource_get_id (surface->resource));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-10-07 19:21:48 +00:00
|
|
|
xwayland_surface = META_XWAYLAND_SURFACE (surface->role);
|
|
|
|
meta_xwayland_surface_associate_with_window (xwayland_surface, window);
|
2014-04-02 15:20:30 +00:00
|
|
|
|
2014-04-08 16:39:15 +00:00
|
|
|
/* Now that we have a surface check if it should have focus. */
|
2023-11-02 13:29:12 +00:00
|
|
|
meta_wayland_compositor_sync_focus (wayland_compositor);
|
2013-08-12 08:06:13 +00:00
|
|
|
}
|
|
|
|
|
2014-03-20 17:12:43 +00:00
|
|
|
static gboolean
|
|
|
|
associate_window_with_surface_id (MetaXWaylandManager *manager,
|
|
|
|
MetaWindow *window,
|
|
|
|
guint32 surface_id)
|
2014-04-02 14:19:39 +00:00
|
|
|
{
|
2014-03-20 17:12:43 +00:00
|
|
|
struct wl_resource *resource;
|
|
|
|
|
|
|
|
resource = wl_client_get_object (manager->client, surface_id);
|
|
|
|
if (resource)
|
|
|
|
{
|
|
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (resource);
|
2018-04-06 13:47:50 +00:00
|
|
|
meta_xwayland_associate_window_with_surface (window, surface);
|
2014-03-20 17:12:43 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_xwayland_handle_wl_surface_id (MetaWindow *window,
|
|
|
|
guint32 surface_id)
|
2013-08-12 08:06:13 +00:00
|
|
|
{
|
2022-05-30 21:48:44 +00:00
|
|
|
MetaDisplay *display = meta_window_get_display (window);
|
|
|
|
MetaContext *context = meta_display_get_context (display);
|
|
|
|
MetaWaylandCompositor *compositor =
|
|
|
|
meta_context_get_wayland_compositor (context);
|
2014-03-20 17:12:43 +00:00
|
|
|
MetaXWaylandManager *manager = &compositor->xwayland_manager;
|
|
|
|
|
|
|
|
if (!associate_window_with_surface_id (manager, window, surface_id))
|
|
|
|
{
|
2018-04-06 13:47:50 +00:00
|
|
|
/* No surface ID yet, schedule this association for whenever the
|
|
|
|
* surface is made known.
|
2014-03-20 17:12:43 +00:00
|
|
|
*/
|
2018-04-06 13:47:50 +00:00
|
|
|
meta_wayland_compositor_schedule_surface_association (compositor,
|
|
|
|
surface_id, window);
|
2014-03-20 17:12:43 +00:00
|
|
|
}
|
2013-08-12 08:06:13 +00:00
|
|
|
}
|
|
|
|
|
2014-04-17 19:03:45 +00:00
|
|
|
static gboolean
|
2020-12-08 16:42:05 +00:00
|
|
|
try_display (int display,
|
|
|
|
char **filename_out,
|
|
|
|
int *fd_out,
|
|
|
|
GError **error)
|
2012-01-07 22:21:32 +00:00
|
|
|
{
|
2014-04-17 19:03:45 +00:00
|
|
|
gboolean ret = FALSE;
|
2012-01-07 22:21:32 +00:00
|
|
|
char *filename;
|
|
|
|
int fd;
|
|
|
|
|
2014-04-17 19:03:45 +00:00
|
|
|
filename = g_strdup_printf ("/tmp/.X%d-lock", display);
|
|
|
|
|
|
|
|
again:
|
|
|
|
fd = open (filename, O_WRONLY | O_CLOEXEC | O_CREAT | O_EXCL, 0444);
|
|
|
|
|
|
|
|
if (fd < 0 && errno == EEXIST)
|
2012-01-07 22:21:32 +00:00
|
|
|
{
|
2014-04-17 19:03:45 +00:00
|
|
|
char pid[11];
|
2012-01-07 22:21:32 +00:00
|
|
|
char *end;
|
|
|
|
pid_t other;
|
2020-12-08 16:42:05 +00:00
|
|
|
int read_bytes;
|
2012-01-07 22:21:32 +00:00
|
|
|
|
2014-04-17 19:03:45 +00:00
|
|
|
fd = open (filename, O_CLOEXEC, O_RDONLY);
|
2020-12-08 16:42:05 +00:00
|
|
|
if (fd < 0)
|
2014-04-17 19:03:45 +00:00
|
|
|
{
|
2020-12-08 16:42:05 +00:00
|
|
|
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 from lock file %s: %s",
|
|
|
|
filename, g_strerror (errno));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT,
|
|
|
|
"Only read %d bytes (needed 11) from lock file: %s",
|
|
|
|
read_bytes, filename);
|
|
|
|
}
|
2014-04-17 19:03:45 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
close (fd);
|
|
|
|
fd = -1;
|
2012-01-07 22:21:32 +00:00
|
|
|
|
xwayland: Fix lockfile size confusion
Similarly to Weston (where this code originated), there were two errors
in the X11 lockfile handling.
Firstly, after reading 11 characters from the lock file (which could
have been placed by any process), there was no guarantee of
NUL-termination, meaning strtol could've theoretically run off the end
of the string.
Secondly, whilst writing the new lock, the trailing NUL byte was not
correctly accounted for. The size passed as an input to snprintf takes
the maximum size of the string including the trailing NUL, whilst the
return (and the input to write) gives the actual size of the string
without the trailing NUL.
The code did attempt to check the return value, however snprintf returns
the size of the _potential_ string written, before snprintf culls it, so
this was off by one, and the LF was not being written.
Signed-off-by: Daniel Stone <daniels@collabora.com>
https://bugzilla.gnome.org/show_bug.cgi?id=774613
2016-11-17 11:00:25 +00:00
|
|
|
pid[10] = '\0';
|
2014-04-17 19:03:45 +00:00
|
|
|
other = strtol (pid, &end, 0);
|
|
|
|
if (end != pid + 10)
|
2012-01-07 22:21:32 +00:00
|
|
|
{
|
2020-12-08 16:42:05 +00:00
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
|
|
|
|
"Can't parse lock file %s", filename);
|
2014-04-17 19:03:45 +00:00
|
|
|
goto out;
|
|
|
|
}
|
2012-01-07 22:21:32 +00:00
|
|
|
|
2014-04-17 19:03:45 +00:00
|
|
|
if (kill (other, 0) < 0 && errno == ESRCH)
|
|
|
|
{
|
2015-04-23 14:41:34 +00:00
|
|
|
/* Process is dead. Try unlinking the lock file and trying again. */
|
2014-04-17 19:03:45 +00:00
|
|
|
if (unlink (filename) < 0)
|
|
|
|
{
|
2020-12-08 16:42:05 +00:00
|
|
|
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
|
|
|
|
"Failed to unlink stale lock file %s: %s",
|
|
|
|
filename, g_strerror (errno));
|
2014-04-17 19:03:45 +00:00
|
|
|
goto out;
|
2014-01-29 15:23:58 +00:00
|
|
|
}
|
2012-01-07 22:21:32 +00:00
|
|
|
|
2014-04-17 19:03:45 +00:00
|
|
|
goto again;
|
|
|
|
}
|
2012-01-07 22:21:32 +00:00
|
|
|
|
2020-12-08 16:42:05 +00:00
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Lock file %s is already occupied", filename);
|
2014-04-17 19:03:45 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
else if (fd < 0)
|
|
|
|
{
|
2020-12-08 16:42:05 +00:00
|
|
|
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
|
|
|
|
"Failed to create lock file %s: %s",
|
|
|
|
filename, g_strerror (errno));
|
2014-04-17 19:03:45 +00:00
|
|
|
goto out;
|
|
|
|
}
|
2012-01-07 22:21:32 +00:00
|
|
|
|
2014-04-17 19:03:45 +00:00
|
|
|
ret = TRUE;
|
2012-01-07 22:21:32 +00:00
|
|
|
|
2014-04-17 19:03:45 +00:00
|
|
|
out:
|
|
|
|
if (!ret)
|
|
|
|
{
|
|
|
|
g_free (filename);
|
|
|
|
filename = NULL;
|
|
|
|
|
2023-01-25 20:33:18 +00:00
|
|
|
g_clear_fd (&fd, NULL);
|
2014-04-17 19:03:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
*filename_out = filename;
|
|
|
|
*fd_out = fd;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
2020-12-08 16:42:05 +00:00
|
|
|
create_lock_file (int display,
|
|
|
|
int *display_out,
|
|
|
|
GError **error)
|
2014-04-17 19:03:45 +00:00
|
|
|
{
|
|
|
|
char *filename;
|
|
|
|
int fd;
|
xwayland: Fix lockfile size confusion
Similarly to Weston (where this code originated), there were two errors
in the X11 lockfile handling.
Firstly, after reading 11 characters from the lock file (which could
have been placed by any process), there was no guarantee of
NUL-termination, meaning strtol could've theoretically run off the end
of the string.
Secondly, whilst writing the new lock, the trailing NUL byte was not
correctly accounted for. The size passed as an input to snprintf takes
the maximum size of the string including the trailing NUL, whilst the
return (and the input to write) gives the actual size of the string
without the trailing NUL.
The code did attempt to check the return value, however snprintf returns
the size of the _potential_ string written, before snprintf culls it, so
this was off by one, and the LF was not being written.
Signed-off-by: Daniel Stone <daniels@collabora.com>
https://bugzilla.gnome.org/show_bug.cgi?id=774613
2016-11-17 11:00:25 +00:00
|
|
|
char pid[12];
|
2014-04-17 19:03:45 +00:00
|
|
|
int size;
|
2015-03-20 19:09:13 +00:00
|
|
|
int number_of_tries = 0;
|
2020-12-08 16:42:05 +00:00
|
|
|
g_autoptr (GError) local_error = NULL;
|
2014-04-17 19:03:45 +00:00
|
|
|
|
2020-12-08 16:42:05 +00:00
|
|
|
while (!try_display (display, &filename, &fd, &local_error))
|
2014-04-17 19:03:45 +00:00
|
|
|
{
|
2020-12-08 16:45:05 +00:00
|
|
|
meta_topic (META_DEBUG_WAYLAND,
|
|
|
|
"Failed to lock X11 display: %s", local_error->message);
|
2020-12-08 16:42:05 +00:00
|
|
|
g_clear_error (&local_error);
|
2014-04-17 19:03:45 +00:00
|
|
|
display++;
|
2015-03-20 19:09:13 +00:00
|
|
|
number_of_tries++;
|
2012-01-07 22:21:32 +00:00
|
|
|
|
2015-03-20 19:09:13 +00:00
|
|
|
/* If we can't get a display after 50 times, then something's wrong. Just
|
2014-04-17 19:03:45 +00:00
|
|
|
* abort in this case. */
|
2015-03-20 19:09:13 +00:00
|
|
|
if (number_of_tries >= 50)
|
2020-12-08 16:42:05 +00:00
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Gave up after trying to lock different "
|
|
|
|
"X11 display lock file 50 times");
|
|
|
|
return NULL;
|
|
|
|
}
|
2012-01-07 22:21:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Subtle detail: we use the pid of the wayland compositor, not the xserver
|
xwayland: Fix lockfile size confusion
Similarly to Weston (where this code originated), there were two errors
in the X11 lockfile handling.
Firstly, after reading 11 characters from the lock file (which could
have been placed by any process), there was no guarantee of
NUL-termination, meaning strtol could've theoretically run off the end
of the string.
Secondly, whilst writing the new lock, the trailing NUL byte was not
correctly accounted for. The size passed as an input to snprintf takes
the maximum size of the string including the trailing NUL, whilst the
return (and the input to write) gives the actual size of the string
without the trailing NUL.
The code did attempt to check the return value, however snprintf returns
the size of the _potential_ string written, before snprintf culls it, so
this was off by one, and the LF was not being written.
Signed-off-by: Daniel Stone <daniels@collabora.com>
https://bugzilla.gnome.org/show_bug.cgi?id=774613
2016-11-17 11:00:25 +00:00
|
|
|
* in the lock file. Another subtlety: snprintf returns the number of bytes
|
|
|
|
* it _would've_ written without either the NUL or the size clamping, hence
|
|
|
|
* the disparity in size. */
|
|
|
|
size = snprintf (pid, 12, "%10d\n", getpid ());
|
2020-12-08 16:42:05 +00:00
|
|
|
errno = 0;
|
2012-01-07 22:21:32 +00:00
|
|
|
if (size != 11 || write (fd, pid, 11) != 11)
|
|
|
|
{
|
2020-12-08 16:42:05 +00:00
|
|
|
if (errno != 0)
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
|
|
|
|
"Failed to write pid to lock file %s: %s",
|
|
|
|
filename, g_strerror (errno));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Failed to write pid to lock file %s", filename);
|
|
|
|
}
|
|
|
|
|
2012-01-07 22:21:32 +00:00
|
|
|
unlink (filename);
|
|
|
|
close (fd);
|
|
|
|
g_free (filename);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
close (fd);
|
|
|
|
|
|
|
|
*display_out = display;
|
|
|
|
return filename;
|
|
|
|
}
|
|
|
|
|
2020-10-17 03:50:31 +00:00
|
|
|
static int
|
2021-01-14 08:56:13 +00:00
|
|
|
bind_to_abstract_socket (int display,
|
|
|
|
GError **error)
|
2020-10-17 03:50:31 +00:00
|
|
|
{
|
|
|
|
struct sockaddr_un addr;
|
|
|
|
socklen_t size, name_size;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
fd = socket (PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
|
|
|
if (fd < 0)
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
|
|
|
|
"Failed to create socket: %s", g_strerror (errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
addr.sun_family = AF_LOCAL;
|
|
|
|
name_size = snprintf (addr.sun_path, sizeof addr.sun_path,
|
2021-03-18 09:22:50 +00:00
|
|
|
"%c%s%d", 0, X11_TMP_UNIX_PATH, display);
|
2020-10-17 03:50:31 +00:00
|
|
|
size = offsetof (struct sockaddr_un, sun_path) + name_size;
|
|
|
|
if (bind (fd, (struct sockaddr *) &addr, size) < 0)
|
|
|
|
{
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
|
|
|
|
"Failed to listen to %s: %s",
|
|
|
|
addr.sun_path + 1, g_strerror (errno));
|
|
|
|
close (fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2012-01-07 22:21:32 +00:00
|
|
|
static int
|
2020-12-08 16:42:05 +00:00
|
|
|
bind_to_unix_socket (int display,
|
|
|
|
GError **error)
|
2012-01-07 22:21:32 +00:00
|
|
|
{
|
|
|
|
struct sockaddr_un addr;
|
|
|
|
socklen_t size, name_size;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
fd = socket (PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
|
|
|
if (fd < 0)
|
2020-12-08 16:42:05 +00:00
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
|
|
|
|
"Failed to create socket: %s", g_strerror (errno));
|
|
|
|
return -1;
|
|
|
|
}
|
2012-01-07 22:21:32 +00:00
|
|
|
|
|
|
|
addr.sun_family = AF_LOCAL;
|
|
|
|
name_size = snprintf (addr.sun_path, sizeof addr.sun_path,
|
2021-03-18 09:22:50 +00:00
|
|
|
"%s%d", X11_TMP_UNIX_PATH, display) + 1;
|
2012-01-07 22:21:32 +00:00
|
|
|
size = offsetof (struct sockaddr_un, sun_path) + name_size;
|
|
|
|
unlink (addr.sun_path);
|
|
|
|
if (bind (fd, (struct sockaddr *) &addr, size) < 0)
|
|
|
|
{
|
2020-12-08 16:42:05 +00:00
|
|
|
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));
|
2012-01-07 22:21:32 +00:00
|
|
|
close (fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-01-29 15:23:58 +00:00
|
|
|
if (listen (fd, 1) < 0)
|
|
|
|
{
|
2020-12-08 16:42:05 +00:00
|
|
|
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
|
|
|
|
"Failed to listen to %s: %s",
|
|
|
|
addr.sun_path, g_strerror (errno));
|
2012-01-07 22:21:32 +00:00
|
|
|
unlink (addr.sun_path);
|
|
|
|
close (fd);
|
|
|
|
return -1;
|
2014-01-29 15:23:58 +00:00
|
|
|
}
|
2012-01-07 22:21:32 +00:00
|
|
|
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2013-08-12 07:46:07 +00:00
|
|
|
static void
|
2015-03-22 01:24:37 +00:00
|
|
|
xserver_died (GObject *source,
|
|
|
|
GAsyncResult *result,
|
|
|
|
gpointer user_data)
|
2013-08-12 07:46:07 +00:00
|
|
|
{
|
2022-05-30 21:48:44 +00:00
|
|
|
MetaXWaylandManager *manager = user_data;
|
|
|
|
MetaWaylandCompositor *compositor = manager->compositor;
|
|
|
|
MetaContext *context = meta_wayland_compositor_get_context (compositor);
|
|
|
|
MetaDisplay *display = meta_context_get_display (context);
|
2015-03-22 01:24:37 +00:00
|
|
|
GSubprocess *proc = G_SUBPROCESS (source);
|
2018-04-12 18:03:03 +00:00
|
|
|
g_autoptr (GError) error = NULL;
|
2021-04-16 18:34:29 +00:00
|
|
|
MetaX11DisplayPolicy x11_display_policy;
|
2015-03-22 01:24:37 +00:00
|
|
|
|
2017-10-25 07:42:49 +00:00
|
|
|
if (!g_subprocess_wait_finish (proc, result, &error))
|
|
|
|
{
|
2018-04-12 18:06:01 +00:00
|
|
|
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
|
|
|
return;
|
|
|
|
|
|
|
|
g_warning ("Failed to finish waiting for Xwayland: %s", error->message);
|
2017-10-25 07:42:49 +00:00
|
|
|
}
|
2021-10-28 13:33:03 +00:00
|
|
|
|
|
|
|
x11_display_policy =
|
|
|
|
meta_context_get_x11_display_policy (compositor->context);
|
|
|
|
if (!g_subprocess_get_successful (proc))
|
2013-08-12 07:46:07 +00:00
|
|
|
{
|
2021-04-16 18:34:29 +00:00
|
|
|
if (x11_display_policy == META_X11_DISPLAY_POLICY_MANDATORY)
|
2019-05-24 19:36:50 +00:00
|
|
|
g_warning ("X Wayland crashed; exiting");
|
|
|
|
else
|
|
|
|
g_warning ("X Wayland crashed; attempting to recover");
|
|
|
|
}
|
|
|
|
|
2021-04-16 18:34:29 +00:00
|
|
|
if (x11_display_policy == META_X11_DISPLAY_POLICY_MANDATORY)
|
2019-05-24 19:36:50 +00:00
|
|
|
{
|
|
|
|
meta_exit (META_EXIT_ERROR);
|
2013-08-12 07:46:07 +00:00
|
|
|
}
|
2021-04-16 18:34:29 +00:00
|
|
|
else if (x11_display_policy == META_X11_DISPLAY_POLICY_ON_DEMAND)
|
2019-05-24 19:36:50 +00:00
|
|
|
{
|
2020-12-08 16:42:05 +00:00
|
|
|
g_autoptr (GError) error = NULL;
|
2018-04-12 18:06:01 +00:00
|
|
|
|
2019-05-24 19:36:50 +00:00
|
|
|
if (display->x11_display)
|
|
|
|
meta_display_shutdown_x11 (display);
|
|
|
|
|
|
|
|
if (!meta_xwayland_init (&compositor->xwayland_manager,
|
2021-05-06 16:49:25 +00:00
|
|
|
compositor,
|
2020-12-08 16:42:05 +00:00
|
|
|
compositor->wayland_display,
|
|
|
|
&error))
|
|
|
|
g_warning ("Failed to init X sockets: %s", error->message);
|
2019-05-24 19:36:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-12 12:58:06 +00:00
|
|
|
static void
|
|
|
|
meta_xwayland_terminate (MetaXWaylandManager *manager)
|
|
|
|
{
|
2022-05-30 21:48:44 +00:00
|
|
|
MetaContext *context =
|
|
|
|
meta_wayland_compositor_get_context (manager->compositor);
|
|
|
|
MetaDisplay *display = meta_context_get_display (context);
|
2021-04-12 12:58:06 +00:00
|
|
|
|
|
|
|
meta_display_shutdown_x11 (display);
|
|
|
|
meta_xwayland_stop_xserver (manager);
|
2022-06-15 11:12:35 +00:00
|
|
|
g_clear_signal_handler (&manager->prepare_shutdown_id, manager->compositor);
|
2021-04-12 12:58:06 +00:00
|
|
|
}
|
|
|
|
|
2013-08-12 13:31:18 +00:00
|
|
|
static int
|
|
|
|
x_io_error (Display *display)
|
|
|
|
{
|
2018-04-12 18:06:01 +00:00
|
|
|
g_warning ("Connection to xwayland lost");
|
2019-05-24 19:36:50 +00:00
|
|
|
|
2013-08-12 13:31:18 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-04-20 17:00:14 +00:00
|
|
|
static int
|
|
|
|
x_io_error_noop (Display *display)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-06-14 14:04:44 +00:00
|
|
|
static void
|
2020-12-02 15:29:06 +00:00
|
|
|
x_io_error_exit (Display *display,
|
|
|
|
void *data)
|
2019-06-14 14:04:44 +00:00
|
|
|
{
|
2022-04-05 21:45:51 +00:00
|
|
|
MetaXWaylandManager *manager = data;
|
2022-05-28 18:18:41 +00:00
|
|
|
MetaContext *context = manager->compositor->context;
|
2022-04-05 21:45:51 +00:00
|
|
|
MetaX11DisplayPolicy x11_display_policy;
|
|
|
|
|
|
|
|
x11_display_policy =
|
2022-05-28 18:18:41 +00:00
|
|
|
meta_context_get_x11_display_policy (context);
|
2022-04-05 21:45:51 +00:00
|
|
|
|
|
|
|
if (x11_display_policy == META_X11_DISPLAY_POLICY_MANDATORY)
|
2022-05-28 18:18:41 +00:00
|
|
|
{
|
|
|
|
GError *error;
|
|
|
|
|
|
|
|
g_warning ("Xwayland terminated, exiting since it was mandatory");
|
|
|
|
error = g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
|
|
"Xwayland exited unexpectedly");
|
|
|
|
meta_context_terminate_with_error (context, error);
|
|
|
|
}
|
2022-04-05 21:45:51 +00:00
|
|
|
else
|
2022-05-28 18:18:41 +00:00
|
|
|
{
|
|
|
|
meta_topic (META_DEBUG_WAYLAND, "Xwayland disappeared");
|
|
|
|
}
|
2019-06-14 14:04:44 +00:00
|
|
|
}
|
2021-04-20 17:00:14 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
x_io_error_exit_noop (Display *display,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
}
|
2019-06-14 14:04:44 +00:00
|
|
|
|
2018-11-12 10:29:44 +00:00
|
|
|
void
|
|
|
|
meta_xwayland_override_display_number (int number)
|
|
|
|
{
|
|
|
|
display_number_override = number;
|
|
|
|
}
|
|
|
|
|
2021-03-18 08:56:34 +00:00
|
|
|
static gboolean
|
|
|
|
ensure_x11_unix_perms (GError **error)
|
|
|
|
{
|
2022-01-28 14:49:11 +00:00
|
|
|
/* Try to detect systems on which /tmp/.X11-unix is owned by neither root nor
|
|
|
|
* ourselves because in that case the owner can take over the socket we create
|
|
|
|
* (symlink races are fixed in linux 800179c9b8a1). This should not be
|
|
|
|
* possible in the first place and systems should come with some way to ensure
|
|
|
|
* that's the case (systemd-tmpfiles, polyinstantiation …).
|
|
|
|
*
|
|
|
|
* That check however only works if we see the root user namespace which might
|
|
|
|
* not be the case when running in e.g. toolbx (root and other user are all
|
|
|
|
* mapped to overflowuid). */
|
|
|
|
struct stat x11_tmp, tmp;
|
|
|
|
|
|
|
|
if (lstat (X11_TMP_UNIX_DIR, &x11_tmp) != 0)
|
2021-03-18 08:56:34 +00:00
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
|
|
|
|
"Failed to check permissions on directory \"%s\": %s",
|
|
|
|
X11_TMP_UNIX_DIR, g_strerror (errno));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2022-01-28 14:49:11 +00:00
|
|
|
if (lstat (TMP_UNIX_DIR, &tmp) != 0)
|
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
|
|
|
|
"Failed to check permissions on directory \"%s\": %s",
|
|
|
|
TMP_UNIX_DIR, g_strerror (errno));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If the directory already exists, it should belong to the same
|
|
|
|
* user as /tmp or belong to ourselves ...
|
|
|
|
* (if /tmp is not owned by root or ourselves we're in deep trouble) */
|
|
|
|
if (x11_tmp.st_uid != tmp.st_uid && x11_tmp.st_uid != getuid ())
|
2021-03-18 08:56:34 +00:00
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
|
|
|
|
"Wrong ownership for directory \"%s\"",
|
|
|
|
X11_TMP_UNIX_DIR);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ... be writable ... */
|
2022-01-28 14:49:11 +00:00
|
|
|
if ((x11_tmp.st_mode & 0022) != 0022)
|
2021-03-18 08:56:34 +00:00
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
|
|
|
|
"Directory \"%s\" is not writable",
|
|
|
|
X11_TMP_UNIX_DIR);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ... and have the sticky bit set */
|
2022-01-28 14:49:11 +00:00
|
|
|
if ((x11_tmp.st_mode & 01000) != 01000)
|
2021-03-18 08:56:34 +00:00
|
|
|
{
|
|
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
|
|
|
|
"Directory \"%s\" is missing the sticky bit",
|
|
|
|
X11_TMP_UNIX_DIR);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2020-12-09 14:04:56 +00:00
|
|
|
static gboolean
|
|
|
|
ensure_x11_unix_dir (GError **error)
|
|
|
|
{
|
2021-03-18 09:22:50 +00:00
|
|
|
if (mkdir (X11_TMP_UNIX_DIR, 01777) != 0)
|
2020-12-09 14:04:56 +00:00
|
|
|
{
|
|
|
|
if (errno == EEXIST)
|
2021-03-18 08:56:34 +00:00
|
|
|
return ensure_x11_unix_perms (error);
|
2020-12-09 14:04:56 +00:00
|
|
|
|
|
|
|
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
|
2021-03-18 09:22:50 +00:00
|
|
|
"Failed to create directory \"%s\": %s",
|
|
|
|
X11_TMP_UNIX_DIR, g_strerror (errno));
|
2020-12-09 14:04:56 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2019-05-25 22:37:57 +00:00
|
|
|
static gboolean
|
2020-12-08 16:42:05 +00:00
|
|
|
open_display_sockets (MetaXWaylandManager *manager,
|
|
|
|
int display_index,
|
2020-10-17 03:50:31 +00:00
|
|
|
int *abstract_fd_out,
|
2020-12-08 16:42:05 +00:00
|
|
|
int *unix_fd_out,
|
|
|
|
GError **error)
|
2019-05-25 22:37:57 +00:00
|
|
|
{
|
2020-10-17 03:50:31 +00:00
|
|
|
int abstract_fd, unix_fd;
|
2019-05-25 22:37:57 +00:00
|
|
|
|
2021-01-14 08:56:13 +00:00
|
|
|
abstract_fd = bind_to_abstract_socket (display_index, error);
|
2020-10-17 03:50:31 +00:00
|
|
|
if (abstract_fd < 0)
|
|
|
|
return FALSE;
|
|
|
|
|
2020-12-08 16:42:05 +00:00
|
|
|
unix_fd = bind_to_unix_socket (display_index, error);
|
2019-05-25 22:37:57 +00:00
|
|
|
if (unix_fd < 0)
|
2020-10-17 03:50:31 +00:00
|
|
|
{
|
|
|
|
close (abstract_fd);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2019-05-25 22:37:57 +00:00
|
|
|
|
2020-10-17 03:50:31 +00:00
|
|
|
*abstract_fd_out = abstract_fd;
|
2019-07-19 20:50:31 +00:00
|
|
|
*unix_fd_out = unix_fd;
|
2019-05-25 22:37:57 +00:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2014-04-02 00:00:59 +00:00
|
|
|
static gboolean
|
2020-12-08 16:42:05 +00:00
|
|
|
choose_xdisplay (MetaXWaylandManager *manager,
|
|
|
|
MetaXWaylandConnection *connection,
|
2021-01-21 17:02:21 +00:00
|
|
|
int *display,
|
2020-12-08 16:42:05 +00:00
|
|
|
GError **error)
|
2012-01-07 22:21:32 +00:00
|
|
|
{
|
2021-01-14 08:56:13 +00:00
|
|
|
int number_of_tries = 0;
|
2015-04-23 14:41:34 +00:00
|
|
|
char *lock_file = NULL;
|
2012-01-07 22:21:32 +00:00
|
|
|
|
2021-01-13 17:28:46 +00:00
|
|
|
if (!ensure_x11_unix_dir (error))
|
|
|
|
return FALSE;
|
|
|
|
|
2012-01-07 22:21:32 +00:00
|
|
|
do
|
|
|
|
{
|
2020-12-08 16:42:05 +00:00
|
|
|
g_autoptr (GError) local_error = NULL;
|
|
|
|
|
2021-01-21 17:02:21 +00:00
|
|
|
lock_file = create_lock_file (*display, display, &local_error);
|
2015-04-23 14:41:34 +00:00
|
|
|
if (!lock_file)
|
2012-01-07 22:21:32 +00:00
|
|
|
{
|
2020-12-08 16:42:05 +00:00
|
|
|
g_prefix_error (&local_error, "Failed to create an X lock file: ");
|
|
|
|
g_propagate_error (error, g_steal_pointer (&local_error));
|
2014-01-29 15:23:58 +00:00
|
|
|
return FALSE;
|
2012-01-07 22:21:32 +00:00
|
|
|
}
|
|
|
|
|
2021-01-21 17:02:21 +00:00
|
|
|
if (!open_display_sockets (manager, *display,
|
2020-10-17 03:50:31 +00:00
|
|
|
&connection->abstract_fd,
|
2019-07-19 20:50:31 +00:00
|
|
|
&connection->unix_fd,
|
2020-12-08 16:42:05 +00:00
|
|
|
&local_error))
|
2012-01-07 22:21:32 +00:00
|
|
|
{
|
2015-04-23 14:41:34 +00:00
|
|
|
unlink (lock_file);
|
2020-10-17 03:50:31 +00:00
|
|
|
|
2021-01-14 08:56:13 +00:00
|
|
|
if (++number_of_tries >= 50)
|
2020-10-17 03:50:31 +00:00
|
|
|
{
|
2021-01-13 17:25:06 +00:00
|
|
|
g_prefix_error (&local_error, "Failed to bind X11 socket: ");
|
|
|
|
g_propagate_error (error, g_steal_pointer (&local_error));
|
2021-10-24 21:57:55 +00:00
|
|
|
g_free (lock_file);
|
2020-10-17 03:50:31 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
2021-01-14 08:56:13 +00:00
|
|
|
|
2021-01-21 17:02:21 +00:00
|
|
|
(*display)++;
|
2021-01-14 08:56:13 +00:00
|
|
|
continue;
|
2012-01-07 22:21:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
while (1);
|
|
|
|
|
2021-01-21 17:02:21 +00:00
|
|
|
connection->display_index = *display;
|
2019-07-19 20:50:31 +00:00
|
|
|
connection->name = g_strdup_printf (":%d", connection->display_index);
|
|
|
|
connection->lock_file = lock_file;
|
2012-01-07 22:21:32 +00:00
|
|
|
|
2014-04-02 00:00:59 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2019-06-18 14:12:46 +00:00
|
|
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FILE, fclose)
|
|
|
|
|
|
|
|
static gboolean
|
2020-12-08 16:42:05 +00:00
|
|
|
prepare_auth_file (MetaXWaylandManager *manager,
|
|
|
|
GError **error)
|
2019-06-18 14:12:46 +00:00
|
|
|
{
|
|
|
|
Xauth auth_entry = { 0 };
|
|
|
|
g_autoptr (FILE) fp = NULL;
|
|
|
|
char auth_data[16];
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
manager->auth_file = g_build_filename (g_get_user_runtime_dir (),
|
|
|
|
".mutter-Xwaylandauth.XXXXXX",
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
if (getrandom (auth_data, sizeof (auth_data), 0) != sizeof (auth_data))
|
|
|
|
{
|
2020-12-08 16:42:05 +00:00
|
|
|
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
|
|
|
|
"Failed to get random data: %s", g_strerror (errno));
|
2019-06-18 14:12:46 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
auth_entry.family = FamilyLocal;
|
2019-06-23 15:44:05 +00:00
|
|
|
auth_entry.address = (char *) g_get_host_name ();
|
2019-06-18 14:12:46 +00:00
|
|
|
auth_entry.address_length = strlen (auth_entry.address);
|
|
|
|
auth_entry.name = (char *) "MIT-MAGIC-COOKIE-1";
|
|
|
|
auth_entry.name_length = strlen (auth_entry.name);
|
|
|
|
auth_entry.data = auth_data;
|
|
|
|
auth_entry.data_length = sizeof (auth_data);
|
|
|
|
|
|
|
|
fd = g_mkstemp (manager->auth_file);
|
|
|
|
if (fd < 0)
|
|
|
|
{
|
2020-12-08 16:42:05 +00:00
|
|
|
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
|
|
|
|
"Failed to open Xauthority file: %s", g_strerror (errno));
|
2019-06-18 14:12:46 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
fp = fdopen (fd, "w+");
|
|
|
|
if (!fp)
|
|
|
|
{
|
2020-12-08 16:42:05 +00:00
|
|
|
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
|
|
|
|
"Failed to open Xauthority stream: %s", g_strerror (errno));
|
2019-06-18 14:12:46 +00:00
|
|
|
close (fd);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!XauWriteAuth (fp, &auth_entry))
|
|
|
|
{
|
2020-12-08 16:42:05 +00:00
|
|
|
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
|
|
|
|
"Error writing to Xauthority file: %s", g_strerror (errno));
|
2019-06-18 14:12:46 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
auth_entry.family = FamilyWild;
|
|
|
|
if (!XauWriteAuth (fp, &auth_entry))
|
|
|
|
{
|
2020-12-08 16:42:05 +00:00
|
|
|
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
|
|
|
|
"Error writing to Xauthority file: %s", g_strerror (errno));
|
2019-06-18 14:12:46 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fflush (fp) == EOF)
|
|
|
|
{
|
2020-12-08 16:42:05 +00:00
|
|
|
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
|
|
|
|
"Error writing to Xauthority file: %s", g_strerror (errno));
|
2019-06-18 14:12:46 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2019-11-19 16:32:27 +00:00
|
|
|
static void
|
|
|
|
on_init_x11_cb (MetaDisplay *display,
|
|
|
|
GAsyncResult *result,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
g_autoptr (GError) error = NULL;
|
|
|
|
|
|
|
|
if (!meta_display_init_x11_finish (display, result, &error))
|
2020-10-02 15:54:56 +00:00
|
|
|
g_warning ("Failed to initialize X11 display: %s", error->message);
|
2019-11-19 16:32:27 +00:00
|
|
|
}
|
|
|
|
|
2014-04-02 14:25:56 +00:00
|
|
|
static gboolean
|
2014-04-17 20:05:08 +00:00
|
|
|
on_displayfd_ready (int fd,
|
|
|
|
GIOCondition condition,
|
|
|
|
gpointer user_data)
|
2014-04-02 14:25:56 +00:00
|
|
|
{
|
2019-11-18 13:04:24 +00:00
|
|
|
GTask *task = user_data;
|
2014-04-02 14:25:56 +00:00
|
|
|
|
2014-04-17 20:05:08 +00:00
|
|
|
/* The server writes its display name to the displayfd
|
|
|
|
* socket when it's ready. We don't care about the data
|
|
|
|
* in the socket, just that it wrote something, since
|
|
|
|
* that means it's ready. */
|
2021-05-04 12:24:03 +00:00
|
|
|
g_task_return_boolean (task, !!(condition & G_IO_IN));
|
2019-11-18 13:04:24 +00:00
|
|
|
g_object_unref (task);
|
2019-05-24 19:36:50 +00:00
|
|
|
|
2014-04-02 14:25:56 +00:00
|
|
|
return G_SOURCE_REMOVE;
|
|
|
|
}
|
|
|
|
|
2021-02-19 18:04:25 +00:00
|
|
|
static int
|
|
|
|
steal_fd (int *fd_ptr)
|
|
|
|
{
|
|
|
|
int fd = *fd_ptr;
|
|
|
|
*fd_ptr = -1;
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2019-11-18 13:04:24 +00:00
|
|
|
void
|
|
|
|
meta_xwayland_start_xserver (MetaXWaylandManager *manager,
|
|
|
|
GCancellable *cancellable,
|
|
|
|
GAsyncReadyCallback callback,
|
|
|
|
gpointer user_data)
|
2014-04-02 00:00:59 +00:00
|
|
|
{
|
2022-05-30 21:48:44 +00:00
|
|
|
MetaWaylandCompositor *compositor = manager->compositor;
|
|
|
|
MetaContext *context = meta_wayland_compositor_get_context (compositor);
|
|
|
|
MetaBackend *backend = meta_context_get_backend (context);
|
2014-04-17 19:37:53 +00:00
|
|
|
int xwayland_client_fd[2];
|
2014-04-17 20:05:08 +00:00
|
|
|
int displayfd[2];
|
2015-03-31 18:47:34 +00:00
|
|
|
g_autoptr(GSubprocessLauncher) launcher = NULL;
|
2015-03-22 01:24:37 +00:00
|
|
|
GSubprocessFlags flags;
|
|
|
|
GError *error = NULL;
|
2019-11-18 13:04:24 +00:00
|
|
|
g_autoptr (GTask) task = NULL;
|
2020-08-12 17:30:04 +00:00
|
|
|
MetaSettings *settings;
|
|
|
|
const char *args[32];
|
|
|
|
int xwayland_disable_extensions;
|
|
|
|
int i, j;
|
2021-03-17 15:18:54 +00:00
|
|
|
#ifdef HAVE_XWAYLAND_TERMINATE_DELAY
|
|
|
|
MetaX11DisplayPolicy x11_display_policy =
|
|
|
|
meta_context_get_x11_display_policy (compositor->context);
|
|
|
|
#endif
|
2022-05-28 21:58:07 +00:00
|
|
|
struct {
|
|
|
|
const char *extension_name;
|
|
|
|
MetaXwaylandExtension disable_extension;
|
|
|
|
} x11_extension_names[] = {
|
|
|
|
{ "SECURITY", META_XWAYLAND_EXTENSION_SECURITY },
|
|
|
|
{ "XTEST", META_XWAYLAND_EXTENSION_XTEST },
|
|
|
|
};
|
2019-11-18 13:04:24 +00:00
|
|
|
|
|
|
|
task = g_task_new (NULL, cancellable, callback, user_data);
|
|
|
|
g_task_set_source_tag (task, meta_xwayland_start_xserver);
|
|
|
|
g_task_set_task_data (task, manager, NULL);
|
2014-04-02 00:00:59 +00:00
|
|
|
|
2012-01-07 22:21:32 +00:00
|
|
|
/* We want xwayland to be a wayland client so we make a socketpair to setup a
|
|
|
|
* wayland protocol connection. */
|
2014-04-17 19:37:53 +00:00
|
|
|
if (socketpair (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, xwayland_client_fd) < 0)
|
2012-01-07 22:21:32 +00:00
|
|
|
{
|
2019-11-18 13:04:24 +00:00
|
|
|
g_task_return_new_error (task,
|
|
|
|
G_IO_ERROR,
|
|
|
|
g_io_error_from_errno (errno),
|
|
|
|
"xwayland_client_fd socketpair failed");
|
|
|
|
return;
|
2012-01-07 22:21:32 +00:00
|
|
|
}
|
|
|
|
|
2014-04-17 20:05:08 +00:00
|
|
|
if (socketpair (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, displayfd) < 0)
|
|
|
|
{
|
2021-02-19 18:04:25 +00:00
|
|
|
close (xwayland_client_fd[0]);
|
|
|
|
close (xwayland_client_fd[1]);
|
|
|
|
|
2019-11-18 13:04:24 +00:00
|
|
|
g_task_return_new_error (task,
|
|
|
|
G_IO_ERROR,
|
|
|
|
g_io_error_from_errno (errno),
|
|
|
|
"displayfd socketpair failed");
|
|
|
|
return;
|
2014-04-17 20:05:08 +00:00
|
|
|
}
|
|
|
|
|
2015-03-22 01:24:37 +00:00
|
|
|
/* xwayland, please. */
|
|
|
|
flags = G_SUBPROCESS_FLAGS_NONE;
|
2014-04-01 23:51:43 +00:00
|
|
|
|
2015-03-22 01:24:37 +00:00
|
|
|
if (getenv ("XWAYLAND_STFU"))
|
|
|
|
{
|
|
|
|
flags |= G_SUBPROCESS_FLAGS_STDOUT_SILENCE;
|
|
|
|
flags |= G_SUBPROCESS_FLAGS_STDERR_SILENCE;
|
2014-04-01 23:51:43 +00:00
|
|
|
}
|
2015-03-22 01:24:37 +00:00
|
|
|
|
2020-08-12 17:30:04 +00:00
|
|
|
settings = meta_backend_get_settings (backend);
|
|
|
|
xwayland_disable_extensions =
|
|
|
|
meta_settings_get_xwayland_disable_extensions (settings);
|
|
|
|
|
2015-03-22 01:24:37 +00:00
|
|
|
launcher = g_subprocess_launcher_new (flags);
|
|
|
|
|
2021-02-19 18:04:25 +00:00
|
|
|
g_subprocess_launcher_take_fd (launcher,
|
|
|
|
steal_fd (&xwayland_client_fd[1]), 3);
|
|
|
|
g_subprocess_launcher_take_fd (launcher,
|
|
|
|
steal_fd (&manager->public_connection.abstract_fd), 4);
|
|
|
|
g_subprocess_launcher_take_fd (launcher,
|
|
|
|
steal_fd (&manager->public_connection.unix_fd), 5);
|
|
|
|
g_subprocess_launcher_take_fd (launcher,
|
|
|
|
steal_fd (&displayfd[1]), 6);
|
|
|
|
g_subprocess_launcher_take_fd (launcher,
|
|
|
|
steal_fd (&manager->private_connection.abstract_fd), 7);
|
2015-03-22 01:24:37 +00:00
|
|
|
|
|
|
|
g_subprocess_launcher_setenv (launcher, "WAYLAND_SOCKET", "3", TRUE);
|
2017-10-25 07:42:49 +00:00
|
|
|
|
2020-08-12 17:30:04 +00:00
|
|
|
i = 0;
|
|
|
|
args[i++] = XWAYLAND_PATH;
|
|
|
|
args[i++] = manager->public_connection.name;
|
|
|
|
args[i++] = "-rootless";
|
|
|
|
args[i++] = "-noreset";
|
|
|
|
args[i++] = "-accessx";
|
|
|
|
args[i++] = "-core";
|
|
|
|
args[i++] = "-auth";
|
|
|
|
args[i++] = manager->auth_file;
|
2021-01-22 10:16:24 +00:00
|
|
|
args[i++] = XWAYLAND_LISTENFD;
|
2020-08-12 17:30:04 +00:00
|
|
|
args[i++] = "4";
|
2021-01-22 10:16:24 +00:00
|
|
|
args[i++] = XWAYLAND_LISTENFD;
|
2020-08-31 16:42:08 +00:00
|
|
|
args[i++] = "5";
|
2020-10-17 03:50:31 +00:00
|
|
|
args[i++] = "-displayfd";
|
|
|
|
args[i++] = "6";
|
2019-07-19 20:50:31 +00:00
|
|
|
#ifdef HAVE_XWAYLAND_INITFD
|
2020-08-12 17:30:04 +00:00
|
|
|
args[i++] = "-initfd";
|
2020-10-17 03:50:31 +00:00
|
|
|
args[i++] = "7";
|
2019-07-19 20:50:31 +00:00
|
|
|
#else
|
2021-01-22 10:16:24 +00:00
|
|
|
args[i++] = XWAYLAND_LISTENFD;
|
2020-10-17 03:50:31 +00:00
|
|
|
args[i++] = "7";
|
2021-03-17 15:18:54 +00:00
|
|
|
#endif
|
2022-01-28 08:56:24 +00:00
|
|
|
|
2023-01-09 14:40:03 +00:00
|
|
|
#ifdef HAVE_XWAYLAND_BYTE_SWAPPED_CLIENTS
|
|
|
|
if (meta_settings_are_xwayland_byte_swapped_clients_allowed (settings))
|
|
|
|
args[i++] = "+byteswappedclients";
|
|
|
|
else
|
|
|
|
args[i++] = "-byteswappedclients";
|
|
|
|
#endif
|
|
|
|
|
2022-01-28 08:56:24 +00:00
|
|
|
if (meta_settings_is_experimental_feature_enabled (settings,
|
2021-03-17 15:18:54 +00:00
|
|
|
META_EXPERIMENTAL_FEATURE_AUTOCLOSE_XWAYLAND))
|
2022-01-28 08:56:24 +00:00
|
|
|
#ifdef HAVE_XWAYLAND_TERMINATE_DELAY
|
|
|
|
{
|
|
|
|
if (x11_display_policy == META_X11_DISPLAY_POLICY_ON_DEMAND)
|
|
|
|
{
|
|
|
|
/* Terminate after a 10 seconds delay */
|
|
|
|
args[i++] = "-terminate";
|
|
|
|
args[i++] = "10";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_warning ("autoclose-xwayland disabled, requires Xwayland on demand");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
2021-03-17 15:18:54 +00:00
|
|
|
{
|
2022-01-28 08:56:24 +00:00
|
|
|
g_warning ("autoclose-xwayland disabled, not supported");
|
2021-03-17 15:18:54 +00:00
|
|
|
}
|
2023-09-29 09:37:20 +00:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_XWAYLAND_ENABLE_EI_PORTAL
|
|
|
|
if (manager->should_enable_ei_portal)
|
|
|
|
{
|
|
|
|
/* Enable portal support */
|
|
|
|
args[i++] = "-enable-ei-portal";
|
|
|
|
}
|
2019-07-19 20:50:31 +00:00
|
|
|
#endif
|
2020-08-12 17:30:04 +00:00
|
|
|
for (j = 0; j < G_N_ELEMENTS (x11_extension_names); j++)
|
|
|
|
{
|
|
|
|
/* Make sure we don't go past the array size - We need room for
|
|
|
|
* 2 arguments, plus the last NULL terminator.
|
|
|
|
*/
|
|
|
|
if (i + 3 > G_N_ELEMENTS (args))
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (xwayland_disable_extensions & x11_extension_names[j].disable_extension)
|
|
|
|
{
|
|
|
|
args[i++] = "-extension";
|
|
|
|
args[i++] = x11_extension_names[j].extension_name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Terminator */
|
|
|
|
args[i++] = NULL;
|
|
|
|
|
|
|
|
manager->proc = g_subprocess_launcher_spawnv (launcher, args, &error);
|
2019-07-19 20:50:31 +00:00
|
|
|
|
2017-10-25 07:42:49 +00:00
|
|
|
if (!manager->proc)
|
2014-04-02 17:03:17 +00:00
|
|
|
{
|
2021-02-19 18:04:25 +00:00
|
|
|
close (displayfd[0]);
|
|
|
|
close (xwayland_client_fd[0]);
|
|
|
|
|
2019-11-18 13:04:24 +00:00
|
|
|
g_task_return_error (task, error);
|
|
|
|
return;
|
2014-04-02 17:03:17 +00:00
|
|
|
}
|
2014-04-01 23:51:43 +00:00
|
|
|
|
2017-10-25 07:42:49 +00:00
|
|
|
manager->xserver_died_cancellable = g_cancellable_new ();
|
|
|
|
g_subprocess_wait_async (manager->proc, manager->xserver_died_cancellable,
|
2022-05-30 21:48:44 +00:00
|
|
|
xserver_died, manager);
|
2019-11-18 13:04:24 +00:00
|
|
|
g_unix_fd_add (displayfd[0], G_IO_IN, on_displayfd_ready,
|
|
|
|
g_steal_pointer (&task));
|
2018-12-10 13:24:43 +00:00
|
|
|
manager->client = wl_client_create (manager->wayland_display,
|
|
|
|
xwayland_client_fd[0]);
|
2019-11-18 13:04:24 +00:00
|
|
|
}
|
2012-01-07 22:21:32 +00:00
|
|
|
|
2019-11-18 13:04:24 +00:00
|
|
|
gboolean
|
|
|
|
meta_xwayland_start_xserver_finish (MetaXWaylandManager *manager,
|
|
|
|
GAsyncResult *result,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
g_assert (g_task_get_source_tag (G_TASK (result)) ==
|
|
|
|
meta_xwayland_start_xserver);
|
2013-08-12 08:06:13 +00:00
|
|
|
|
2019-11-18 13:04:24 +00:00
|
|
|
return g_task_propagate_boolean (G_TASK (result), error);
|
2018-12-10 13:24:43 +00:00
|
|
|
}
|
|
|
|
|
2019-05-24 19:36:50 +00:00
|
|
|
static gboolean
|
|
|
|
xdisplay_connection_activity_cb (gint fd,
|
|
|
|
GIOCondition cond,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
2020-10-17 04:01:44 +00:00
|
|
|
MetaXWaylandManager *manager = user_data;
|
2022-05-30 21:48:44 +00:00
|
|
|
MetaContext *context =
|
|
|
|
meta_wayland_compositor_get_context (manager->compositor);
|
|
|
|
MetaDisplay *display = meta_context_get_display (context);
|
2019-05-24 19:36:50 +00:00
|
|
|
|
2019-11-18 13:04:24 +00:00
|
|
|
meta_display_init_x11 (display, NULL,
|
|
|
|
(GAsyncReadyCallback) on_init_x11_cb, NULL);
|
2019-05-24 19:36:50 +00:00
|
|
|
|
2020-10-17 04:01:44 +00:00
|
|
|
/* Stop watching both file descriptors */
|
|
|
|
g_clear_handle_id (&manager->abstract_fd_watch_id, g_source_remove);
|
|
|
|
g_clear_handle_id (&manager->unix_fd_watch_id, g_source_remove);
|
|
|
|
|
2019-05-24 19:36:50 +00:00
|
|
|
return G_SOURCE_REMOVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_xwayland_stop_xserver (MetaXWaylandManager *manager)
|
|
|
|
{
|
|
|
|
if (manager->proc)
|
|
|
|
g_subprocess_send_signal (manager->proc, SIGTERM);
|
|
|
|
g_clear_object (&manager->xserver_died_cancellable);
|
|
|
|
g_clear_object (&manager->proc);
|
2019-05-24 19:09:32 +00:00
|
|
|
}
|
|
|
|
|
2022-06-15 11:12:35 +00:00
|
|
|
static void
|
|
|
|
meta_xwayland_connection_release (MetaXWaylandConnection *connection)
|
|
|
|
{
|
|
|
|
unlink (connection->lock_file);
|
|
|
|
g_clear_pointer (&connection->lock_file, g_free);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_xwayland_shutdown (MetaWaylandCompositor *compositor)
|
|
|
|
{
|
|
|
|
MetaXWaylandManager *manager = &compositor->xwayland_manager;
|
2023-01-12 13:18:31 +00:00
|
|
|
MetaContext *context = meta_wayland_compositor_get_context (compositor);
|
|
|
|
MetaDisplay *display = meta_context_get_display (context);
|
2022-06-15 11:12:35 +00:00
|
|
|
MetaX11Display *x11_display;
|
|
|
|
char path[256];
|
|
|
|
|
|
|
|
g_cancellable_cancel (manager->xserver_died_cancellable);
|
|
|
|
|
|
|
|
XSetIOErrorHandler (x_io_error_noop);
|
|
|
|
x11_display = display->x11_display;
|
|
|
|
if (x11_display)
|
|
|
|
{
|
|
|
|
XSetIOErrorExitHandler (meta_x11_display_get_xdisplay (x11_display),
|
|
|
|
x_io_error_exit_noop, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
meta_xwayland_terminate (manager);
|
|
|
|
|
|
|
|
if (manager->public_connection.name)
|
|
|
|
{
|
|
|
|
snprintf (path, sizeof path, "%s%d", X11_TMP_UNIX_PATH,
|
|
|
|
manager->public_connection.display_index);
|
|
|
|
unlink (path);
|
|
|
|
g_clear_pointer (&manager->public_connection.name, g_free);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (manager->private_connection.name)
|
|
|
|
{
|
|
|
|
snprintf (path, sizeof path, "%s%d", X11_TMP_UNIX_PATH,
|
|
|
|
manager->private_connection.display_index);
|
|
|
|
unlink (path);
|
|
|
|
g_clear_pointer (&manager->private_connection.name, g_free);
|
|
|
|
}
|
|
|
|
|
|
|
|
meta_xwayland_connection_release (&manager->public_connection);
|
|
|
|
meta_xwayland_connection_release (&manager->private_connection);
|
|
|
|
|
|
|
|
if (manager->auth_file)
|
|
|
|
{
|
|
|
|
unlink (manager->auth_file);
|
|
|
|
g_clear_pointer (&manager->auth_file, g_free);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-10 13:24:43 +00:00
|
|
|
gboolean
|
2021-05-06 16:49:25 +00:00
|
|
|
meta_xwayland_init (MetaXWaylandManager *manager,
|
|
|
|
MetaWaylandCompositor *compositor,
|
|
|
|
struct wl_display *wl_display,
|
|
|
|
GError **error)
|
2018-12-10 13:24:43 +00:00
|
|
|
{
|
2021-04-16 18:34:29 +00:00
|
|
|
MetaContext *context = compositor->context;
|
2021-02-25 15:19:51 +00:00
|
|
|
MetaX11DisplayPolicy policy;
|
2021-01-21 17:02:21 +00:00
|
|
|
int display = 0;
|
|
|
|
|
|
|
|
if (display_number_override != -1)
|
|
|
|
display = display_number_override;
|
|
|
|
else if (g_getenv ("RUNNING_UNDER_GDM"))
|
|
|
|
display = 1024;
|
|
|
|
|
2019-07-19 20:50:31 +00:00
|
|
|
if (!manager->public_connection.name)
|
2019-05-24 19:36:50 +00:00
|
|
|
{
|
2021-01-21 17:02:21 +00:00
|
|
|
if (!choose_xdisplay (manager, &manager->public_connection, &display, error))
|
2019-07-19 20:50:31 +00:00
|
|
|
return FALSE;
|
2021-01-21 17:02:21 +00:00
|
|
|
|
|
|
|
display++;
|
|
|
|
if (!choose_xdisplay (manager, &manager->private_connection, &display, error))
|
2019-05-24 19:36:50 +00:00
|
|
|
return FALSE;
|
2019-08-13 18:52:34 +00:00
|
|
|
|
2020-12-08 16:42:05 +00:00
|
|
|
if (!prepare_auth_file (manager, error))
|
2019-08-13 18:52:34 +00:00
|
|
|
return FALSE;
|
2019-05-24 19:36:50 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-07-19 20:50:31 +00:00
|
|
|
if (!open_display_sockets (manager,
|
|
|
|
manager->public_connection.display_index,
|
2020-10-17 03:50:31 +00:00
|
|
|
&manager->public_connection.abstract_fd,
|
2019-07-19 20:50:31 +00:00
|
|
|
&manager->public_connection.unix_fd,
|
2020-12-08 16:42:05 +00:00
|
|
|
error))
|
2019-07-19 20:50:31 +00:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (!open_display_sockets (manager,
|
|
|
|
manager->private_connection.display_index,
|
2020-10-17 03:50:31 +00:00
|
|
|
&manager->private_connection.abstract_fd,
|
2019-07-19 20:50:31 +00:00
|
|
|
&manager->private_connection.unix_fd,
|
2020-12-08 16:42:05 +00:00
|
|
|
error))
|
2019-05-24 19:36:50 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
2015-04-23 14:26:38 +00:00
|
|
|
|
2020-12-08 16:45:05 +00:00
|
|
|
g_message ("Using public X11 display %s, (using %s for managed services)",
|
|
|
|
manager->public_connection.name,
|
|
|
|
manager->private_connection.name);
|
|
|
|
|
2022-04-05 21:45:51 +00:00
|
|
|
manager->compositor = compositor;
|
2018-12-10 13:24:43 +00:00
|
|
|
manager->wayland_display = wl_display;
|
2021-04-16 18:34:29 +00:00
|
|
|
policy = meta_context_get_x11_display_policy (context);
|
2019-05-24 19:36:50 +00:00
|
|
|
|
2021-02-25 15:19:51 +00:00
|
|
|
if (policy == META_X11_DISPLAY_POLICY_ON_DEMAND)
|
2019-05-24 19:36:50 +00:00
|
|
|
{
|
2020-10-17 04:01:44 +00:00
|
|
|
manager->abstract_fd_watch_id =
|
|
|
|
g_unix_fd_add (manager->public_connection.abstract_fd, G_IO_IN,
|
|
|
|
xdisplay_connection_activity_cb, manager);
|
|
|
|
manager->unix_fd_watch_id =
|
|
|
|
g_unix_fd_add (manager->public_connection.unix_fd, G_IO_IN,
|
|
|
|
xdisplay_connection_activity_cb, manager);
|
2019-05-24 19:36:50 +00:00
|
|
|
}
|
|
|
|
|
2022-06-15 11:12:35 +00:00
|
|
|
if (policy != META_X11_DISPLAY_POLICY_DISABLED)
|
|
|
|
manager->prepare_shutdown_id = g_signal_connect (compositor, "prepare-shutdown",
|
|
|
|
G_CALLBACK (meta_xwayland_shutdown),
|
|
|
|
NULL);
|
|
|
|
|
2022-06-15 11:24:45 +00:00
|
|
|
/* Xwayland specific protocol, needs to be filtered out for all other clients */
|
|
|
|
meta_xwayland_grab_keyboard_init (compositor);
|
2023-01-27 14:16:14 +00:00
|
|
|
|
2019-11-18 13:04:24 +00:00
|
|
|
return TRUE;
|
2012-01-07 22:21:32 +00:00
|
|
|
}
|
|
|
|
|
2020-11-11 12:17:14 +00:00
|
|
|
static void
|
2022-05-30 21:48:44 +00:00
|
|
|
monitors_changed_cb (MetaMonitorManager *monitor_manager,
|
|
|
|
MetaXWaylandManager *manager)
|
2020-11-11 12:17:14 +00:00
|
|
|
{
|
2022-05-30 21:48:44 +00:00
|
|
|
MetaContext *context =
|
|
|
|
meta_wayland_compositor_get_context (manager->compositor);
|
|
|
|
MetaDisplay *display = meta_context_get_display (context);
|
|
|
|
MetaX11Display *x11_display = display->x11_display;
|
2020-11-11 12:17:14 +00:00
|
|
|
|
2021-03-23 16:03:32 +00:00
|
|
|
meta_xwayland_set_primary_output (x11_display);
|
2020-11-11 12:17:14 +00:00
|
|
|
}
|
|
|
|
|
2018-06-30 07:04:48 +00:00
|
|
|
static void
|
2021-04-20 16:41:07 +00:00
|
|
|
on_x11_display_closing (MetaDisplay *display,
|
|
|
|
MetaXWaylandManager *manager)
|
2018-06-30 07:04:48 +00:00
|
|
|
{
|
2021-03-23 15:57:00 +00:00
|
|
|
MetaX11Display *x11_display = meta_display_get_x11_display (display);
|
2022-05-30 21:48:44 +00:00
|
|
|
MetaMonitorManager *monitor_manager =
|
|
|
|
monitor_manager_from_x11_display (x11_display);
|
2019-08-19 13:48:17 +00:00
|
|
|
|
2021-03-23 15:57:00 +00:00
|
|
|
meta_xwayland_shutdown_dnd (manager, x11_display);
|
2022-05-30 21:48:44 +00:00
|
|
|
g_signal_handlers_disconnect_by_func (monitor_manager,
|
2020-11-11 12:17:14 +00:00
|
|
|
monitors_changed_cb,
|
2022-05-30 21:48:44 +00:00
|
|
|
manager);
|
2018-06-30 07:04:48 +00:00
|
|
|
}
|
|
|
|
|
2020-11-11 12:17:14 +00:00
|
|
|
static void
|
|
|
|
meta_xwayland_init_xrandr (MetaXWaylandManager *manager,
|
2021-03-23 16:03:32 +00:00
|
|
|
MetaX11Display *x11_display)
|
2020-11-11 12:17:14 +00:00
|
|
|
{
|
2022-05-30 21:48:44 +00:00
|
|
|
MetaMonitorManager *monitor_manager =
|
|
|
|
monitor_manager_from_x11_display (x11_display);
|
2021-03-23 16:03:32 +00:00
|
|
|
Display *xdisplay = meta_x11_display_get_xdisplay (x11_display);
|
2020-11-11 12:17:14 +00:00
|
|
|
|
|
|
|
manager->has_xrandr = XRRQueryExtension (xdisplay,
|
|
|
|
&manager->rr_event_base,
|
|
|
|
&manager->rr_error_base);
|
|
|
|
|
|
|
|
if (!manager->has_xrandr)
|
|
|
|
return;
|
|
|
|
|
|
|
|
XRRSelectInput (xdisplay, DefaultRootWindow (xdisplay),
|
|
|
|
RRCrtcChangeNotifyMask | RROutputChangeNotifyMask);
|
|
|
|
|
|
|
|
g_signal_connect (monitor_manager, "monitors-changed",
|
2022-05-30 21:48:44 +00:00
|
|
|
G_CALLBACK (monitors_changed_cb), manager);
|
2020-11-11 12:17:14 +00:00
|
|
|
|
2021-03-23 16:03:32 +00:00
|
|
|
meta_xwayland_set_primary_output (x11_display);
|
2020-11-11 12:17:14 +00:00
|
|
|
}
|
|
|
|
|
2021-03-23 15:47:45 +00:00
|
|
|
static void
|
|
|
|
on_x11_display_setup (MetaDisplay *display,
|
|
|
|
MetaXWaylandManager *manager)
|
2013-08-12 13:31:18 +00:00
|
|
|
{
|
2021-03-23 16:03:32 +00:00
|
|
|
MetaX11Display *x11_display = meta_display_get_x11_display (display);
|
2019-05-24 19:09:32 +00:00
|
|
|
|
2021-03-23 15:57:00 +00:00
|
|
|
meta_xwayland_init_dnd (x11_display);
|
2021-03-23 16:03:32 +00:00
|
|
|
meta_xwayland_init_xrandr (manager, x11_display);
|
2021-03-23 15:47:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_xwayland_init_display (MetaXWaylandManager *manager,
|
|
|
|
MetaDisplay *display)
|
|
|
|
{
|
|
|
|
g_signal_connect (display, "x11-display-setup",
|
|
|
|
G_CALLBACK (on_x11_display_setup), manager);
|
|
|
|
g_signal_connect (display, "x11-display-closing",
|
|
|
|
G_CALLBACK (on_x11_display_closing), manager);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_xwayland_setup_xdisplay (MetaXWaylandManager *manager,
|
|
|
|
Display *xdisplay)
|
|
|
|
{
|
2013-08-12 13:31:18 +00:00
|
|
|
/* We install an X IO error handler in addition to the child watch,
|
|
|
|
because after Xlib connects our child watch may not be called soon
|
|
|
|
enough, and therefore we won't crash when X exits (and most important
|
|
|
|
we won't reset the tty).
|
|
|
|
*/
|
|
|
|
XSetIOErrorHandler (x_io_error);
|
2021-03-23 15:43:52 +00:00
|
|
|
XSetIOErrorExitHandler (xdisplay, x_io_error_exit, manager);
|
2014-10-10 16:55:00 +00:00
|
|
|
|
xwayland: Mark our X11 connection terminatable
The connection to the Xserver for the X11 window manager part of mutter
even on Wayland may prevent the Xserver from shutting down.
Currently, what mutter does is to check the X11 clients still connected
to Xwayland using the XRes extension, with a list of X11 clients that
can be safely ignored (typically the GNOME XSettings daemon, the IBus
daemon, pulseaudio and even mutter window manager itself).
When there is just those known clients remaining, mutter would kill
Xwayland automatically.
But that's racy, because between the time mutter checks with Xwayland
the remaining clients and the time it actually kills the process, a new
X11 client might have come along and won't be able to connect to
Xwayland that mutter is just about to kill.
Because of that, the feature “autoclose-xwayland” is marked as an
experimental feature in mutter and not enabled by default.
Thankfully, the Xserver has all it takes to manage that already, and
is even capable of terminating itself once all X11 clients are gone (the
-terminate option on the command line).
With XFixes version 6, the X11 clients can declare themselves
"terminatable", so that the Xserver could simply ignore those X11
clients when checking the remaining clients and terminate itself
automatically.
Use that mechanism to declare mutter's own connection to the Xserver as
"terminatable" when Xwayland is started on demand so that it won't hold
Xwayland alive for the sole purpose of mutter itself.
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1794>
2021-03-17 14:44:45 +00:00
|
|
|
XFixesSetClientDisconnectMode (xdisplay, XFixesClientDisconnectFlagTerminate);
|
2013-08-12 13:31:18 +00:00
|
|
|
}
|
|
|
|
|
2020-11-11 12:17:14 +00:00
|
|
|
static void
|
2021-03-23 16:03:32 +00:00
|
|
|
meta_xwayland_set_primary_output (MetaX11Display *x11_display)
|
2020-11-11 12:17:14 +00:00
|
|
|
{
|
2021-03-23 16:03:32 +00:00
|
|
|
Display *xdisplay = meta_x11_display_get_xdisplay (x11_display);
|
2022-05-30 21:48:44 +00:00
|
|
|
MetaMonitorManager *monitor_manager =
|
|
|
|
monitor_manager_from_x11_display (x11_display);
|
2020-11-11 12:17:14 +00:00
|
|
|
XRRScreenResources *resources;
|
|
|
|
MetaLogicalMonitor *primary_monitor;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
primary_monitor =
|
|
|
|
meta_monitor_manager_get_primary_logical_monitor (monitor_manager);
|
|
|
|
|
|
|
|
if (!primary_monitor)
|
|
|
|
return;
|
|
|
|
|
|
|
|
resources = XRRGetScreenResourcesCurrent (xdisplay,
|
|
|
|
DefaultRootWindow (xdisplay));
|
|
|
|
if (!resources)
|
|
|
|
return;
|
|
|
|
|
2024-01-03 14:43:36 +00:00
|
|
|
mtk_x11_error_trap_push (x11_display->xdisplay);
|
2020-11-11 12:17:14 +00:00
|
|
|
for (i = 0; i < resources->noutput; i++)
|
|
|
|
{
|
|
|
|
RROutput output_id = resources->outputs[i];
|
|
|
|
XRROutputInfo *xrandr_output;
|
|
|
|
XRRCrtcInfo *crtc_info = NULL;
|
2023-07-19 23:46:15 +00:00
|
|
|
MtkRectangle crtc_geometry;
|
2020-11-11 12:17:14 +00:00
|
|
|
|
|
|
|
xrandr_output = XRRGetOutputInfo (xdisplay, resources, output_id);
|
|
|
|
if (!xrandr_output)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (xrandr_output->crtc)
|
|
|
|
crtc_info = XRRGetCrtcInfo (xdisplay, resources, xrandr_output->crtc);
|
|
|
|
|
|
|
|
XRRFreeOutputInfo (xrandr_output);
|
|
|
|
|
|
|
|
if (!crtc_info)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
crtc_geometry.x = crtc_info->x;
|
|
|
|
crtc_geometry.y = crtc_info->y;
|
|
|
|
crtc_geometry.width = crtc_info->width;
|
|
|
|
crtc_geometry.height = crtc_info->height;
|
|
|
|
|
|
|
|
XRRFreeCrtcInfo (crtc_info);
|
|
|
|
|
2023-07-19 15:14:13 +00:00
|
|
|
if (mtk_rectangle_equal (&crtc_geometry, &primary_monitor->rect))
|
2020-11-11 12:17:14 +00:00
|
|
|
{
|
|
|
|
XRRSetOutputPrimary (xdisplay, DefaultRootWindow (xdisplay),
|
|
|
|
output_id);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2024-01-03 14:43:36 +00:00
|
|
|
mtk_x11_error_trap_pop (x11_display->xdisplay);
|
2020-11-11 12:17:14 +00:00
|
|
|
|
|
|
|
XRRFreeScreenResources (resources);
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
2022-05-30 21:48:44 +00:00
|
|
|
meta_xwayland_manager_handle_xevent (MetaXWaylandManager *manager,
|
|
|
|
XEvent *event)
|
2020-11-11 12:17:14 +00:00
|
|
|
{
|
2022-05-30 21:48:44 +00:00
|
|
|
if (meta_xwayland_dnd_handle_xevent (manager, event))
|
2020-11-11 12:17:14 +00:00
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
if (manager->has_xrandr && event->type == manager->rr_event_base + RRNotify)
|
|
|
|
{
|
2022-05-30 21:48:44 +00:00
|
|
|
MetaContext *context =
|
|
|
|
meta_wayland_compositor_get_context (manager->compositor);
|
|
|
|
MetaDisplay *display = meta_context_get_display (context);
|
|
|
|
MetaX11Display *x11_display = meta_display_get_x11_display (display);
|
2021-03-23 16:03:32 +00:00
|
|
|
|
|
|
|
meta_xwayland_set_primary_output (x11_display);
|
2020-11-11 12:17:14 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
2022-04-05 21:46:42 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2023-09-29 14:26:41 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
meta_xwayland_set_should_enable_ei_portal (MetaXWaylandManager *manager,
|
|
|
|
gboolean should_enable_ei_portal)
|
|
|
|
{
|
|
|
|
manager->should_enable_ei_portal = should_enable_ei_portal;
|
|
|
|
}
|