Compare commits

...

17 Commits

Author SHA1 Message Date
Carlos Garnacho
8aeec308fb xwayland: Allow setting up maintenance processes
This is made a signal, so the upper layers (read: gnome-shell) may
decide what to spawn, whether to add a GSetting, and whatnot. The
only signal argument contains the appropriate display to use for
this kind of setup.
2019-08-01 18:11:14 +02:00
Carlos Garnacho
252fd771b1 wayland: Set up initialization X11 socket
This is used by GDK and the X11 bits, but may also be used for
other initialization services we might need to run along with
Xwayland initialization.
2019-08-01 18:11:14 +02:00
Carlos Garnacho
41bff1e997 wayland: Implement on-demand start of Xwayland
The Xwayland manager now has 4 distinct phases:
- Init and shutdown (Happening together with the compositor itself)
- Start and stop

In these last 2 phases, handle orderly initialization and shutdown
of Xwayland. On initialization We will simply find out what is a
proper display name, and set up the envvar and socket so that clients
think there is a X server.

Whenever we detect data on this socket, we enter the start phase
that will launch Xwayland, and plunge the socket directly to it.
In this phase we now also set up the MetaX11Display.

The stop phase is pretty much the opposite, we will shutdown the
MetaX11Display and all related data, terminate the Xwayland
process, and restore the listening sockets. This phase happens
on a timeout whenever the last known X11 MetaWindow is gone. If no
new X clients come back in this timeout, the X server will be
eventually terminated.

The shutdown phase happens on compositor shutdown and is completely
uninteresting. Some bits there moved into the stop phase as might
happen over and over.

This is all controlled by META_DISPLAY_POLICY_ON_DEMAND and
the "autostart-xwayland" experimental setting.
2019-08-01 18:11:14 +02:00
Carlos Garnacho
323742e736 core: Avoid queueing a stack operation on the frame when the X11 is closing
When rushing to unmanage X11 windows after the X11 connection is closed/ing,
this would succeed at creating a stack operation for no longer known windows.
Simply avoid to queue a stack operation if we know it's meaningless.
2019-08-01 18:11:14 +02:00
Carlos Garnacho
14f41f3130 x11: Add "closing" flag to MetaX11Display
So code not directly in dispose() can know to avoid certain things
when the X11 display is about to close.
2019-08-01 18:11:14 +02:00
Carlos Garnacho
21b4cf8a50 x11: Shuffle x11-stack destruction in MetaX11Display dispose
Unmanaging the windows may trigger stack operations that we later try
to synchronize despite being in dispose() stage. This may trigger
MetaStackTracker warnings when trying to apply those operations.

Switching destruction order (First dispose the X11 stack representation,
then unmanage windows) won't trigger further stack changes on X11 windows
after having signaled MetaDisplay::x11-display-closing.
2019-08-01 18:11:14 +02:00
Carlos Garnacho
a4f47820c3 wayland: Add setting/api to check the policy to set up the X11 display
This replaces meta_should_autostart_x11_display(). The "on-demand" policy
is not honored yet.
2019-08-01 18:11:14 +02:00
Carlos Garnacho
471eca3745 wayland: Refactor code setting up the display socket
So it may be reused when we need to open those again.
2019-08-01 18:11:14 +02:00
Carlos Garnacho
c1f39514ca wayland: Add tracking of X11 windows
This is unused ATM, but will be used to check whether it is safe to
shut Xwayland down.
2019-08-01 18:11:14 +02:00
Carlos Garnacho
038720fecc compositor: Add explicit API call to redirect X11 windows
This is not useful yet, but will be when Xwayland may restart
2019-08-01 18:11:14 +02:00
Carlos Garnacho
d367d97364 wayland: Disconnect signal when the display closes
It would be potentially left dangling if the display were closed, and
reconnected again when restarting the server.
2019-08-01 18:11:14 +02:00
Carlos Garnacho
885f89a217 wayland: Rename xwayland init/shutdown functions
The start/stop verbs will be reused later when we can start and
stop the X server. Rename these functions to init/shutdown, and
init_xserver() to start_xserver().
2019-08-01 18:11:14 +02:00
Carlos Garnacho
21411faeb1 core: Manage only X11 windows when (re)starting
What "restart" means is somewhat different between x11 and wayland
sessions. A X11 compositor may restart itself, thus having to manage
again all the client windows that were running. A wayland compositor
cannot restart itself, but might restart X11, in which case there's
possibly a number of wayland clients, plus some x11 app that is
being started.

