2014-04-01 20:35:26 -04:00
|
|
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
|
|
|
|
2012-01-07 17:21:32 -05: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
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|
|
|
* 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
2014-04-01 20:35:26 -04:00
|
|
|
#include "config.h"
|
|
|
|
|
2018-07-10 04:36:24 -04:00
|
|
|
#include "wayland/meta-xwayland.h"
|
|
|
|
#include "wayland/meta-xwayland-private.h"
|
2012-01-07 17:21:32 -05:00
|
|
|
|
|
|
|
#include <errno.h>
|
2018-07-10 04:36:24 -04:00
|
|
|
#include <glib-unix.h>
|
|
|
|
#include <glib.h>
|
2012-01-07 17:21:32 -05:00
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/un.h>
|
2019-06-20 06:11:29 -04:00
|
|
|
#if defined(HAVE_SYS_RANDOM)
|
2019-06-18 10:12:46 -04:00
|
|
|
#include <sys/random.h>
|
2019-06-20 06:11:29 -04:00
|
|
|
#elif defined(HAVE_LINUX_RANDOM)
|
|
|
|
#include <linux/random.h>
|
|
|
|
#endif
|
2019-06-18 10:12:46 -04:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <X11/Xauth.h>
|
2012-01-07 17:21:32 -05:00
|
|
|
|
2015-07-08 04:14:00 -04:00
|
|
|
#include "compositor/meta-surface-actor-wayland.h"
|
2019-06-27 13:33:24 -04:00
|
|
|
#include "compositor/meta-window-actor-private.h"
|
2019-05-24 15:36:50 -04:00
|
|
|
#include "core/main-private.h"
|
2018-07-10 04:36:24 -04:00
|
|
|
#include "meta/main.h"
|
2017-12-20 06:07:40 -05:00
|
|
|
#include "wayland/meta-wayland-actor-surface.h"
|
2019-05-24 15:09:32 -04:00
|
|
|
#include "x11/meta-x11-display-private.h"
|
2015-07-08 04:14:00 -04:00
|
|
|
|
2018-12-19 03:04:25 -05:00
|
|
|
enum
|
|
|
|
{
|
2016-04-01 08:57:19 -04:00
|
|
|
XWAYLAND_SURFACE_WINDOW_ASSOCIATED,
|
|
|
|
|
|
|
|
XWAYLAND_SURFACE_LAST_SIGNAL
|
|
|
|
};
|
|
|
|
|
|
|
|
guint xwayland_surface_signals[XWAYLAND_SURFACE_LAST_SIGNAL];
|
|
|
|
|
2015-07-08 04:14:00 -04:00
|
|
|
#define META_TYPE_WAYLAND_SURFACE_ROLE_XWAYLAND (meta_wayland_surface_role_xwayland_get_type ())
|
|
|
|
G_DECLARE_FINAL_TYPE (MetaWaylandSurfaceRoleXWayland,
|
|
|
|
meta_wayland_surface_role_xwayland,
|
|
|
|
META, WAYLAND_SURFACE_ROLE_XWAYLAND,
|
2017-12-20 06:07:40 -05:00
|
|
|
MetaWaylandActorSurface)
|
2015-07-08 04:14:00 -04:00
|
|
|
|
|
|
|
struct _MetaWaylandSurfaceRoleXWayland
|
|
|
|
{
|
2017-12-20 06:07:40 -05:00
|
|
|
MetaWaylandActorSurface parent;
|
2015-07-08 04:14:00 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
G_DEFINE_TYPE (MetaWaylandSurfaceRoleXWayland,
|
|
|
|
meta_wayland_surface_role_xwayland,
|
2017-12-20 06:07:40 -05:00
|
|
|
META_TYPE_WAYLAND_ACTOR_SURFACE)
|
2015-07-08 04:14:00 -04:00
|
|
|
|
2018-11-12 05:29:44 -05:00
|
|
|
static int display_number_override = -1;
|
|
|
|
|
2019-05-24 15:36:50 -04:00
|
|
|
static void meta_xwayland_stop_xserver (MetaXWaylandManager *manager);
|
|
|
|
|
2018-04-06 09:47:50 -04:00
|
|
|
void
|
|
|
|
meta_xwayland_associate_window_with_surface (MetaWindow *window,
|
|
|
|
MetaWaylandSurface *surface)
|
2013-08-12 04:06:13 -04:00
|
|
|
{
|
2014-04-02 10:19:39 -04:00
|
|
|
MetaDisplay *display = window->display;
|
2019-06-27 13:33:24 -04:00
|
|
|
MetaWindowActor *window_actor;
|
2014-01-31 11:24:02 -05:00
|
|
|
|
2019-02-06 17:04:13 -05:00
|
|
|
/* If the window has an existing surface, like if we're
|
|
|
|
* undecorating or decorating the window, then we need
|
|
|
|
* to detach the window from its old surface.
|
|
|
|
*/
|
|
|
|
if (window->surface)
|
|
|
|
{
|
|
|
|
meta_wayland_surface_set_window (window->surface, NULL);
|
|
|
|
window->surface = NULL;
|
|
|
|
}
|
|
|
|
|
2015-08-20 04:54:45 -04:00
|
|
|
if (!meta_wayland_surface_assign_role (surface,
|
2016-01-28 04:14:06 -05:00
|
|
|
META_TYPE_WAYLAND_SURFACE_ROLE_XWAYLAND,
|
|
|
|
NULL))
|
2015-08-20 04:54:45 -04: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;
|
|
|
|
}
|
|
|
|
|
2014-01-31 11:24:02 -05:00
|
|
|
window->surface = surface;
|
2016-04-01 08:57:19 -04:00
|
|
|
meta_wayland_surface_set_window (surface, window);
|
|
|
|
g_signal_emit (surface->role,
|
|
|
|
xwayland_surface_signals[XWAYLAND_SURFACE_WINDOW_ASSOCIATED],
|
|
|
|
0);
|
2014-02-24 19:22:56 -05:00
|
|
|
|
2019-06-27 13:33:24 -04:00
|
|
|
window_actor = meta_window_actor_from_window (window);
|
|
|
|
if (window_actor)
|
|
|
|
{
|
|
|
|
MetaSurfaceActor *surface_actor;
|
|
|
|
|
|
|
|
surface_actor = meta_wayland_surface_get_actor (surface);
|
|
|
|
meta_window_actor_assign_surface_actor (window_actor, surface_actor);
|
|
|
|
}
|
2014-04-02 11:20:30 -04:00
|
|
|
|
2014-04-08 12:39:15 -04:00
|
|
|
/* Now that we have a surface check if it should have focus. */
|
|
|
|
meta_display_sync_wayland_input_focus (display);
|
2013-08-12 04:06:13 -04:00
|
|
|
}
|
|
|
|
|
2014-03-20 13:12:43 -04:00
|
|
|
static gboolean
|
|
|
|
associate_window_with_surface_id (MetaXWaylandManager *manager,
|
|
|
|
MetaWindow *window,
|
|
|
|
guint32 surface_id)
|
2014-04-02 10:19:39 -04:00
|
|
|
{
|
2014-03-20 13:12:43 -04: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 09:47:50 -04:00
|
|
|
meta_xwayland_associate_window_with_surface (window, surface);
|
2014-03-20 13:12:43 -04:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_xwayland_handle_wl_surface_id (MetaWindow *window,
|
|
|
|
guint32 surface_id)
|
2013-08-12 04:06:13 -04:00
|
|
|
{
|
2014-03-20 13:12:43 -04:00
|
|
|
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
|
|
|
|
MetaXWaylandManager *manager = &compositor->xwayland_manager;
|
|
|
|
|
|
|
|
if (!associate_window_with_surface_id (manager, window, surface_id))
|
|
|
|
{
|
2018-04-06 09:47:50 -04:00
|
|
|
/* No surface ID yet, schedule this association for whenever the
|
|
|
|
* surface is made known.
|
2014-03-20 13:12:43 -04:00
|
|
|
*/
|
2018-04-06 09:47:50 -04:00
|
|
|
meta_wayland_compositor_schedule_surface_association (compositor,
|
|
|
|
surface_id, window);
|
2014-03-20 13:12:43 -04:00
|
|
|
}
|
2013-08-12 04:06:13 -04:00
|
|
|
}
|
|
|
|
|
2015-09-16 03:49:46 -04:00
|
|
|
gboolean
|
|
|
|
meta_xwayland_is_xwayland_surface (MetaWaylandSurface *surface)
|
|
|
|
{
|
|
|
|
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
|
|
|
|
MetaXWaylandManager *manager = &compositor->xwayland_manager;
|
|
|
|
|
|
|
|
return wl_resource_get_client (surface->resource) == manager->client;
|
|
|
|
}
|
|
|
|
|
2014-04-17 15:03:45 -04:00
|
|
|
static gboolean
|
|
|
|
try_display (int display,
|
|
|
|
char **filename_out,
|
|
|
|
int *fd_out)
|
2012-01-07 17:21:32 -05:00
|
|
|
{
|
2014-04-17 15:03:45 -04:00
|
|
|
gboolean ret = FALSE;
|
2012-01-07 17:21:32 -05:00
|
|
|
char *filename;
|
|
|
|
int fd;
|
|
|
|
|
2014-04-17 15:03:45 -04: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 17:21:32 -05:00
|
|
|
{
|
2014-04-17 15:03:45 -04:00
|
|
|
char pid[11];
|
2012-01-07 17:21:32 -05:00
|
|
|
char *end;
|
|
|
|
pid_t other;
|
|
|
|
|
2014-04-17 15:03:45 -04:00
|
|
|
fd = open (filename, O_CLOEXEC, O_RDONLY);
|
|
|
|
if (fd < 0 || read (fd, pid, 11) != 11)
|
|
|
|
{
|
|
|
|
g_warning ("can't read lock file %s: %m", filename);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
close (fd);
|
|
|
|
fd = -1;
|
2012-01-07 17:21:32 -05: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 06:00:25 -05:00
|
|
|
pid[10] = '\0';
|
2014-04-17 15:03:45 -04:00
|
|
|
other = strtol (pid, &end, 0);
|
|
|
|
if (end != pid + 10)
|
2012-01-07 17:21:32 -05:00
|
|
|
{
|
2014-04-17 15:03:45 -04:00
|
|
|
g_warning ("can't parse lock file %s", filename);
|
|
|
|
goto out;
|
|
|
|
}
|
2012-01-07 17:21:32 -05:00
|
|
|
|
2014-04-17 15:03:45 -04:00
|
|
|
if (kill (other, 0) < 0 && errno == ESRCH)
|
|
|
|
{
|
2015-04-23 10:41:34 -04:00
|
|
|
/* Process is dead. Try unlinking the lock file and trying again. */
|
2014-04-17 15:03:45 -04:00
|
|
|
if (unlink (filename) < 0)
|
|
|
|
{
|
|
|
|
g_warning ("failed to unlink stale lock file %s: %m", filename);
|
|
|
|
goto out;
|
2014-01-29 10:23:58 -05:00
|
|
|
}
|
2012-01-07 17:21:32 -05:00
|
|
|
|
2014-04-17 15:03:45 -04:00
|
|
|
goto again;
|
|
|
|
}
|
2012-01-07 17:21:32 -05:00
|
|
|
|
2014-04-17 15:03:45 -04:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
else if (fd < 0)
|
|
|
|
{
|
|
|
|
g_warning ("failed to create lock file %s: %m", filename);
|
|
|
|
goto out;
|
|
|
|
}
|
2012-01-07 17:21:32 -05:00
|
|
|
|
2014-04-17 15:03:45 -04:00
|
|
|
ret = TRUE;
|
2012-01-07 17:21:32 -05:00
|
|
|
|
2014-04-17 15:03:45 -04:00
|
|
|
out:
|
|
|
|
if (!ret)
|
|
|
|
{
|
|
|
|
g_free (filename);
|
|
|
|
filename = NULL;
|
|
|
|
|
|
|
|
if (fd >= 0)
|
2012-01-07 17:21:32 -05:00
|
|
|
{
|
2014-04-17 15:03:45 -04:00
|
|
|
close (fd);
|
|
|
|
fd = -1;
|
2012-01-07 17:21:32 -05:00
|
|
|
}
|
2014-04-17 15:03:45 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
*filename_out = filename;
|
|
|
|
*fd_out = fd;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
2015-04-23 10:41:34 -04:00
|
|
|
create_lock_file (int display, int *display_out)
|
2014-04-17 15:03:45 -04: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 06:00:25 -05:00
|
|
|
char pid[12];
|
2014-04-17 15:03:45 -04:00
|
|
|
int size;
|
2015-03-20 15:09:13 -04:00
|
|
|
int number_of_tries = 0;
|
2014-04-17 15:03:45 -04:00
|
|
|
|
|
|
|
while (!try_display (display, &filename, &fd))
|
|
|
|
{
|
|
|
|
display++;
|
2015-03-20 15:09:13 -04:00
|
|
|
number_of_tries++;
|
2012-01-07 17:21:32 -05:00
|
|
|
|
2015-03-20 15:09:13 -04:00
|
|
|
/* If we can't get a display after 50 times, then something's wrong. Just
|
2014-04-17 15:03:45 -04:00
|
|
|
* abort in this case. */
|
2015-03-20 15:09:13 -04:00
|
|
|
if (number_of_tries >= 50)
|
2014-04-17 15:03:45 -04:00
|
|
|
return NULL;
|
2012-01-07 17:21:32 -05: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 06:00:25 -05: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 ());
|
2012-01-07 17:21:32 -05:00
|
|
|
if (size != 11 || write (fd, pid, 11) != 11)
|
|
|
|
{
|
|
|
|
unlink (filename);
|
|
|
|
close (fd);
|
|
|
|
g_warning ("failed to write pid to lock file %s", filename);
|
|
|
|
g_free (filename);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
close (fd);
|
|
|
|
|
|
|
|
*display_out = display;
|
|
|
|
return filename;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2016-08-06 10:17:33 -04:00
|
|
|
bind_to_abstract_socket (int display,
|
|
|
|
gboolean *fatal)
|
2012-01-07 17:21:32 -05:00
|
|
|
{
|
|
|
|
struct sockaddr_un addr;
|
|
|
|
socklen_t size, name_size;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
fd = socket (PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
|
|
|
if (fd < 0)
|
2016-08-06 10:17:33 -04:00
|
|
|
{
|
|
|
|
*fatal = TRUE;
|
|
|
|
g_warning ("Failed to create socket: %m");
|
|
|
|
return -1;
|
|
|
|
}
|
2012-01-07 17:21:32 -05:00
|
|
|
|
|
|
|
addr.sun_family = AF_LOCAL;
|
|
|
|
name_size = snprintf (addr.sun_path, sizeof addr.sun_path,
|
|
|
|
"%c/tmp/.X11-unix/X%d", 0, display);
|
|
|
|
size = offsetof (struct sockaddr_un, sun_path) + name_size;
|
|
|
|
if (bind (fd, (struct sockaddr *) &addr, size) < 0)
|
|
|
|
{
|
2016-08-06 10:17:33 -04:00
|
|
|
*fatal = errno != EADDRINUSE;
|
2014-04-01 19:57:55 -04:00
|
|
|
g_warning ("failed to bind to @%s: %m", addr.sun_path + 1);
|
2012-01-07 17:21:32 -05:00
|
|
|
close (fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (listen (fd, 1) < 0)
|
|
|
|
{
|
2016-08-06 10:17:33 -04:00
|
|
|
*fatal = errno != EADDRINUSE;
|
|
|
|
g_warning ("Failed to listen on abstract socket @%s: %m",
|
|
|
|
addr.sun_path + 1);
|
2012-01-07 17:21:32 -05:00
|
|
|
close (fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
bind_to_unix_socket (int display)
|
|
|
|
{
|
|
|
|
struct sockaddr_un addr;
|
|
|
|
socklen_t size, name_size;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
fd = socket (PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
|
|
|
if (fd < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
addr.sun_family = AF_LOCAL;
|
|
|
|
name_size = snprintf (addr.sun_path, sizeof addr.sun_path,
|
|
|
|
"/tmp/.X11-unix/X%d", display) + 1;
|
|
|
|
size = offsetof (struct sockaddr_un, sun_path) + name_size;
|
|
|
|
unlink (addr.sun_path);
|
|
|
|
if (bind (fd, (struct sockaddr *) &addr, size) < 0)
|
|
|
|
{
|
2014-04-01 19:57:55 -04:00
|
|
|
g_warning ("failed to bind to %s: %m\n", addr.sun_path);
|
2012-01-07 17:21:32 -05:00
|
|
|
close (fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-01-29 10:23:58 -05:00
|
|
|
if (listen (fd, 1) < 0)
|
|
|
|
{
|
2012-01-07 17:21:32 -05:00
|
|
|
unlink (addr.sun_path);
|
|
|
|
close (fd);
|
|
|
|
return -1;
|
2014-01-29 10:23:58 -05:00
|
|
|
}
|
2012-01-07 17:21:32 -05:00
|
|
|
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2013-08-12 03:46:07 -04:00
|
|
|
static void
|
2015-03-21 21:24:37 -04:00
|
|
|
xserver_died (GObject *source,
|
|
|
|
GAsyncResult *result,
|
|
|
|
gpointer user_data)
|
2013-08-12 03:46:07 -04:00
|
|
|
{
|
2015-03-21 21:24:37 -04:00
|
|
|
GSubprocess *proc = G_SUBPROCESS (source);
|
2018-04-12 14:03:03 -04:00
|
|
|
g_autoptr (GError) error = NULL;
|
2015-03-21 21:24:37 -04:00
|
|
|
|
2017-10-25 03:42:49 -04:00
|
|
|
if (!g_subprocess_wait_finish (proc, result, &error))
|
|
|
|
{
|
2018-04-12 14:06:01 -04: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 03:42:49 -04:00
|
|
|
}
|
|
|
|
else if (!g_subprocess_get_successful (proc))
|
2013-08-12 03:46:07 -04:00
|
|
|
{
|
2019-05-24 15:36:50 -04:00
|
|
|
if (meta_get_x11_display_policy () == META_DISPLAY_POLICY_MANDATORY)
|
|
|
|
g_warning ("X Wayland crashed; exiting");
|
|
|
|
else
|
|
|
|
g_warning ("X Wayland crashed; attempting to recover");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (meta_get_x11_display_policy () == META_DISPLAY_POLICY_MANDATORY)
|
|
|
|
{
|
|
|
|
meta_exit (META_EXIT_ERROR);
|
2013-08-12 03:46:07 -04:00
|
|
|
}
|
2019-05-24 15:36:50 -04:00
|
|
|
else if (meta_get_x11_display_policy () == META_DISPLAY_POLICY_ON_DEMAND)
|
|
|
|
{
|
|
|
|
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
|
|
|
|
MetaDisplay *display = meta_get_display ();
|
2018-04-12 14:06:01 -04:00
|
|
|
|
2019-05-24 15:36:50 -04:00
|
|
|
if (display->x11_display)
|
|
|
|
meta_display_shutdown_x11 (display);
|
|
|
|
|
|
|
|
if (!meta_xwayland_init (&compositor->xwayland_manager,
|
|
|
|
compositor->wayland_display))
|
|
|
|
g_warning ("Failed to init X sockets");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
shutdown_xwayland_cb (gpointer data)
|
|
|
|
{
|
|
|
|
MetaXWaylandManager *manager = data;
|
|
|
|
|
|
|
|
meta_verbose ("Shutting down Xwayland");
|
|
|
|
manager->xserver_grace_period_id = 0;
|
|
|
|
meta_display_shutdown_x11 (meta_get_display ());
|
|
|
|
meta_xwayland_stop_xserver (manager);
|
|
|
|
return G_SOURCE_REMOVE;
|
2013-08-12 03:46:07 -04:00
|
|
|
}
|
|
|
|
|
2013-08-12 09:31:18 -04:00
|
|
|
static int
|
|
|
|
x_io_error (Display *display)
|
|
|
|
{
|
2018-04-12 14:06:01 -04:00
|
|
|
g_warning ("Connection to xwayland lost");
|
2019-05-24 15:36:50 -04:00
|
|
|
|
|
|
|
if (meta_get_x11_display_policy () == META_DISPLAY_POLICY_MANDATORY)
|
|
|
|
meta_exit (META_EXIT_ERROR);
|
2013-08-12 09:31:18 -04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-12 05:29:44 -05:00
|
|
|
void
|
|
|
|
meta_xwayland_override_display_number (int number)
|
|
|
|
{
|
|
|
|
display_number_override = number;
|
|
|
|
}
|
|
|
|
|
2019-05-25 18:37:57 -04:00
|
|
|
static gboolean
|
|
|
|
open_display_sockets (MetaXWaylandManager *manager,
|
|
|
|
int display_index,
|
|
|
|
gboolean *fatal)
|
|
|
|
{
|
|
|
|
int abstract_fd, unix_fd;
|
|
|
|
|
|
|
|
abstract_fd = bind_to_abstract_socket (display_index,
|
|
|
|
fatal);
|
|
|
|
if (abstract_fd < 0)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
unix_fd = bind_to_unix_socket (display_index);
|
|
|
|
if (unix_fd < 0)
|
|
|
|
{
|
|
|
|
*fatal = FALSE;
|
|
|
|
close (abstract_fd);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
manager->abstract_fd = abstract_fd;
|
|
|
|
manager->unix_fd = unix_fd;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2014-04-01 20:00:59 -04:00
|
|
|
static gboolean
|
|
|
|
choose_xdisplay (MetaXWaylandManager *manager)
|
2012-01-07 17:21:32 -05:00
|
|
|
{
|
|
|
|
int display = 0;
|
2015-04-23 10:41:34 -04:00
|
|
|
char *lock_file = NULL;
|
2016-08-06 10:17:33 -04:00
|
|
|
gboolean fatal = FALSE;
|
2012-01-07 17:21:32 -05:00
|
|
|
|
2018-11-12 05:29:44 -05:00
|
|
|
if (display_number_override != -1)
|
|
|
|
display = display_number_override;
|
2018-11-22 11:59:58 -05:00
|
|
|
else if (g_getenv ("RUNNING_UNDER_GDM"))
|
2015-03-16 10:57:44 -04:00
|
|
|
display = 1024;
|
|
|
|
|
2012-01-07 17:21:32 -05:00
|
|
|
do
|
|
|
|
{
|
2015-04-23 10:41:34 -04:00
|
|
|
lock_file = create_lock_file (display, &display);
|
|
|
|
if (!lock_file)
|
2012-01-07 17:21:32 -05:00
|
|
|
{
|
2014-01-29 10:23:58 -05:00
|
|
|
g_warning ("Failed to create an X lock file");
|
|
|
|
return FALSE;
|
2012-01-07 17:21:32 -05:00
|
|
|
}
|
|
|
|
|
2019-05-25 18:37:57 -04:00
|
|
|
if (!open_display_sockets (manager, display, &fatal))
|
2012-01-07 17:21:32 -05:00
|
|
|
{
|
2015-04-23 10:41:34 -04:00
|
|
|
unlink (lock_file);
|
2012-01-07 17:21:32 -05:00
|
|
|
|
2016-08-06 10:17:33 -04:00
|
|
|
if (!fatal)
|
2012-01-07 17:21:32 -05:00
|
|
|
{
|
|
|
|
display++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
2016-08-06 10:17:33 -04:00
|
|
|
{
|
2019-05-25 18:37:57 -04:00
|
|
|
g_warning ("Failed to bind X11 socket");
|
2016-08-06 10:17:33 -04:00
|
|
|
return FALSE;
|
|
|
|
}
|
2012-01-07 17:21:32 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
while (1);
|
|
|
|
|
2014-02-03 19:37:23 -05:00
|
|
|
manager->display_index = display;
|
2014-04-01 19:38:05 -04:00
|
|
|
manager->display_name = g_strdup_printf (":%d", manager->display_index);
|
2015-04-23 10:41:34 -04:00
|
|
|
manager->lock_file = lock_file;
|
2012-01-07 17:21:32 -05:00
|
|
|
|
2014-04-01 20:00:59 -04:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2019-06-18 10:12:46 -04:00
|
|
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FILE, fclose)
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
prepare_auth_file (MetaXWaylandManager *manager)
|
|
|
|
{
|
|
|
|
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))
|
|
|
|
{
|
|
|
|
g_warning ("Failed to get random data: %s", g_strerror (errno));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
auth_entry.family = FamilyLocal;
|
2019-06-23 11:44:05 -04:00
|
|
|
auth_entry.address = (char *) g_get_host_name ();
|
2019-06-18 10:12:46 -04: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)
|
|
|
|
{
|
|
|
|
g_warning ("Failed to open Xauthority file: %s", g_strerror (errno));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
fp = fdopen (fd, "w+");
|
|
|
|
if (!fp)
|
|
|
|
{
|
|
|
|
g_warning ("Failed to open Xauthority stream: %s", g_strerror (errno));
|
|
|
|
close (fd);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!XauWriteAuth (fp, &auth_entry))
|
|
|
|
{
|
|
|
|
g_warning ("Error writing to Xauthority file: %s", g_strerror (errno));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
auth_entry.family = FamilyWild;
|
|
|
|
if (!XauWriteAuth (fp, &auth_entry))
|
|
|
|
{
|
|
|
|
g_warning ("Error writing to Xauthority file: %s", g_strerror (errno));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fflush (fp) == EOF)
|
|
|
|
{
|
|
|
|
g_warning ("Error writing to Xauthority file: %s", g_strerror (errno));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2019-08-19 09:50:54 -04:00
|
|
|
static void
|
|
|
|
add_local_user_to_xhost (Display *xdisplay)
|
|
|
|
{
|
|
|
|
XHostAddress host_entry;
|
|
|
|
XServerInterpretedAddress siaddr;
|
|
|
|
|
|
|
|
siaddr.type = (char *) "localuser";
|
|
|
|
siaddr.typelength = strlen (siaddr.type);
|
|
|
|
siaddr.value = (char *) g_get_user_name();
|
|
|
|
siaddr.valuelength = strlen (siaddr.value);
|
|
|
|
|
|
|
|
host_entry.family = FamilyServerInterpreted;
|
|
|
|
host_entry.address = (char *) &siaddr;
|
|
|
|
|
|
|
|
XAddHost (xdisplay, &host_entry);
|
|
|
|
}
|
|
|
|
|
2014-04-02 10:22:01 -04:00
|
|
|
static void
|
|
|
|
xserver_finished_init (MetaXWaylandManager *manager)
|
|
|
|
{
|
|
|
|
/* At this point xwayland is all setup to start accepting
|
|
|
|
* connections so we can quit the transient initialization mainloop
|
|
|
|
* and unblock meta_wayland_init() to continue initializing mutter.
|
|
|
|
* */
|
|
|
|
g_main_loop_quit (manager->init_loop);
|
|
|
|
g_clear_pointer (&manager->init_loop, g_main_loop_unref);
|
|
|
|
}
|
|
|
|
|
2014-04-02 10:25:56 -04:00
|
|
|
static gboolean
|
2014-04-17 16:05:08 -04:00
|
|
|
on_displayfd_ready (int fd,
|
|
|
|
GIOCondition condition,
|
|
|
|
gpointer user_data)
|
2014-04-02 10:25:56 -04:00
|
|
|
{
|
|
|
|
MetaXWaylandManager *manager = user_data;
|
2019-05-24 15:36:50 -04:00
|
|
|
MetaDisplay *display = meta_get_display ();
|
2014-04-02 10:25:56 -04:00
|
|
|
|
2014-04-17 16:05:08 -04: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. */
|
2014-04-02 10:25:56 -04:00
|
|
|
xserver_finished_init (manager);
|
|
|
|
|
2019-05-24 15:36:50 -04:00
|
|
|
if (meta_get_x11_display_policy () == META_DISPLAY_POLICY_ON_DEMAND)
|
|
|
|
meta_display_init_x11 (display, NULL);
|
|
|
|
|
2014-04-02 10:25:56 -04:00
|
|
|
return G_SOURCE_REMOVE;
|
|
|
|
}
|
|
|
|
|
2018-12-10 08:24:43 -05:00
|
|
|
static gboolean
|
2019-05-24 14:52:17 -04:00
|
|
|
meta_xwayland_start_xserver (MetaXWaylandManager *manager)
|
2014-04-01 20:00:59 -04:00
|
|
|
{
|
2014-04-17 15:37:53 -04:00
|
|
|
int xwayland_client_fd[2];
|
2014-04-17 16:05:08 -04:00
|
|
|
int displayfd[2];
|
2015-03-31 14:47:34 -04:00
|
|
|
g_autoptr(GSubprocessLauncher) launcher = NULL;
|
2015-03-21 21:24:37 -04:00
|
|
|
GSubprocessFlags flags;
|
|
|
|
GError *error = NULL;
|
2014-04-01 20:00:59 -04:00
|
|
|
|
2012-01-07 17:21:32 -05:00
|
|
|
/* We want xwayland to be a wayland client so we make a socketpair to setup a
|
|
|
|
* wayland protocol connection. */
|
2014-04-17 15:37:53 -04:00
|
|
|
if (socketpair (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, xwayland_client_fd) < 0)
|
2012-01-07 17:21:32 -05:00
|
|
|
{
|
2014-04-17 15:37:53 -04:00
|
|
|
g_warning ("xwayland_client_fd socketpair failed\n");
|
2018-12-10 08:24:43 -05:00
|
|
|
return FALSE;
|
2012-01-07 17:21:32 -05:00
|
|
|
}
|
|
|
|
|
2014-04-17 16:05:08 -04:00
|
|
|
if (socketpair (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, displayfd) < 0)
|
|
|
|
{
|
|
|
|
g_warning ("displayfd socketpair failed\n");
|
2018-12-10 08:24:43 -05:00
|
|
|
return FALSE;
|
2014-04-17 16:05:08 -04:00
|
|
|
}
|
|
|
|
|
2015-03-21 21:24:37 -04:00
|
|
|
/* xwayland, please. */
|
|
|
|
flags = G_SUBPROCESS_FLAGS_NONE;
|
2014-04-01 19:51:43 -04:00
|
|
|
|
2015-03-21 21:24:37 -04:00
|
|
|
if (getenv ("XWAYLAND_STFU"))
|
|
|
|
{
|
|
|
|
flags |= G_SUBPROCESS_FLAGS_STDOUT_SILENCE;
|
|
|
|
flags |= G_SUBPROCESS_FLAGS_STDERR_SILENCE;
|
2014-04-01 19:51:43 -04:00
|
|
|
}
|
2015-03-21 21:24:37 -04:00
|
|
|
|
|
|
|
launcher = g_subprocess_launcher_new (flags);
|
|
|
|
|
|
|
|
g_subprocess_launcher_take_fd (launcher, xwayland_client_fd[1], 3);
|
|
|
|
g_subprocess_launcher_take_fd (launcher, manager->abstract_fd, 4);
|
|
|
|
g_subprocess_launcher_take_fd (launcher, manager->unix_fd, 5);
|
|
|
|
g_subprocess_launcher_take_fd (launcher, displayfd[1], 6);
|
|
|
|
|
|
|
|
g_subprocess_launcher_setenv (launcher, "WAYLAND_SOCKET", "3", TRUE);
|
2017-10-25 03:42:49 -04:00
|
|
|
|
|
|
|
manager->proc = g_subprocess_launcher_spawn (launcher, &error,
|
|
|
|
XWAYLAND_PATH, manager->display_name,
|
|
|
|
"-rootless",
|
2019-05-24 05:47:49 -04:00
|
|
|
"-noreset",
|
2017-09-14 03:20:30 -04:00
|
|
|
"-accessx",
|
2017-10-25 03:42:49 -04:00
|
|
|
"-core",
|
2019-06-18 10:12:46 -04:00
|
|
|
"-auth", manager->auth_file,
|
2017-10-25 03:42:49 -04:00
|
|
|
"-listen", "4",
|
|
|
|
"-listen", "5",
|
|
|
|
"-displayfd", "6",
|
|
|
|
NULL);
|
|
|
|
if (!manager->proc)
|
2014-04-02 13:03:17 -04:00
|
|
|
{
|
2015-03-21 21:24:37 -04:00
|
|
|
g_error ("Failed to spawn Xwayland: %s", error->message);
|
2018-12-10 08:24:43 -05:00
|
|
|
return FALSE;
|
2014-04-02 13:03:17 -04:00
|
|
|
}
|
2014-04-01 19:51:43 -04:00
|
|
|
|
2017-10-25 03:42:49 -04:00
|
|
|
manager->xserver_died_cancellable = g_cancellable_new ();
|
|
|
|
g_subprocess_wait_async (manager->proc, manager->xserver_died_cancellable,
|
|
|
|
xserver_died, NULL);
|
2014-04-17 16:05:08 -04:00
|
|
|
g_unix_fd_add (displayfd[0], G_IO_IN, on_displayfd_ready, manager);
|
2018-12-10 08:24:43 -05:00
|
|
|
manager->client = wl_client_create (manager->wayland_display,
|
|
|
|
xwayland_client_fd[0]);
|
2012-01-07 17:21:32 -05:00
|
|
|
|
2013-08-12 04:06:13 -04:00
|
|
|
/* We need to run a mainloop until we know xwayland has a binding
|
|
|
|
* for our xserver interface at which point we can assume it's
|
|
|
|
* ready to start accepting connections. */
|
2014-02-03 19:37:23 -05:00
|
|
|
manager->init_loop = g_main_loop_new (NULL, FALSE);
|
|
|
|
g_main_loop_run (manager->init_loop);
|
2013-08-12 04:06:13 -04:00
|
|
|
|
2018-12-10 08:24:43 -05:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2019-05-24 15:36:50 -04:00
|
|
|
static gboolean
|
|
|
|
xdisplay_connection_activity_cb (gint fd,
|
|
|
|
GIOCondition cond,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
MetaXWaylandManager *manager = user_data;
|
|
|
|
|
|
|
|
if (!meta_xwayland_start_xserver (manager))
|
|
|
|
g_critical ("Could not start Xserver");
|
|
|
|
|
|
|
|
return G_SOURCE_REMOVE;
|
|
|
|
}
|
|
|
|
|
2019-08-13 14:56:32 -04:00
|
|
|
static void
|
|
|
|
meta_xwayland_stop_xserver_timeout (MetaXWaylandManager *manager)
|
|
|
|
{
|
|
|
|
if (manager->xserver_grace_period_id)
|
|
|
|
return;
|
|
|
|
|
|
|
|
manager->xserver_grace_period_id =
|
|
|
|
g_timeout_add_seconds (10, shutdown_xwayland_cb, manager);
|
|
|
|
}
|
|
|
|
|
2019-05-24 15:09:32 -04:00
|
|
|
static void
|
|
|
|
window_unmanaged_cb (MetaWindow *window,
|
|
|
|
MetaXWaylandManager *manager)
|
|
|
|
{
|
|
|
|
manager->x11_windows = g_list_remove (manager->x11_windows, window);
|
|
|
|
g_signal_handlers_disconnect_by_func (window,
|
|
|
|
window_unmanaged_cb,
|
|
|
|
manager);
|
2019-05-24 15:36:50 -04:00
|
|
|
if (!manager->x11_windows)
|
|
|
|
{
|
|
|
|
meta_verbose ("All X11 windows gone, setting shutdown timeout");
|
2019-08-13 14:56:32 -04:00
|
|
|
meta_xwayland_stop_xserver_timeout (manager);
|
2019-05-24 15:36:50 -04:00
|
|
|
}
|
2019-05-24 15:09:32 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
window_created_cb (MetaDisplay *display,
|
|
|
|
MetaWindow *window,
|
|
|
|
MetaXWaylandManager *manager)
|
|
|
|
{
|
|
|
|
/* Ignore all internal windows */
|
|
|
|
if (!window->xwindow ||
|
|
|
|
meta_window_get_client_pid (window) == getpid ())
|
|
|
|
return;
|
|
|
|
|
|
|
|
manager->x11_windows = g_list_prepend (manager->x11_windows, window);
|
|
|
|
g_signal_connect (window, "unmanaged",
|
|
|
|
G_CALLBACK (window_unmanaged_cb), manager);
|
2019-05-24 15:36:50 -04:00
|
|
|
|
|
|
|
if (manager->xserver_grace_period_id)
|
|
|
|
{
|
|
|
|
g_source_remove (manager->xserver_grace_period_id);
|
|
|
|
manager->xserver_grace_period_id = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_xwayland_stop_xserver (MetaXWaylandManager *manager)
|
|
|
|
{
|
|
|
|
if (manager->proc)
|
|
|
|
g_subprocess_send_signal (manager->proc, SIGTERM);
|
|
|
|
g_signal_handlers_disconnect_by_func (meta_get_display (),
|
|
|
|
window_created_cb,
|
|
|
|
manager);
|
|
|
|
g_clear_object (&manager->xserver_died_cancellable);
|
|
|
|
g_clear_object (&manager->proc);
|
2019-05-24 15:09:32 -04:00
|
|
|
}
|
|
|
|
|
2018-12-10 08:24:43 -05:00
|
|
|
gboolean
|
2019-05-24 14:52:17 -04:00
|
|
|
meta_xwayland_init (MetaXWaylandManager *manager,
|
|
|
|
struct wl_display *wl_display)
|
2018-12-10 08:24:43 -05:00
|
|
|
{
|
2019-05-24 15:36:50 -04:00
|
|
|
MetaDisplayPolicy policy;
|
|
|
|
gboolean fatal;
|
|
|
|
|
|
|
|
if (!manager->display_name)
|
|
|
|
{
|
|
|
|
if (!choose_xdisplay (manager))
|
|
|
|
return FALSE;
|
2019-08-13 14:52:34 -04:00
|
|
|
|
|
|
|
if (!prepare_auth_file (manager))
|
|
|
|
return FALSE;
|
2019-05-24 15:36:50 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!open_display_sockets (manager, manager->display_index, &fatal))
|
|
|
|
return FALSE;
|
|
|
|
}
|
2015-04-23 10:26:38 -04:00
|
|
|
|
2018-12-10 08:24:43 -05:00
|
|
|
manager->wayland_display = wl_display;
|
2019-05-24 15:36:50 -04:00
|
|
|
policy = meta_get_x11_display_policy ();
|
|
|
|
|
|
|
|
if (policy == META_DISPLAY_POLICY_MANDATORY)
|
|
|
|
{
|
|
|
|
return meta_xwayland_start_xserver (manager);
|
|
|
|
}
|
|
|
|
else if (policy == META_DISPLAY_POLICY_ON_DEMAND)
|
|
|
|
{
|
|
|
|
g_unix_fd_add (manager->abstract_fd, G_IO_IN,
|
|
|
|
xdisplay_connection_activity_cb, manager);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
2012-01-07 17:21:32 -05:00
|
|
|
}
|
|
|
|
|
2018-06-30 03:04:48 -04:00
|
|
|
static void
|
|
|
|
on_x11_display_closing (MetaDisplay *display)
|
|
|
|
{
|
2019-08-19 09:48:17 -04:00
|
|
|
Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display);
|
|
|
|
|
|
|
|
meta_xwayland_shutdown_dnd (xdisplay);
|
2019-05-24 14:57:16 -04:00
|
|
|
g_signal_handlers_disconnect_by_func (display,
|
|
|
|
on_x11_display_closing,
|
|
|
|
NULL);
|
2018-06-30 03:04:48 -04:00
|
|
|
}
|
|
|
|
|
2013-08-12 09:31:18 -04:00
|
|
|
/* To be called right after connecting */
|
|
|
|
void
|
2019-08-19 09:36:32 -04:00
|
|
|
meta_xwayland_complete_init (MetaDisplay *display,
|
|
|
|
Display *xdisplay)
|
2013-08-12 09:31:18 -04:00
|
|
|
{
|
2019-05-24 15:09:32 -04:00
|
|
|
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
|
|
|
|
MetaXWaylandManager *manager = &compositor->xwayland_manager;
|
|
|
|
|
2013-08-12 09:31:18 -04: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);
|
2014-10-10 12:55:00 -04:00
|
|
|
|
2018-06-30 03:04:48 -04:00
|
|
|
g_signal_connect (display, "x11-display-closing",
|
|
|
|
G_CALLBACK (on_x11_display_closing), NULL);
|
2019-08-19 09:48:17 -04:00
|
|
|
meta_xwayland_init_dnd (xdisplay);
|
2019-08-19 09:50:54 -04:00
|
|
|
add_local_user_to_xhost (xdisplay);
|
2019-05-24 15:09:32 -04:00
|
|
|
|
2019-08-07 12:30:58 -04:00
|
|
|
if (meta_get_x11_display_policy () == META_DISPLAY_POLICY_ON_DEMAND)
|
|
|
|
{
|
2019-08-13 14:56:32 -04:00
|
|
|
meta_xwayland_stop_xserver_timeout (manager);
|
2019-08-07 12:30:58 -04:00
|
|
|
g_signal_connect (meta_get_display (), "window-created",
|
|
|
|
G_CALLBACK (window_created_cb), manager);
|
|
|
|
}
|
2013-08-12 09:31:18 -04:00
|
|
|
}
|
|
|
|
|
2012-01-07 17:21:32 -05:00
|
|
|
void
|
2019-05-24 14:52:17 -04:00
|
|
|
meta_xwayland_shutdown (MetaXWaylandManager *manager)
|
2012-01-07 17:21:32 -05:00
|
|
|
{
|
|
|
|
char path[256];
|
|
|
|
|
2017-10-25 03:42:49 -04:00
|
|
|
g_cancellable_cancel (manager->xserver_died_cancellable);
|
2014-10-10 12:55:00 -04:00
|
|
|
|
2014-02-03 19:37:23 -05:00
|
|
|
snprintf (path, sizeof path, "/tmp/.X11-unix/X%d", manager->display_index);
|
2012-01-07 17:21:32 -05:00
|
|
|
unlink (path);
|
|
|
|
|
2015-04-23 10:34:43 -04:00
|
|
|
g_clear_pointer (&manager->display_name, g_free);
|
2019-06-18 10:12:46 -04:00
|
|
|
if (manager->auth_file)
|
|
|
|
{
|
|
|
|
unlink (manager->auth_file);
|
|
|
|
g_clear_pointer (&manager->auth_file, g_free);
|
|
|
|
}
|
2015-04-23 10:34:43 -04:00
|
|
|
if (manager->lock_file)
|
|
|
|
{
|
|
|
|
unlink (manager->lock_file);
|
|
|
|
g_clear_pointer (&manager->lock_file, g_free);
|
|
|
|
}
|
2012-01-07 17:21:32 -05:00
|
|
|
}
|
2015-07-08 04:14:00 -04:00
|
|
|
|
|
|
|
static void
|
|
|
|
xwayland_surface_assigned (MetaWaylandSurfaceRole *surface_role)
|
|
|
|
{
|
|
|
|
MetaWaylandSurface *surface =
|
|
|
|
meta_wayland_surface_role_get_surface (surface_role);
|
2017-12-20 06:07:40 -05:00
|
|
|
MetaWaylandSurfaceRoleClass *surface_role_class =
|
|
|
|
META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_surface_role_xwayland_parent_class);
|
2015-07-08 04:14:00 -04:00
|
|
|
|
|
|
|
/* See comment in xwayland_surface_commit for why we reply even though the
|
|
|
|
* surface may not be drawn the next frame.
|
|
|
|
*/
|
|
|
|
wl_list_insert_list (&surface->compositor->frame_callbacks,
|
|
|
|
&surface->pending_frame_callback_list);
|
|
|
|
wl_list_init (&surface->pending_frame_callback_list);
|
2017-12-20 06:07:40 -05:00
|
|
|
|
|
|
|
surface_role_class->assigned (surface_role);
|
2015-07-08 04:14:00 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
xwayland_surface_commit (MetaWaylandSurfaceRole *surface_role,
|
|
|
|
MetaWaylandPendingState *pending)
|
|
|
|
{
|
|
|
|
MetaWaylandSurface *surface =
|
|
|
|
meta_wayland_surface_role_get_surface (surface_role);
|
2017-12-20 06:07:40 -05:00
|
|
|
MetaWaylandSurfaceRoleClass *surface_role_class =
|
|
|
|
META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_surface_role_xwayland_parent_class);
|
2015-07-08 04:14:00 -04:00
|
|
|
|
|
|
|
/* For Xwayland windows, throttling frames when the window isn't actually
|
|
|
|
* drawn is less useful, because Xwayland still has to do the drawing sent
|
|
|
|
* from the application - the throttling would only be of sending us damage
|
|
|
|
* messages, so we simplify and send frame callbacks after the next paint of
|
|
|
|
* the screen, whether the window was drawn or not.
|
|
|
|
*
|
|
|
|
* Currently it may take a few frames before we draw the window, for not
|
|
|
|
* completely understood reasons, and in that case, not thottling frame
|
|
|
|
* callbacks to drawing has the happy side effect that we avoid showing the
|
|
|
|
* user the initial black frame from when the window is mapped empty.
|
|
|
|
*/
|
|
|
|
meta_wayland_surface_queue_pending_state_frame_callbacks (surface, pending);
|
2017-12-20 06:07:40 -05:00
|
|
|
|
|
|
|
surface_role_class->commit (surface_role, pending);
|
2015-07-08 04:14:00 -04:00
|
|
|
}
|
|
|
|
|
2016-01-14 04:43:47 -05:00
|
|
|
static MetaWaylandSurface *
|
|
|
|
xwayland_surface_get_toplevel (MetaWaylandSurfaceRole *surface_role)
|
|
|
|
{
|
|
|
|
return meta_wayland_surface_role_get_surface (surface_role);
|
|
|
|
}
|
|
|
|
|
2019-09-06 09:13:24 -04:00
|
|
|
static double
|
|
|
|
xwayland_surface_get_geometry_scale (MetaWaylandActorSurface *actor_surface)
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2019-04-16 17:35:28 -04:00
|
|
|
static void
|
|
|
|
xwayland_surface_sync_actor_state (MetaWaylandActorSurface *actor_surface)
|
|
|
|
{
|
|
|
|
MetaWaylandSurfaceRole *surface_role =
|
|
|
|
META_WAYLAND_SURFACE_ROLE (actor_surface);
|
|
|
|
MetaWaylandSurface *surface =
|
|
|
|
meta_wayland_surface_role_get_surface (surface_role);
|
|
|
|
MetaWaylandActorSurfaceClass *actor_surface_class =
|
|
|
|
META_WAYLAND_ACTOR_SURFACE_CLASS (meta_wayland_surface_role_xwayland_parent_class);
|
|
|
|
|
|
|
|
if (surface->window)
|
|
|
|
actor_surface_class->sync_actor_state (actor_surface);
|
|
|
|
}
|
|
|
|
|
2019-09-04 12:35:08 -04:00
|
|
|
static void
|
|
|
|
xwayland_surface_finalize (GObject *object)
|
|
|
|
{
|
|
|
|
MetaWaylandSurfaceRole *surface_role =
|
|
|
|
META_WAYLAND_SURFACE_ROLE (object);
|
|
|
|
MetaWaylandSurface *surface =
|
|
|
|
meta_wayland_surface_role_get_surface (surface_role);
|
|
|
|
GObjectClass *parent_object_class =
|
|
|
|
G_OBJECT_CLASS (meta_wayland_surface_role_xwayland_parent_class);
|
|
|
|
MetaWindow *window;
|
|
|
|
|
|
|
|
window = surface->window;
|
|
|
|
if (window)
|
|
|
|
{
|
|
|
|
meta_wayland_surface_set_window (surface, NULL);
|
|
|
|
window->surface = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
parent_object_class->finalize (object);
|
|
|
|
}
|
|
|
|
|
2015-07-08 04:14:00 -04:00
|
|
|
static void
|
|
|
|
meta_wayland_surface_role_xwayland_init (MetaWaylandSurfaceRoleXWayland *role)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
meta_wayland_surface_role_xwayland_class_init (MetaWaylandSurfaceRoleXWaylandClass *klass)
|
|
|
|
{
|
2019-09-04 12:35:08 -04:00
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
2015-07-08 04:14:00 -04:00
|
|
|
MetaWaylandSurfaceRoleClass *surface_role_class =
|
|
|
|
META_WAYLAND_SURFACE_ROLE_CLASS (klass);
|
2019-04-16 17:35:28 -04:00
|
|
|
MetaWaylandActorSurfaceClass *actor_surface_class =
|
|
|
|
META_WAYLAND_ACTOR_SURFACE_CLASS (klass);
|
2015-07-08 04:14:00 -04:00
|
|
|
|
2019-09-04 12:35:08 -04:00
|
|
|
object_class->finalize = xwayland_surface_finalize;
|
|
|
|
|
2015-07-08 04:14:00 -04:00
|
|
|
surface_role_class->assigned = xwayland_surface_assigned;
|
|
|
|
surface_role_class->commit = xwayland_surface_commit;
|
2016-01-14 04:43:47 -05:00
|
|
|
surface_role_class->get_toplevel = xwayland_surface_get_toplevel;
|
2016-04-01 08:57:19 -04:00
|
|
|
|
2019-09-06 09:13:24 -04:00
|
|
|
actor_surface_class->get_geometry_scale = xwayland_surface_get_geometry_scale;
|
2019-04-16 17:35:28 -04:00
|
|
|
actor_surface_class->sync_actor_state = xwayland_surface_sync_actor_state;
|
|
|
|
|
2016-04-01 08:57:19 -04:00
|
|
|
xwayland_surface_signals[XWAYLAND_SURFACE_WINDOW_ASSOCIATED] =
|
|
|
|
g_signal_new ("window-associated",
|
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
0, NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
2015-07-08 04:14:00 -04:00
|
|
|
}
|