diff options
Diffstat (limited to 'backend/session')
-rw-r--r-- | backend/session/direct.c | 3 | ||||
-rw-r--r-- | backend/session/libseat.c | 190 | ||||
-rw-r--r-- | backend/session/logind.c | 5 | ||||
-rw-r--r-- | backend/session/meson.build | 9 | ||||
-rw-r--r-- | backend/session/noop.c | 3 | ||||
-rw-r--r-- | backend/session/session.c | 24 |
6 files changed, 228 insertions, 6 deletions
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 <wlr/backend/session/interface.h> #include <wlr/util/log.h> #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 <assert.h> +#include <errno.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <wayland-server-core.h> +#include <wlr/backend/session/interface.h> +#include <wlr/config.h> +#include <wlr/util/log.h> +#include "backend/session/session.h" +#include "util/signal.h" + +#include <libseat.h> + +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 <wlr/backend/session/interface.h> #include <wlr/config.h> #include <wlr/util/log.h> +#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 <wayland-server-core.h> #include <wlr/backend/session/interface.h> #include <wlr/util/log.h> +#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 <wlr/util/log.h> #include <xf86drm.h> #include <xf86drmMode.h> +#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"); |