backend/session: Remove session_impl

libseat provides all session functionality, so there is no longer need
for a session backend abstraction. The libseat device ID, seat handle
and event loop handle are moved to the main wlr_session and wlr_device
structs.
This commit is contained in:
Kenny Levinsen 2021-04-11 16:27:46 +02:00 committed by Simon Ser
parent 3f87c2caea
commit 7f09085461
7 changed files with 140 additions and 284 deletions

View file

@ -1,218 +0,0 @@
#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.events.active, NULL);
}
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.events.active, NULL);
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 enum wlr_log_importance libseat_log_level_to_wlr(
enum libseat_log_level level) {
switch (level) {
case LIBSEAT_LOG_LEVEL_ERROR:
return WLR_ERROR;
case LIBSEAT_LOG_LEVEL_INFO:
return WLR_INFO;
default:
return WLR_DEBUG;
}
}
static void log_libseat(enum libseat_log_level level,
const char *fmt, va_list args) {
enum wlr_log_importance importance = libseat_log_level_to_wlr(level);
static char wlr_fmt[1024];
snprintf(wlr_fmt, sizeof(wlr_fmt), "[libseat] %s", fmt);
_wlr_vlog(importance, wlr_fmt, args);
}
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);
libseat_set_log_handler(log_libseat);
libseat_set_log_level(LIBSEAT_LOG_LEVEL_INFO);
// libseat will take care of updating the logind state if necessary
setenv("XDG_SESSION_TYPE", "wayland", 1);
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) == 0;
}
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,
};

View file

@ -3,10 +3,5 @@ libseat = dependency('libseat',
fallback: ['seatd', 'libseat'],
default_options: ['server=disabled', 'man-pages=disabled'],
)
wlr_files += files(
'session.c',
'libseat.c'
)
wlr_files += files('session.c')
wlr_deps += libseat

View file