For the latter case, the assert will break, so just make it
conditional. Also rename the function so it's more clear that it
only affects X11 windows.
2019-08-01 18:11:14 +02:00
Carlos Garnacho
cf4a9b3f6a x11: Do not queue stack operation for guard window
In the case mutter is a x11 compositor, it doesn't matter much
since the stack tracker will go away soon. In the case this is a
wayland compositor with mandatory Xwayland, it matters even less
since the session would be shutting down in those paths.

But if this a wayland compositor that can start Xwayland on demand,
this is even harmful, as the MetaStackTracker should be cleared of
x11 windows at this moment, and we actually did right before dispose
on ::x11-display-closing.
2019-08-01 18:11:14 +02:00
Carlos Garnacho
1226c599c9 core: Prepare MetaStackTracker for X11 display being closed
If the display is closed prematurely, go through all windows that
look X11-y and remove them for future calculations. This is not
strictly needed as Xwayland should shut down orderly (thus no client
windows be there), but doesn't hurt to prepare in advance for the
cases where it might not be the case.
2019-08-01 18:11:14 +02:00
Carlos Garnacho
c9459fa096 x11: Add meta_x11_get_display_name() function
Instead of poking the DISPLAY envvar at places.
2019-08-01 18:11:14 +02:00
Carlos Garnacho
d31fb640d5 core: Ensure passive key grabs are only set up on X11
We don't strictly need it for wayland compositors, yet there are
paths where we try to trigger those passive grabs there. Just
skip those on the high level code (where "is it x11" decisions
are taken) like we do with passive button grabs.
2019-08-01 18:11:14 +02:00
19 changed files with 409 additions and 109 deletions

View File

@@ -124,6 +124,8 @@
real-time scheduling. The executable
or user must have CAP_SYS_NICE.
Requires a restart.
• “autostart-xwayland” — initializes Xwayland lazily if there are
X11 clients. Requires restart.
</description>
</key>

View File

@@ -34,6 +34,7 @@ typedef enum _MetaExperimentalFeature
META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER = (1 << 0),
META_EXPERIMENTAL_FEATURE_KMS_MODIFIERS = (1 << 1),
META_EXPERIMENTAL_FEATURE_RT_SCHEDULER = (1 << 2),
META_EXPERIMENTAL_FEATURE_AUTOSTART_XWAYLAND = (1 << 3),
} MetaExperimentalFeature;
#define META_TYPE_SETTINGS (meta_settings_get_type ())

View File

@@ -266,6 +266,8 @@ experimental_features_handler (GVariant *features_variant,
features |= META_EXPERIMENTAL_FEATURE_KMS_MODIFIERS;
else if (g_str_equal (feature, "rt-scheduler"))
features |= META_EXPERIMENTAL_FEATURE_RT_SCHEDULER;
else if (g_str_equal (feature, "autostart-xwayland"))
features |= META_EXPERIMENTAL_FEATURE_AUTOSTART_XWAYLAND;
else
g_info ("Unknown experimental feature '%s'\n", feature);
}

View File

@@ -74,4 +74,6 @@ MetaInhibitShortcutsDialog * meta_compositor_create_inhibit_shortcuts_dialog (Me
void meta_compositor_locate_pointer (MetaCompositor *compositor);
void meta_compositor_redirect_x11_windows (MetaCompositor *compositor);
#endif /* META_COMPOSITOR_PRIVATE_H */

View File

@@ -516,6 +516,15 @@ redirect_windows (MetaX11Display *x11_display)
}
}
void
meta_compositor_redirect_x11_windows (MetaCompositor *compositor)
{
MetaDisplay *display = compositor->display;
if (display->x11_display)
redirect_windows (display->x11_display);
}
void
meta_compositor_manage (MetaCompositor *compositor)
{
@@ -595,8 +604,7 @@ meta_compositor_manage (MetaCompositor *compositor)
compositor->have_x11_sync_object = meta_sync_ring_init (xdisplay);
}
if (display->x11_display)
redirect_windows (display->x11_display);
meta_compositor_redirect_x11_windows (compositor);
compositor->plugin_mgr = meta_plugin_manager_new (compositor);
}

View File

@@ -264,7 +264,7 @@ struct _MetaDisplayClass
gboolean meta_display_open (void);
void meta_display_manage_all_windows (MetaDisplay *display);
void meta_display_manage_all_xwindows (MetaDisplay *display);
void meta_display_unmanage_windows (MetaDisplay *display,
guint32 timestamp);

