From bad1e9afa8ea7d8927c8b4df83d3f277379dd54e Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sat, 25 Jul 2020 21:53:06 +0200 Subject: [PATCH] session: Add libseat backend --- .builds/alpine.yml | 2 +- .builds/archlinux.yml | 1 + .builds/freebsd.yml | 1 + backend/session/direct.c | 3 + backend/session/libseat.c | 190 ++++++++++++++++++++++++++++++ backend/session/logind.c | 5 + backend/session/meson.build | 9 ++ backend/session/noop.c | 3 + backend/session/session.c | 24 +++- include/backend/session/session.h | 8 ++ include/wlr/config.h.in | 2 + meson.build | 2 + meson_options.txt | 1 + 13 files changed, 244 insertions(+), 7 deletions(-) create mode 100644 backend/session/libseat.c create mode 100644 include/backend/session/session.h diff --git a/.builds/alpine.yml b/.builds/alpine.yml index 13221d25..402f72f6 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -16,7 +16,7 @@ sources: tasks: - setup: | cd wlroots - meson build -Dauto_features=enabled -Dlogind=disabled -Dxcb-errors=disabled + meson build -Dauto_features=enabled -Dlogind=disabled -Dlibseat=disabled -Dxcb-errors=disabled - build: | cd wlroots ninja -C build diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index b3b1a3c0..9cf2f84f 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -12,6 +12,7 @@ packages: - xcb-util-errors - xcb-util-image - xcb-util-wm + - seatd sources: - https://github.com/swaywm/wlroots tasks: diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index a0dfc442..74553f7b 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -18,6 +18,7 @@ packages: - x11/pixman - x11/xcb-util-errors - x11/xcb-util-wm +- sysutils/seatd sources: - https://github.com/swaywm/wlroots tasks: diff --git a/backend/session/direct.c b/backend/session/direct.c index 4ffd711d..f9041070 100644 --- a/backend/session/direct.c +++ b/backend/session/direct.c @@ -18,6 +18,7 @@ #include #include #include "backend/session/direct-ipc.h" +#include "backend/session/session.h" #include "util/signal.h" enum { DRM_MAJOR = 226 }; @@ -246,6 +247,7 @@ static struct wlr_session *direct_session_create(struct wl_display *disp) { return NULL; } + session_init(&session->base); session->sock = direct_ipc_init(&session->child); if (session->sock == -1) { goto error_session; @@ -267,6 +269,7 @@ static struct wlr_session *direct_session_create(struct wl_display *disp) { snprintf(session->base.seat, sizeof(session->base.seat), "%s", seat); session->base.impl = &session_direct; + session->base.active = true; wlr_log(WLR_INFO, "Successfully loaded direct session"); return &session->base; diff --git a/backend/session/libseat.c b/backend/session/libseat.c new file mode 100644 index 00000000..77226204 --- /dev/null +++ b/backend/session/libseat.c @@ -0,0 +1,190 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "backend/session/session.h" +#include "util/signal.h" + +#include + +const struct session_impl session_libseat; + +struct libseat_device { + struct wl_list link; + int fd; + int device_id; +}; + +struct libseat_session { + struct wlr_session base; + + struct libseat *seat; + struct wl_event_source *event; + struct wl_list devices; +}; + +static void handle_enable_seat(struct libseat *seat, void *data) { + struct libseat_session *session = data; + session->base.active = true; + wlr_signal_emit_safe(&session->base.session_signal, session); +} + +static void handle_disable_seat(struct libseat *seat, void *data) { + struct libseat_session *session = data; + session->base.active = false; + wlr_signal_emit_safe(&session->base.session_signal, session); + libseat_disable_seat(session->seat); +} + +static int libseat_event(int fd, uint32_t mask, void *data) { + struct libseat *seat = data; + libseat_dispatch(seat, 0); + return 1; +} + +static struct libseat_seat_listener seat_listener = { + .enable_seat = handle_enable_seat, + .disable_seat = handle_disable_seat, +}; + +static struct libseat_session *libseat_session_from_session( + struct wlr_session *base) { + assert(base->impl == &session_libseat); + return (struct libseat_session *)base; +} + +static struct wlr_session *libseat_session_create(struct wl_display *disp) { + struct libseat_session *session = calloc(1, sizeof(*session)); + if (!session) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + return NULL; + } + + session_init(&session->base); + wl_list_init(&session->devices); + + session->seat = libseat_open_seat(&seat_listener, session); + if (session->seat == NULL) { + wlr_log_errno(WLR_ERROR, "Unable to create seat"); + goto error; + } + + const char *seat_name = libseat_seat_name(session->seat); + if (seat_name == NULL) { + wlr_log_errno(WLR_ERROR, "Unable to get seat info"); + goto error; + } + snprintf(session->base.seat, sizeof(session->base.seat), "%s", seat_name); + + struct wl_event_loop *event_loop = wl_display_get_event_loop(disp); + session->event = wl_event_loop_add_fd(event_loop, libseat_get_fd(session->seat), + WL_EVENT_READABLE, libseat_event, session->seat); + if (session->event == NULL) { + wlr_log(WLR_ERROR, "Failed to create libseat event source"); + goto error; + } + + // We may have received enable_seat immediately after the open_seat result, + // so, dispatch once without timeout to speed up activation. + if (libseat_dispatch(session->seat, 0) == -1) { + wlr_log_errno(WLR_ERROR, "libseat dispatch failed"); + goto error; + } + + wlr_log(WLR_INFO, "Successfully loaded libseat session"); + session->base.impl = &session_libseat; + return &session->base; + +error: + if (session->seat != NULL) { + libseat_close_seat(session->seat); + } + if (session->event != NULL) { + wl_event_source_remove(session->event); + } + free(session); + return NULL; +} + +static void libseat_session_destroy(struct wlr_session *base) { + struct libseat_session *session = libseat_session_from_session(base); + + libseat_close_seat(session->seat); + wl_event_source_remove(session->event); + free(session); +} + +static struct libseat_device *find_device_by_fd(struct libseat_session *session, int fd) { + struct libseat_device *dev; + wl_list_for_each(dev, &session->devices, link) { + if (dev->fd == fd) { + return dev; + } + } + return NULL; +} + +static int libseat_session_open_device(struct wlr_session *base, const char *path) { + struct libseat_session *session = libseat_session_from_session(base); + + int fd; + int device_id = libseat_open_device(session->seat, path, &fd); + if (device_id == -1) { + wlr_log_errno(WLR_ERROR, "Failed to open device '%s'", path); + return -1; + } + + struct libseat_device *dev = calloc(1, sizeof(struct libseat_device)); + if (dev == NULL) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + libseat_close_device(session->seat, device_id); + return -1; + } + + dev->fd = fd; + dev->device_id = device_id; + wl_list_insert(&session->devices, &dev->link); + + return fd; +} + +static void libseat_session_close_device(struct wlr_session *base, int fd) { + struct libseat_session *session = libseat_session_from_session(base); + + struct libseat_device *dev = find_device_by_fd(session, fd); + if (dev == NULL) { + wlr_log(WLR_ERROR, "No device with fd %d found", fd); + close(fd); + return; + } + + if (libseat_close_device(session->seat, dev->device_id) == -1) { + wlr_log_errno(WLR_ERROR, "Failed to close device %d", dev->device_id); + } + + wl_list_remove(&dev->link); + free(dev); + close(fd); +} + +static bool libseat_change_vt(struct wlr_session *base, unsigned vt) { + struct libseat_session *session = libseat_session_from_session(base); + return libseat_switch_session(session->seat, vt); +} + +const struct session_impl session_libseat = { + .create = libseat_session_create, + .destroy = libseat_session_destroy, + .open = libseat_session_open_device, + .close = libseat_session_close_device, + .change_vt = libseat_change_vt, +}; diff --git a/backend/session/logind.c b/backend/session/logind.c index c5d0cb29..a460cbe2 100644 --- a/backend/session/logind.c +++ b/backend/session/logind.c @@ -13,6 +13,7 @@ #include #include #include +#include "backend/session/session.h" #include "util/signal.h" #if WLR_HAS_SYSTEMD @@ -778,6 +779,8 @@ static struct wlr_session *logind_session_create(struct wl_display *disp) { return NULL; } + session_init(&session->base); + if (!get_display_session(&session->id)) { goto error; } @@ -855,6 +858,8 @@ static struct wlr_session *logind_session_create(struct wl_display *disp) { wlr_log(WLR_INFO, "Successfully loaded logind session"); session->base.impl = &session_logind; + session->base.active = true; + return &session->base; error_bus: diff --git a/backend/session/meson.build b/backend/session/meson.build index 81ff6d85..4c83685e 100644 --- a/backend/session/meson.build +++ b/backend/session/meson.build @@ -62,3 +62,12 @@ if logind_found wlr_files += files('logind.c') wlr_deps += logind endif + +# libseat + +libseat = dependency('libseat', required: get_option('libseat')) +if libseat.found() + wlr_files += files('libseat.c') + wlr_deps += libseat + conf_data.set10('WLR_HAS_LIBSEAT', true) +endif diff --git a/backend/session/noop.c b/backend/session/noop.c index 0e13a177..3f293775 100644 --- a/backend/session/noop.c +++ b/backend/session/noop.c @@ -6,6 +6,7 @@ #include #include #include +#include "backend/session/session.h" #include "util/signal.h" const struct session_impl session_noop; @@ -33,7 +34,9 @@ static struct wlr_session *noop_session_create(struct wl_display *disp) { return NULL; } + session_init(session); session->impl = &session_noop; + session->active = true; wlr_log(WLR_INFO, "Successfully initialized noop session"); return session; diff --git a/backend/session/session.c b/backend/session/session.c index 01eeffd9..d8e9509d 100644 --- a/backend/session/session.c +++ b/backend/session/session.c @@ -13,13 +13,18 @@ #include #include #include +#include "backend/session/session.h" #include "util/signal.h" +extern const struct session_impl session_libseat; extern const struct session_impl session_logind; extern const struct session_impl session_direct; extern const struct session_impl session_noop; static const struct session_impl *impls[] = { +#if WLR_HAS_LIBSEAT + &session_libseat, +#endif #if WLR_HAS_SYSTEMD || WLR_HAS_ELOGIND &session_logind, #endif @@ -65,12 +70,24 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) { wlr_session_destroy(session); } +void session_init(struct wlr_session *session) { + wl_signal_init(&session->session_signal); + wl_signal_init(&session->events.destroy); + wl_list_init(&session->devices); +} + struct wlr_session *wlr_session_create(struct wl_display *disp) { struct wlr_session *session = NULL; const char *env_wlr_session = getenv("WLR_SESSION"); if (env_wlr_session) { - if (strcmp(env_wlr_session, "logind") == 0 || + if (strcmp(env_wlr_session, "libseat") == 0) { +#if WLR_HAS_LIBSEAT + session = session_libseat.create(disp); +#else + wlr_log(WLR_ERROR, "wlroots is not compiled with libseat support"); +#endif + } else if (strcmp(env_wlr_session, "logind") == 0 || strcmp(env_wlr_session, "systemd") == 0) { #if WLR_HAS_SYSTEMD || WLR_HAS_ELOGIND session = session_logind.create(disp); @@ -97,11 +114,6 @@ struct wlr_session *wlr_session_create(struct wl_display *disp) { return NULL; } - session->active = true; - wl_signal_init(&session->session_signal); - wl_signal_init(&session->events.destroy); - wl_list_init(&session->devices); - session->udev = udev_new(); if (!session->udev) { wlr_log_errno(WLR_ERROR, "Failed to create udev context"); diff --git a/include/backend/session/session.h b/include/backend/session/session.h new file mode 100644 index 00000000..626f470a --- /dev/null +++ b/include/backend/session/session.h @@ -0,0 +1,8 @@ +#ifndef BACKEND_SESSION_SESSION_H +#define BACKEND_SESSION_SESSION_H + +struct wlr_session; + +void session_init(struct wlr_session *session); + +#endif diff --git a/include/wlr/config.h.in b/include/wlr/config.h.in index a7691ff9..77a15598 100644 --- a/include/wlr/config.h.in +++ b/include/wlr/config.h.in @@ -8,6 +8,8 @@ #mesondefine WLR_HAS_SYSTEMD #mesondefine WLR_HAS_ELOGIND +#mesondefine WLR_HAS_LIBSEAT + #mesondefine WLR_HAS_X11_BACKEND #mesondefine WLR_HAS_XWAYLAND diff --git a/meson.build b/meson.build index 4abe6318..ca26391e 100644 --- a/meson.build +++ b/meson.build @@ -82,6 +82,7 @@ endif conf_data = configuration_data() conf_data.set10('WLR_HAS_SYSTEMD', false) conf_data.set10('WLR_HAS_ELOGIND', false) +conf_data.set10('WLR_HAS_LIBSEAT', false) conf_data.set10('WLR_HAS_X11_BACKEND', false) conf_data.set10('WLR_HAS_XWAYLAND', false) conf_data.set10('WLR_HAS_XCB_ERRORS', false) @@ -176,6 +177,7 @@ meson.override_dependency('wlroots', wlroots) summary({ 'systemd': conf_data.get('WLR_HAS_SYSTEMD', 0), 'elogind': conf_data.get('WLR_HAS_ELOGIND', 0), + 'libseat': conf_data.get('WLR_HAS_LIBSEAT', 0), 'xwayland': conf_data.get('WLR_HAS_XWAYLAND', 0), 'x11_backend': conf_data.get('WLR_HAS_X11_BACKEND', 0), 'xcb-icccm': conf_data.get('WLR_HAS_XCB_ICCCM', 0), diff --git a/meson_options.txt b/meson_options.txt index 894113e7..382ef2a6 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,5 +1,6 @@ option('logind', type: 'feature', value: 'auto', description: 'Enable support for rootless session via logind') option('logind-provider', type: 'combo', choices: ['auto', 'systemd', 'elogind'], value: 'auto', description: 'Provider of logind support library') +option('libseat', type: 'feature', value: 'auto', description: 'Enable support for rootless session via libseat') option('xcb-errors', type: 'feature', value: 'auto', description: 'Use xcb-errors util library') option('xcb-icccm', type: 'feature', value: 'auto', description: 'Use xcb-icccm util library') option('xwayland', type: 'feature', value: 'auto', yield: true, description: 'Enable support for X11 applications')