@ -1,8 +1,10 @@
#define _POSIX_C_SOURCE 200809L
#include <assert.h>
#include <libudev.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
@ -10,7 +12,6 @@
#include <time.h>
#include <wayland-server-core.h>
#include <wlr/backend/session.h>
#include <wlr/backend/session/interface.h>
#include <wlr/config.h>
#include <wlr/util/log.h>
#include <xf86drm.h>
@ -18,15 +19,113 @@
#include "backend/session/session.h"
#include "util/signal.h"
#include <libseat.h>
#define WAIT_GPU_TIMEOUT 10000 // ms
extern const struct session_impl session_libseat;
static void handle_enable_seat(struct libseat *seat, void *data) {
struct wlr_session *session = data;
session->active = true;
wlr_signal_emit_safe(&session->events.active, NULL);
}
static const struct session_impl *const impls[] = {
&session_libseat,
NULL,
static void handle_disable_seat(struct libseat *seat, void *data) {
struct wlr_session *session = data;
session->active = false;
wlr_signal_emit_safe(&session->events.active, NULL);
libseat_disable_seat(session->seat_handle);
}
static int libseat_event(int fd, uint32_t mask, void *data) {
struct wlr_session *session = data;
if (libseat_dispatch(session->seat_handle, 0) == -1) {
wlr_log_errno(WLR_ERROR, "Failed to dispatch libseat");
wl_display_terminate(session->display);
}
return 1;
}
static struct libseat_seat_listener seat_listener = {
.enable_seat = handle_enable_seat,
.disable_seat = handle_disable_seat,
};
static enum wlr_log_importance libseat_log_level_to_wlr(
enum libseat_log_level level) {
switch (level) {
case LIBSEAT_LOG_LEVEL_ERROR:
return WLR_ERROR;
case LIBSEAT_LOG_LEVEL_INFO:
return WLR_INFO;
default:
return WLR_DEBUG;
}
}
static void log_libseat(enum libseat_log_level level,
const char *fmt, va_list args) {
enum wlr_log_importance importance = libseat_log_level_to_wlr(level);
static char wlr_fmt[1024];
snprintf(wlr_fmt, sizeof(wlr_fmt), "[libseat] %s", fmt);
_wlr_vlog(importance, wlr_fmt, args);
}
static int libseat_session_init(struct wlr_session *session, struct wl_display *disp) {
libseat_set_log_handler(log_libseat);
libseat_set_log_level(LIBSEAT_LOG_LEVEL_INFO);
// libseat will take care of updating the logind state if necessary
setenv("XDG_SESSION_TYPE", "wayland", 1);
session->seat_handle = libseat_open_seat(&seat_listener, session);
if (session->seat_handle == NULL) {
wlr_log_errno(WLR_ERROR, "Unable to create seat");
return -1;
}
const char *seat_name = libseat_seat_name(session->seat_handle);
if (seat_name == NULL) {
wlr_log_errno(WLR_ERROR, "Unable to get seat info");
goto error;
}
snprintf(session->seat, sizeof(session->seat), "%s", seat_name);
struct wl_event_loop *event_loop = wl_display_get_event_loop(disp);
session->libseat_event = wl_event_loop_add_fd(event_loop, libseat_get_fd(session->seat_handle),
WL_EVENT_READABLE, libseat_event, session);
if (session->libseat_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_handle, 0) == -1) {
wlr_log_errno(WLR_ERROR, "libseat dispatch failed");
goto error_dispatch;
}
wlr_log(WLR_INFO, "Successfully loaded libseat session");
return 0;
error_dispatch:
wl_event_source_remove(session->libseat_event);
session->libseat_event = NULL;
error:
libseat_close_seat(session->seat_handle);
session->seat_handle = NULL;
return -1;
}
static void libseat_session_finish(struct wlr_session *session) {
libseat_close_seat(session->seat_handle);
wl_event_source_remove(session->libseat_event);
session->seat_handle = NULL;
session->libseat_event = NULL;
}
static bool is_drm_card(const char *sysname) {
const char prefix[] = "card";
if (strncmp(sysname, prefix, strlen(prefix)) != 0) {
@ -94,34 +193,21 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) {
wlr_session_destroy(session);
}
void session_init(struct wlr_session *session) {
struct wlr_session *wlr_session_create(struct wl_display *disp) {
struct wlr_session *session = calloc(1, sizeof(*session));
if (!session) {
wlr_log_errno(WLR_ERROR, "Allocation failed");
return NULL;
}
wl_signal_init(&session->events.active);
wl_signal_init(&session->events.add_drm_card);
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, "libseat") == 0) {
session = session_libseat.create(disp);
} else {
wlr_log(WLR_ERROR, "Unsupported WLR_SESSION: %s",
env_wlr_session);
}
} else {
const struct session_impl *const *iter;
for (iter = impls; !session && *iter; ++iter) {
session = (*iter)->create(disp);
}
}
if (!session) {
if (libseat_session_init(session, disp) == -1) {
wlr_log(WLR_ERROR, "Failed to load session backend");
return NULL;
goto error_open;
}
session->udev = udev_new();
@ -161,7 +247,9 @@ error_mon:
error_udev:
udev_unref(session->udev);
error_session:
session->impl->destroy(session);
libseat_session_finish(session);
error_open:
free(session);
return NULL;
}
@ -177,13 +265,16 @@ void wlr_session_destroy(struct wlr_session *session) {
udev_monitor_unref(session->mon);
udev_unref(session->udev);
session->impl->destroy(session);
libseat_session_finish(session);
free(session);
}
struct wlr_device *wlr_session_open_file(struct wlr_session *session,
const char *path) {
int fd = session->impl->open(session, path);
if (fd < 0) {
int fd;
int device_id = libseat_open_device(session->seat_handle, path, &fd);
if (device_id == -1) {
wlr_log_errno(WLR_ERROR, "Failed to open device: '%s'", path);
return NULL;
}
@ -201,12 +292,14 @@ struct wlr_device *wlr_session_open_file(struct wlr_session *session,
dev->fd = fd;
dev->dev = st.st_rdev;
dev->device_id = device_id;
wl_signal_init(&dev->events.change);
wl_list_insert(&session->devices, &dev->link);
return dev;
error:
libseat_close_device(session->seat_handle, device_id);
free(dev);
close(fd);
return NULL;
@ -214,7 +307,9 @@ error:
void wlr_session_close_file(struct wlr_session *session,
struct wlr_device *dev) {
session->impl->close(session, dev->fd);
if (libseat_close_device(session->seat_handle, dev->device_id) == -1) {
wlr_log_errno(WLR_ERROR, "Failed to close device %d", dev->device_id);
}
wl_list_remove(&dev->link);
free(dev);
}
@ -223,8 +318,7 @@ bool wlr_session_change_vt(struct wlr_session *session, unsigned vt) {
if (!session) {
return false;
}
return session->impl->change_vt(session, vt);
return libseat_switch_session(session->seat_handle, vt) == 0;
}
/* Tests if 'path' is KMS compatible by trying to open it.

View file

@ -6,8 +6,6 @@ wlroots reads these environment variables
libinput, drm, wayland, x11, headless, noop)
* *WLR_NO_HARDWARE_CURSORS*: set to 1 to use software cursors instead of
hardware cursors
* *WLR_SESSION*: specifies the `wlr_session` to be used (available sessions:
libseat)
* *WLR_DIRECT_TTY*: specifies the tty to be used (instead of using /dev/tty)
* *WLR_XWAYLAND*: specifies the path to an Xwayland binary to be used (instead
of following shell search semantics for "Xwayland")

View file

@ -3,6 +3,12 @@
struct wlr_session;
struct wlr_session *libseat_session_create(struct wl_display *disp);
void libseat_session_destroy(struct wlr_session *base);
int libseat_session_open_device(struct wlr_session *base, const char *path);
void libseat_session_close_device(struct wlr_session *base, int fd);
bool libseat_change_vt(struct wlr_session *base, unsigned vt);
void session_init(struct wlr_session *session);
#endif

View file

@ -6,10 +6,11 @@
#include <sys/types.h>
#include <wayland-server-core.h>
struct session_impl;
struct libseat;
struct wlr_device {
int fd;
int device_id;
dev_t dev;
struct wl_list link;
@ -19,7 +20,6 @@ struct wlr_device {
};
struct wlr_session {
const struct session_impl *impl;
/*
* Signal for when the session becomes active/inactive.
* It's called when we swap virtual terminal.
@ -37,6 +37,9 @@ struct wlr_session {
struct udev_monitor *mon;
struct wl_event_source *udev_event;
struct libseat *seat_handle;
struct wl_event_source *libseat_event;
struct wl_list devices;
struct wl_display *display;

View file

@ -1,22 +0,0 @@
/*
* This an unstable interface of wlroots. No guarantees are made regarding the
* future consistency of this API.
*/
#ifndef WLR_USE_UNSTABLE
#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
#endif
#ifndef WLR_BACKEND_SESSION_INTERFACE_H
#define WLR_BACKEND_SESSION_INTERFACE_H
#include <wlr/backend/session.h>
struct session_impl {
struct wlr_session *(*create)(struct wl_display *disp);
void (*destroy)(struct wlr_session *session);
int (*open)(struct wlr_session *session, const char *path);
void (*close)(struct wlr_session *session, int fd);
bool (*change_vt)(struct wlr_session *session, unsigned vt);
};
#endif