Skip to content

Commit

Permalink
Add a generic wayland system compositor support
Browse files Browse the repository at this point in the history
This adds a generic wayland system compositor impl based on the old
unity-system-compositor. This allows lightdm to handle a generic nested
wayland compositor setup.

This does not implement xwayland to allow to run x sessions on top of a
wayland system compositor.
  • Loading branch information
mariogrip committed Jul 13, 2020
1 parent fe818e6 commit 63d6b2e
Show file tree
Hide file tree
Showing 9 changed files with 941 additions and 1 deletion.
2 changes: 2 additions & 0 deletions common/configuration.c
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,8 @@ config_init (Configuration *config)
g_hash_table_insert (config->priv->seat_keys, "xdmcp-key", GINT_TO_POINTER (KEY_SUPPORTED));
g_hash_table_insert (config->priv->seat_keys, "unity-compositor-command", GINT_TO_POINTER (KEY_DEPRECATED));
g_hash_table_insert (config->priv->seat_keys, "unity-compositor-timeout", GINT_TO_POINTER (KEY_DEPRECATED));
g_hash_table_insert (config->priv->seat_keys, "wayland-compositor-command", GINT_TO_POINTER (KEY_SUPPORTED));
g_hash_table_insert (config->priv->seat_keys, "wayland-compositor-timeout", GINT_TO_POINTER (KEY_SUPPORTED));
g_hash_table_insert (config->priv->seat_keys, "greeter-session", GINT_TO_POINTER (KEY_SUPPORTED));
g_hash_table_insert (config->priv->seat_keys, "greeter-hide-users", GINT_TO_POINTER (KEY_SUPPORTED));
g_hash_table_insert (config->priv->seat_keys, "greeter-allow-guest", GINT_TO_POINTER (KEY_SUPPORTED));
Expand Down
6 changes: 5 additions & 1 deletion data/lightdm.conf
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
# [Seat:seat0] matches the seat named "seat0".
# [Seat:seat-thin-client*] matches all seats that have names that start with "seat-thin-client".
#
# type = Seat type (local, xremote)
# type = Seat type (local, xremote, wayland-system-compositor)
# pam-service = PAM service to use for login
# pam-autologin-service = PAM service to use for autologin
# pam-greeter-service = PAM service to use for greeters
Expand All @@ -59,6 +59,8 @@
# xdmcp-manager = XDMCP manager to connect to (implies xserver-allow-tcp=true)
# xdmcp-port = XDMCP UDP/IP port to communicate on
# xdmcp-key = Authentication key to use for XDM-AUTHENTICATION-1 (stored in keys.conf)
# wayland-compositor-command = Wayland compositor command to run (can also contain arguments e.g. wayland-system-compositor -special-option)
# wayland-compositor-timeout = Number of seconds to wait for compositor to start
# greeter-session = Session to load for greeter
# greeter-hide-users = True to hide the user list
# greeter-allow-guest = True if the greeter should show a guest login option
Expand Down Expand Up @@ -99,6 +101,8 @@
#xdmcp-manager=
#xdmcp-port=177
#xdmcp-key=
#wayland-compositor-command=wayland-system-compositor
#wayland-compositor-timeout=60
#greeter-session=example-gtk-gnome
#greeter-hide-users=false
#greeter-allow-guest=true
Expand Down
4 changes: 4 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ lightdm_SOURCES = \
seat.h \
seat-local.c \
seat-local.h \
seat-wayland-system-compositor.c \
seat-wayland-system-compositor.h \
seat-xdmcp-session.c \
seat-xdmcp-session.h \
seat-xremote.c \
Expand All @@ -49,6 +51,8 @@ lightdm_SOURCES = \
session-config.h \
shared-data-manager.c \
shared-data-manager.h \
wayland-system-compositor.c \
wayland-system-compositor.h \
vnc-server.c \
vnc-server.h \
vt.c \
Expand Down
2 changes: 2 additions & 0 deletions src/display-manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "configuration.h"
#include "seat-local.h"
#include "seat-xremote.h"
#include "seat-wayland-system-compositor.h"
#include "plymouth.h"