View File

@@ -49,6 +49,7 @@
#include "backends/x11/meta-backend-x11.h"
#include "backends/x11/cm/meta-backend-x11-cm.h"
#include "clutter/x11/clutter-x11.h"
#include "compositor/compositor-private.h"
#include "core/bell.h"
#include "core/boxes-private.h"
#include "core/display-private.h"
@@ -149,6 +150,7 @@ enum
SHOWING_DESKTOP_CHANGED,
RESTACKED,
WORKAREAS_CHANGED,
INIT_XSERVER,
LAST_SIGNAL
};
@@ -479,6 +481,13 @@ meta_display_class_init (MetaDisplayClass *klass)
0, NULL, NULL, NULL,
G_TYPE_NONE, 0);
display_signals[INIT_XSERVER] =
g_signal_new ("init-xserver",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0, NULL, NULL, NULL,
G_TYPE_NONE, 1, G_TYPE_INT);
g_object_class_install_property (object_class,
PROP_FOCUS_WINDOW,
g_param_spec_object ("focus-window",
@@ -643,10 +652,15 @@ meta_display_init_x11 (MetaDisplay *display,
display->x11_display = x11_display;
g_signal_emit (display, display_signals[X11_DISPLAY_OPENED], 0);
meta_x11_display_create_guard_window (x11_display);
if (!display->display_opening)
meta_display_manage_all_windows (display);
if (meta_get_x11_display_policy () == META_DISPLAY_POLICY_ON_DEMAND)
{
meta_x11_display_create_guard_window (x11_display);
if (!display->display_opening)
meta_display_manage_all_xwindows (display);
meta_compositor_redirect_x11_windows (display->compositor);
}
return TRUE;
}
@@ -758,7 +772,7 @@ meta_display_open (void)
display->selection = meta_selection_new (display);
meta_clipboard_manager_init (display);
if (meta_should_autostart_x11_display ())
if (meta_get_x11_display_policy () == META_DISPLAY_POLICY_MANDATORY)
{
if (!meta_display_init_x11 (display, &error))
g_error ("Failed to start Xwayland: %s", error->message);
@@ -797,7 +811,7 @@ meta_display_open (void)
* we start out with no windows.
*/
if (!meta_is_wayland_compositor ())
meta_display_manage_all_windows (display);
meta_display_manage_all_xwindows (display);
if (old_active_xwindow != None)
{
@@ -2448,7 +2462,7 @@ meta_resize_gravity_from_grab_op (MetaGrabOp op)
}
void
meta_display_manage_all_windows (MetaDisplay *display)
meta_display_manage_all_xwindows (MetaDisplay *display)
{
guint64 *_children;
guint64 *children;
@@ -2462,7 +2476,8 @@ meta_display_manage_all_windows (MetaDisplay *display)
for (i = 0; i < n_children; ++i)
{
g_assert (META_STACK_ID_IS_X11 (children[i]));
if (!META_STACK_ID_IS_X11 (children[i]))
continue;
meta_window_x11_new (display, children[i], TRUE,
META_COMP_EFFECT_NONE);
}

View File

@@ -190,9 +190,14 @@ meta_window_destroy_frame (MetaWindow *window)
"Incrementing unmaps_pending on %s for reparent back to root\n", window->desc);
window->unmaps_pending += 1;
}
meta_stack_tracker_record_add (window->display->stack_tracker,
window->xwindow,
XNextRequest (x11_display->xdisplay));
if (!x11_display->closing)
{
meta_stack_tracker_record_add (window->display->stack_tracker,
window->xwindow,
XNextRequest (x11_display->xdisplay));
}
XReparentWindow (x11_display->xdisplay,
window->xwindow,
x11_display->xroot,

View File

@@ -1570,6 +1570,8 @@ meta_window_grab_keys (MetaWindow *window)
MetaDisplay *display = window->display;
MetaKeyBindingManager *keys = &display->key_binding_manager;
if (!meta_is_wayland_compositor ())
return;
if (window->all_keys_grabbed)
return;
@@ -1604,7 +1606,7 @@ meta_window_grab_keys (MetaWindow *window)
void
meta_window_ungrab_keys (MetaWindow *window)
{
if (window->keys_grabbed)
if (!meta_is_wayland_compositor () && window->keys_grabbed)
{
MetaDisplay *display = window->display;
MetaKeyBindingManager *keys = &display->key_binding_manager;
@@ -1663,7 +1665,11 @@ meta_display_grab_accelerator (MetaDisplay *display,
return META_KEYBINDING_ACTION_NONE;
}
meta_change_keygrab (keys, display->x11_display->xroot, TRUE, &resolved_combo);
if (!meta_is_wayland_compositor ())
{
meta_change_keygrab (keys, display->x11_display->xroot,
TRUE, &resolved_combo);
}
grab = g_new0 (MetaKeyGrab, 1);
grab->action = next_dynamic_keybinding_action ();
@@ -1709,8 +1715,11 @@ meta_display_ungrab_accelerator (MetaDisplay *display,
{
int i;
meta_change_keygrab (keys, display->x11_display->xroot,
FALSE, &binding->resolved_combo);
if (!meta_is_wayland_compositor ())
{
meta_change_keygrab (keys, display->x11_display->xroot,
FALSE, &binding->resolved_combo);
}
for (i = 0; i < binding->resolved_combo.len; i++)
{
@@ -1788,7 +1797,7 @@ meta_window_grab_all_keys (MetaWindow *window,
guint32 timestamp)
{
Window grabwindow;
gboolean retval;
gboolean retval = TRUE;
if (window->all_keys_grabbed)
return FALSE;
@@ -1804,25 +1813,29 @@ meta_window_grab_all_keys (MetaWindow *window,
window->desc);
meta_window_focus (window, timestamp);
grabwindow = meta_window_x11_get_toplevel_xwindow (window);
meta_topic (META_DEBUG_KEYBINDINGS,
"Grabbing all keys on window %s\n", window->desc);
retval = grab_keyboard (grabwindow, timestamp, XIGrabModeAsync);
if (retval)
if (!meta_is_wayland_compositor ())
{
window->keys_grabbed = FALSE;
window->all_keys_grabbed = TRUE;
window->grab_on_frame = window->frame != NULL;
grabwindow = meta_window_x11_get_toplevel_xwindow (window);
meta_topic (META_DEBUG_KEYBINDINGS,
"Grabbing all keys on window %s\n", window->desc);
retval = grab_keyboard (grabwindow, timestamp, XIGrabModeAsync);
if (retval)
{
window->keys_grabbed = FALSE;
window->all_keys_grabbed = TRUE;
window->grab_on_frame = window->frame != NULL;
}
}
return retval;
}
void
meta_window_ungrab_all_keys (MetaWindow *window, guint32 timestamp)
meta_window_ungrab_all_keys (MetaWindow *window,
guint32 timestamp)
{
if (window->all_keys_grabbed)
if (!meta_is_wayland_compositor () && window->all_keys_grabbed)
{
ungrab_keyboard (timestamp);

View File

@@ -30,10 +30,17 @@ typedef enum _MetaCompositorType
META_COMPOSITOR_TYPE_X11,
} MetaCompositorType;
typedef enum _MetaDisplayPolicy
{
META_DISPLAY_POLICY_MANDATORY,
META_DISPLAY_POLICY_ON_DEMAND,
META_DISPLAY_POLICY_DISABLED,
} MetaDisplayPolicy;
META_EXPORT_TEST
void meta_override_compositor_configuration (MetaCompositorType compositor_type,
GType backend_gtype);
gboolean meta_should_autostart_x11_display (void);
MetaDisplayPolicy meta_get_x11_display_policy (void);
#endif /* META_MAIN_PRIVATE_H */

View File

@@ -717,15 +717,27 @@ prefs_changed_callback (MetaPreference pref,
}
}
gboolean
meta_should_autostart_x11_display (void)
MetaDisplayPolicy
meta_get_x11_display_policy (void)
{
MetaBackend *backend = meta_get_backend ();
gboolean wants_x11 = TRUE;
if (META_IS_BACKEND_X11_CM (backend))
return META_DISPLAY_POLICY_MANDATORY;
#ifdef HAVE_WAYLAND
wants_x11 = !opt_no_x11;
if (meta_is_wayland_compositor ())
{
MetaSettings *settings = meta_backend_get_settings (backend);
if (opt_no_x11)
return META_DISPLAY_POLICY_DISABLED;
if (meta_settings_is_experimental_feature_enabled (settings,
META_EXPERIMENTAL_FEATURE_AUTOSTART_XWAYLAND))
return META_DISPLAY_POLICY_ON_DEMAND;
}
#endif
return META_IS_BACKEND_X11_CM (backend) || wants_x11;
return META_DISPLAY_POLICY_MANDATORY;
}

View File

@@ -114,7 +114,7 @@ meta_launch_context_constructed (GObject *object)
G_OBJECT_CLASS (meta_launch_context_parent_class)->constructed (object);
x11_display = getenv ("DISPLAY");
x11_display = meta_x11_get_display_name ();
wayland_display = getenv ("WAYLAND_DISPLAY");
if (x11_display)

View File

@@ -508,6 +508,42 @@ query_xserver_stack (MetaDisplay *display,
XFree (children);
}
static void
drop_x11_windows (MetaDisplay *display,
MetaStackTracker *tracker)
{
GArray *new_stack;
GList *l;
int i;
tracker->xserver_serial = 0;
new_stack = g_array_new (FALSE, FALSE, sizeof (guint64));
for (i = 0; i < tracker->verified_stack->len; i++)
{
guint64 window = g_array_index (tracker->verified_stack, guint64, i);
if (!META_STACK_ID_IS_X11 (window))
g_array_append_val (new_stack, window);
}
g_array_unref (tracker->verified_stack);
tracker->verified_stack = new_stack;
l = tracker->unverified_predictions->head;
while (l)
{
MetaStackOp *op = l->data;
GList *next = l->next;
if (META_STACK_ID_IS_X11 (op->any.window))
g_queue_remove (tracker->unverified_predictions, op);
l = next;
}
}
MetaStackTracker *
meta_stack_tracker_new (MetaDisplay *display)
{
@@ -523,6 +559,10 @@ meta_stack_tracker_new (MetaDisplay *display)
"x11-display-opened",
G_CALLBACK (query_xserver_stack),
tracker);
g_signal_connect (display,
"x11-display-closing",
G_CALLBACK (drop_x11_windows),
tracker);
meta_stack_tracker_dump (tracker);
@@ -546,6 +586,9 @@ meta_stack_tracker_free (MetaStackTracker *tracker)
g_signal_handlers_disconnect_by_func (tracker->display,
(gpointer)query_xserver_stack,
tracker);
g_signal_handlers_disconnect_by_func (tracker->display,
drop_x11_windows,
tracker);
g_free (tracker);
}

View File

@@ -48,16 +48,26 @@ typedef struct
char *lock_file;
int abstract_fd;
int unix_fd;
char *name;
} MetaXWaylandConnection;
typedef struct
{
MetaXWaylandConnection private_connection;
MetaXWaylandConnection public_connection;
guint xserver_grace_period_id;
struct wl_display *wayland_display;
struct wl_client *client;
struct wl_resource *xserver_resource;
char *display_name;
char *auth_file;
GCancellable *xserver_died_cancellable;
GSubprocess *proc;
GMainLoop *init_loop;
GList *x11_windows;
MetaXWaylandDnd *dnd;
} MetaXWaylandManager;

View File

@@ -418,9 +418,9 @@ meta_wayland_init (void)
meta_wayland_eglstream_controller_init (compositor);
#endif
if (meta_should_autostart_x11_display ())
if (meta_get_x11_display_policy () != META_DISPLAY_POLICY_DISABLED)
{
if (!meta_xwayland_start (&compositor->xwayland_manager, compositor->wayland_display))
if (!meta_xwayland_init (&compositor->xwayland_manager, compositor->wayland_display))
g_error ("Failed to start X Wayland");
}
@@ -443,9 +443,9 @@ meta_wayland_init (void)
compositor->display_name = g_strdup (display_name);
}
if (meta_should_autostart_x11_display ())
if (meta_get_x11_display_policy () != META_DISPLAY_POLICY_DISABLED)
{
set_gnome_env ("DISPLAY", meta_wayland_get_xwayland_display_name (compositor));
set_gnome_env ("DISPLAY", compositor->xwayland_manager.public_connection.name);
set_gnome_env ("XAUTHORITY", meta_wayland_get_xwayland_auth_file (compositor));
}
@@ -461,7 +461,7 @@ meta_wayland_get_wayland_display_name (MetaWaylandCompositor *compositor)
const char *
meta_wayland_get_xwayland_display_name (MetaWaylandCompositor *compositor)
{
return compositor->xwayland_manager.display_name;
return compositor->xwayland_manager.private_connection.name;
}
void
@@ -471,7 +471,7 @@ meta_wayland_finalize (void)
compositor = meta_wayland_compositor_get_default ();
meta_xwayland_stop (&compositor->xwayland_manager);
meta_xwayland_shutdown (&compositor->xwayland_manager);
g_clear_pointer (&compositor->display_name, g_free);
}

View File

@@ -25,14 +25,14 @@
#include "wayland/meta-wayland-private.h"
gboolean
meta_xwayland_start (MetaXWaylandManager *manager,
struct wl_display *display);
meta_xwayland_init (MetaXWaylandManager *manager,
struct wl_display *display);
void
meta_xwayland_complete_init (MetaDisplay *display);
void
meta_xwayland_stop (MetaXWaylandManager *manager);
meta_xwayland_shutdown (MetaXWaylandManager *manager);
/* wl_data_device/X11 selection interoperation */
void meta_xwayland_init_dnd (void);

View File

@@ -41,6 +41,7 @@
#include "compositor/meta-surface-actor-wayland.h"
#include "compositor/meta-window-actor-private.h"
#include "core/main-private.h"
#include "meta/main.h"
#include "wayland/meta-wayland-actor-surface.h"
@@ -70,6 +71,8 @@ G_DEFINE_TYPE (MetaWaylandSurfaceRoleXWayland,
static int display_number_override = -1;
static void meta_xwayland_stop_xserver (MetaXWaylandManager *manager);
void
meta_xwayland_associate_window_with_surface (MetaWindow *window,
MetaWaylandSurface *surface)
@@ -368,24 +371,45 @@ xserver_died (GObject *source,
g_warning ("Failed to finish waiting for Xwayland: %s", error->message);
}
else if (!g_subprocess_get_successful (proc))
g_warning ("X Wayland crashed; exiting");
else
{
/* For now we simply abort if we see the server exit.
*
* In the future X will only be loaded lazily for legacy X support
* but for now it's a hard requirement. */
g_warning ("Spurious exit of X Wayland server");
}
g_warning ("X Wayland process exited");
meta_exit (META_EXIT_ERROR);
if (meta_get_x11_display_policy () == META_DISPLAY_POLICY_MANDATORY)
{
meta_exit (META_EXIT_ERROR);
}
else if (meta_get_x11_display_policy () == META_DISPLAY_POLICY_ON_DEMAND)
{
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
MetaDisplay *display = meta_get_display ();
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;
g_debug ("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;
}
static int
x_io_error (Display *display)
{
g_warning ("Connection to xwayland lost");
meta_exit (META_EXIT_ERROR);
if (meta_get_x11_display_policy () == META_DISPLAY_POLICY_MANDATORY)
meta_exit (META_EXIT_ERROR);
return 0;
}
@@ -397,7 +421,36 @@ meta_xwayland_override_display_number (int number)
}
static gboolean
choose_xdisplay (MetaXWaylandManager *manager)
open_display_sockets (MetaXWaylandManager *manager,
int display_index,
int *abstract_fd_out,
int *unix_fd_out,
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;
}
*abstract_fd_out = abstract_fd;
*unix_fd_out = unix_fd;
return TRUE;
}
static gboolean
choose_xdisplay (MetaXWaylandManager *manager,
MetaXWaylandConnection *connection)
{
int display = 0;
char *lock_file = NULL;
@@ -417,8 +470,10 @@ choose_xdisplay (MetaXWaylandManager *manager)
return FALSE;
}
manager->abstract_fd = bind_to_abstract_socket (display, &fatal);
if (manager->abstract_fd < 0)
if (!open_display_sockets (manager, display,
&connection->abstract_fd,
&connection->unix_fd,
&fatal))
{
unlink (lock_file);
@@ -429,27 +484,18 @@ choose_xdisplay (MetaXWaylandManager *manager)
}
else
{
g_warning ("Failed to bind abstract socket");
g_warning ("Failed to bind X11 socket");
return FALSE;
}
}
manager->unix_fd = bind_to_unix_socket (display);
if (manager->unix_fd < 0)
{
unlink (lock_file);
close (manager->abstract_fd);
display++;
continue;
}
break;
}
while (1);
manager->display_index = display;
manager->display_name = g_strdup_printf (":%d", manager->display_index);
manager->lock_file = lock_file;
connection->display_index = display;
connection->name = g_strdup_printf (":%d", connection->display_index);
connection->lock_file = lock_file;
return TRUE;
}
@@ -536,6 +582,7 @@ on_displayfd_ready (int fd,
gpointer user_data)
{
MetaXWaylandManager *manager = user_data;
MetaDisplay *display = meta_get_display ();
/* The server writes its display name to the displayfd
* socket when it's ready. We don't care about the data
@@ -543,11 +590,17 @@ on_displayfd_ready (int fd,
* that means it's ready. */
xserver_finished_init (manager);
g_signal_emit_by_name (display, "init-xserver",
manager->private_connection.display_index);
if (meta_get_x11_display_policy () == META_DISPLAY_POLICY_ON_DEMAND)
meta_display_init_x11 (display, NULL);
return G_SOURCE_REMOVE;
}
static gboolean
meta_xwayland_init_xserver (MetaXWaylandManager *manager)
meta_xwayland_start_xserver (MetaXWaylandManager *manager)
{
int xwayland_client_fd[2];
int displayfd[2];
@@ -581,14 +634,15 @@ meta_xwayland_init_xserver (MetaXWaylandManager *manager)
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, manager->public_connection.abstract_fd, 4);
g_subprocess_launcher_take_fd (launcher, manager->public_connection.unix_fd, 5);
g_subprocess_launcher_take_fd (launcher, displayfd[1], 6);
g_subprocess_launcher_take_fd (launcher, manager->private_connection.abstract_fd, 7);
g_subprocess_launcher_setenv (launcher, "WAYLAND_SOCKET", "3", TRUE);
manager->proc = g_subprocess_launcher_spawn (launcher, &error,
XWAYLAND_PATH, manager->display_name,
XWAYLAND_PATH, manager->public_connection.name,
"-rootless",
"-noreset",
"-accessx",
@@ -597,6 +651,7 @@ meta_xwayland_init_xserver (MetaXWaylandManager *manager)
"-listen", "4",
"-listen", "5",
"-displayfd", "6",
"-initfd", "7",
NULL);
if (!manager->proc)
{
@@ -620,30 +675,133 @@ meta_xwayland_init_xserver (MetaXWaylandManager *manager)
return TRUE;
}
gboolean
meta_xwayland_start (MetaXWaylandManager *manager,
struct wl_display *wl_display)
static gboolean
xdisplay_connection_activity_cb (gint fd,
GIOCondition cond,
gpointer user_data)
{
if (!choose_xdisplay (manager))
return FALSE;
MetaXWaylandManager *manager = user_data;
if (!meta_xwayland_start_xserver (manager))
g_critical ("Could not start Xserver");
return G_SOURCE_REMOVE;
}
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);
if (!manager->x11_windows)
{
g_debug ("All X11 windows gone, setting shutdown timeout");
manager->xserver_grace_period_id =
g_timeout_add_seconds (10, shutdown_xwayland_cb, manager);
}
}
static void
window_created_cb (MetaDisplay *display,
MetaWindow *window,
MetaXWaylandManager *manager)
{
if (window->xwindow &&
meta_window_get_client_pid (window) != getpid ())
{
manager->x11_windows = g_list_prepend (manager->x11_windows, window);
g_signal_connect (window, "unmanaged",
G_CALLBACK (window_unmanaged_cb), manager);
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);
}
gboolean
meta_xwayland_init (MetaXWaylandManager *manager,
struct wl_display *wl_display)
{
MetaDisplayPolicy policy;
gboolean fatal;
if (!manager->public_connection.name)
{
if (!choose_xdisplay (manager, &manager->public_connection))
return FALSE;
if (!choose_xdisplay (manager, &manager->private_connection))
return FALSE;
}
else
{
if (!open_display_sockets (manager,
manager->public_connection.display_index,
&manager->public_connection.abstract_fd,
&manager->public_connection.unix_fd,
&fatal))
return FALSE;
if (!open_display_sockets (manager,
manager->private_connection.display_index,
&manager->private_connection.abstract_fd,
&manager->private_connection.unix_fd,
&fatal))
return FALSE;
}
if (!prepare_auth_file (manager))
return FALSE;
manager->wayland_display = wl_display;
return meta_xwayland_init_xserver (manager);
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->public_connection.abstract_fd, G_IO_IN,
xdisplay_connection_activity_cb, manager);
return TRUE;
}
return FALSE;
}
static void
on_x11_display_closing (MetaDisplay *display)
{
meta_xwayland_shutdown_dnd ();
g_signal_handlers_disconnect_by_func (display,
on_x11_display_closing,
NULL);
}
/* To be called right after connecting */
void
meta_xwayland_complete_init (MetaDisplay *display)
{
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
MetaXWaylandManager *manager = &compositor->xwayland_manager;
/* 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
@@ -654,31 +812,41 @@ meta_xwayland_complete_init (MetaDisplay *display)
g_signal_connect (display, "x11-display-closing",
G_CALLBACK (on_x11_display_closing), NULL);
meta_xwayland_init_dnd ();
g_signal_connect (meta_get_display (), "window-created",
G_CALLBACK (window_created_cb), manager);
}
void
meta_xwayland_stop (MetaXWaylandManager *manager)
meta_xwayland_shutdown (MetaXWaylandManager *manager)
{
char path[256];
g_cancellable_cancel (manager->xserver_died_cancellable);
g_clear_object (&manager->proc);
g_clear_object (&manager->xserver_died_cancellable);
snprintf (path, sizeof path, "/tmp/.X11-unix/X%d", manager->display_index);
snprintf (path, sizeof path, "/tmp/.X11-unix/X%d", manager->public_connection.display_index);
unlink (path);
g_clear_pointer (&manager->display_name, g_free);
snprintf (path, sizeof path, "/tmp/.X11-unix/X%d", manager->private_connection.display_index);
unlink (path);
g_clear_pointer (&manager->public_connection.name, g_free);
g_clear_pointer (&manager->private_connection.name, g_free);
if (manager->public_connection.lock_file)
{
unlink (manager->public_connection.lock_file);
g_clear_pointer (&manager->public_connection.lock_file, g_free);
}
if (manager->private_connection.lock_file)
{
unlink (manager->private_connection.lock_file);
g_clear_pointer (&manager->private_connection.lock_file, g_free);
}
if (manager->auth_file)
{
unlink (manager->auth_file);
g_clear_pointer (&manager->auth_file, g_free);
}
if (manager->lock_file)
{
unlink (manager->lock_file);
g_clear_pointer (&manager->lock_file, g_free);
}
}
static void

View File

@@ -144,6 +144,8 @@ struct _MetaX11Display
guint keys_grabbed : 1;
guint closing : 1;
/* we use property updates as sentinels for certain window focus events
* to avoid some race conditions on EnterNotify events
*/
@@ -249,4 +251,6 @@ void meta_x11_display_set_input_focus (MetaX11Display *x11_display,
Window xwindow,
guint32 timestamp);
const gchar * meta_x11_get_display_name (void);
#endif /* META_X11_DISPLAY_PRIVATE_H */

View File

@@ -129,17 +129,19 @@ meta_x11_display_dispose (GObject *object)
{
MetaX11Display *x11_display = META_X11_DISPLAY (object);
x11_display->closing = TRUE;
meta_x11_startup_notification_release (x11_display);
meta_prefs_remove_listener (prefs_changed_callback, x11_display);
meta_x11_display_ungrab_keys (x11_display);
g_clear_object (&x11_display->x11_stack);
meta_x11_selection_shutdown (x11_display);
meta_x11_display_unmanage_windows (x11_display);
g_clear_object (&x11_display->x11_stack);
if (x11_display->ui)
{
meta_ui_free (x11_display->ui);
@@ -182,21 +184,8 @@ meta_x11_display_dispose (GObject *object)
if (x11_display->guard_window != None)
{
MetaStackTracker *stack_tracker = x11_display->display->stack_tracker;
if (stack_tracker)
{
unsigned long serial;
serial = XNextRequest (x11_display->xdisplay);
meta_stack_tracker_record_remove (stack_tracker,
x11_display->guard_window,
serial);
}
XUnmapWindow (x11_display->xdisplay, x11_display->guard_window);
XDestroyWindow (x11_display->xdisplay, x11_display->guard_window);
x11_display->guard_window = None;
}
@@ -988,6 +977,25 @@ meta_set_gnome_wm_keybindings (const char *wm_keybindings)
gnome_wm_keybindings = wm_keybindings;
}
const gchar *
meta_x11_get_display_name (void)
{
#ifdef HAVE_WAYLAND
if (meta_is_wayland_compositor ())
{
MetaWaylandCompositor *compositor;
compositor = meta_wayland_compositor_get_default ();
return meta_wayland_get_xwayland_display_name (compositor);
}
else
#endif
{
return g_getenv ("DISPLAY");
}
}
gboolean
meta_x11_init_gdk_display (GError **error)
{
@@ -996,7 +1004,7 @@ meta_x11_init_gdk_display (GError **error)
const char *gdk_gl_env = NULL;
Display *xdisplay;
xdisplay_name = g_getenv ("DISPLAY");
xdisplay_name = meta_x11_get_display_name ();
if (!xdisplay_name)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,