enum {
Expand Down Expand Up @@ -166,6 +167,7 @@ display_manager_init (DisplayManager *manager)
/* Load the seat modules */
seat_register_module ("local", SEAT_LOCAL_TYPE);
seat_register_module ("xremote", SEAT_XREMOTE_TYPE);
seat_register_module ("wayland-system-compositor", SEAT_WAYLAND_SYSTEM_COMPOSITOR_TYPE);
}

static void
Expand Down
2 changes: 2 additions & 0 deletions src/lightdm.c
Original file line number Diff line number Diff line change
Expand Up @@ -772,6 +772,8 @@ main (int argc, char **argv)
config_set_string (config_get_instance (), "Seat:*", "xmir-command", "Xmir");
if (!config_has_key (config_get_instance (), "Seat:*", "xserver-share"))
config_set_boolean (config_get_instance (), "Seat:*", "xserver-share", TRUE);
if (!config_has_key (config_get_instance (), "Seat:*", "wayland-compositor-command"))
config_set_string (config_get_instance (), "Seat:*", "wayland-compositor-command", "wayland-system-compositor");
if (!config_has_key (config_get_instance (), "Seat:*", "start-session"))
config_set_boolean (config_get_instance (), "Seat:*", "start-session", TRUE);
if (!config_has_key (config_get_instance (), "Seat:*", "allow-user-switching"))
Expand Down
293 changes: 293 additions & 0 deletions src/seat-wayland-system-compositor.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,293 @@
/*
* Copyright (C) 2012-2013 Robert Ancell.
* Copyright (C) 2020 UBports Foundation.
* Author(s): Robert Ancell <[email protected]>
* Marius Gripsgard <[email protected]>
*
* 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 3 of the License, or (at your option) any later
* version. See http://www.gnu.org/copyleft/gpl.html the full text of the
* license.
*/

#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <glib/gstdio.h>

#include "seat-wayland-system-compositor.h"
#include "configuration.h"
#include "wayland-system-compositor.h"
#include "vt.h"
#include "plymouth.h"

typedef struct
{
/* System compositor */
WaylandSystemCompositor *compositor;

/* The currently visible session */
Session *active_session;
DisplayServer *active_display_server;
} SeatWaylandSystemCompositorPrivate;

G_DEFINE_TYPE_WITH_PRIVATE (SeatWaylandSystemCompositor, seat_wayland_system_compositor, SEAT_TYPE)

static void
seat_wayland_system_compositor_setup (Seat *seat)
{
seat_set_supports_multi_session (seat, TRUE);
SEAT_CLASS (seat_wayland_system_compositor_parent_class)->setup (seat);
}

static void
check_stopped (SeatWaylandSystemCompositor *seat)
{
SeatWaylandSystemCompositorPrivate *priv = seat_wayland_system_compositor_get_instance_private (seat);
if (!priv->compositor)
SEAT_CLASS (seat_wayland_system_compositor_parent_class)->stop (SEAT (seat));
}

static void
compositor_ready_cb (WaylandSystemCompositor *compositor, SeatWaylandSystemCompositor *seat)
{
l_debug (seat, "Compositor ready");

SEAT_CLASS (seat_wayland_system_compositor_parent_class)->start (SEAT (seat));
}

static void
compositor_stopped_cb (WaylandSystemCompositor *compositor, SeatWaylandSystemCompositor *seat)
{
SeatWaylandSystemCompositorPrivate *priv = seat_wayland_system_compositor_get_instance_private (seat);

l_debug (seat, "Compositor stopped");

g_clear_object (&priv->compositor);

if (seat_get_is_stopping (SEAT (seat)))
check_stopped (seat);
else
seat_stop (SEAT (seat));
}

static gboolean
seat_wayland_system_compositor_start (Seat *seat)
{
SeatWaylandSystemCompositorPrivate *priv = seat_wayland_system_compositor_get_instance_private (SEAT_WAYLAND_SYSTEM_COMPOSITOR (seat));

/* Replace Plymouth if it is running */
gint vt = -1;
if (plymouth_get_is_active () && plymouth_has_active_vt ())
{
gint active_vt = vt_get_active ();
if (active_vt >= vt_get_min ())
{
vt = active_vt;
plymouth_quit (TRUE);
}
else
l_debug (seat, "Plymouth is running on VT %d, but this is less than the configured minimum of %d so not replacing it", active_vt, vt_get_min ());
}
if (plymouth_get_is_active ())
plymouth_quit (FALSE);
if (vt < 0)
vt = vt_can_multi_seat () ? vt_get_unused () : 0;
if (vt < 0)
{
l_debug (seat, "Failed to get a VT to run on");
return FALSE;
}

int timeout = seat_get_integer_property (SEAT (seat), "wayland-compositor-timeout");
if (timeout <= 0)
timeout = 60;

priv->compositor = wayland_system_compositor_new ();
g_signal_connect (priv->compositor, DISPLAY_SERVER_SIGNAL_READY, G_CALLBACK (compositor_ready_cb), seat);
g_signal_connect (priv->compositor, DISPLAY_SERVER_SIGNAL_STOPPED, G_CALLBACK (compositor_stopped_cb), seat);
wayland_system_compositor_set_command (priv->compositor, seat_get_string_property (SEAT (seat), "wayland-compositor-command"));
wayland_system_compositor_set_vt (priv->compositor, vt);
wayland_system_compositor_set_timeout (priv->compositor, timeout);

return display_server_start (DISPLAY_SERVER (priv->compositor));
}

static DisplayServer *
seat_wayland_system_compositor_create_display_server (Seat *seat, Session *session)
{
SeatWaylandSystemCompositorPrivate *priv = seat_wayland_system_compositor_get_instance_private (SEAT_WAYLAND_SYSTEM_COMPOSITOR (seat));

const gchar *session_type = session_get_session_type (session);
if (strcmp (session_type, "mir") == 0 || strcmp (session_type, "wayland") == 0)
return g_object_ref (DISPLAY_SERVER (priv->compositor));
else
{
l_warning (seat, "Can't create unsupported display server '%s'", session_type);
return NULL;
}
}

static gboolean
seat_wayland_system_compositor_display_server_is_used (Seat *seat, DisplayServer *display_server)
{
SeatWaylandSystemCompositorPrivate *priv = seat_wayland_system_compositor_get_instance_private (SEAT_WAYLAND_SYSTEM_COMPOSITOR (seat));

if (display_server == DISPLAY_SERVER (priv->compositor))
return TRUE;

return SEAT_CLASS (seat_wayland_system_compositor_parent_class)->display_server_is_used (seat, display_server);
}

static GreeterSession *
seat_wayland_system_compositor_create_greeter_session (Seat *seat)
{
SeatWaylandSystemCompositorPrivate *priv = seat_wayland_system_compositor_get_instance_private (SEAT_WAYLAND_SYSTEM_COMPOSITOR (seat));

GreeterSession *greeter_session = SEAT_CLASS (seat_wayland_system_compositor_parent_class)->create_greeter_session (seat);
session_set_env (SESSION (greeter_session), "XDG_SEAT", seat_get_name (seat));

gint vt = display_server_get_vt (DISPLAY_SERVER (priv->compositor));
if (vt >= 0)
{
g_autofree gchar *value = g_strdup_printf ("%d", vt);
session_set_env (SESSION (greeter_session), "XDG_VTNR", value);
}

return greeter_session;
}

static Session *
seat_wayland_system_compositor_create_session (Seat *seat)
{
SeatWaylandSystemCompositorPrivate *priv = seat_wayland_system_compositor_get_instance_private (SEAT_WAYLAND_SYSTEM_COMPOSITOR (seat));

Session *session = SEAT_CLASS (seat_wayland_system_compositor_parent_class)->create_session (seat);
session_set_env (session, "XDG_SEAT", seat_get_name (seat));

gint vt = display_server_get_vt (DISPLAY_SERVER (priv->compositor));
if (vt >= 0)
{
g_autofree gchar *value = g_strdup_printf ("%d", vt);
session_set_env (SESSION (session), "XDG_VTNR", value);
}

return session;
}

static const gchar *
get_mir_id (Session *session)
{
if (!session)
return NULL;

DisplayServer *display_server = session_get_display_server (session);
if (IS_WAYLAND_SYSTEM_COMPOSITOR (display_server))
return session_get_env (session, "MIR_SERVER_NAME");

return NULL;
}

static void
seat_wayland_system_compositor_set_active_session (Seat *seat, Session *session)
{
SeatWaylandSystemCompositorPrivate *priv = seat_wayland_system_compositor_get_instance_private (SEAT_WAYLAND_SYSTEM_COMPOSITOR (seat));

const gchar *old_id = get_mir_id (priv->active_session);
const gchar *new_id = get_mir_id (session);

g_clear_object (&priv->active_session);
priv->active_session = g_object_ref (session);

if (g_strcmp0 (old_id, new_id) != 0)
wayland_system_compositor_set_active_session (priv->compositor, new_id);

SEAT_CLASS (seat_wayland_system_compositor_parent_class)->set_active_session (seat, session);
}

static Session *
seat_wayland_system_compositor_get_active_session (Seat *seat)
{
SeatWaylandSystemCompositorPrivate *priv = seat_wayland_system_compositor_get_instance_private (SEAT_WAYLAND_SYSTEM_COMPOSITOR (seat));
return priv->active_session;
}

static void
seat_wayland_system_compositor_set_next_session (Seat *seat, Session *session)
{
SeatWaylandSystemCompositorPrivate *priv = seat_wayland_system_compositor_get_instance_private (SEAT_WAYLAND_SYSTEM_COMPOSITOR (seat));

if (!session)
return;

const gchar *id = session_get_env (session, "MIR_SERVER_NAME");

if (id)
{
l_debug (seat, "Marking Mir session %s as the next session", id);
wayland_system_compositor_set_next_session (priv->compositor, id);
}
else
{
l_debug (seat, "Failed to work out session ID to mark");
}

SEAT_CLASS (seat_wayland_system_compositor_parent_class)->set_next_session (seat, session);
}

static void
seat_wayland_system_compositor_run_script (Seat *seat, DisplayServer *display_server, Process *script)
{
SEAT_CLASS (seat_wayland_system_compositor_parent_class)->run_script (seat, display_server, script);
}

static void
seat_wayland_system_compositor_stop (Seat *seat)
{
SeatWaylandSystemCompositorPrivate *priv = seat_wayland_system_compositor_get_instance_private (SEAT_WAYLAND_SYSTEM_COMPOSITOR (seat));

/* Stop the compositor first */
if (priv->compositor)
display_server_stop (DISPLAY_SERVER (priv->compositor));

check_stopped (SEAT_WAYLAND_SYSTEM_COMPOSITOR (seat));
}

static void
seat_wayland_system_compositor_init (SeatWaylandSystemCompositor *seat)
{
}

static void
seat_wayland_system_compositor_finalize (GObject *object)
{
SeatWaylandSystemCompositor *seat = SEAT_WAYLAND_SYSTEM_COMPOSITOR (object);
SeatWaylandSystemCompositorPrivate *priv = seat_wayland_system_compositor_get_instance_private (seat);

g_clear_object (&priv->compositor);
g_clear_object (&priv->active_session);
g_clear_object (&priv->active_display_server);

G_OBJECT_CLASS (seat_wayland_system_compositor_parent_class)->finalize (object);
}

static void
seat_wayland_system_compositor_class_init (SeatWaylandSystemCompositorClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
SeatClass *seat_class = SEAT_CLASS (klass);

object_class->finalize = seat_wayland_system_compositor_finalize;
seat_class->setup = seat_wayland_system_compositor_setup;
seat_class->start = seat_wayland_system_compositor_start;
seat_class->create_display_server = seat_wayland_system_compositor_create_display_server;
seat_class->display_server_is_used = seat_wayland_system_compositor_display_server_is_used;
seat_class->create_greeter_session = seat_wayland_system_compositor_create_greeter_session;
seat_class->create_session = seat_wayland_system_compositor_create_session;
seat_class->set_active_session = seat_wayland_system_compositor_set_active_session;
seat_class->get_active_session = seat_wayland_system_compositor_get_active_session;
seat_class->set_next_session = seat_wayland_system_compositor_set_next_session;
seat_class->run_script = seat_wayland_system_compositor_run_script;
seat_class->stop = seat_wayland_system_compositor_stop;
}
Loading

0 comments on commit 63d6b2e

Please sign in to comment.