diff --git a/backend/backend.c b/backend/backend.c index 3d84aa636..faf9bdea0 100644 --- a/backend/backend.c +++ b/backend/backend.c @@ -32,6 +32,10 @@ #include #endif +#if WLR_HAS_WSCONS_BACKEND +#include +#endif + #define WAIT_SESSION_TIMEOUT 10000 // ms void wlr_backend_init(struct wlr_backend *backend, @@ -287,6 +291,15 @@ static struct wlr_backend *attempt_libinput_backend(struct wlr_session *session) #endif } +static struct wlr_backend *attempt_wscons_backend(struct wlr_session *session) { +#if WLR_HAS_WSCONS_BACKEND + return wlr_wscons_backend_create(session); +#else + wlr_log(WLR_ERROR, "Cannot create wscons backend: disabled at compile-time"); + return NULL; +#endif +} + static bool attempt_backend_by_name(struct wl_event_loop *loop, struct wlr_backend *multi, char *name, struct wlr_session **session_ptr) { @@ -297,8 +310,9 @@ static bool attempt_backend_by_name(struct wl_event_loop *loop, backend = attempt_x11_backend(loop, NULL); } else if (strcmp(name, "headless") == 0) { backend = attempt_headless_backend(loop); - } else if (strcmp(name, "drm") == 0 || strcmp(name, "libinput") == 0) { - // DRM and libinput need a session + } else if (strcmp(name, "drm") == 0 || strcmp(name, "libinput") == 0 + || strcmp(name, "wscons") == 0) { + // DRM and libinput/wscons need a session if (*session_ptr == NULL) { *session_ptr = session_create_and_wait(loop); if (*session_ptr == NULL) { @@ -309,6 +323,8 @@ static bool attempt_backend_by_name(struct wl_event_loop *loop, if (strcmp(name, "libinput") == 0) { backend = attempt_libinput_backend(*session_ptr); + } else if (strcmp(name, "wscons") == 0) { + backend = attempt_wscons_backend(*session_ptr); } else { // attempt_drm_backend() adds the multi drm backends itself return attempt_drm_backend(multi, *session_ptr) != NULL; @@ -393,13 +409,24 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_event_loop *loop, goto success; } - // Attempt DRM+libinput + // Attempt DRM+libinput/wscons session = session_create_and_wait(loop); if (!session) { wlr_log(WLR_ERROR, "Failed to start a DRM session"); goto error; } +#if WLR_HAS_WSCONS_BACKEND + struct wlr_backend *wscons = attempt_wscons_backend(session); + if (!wscons) { + wlr_log(WLR_ERROR, "Failed to start wscons backend"); + goto error; + } + wlr_multi_backend_add(multi, wscons); + if (!auto_backend_monitor_create(multi, wscons)) { + goto error; + } +#else struct wlr_backend *libinput = attempt_libinput_backend(session); if (libinput) { wlr_multi_backend_add(multi, libinput); @@ -414,6 +441,7 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_event_loop *loop, wlr_log(WLR_ERROR, "Set WLR_LIBINPUT_NO_DEVICES=1 to skip libinput"); goto error; } +#endif struct wlr_backend *primary_drm = attempt_drm_backend(multi, session); if (primary_drm == NULL) { diff --git a/backend/libinput/backend.c b/backend/libinput/backend.c index 909292864..ba51ff3c3 100644 --- a/backend/libinput/backend.c +++ b/backend/libinput/backend.c @@ -7,6 +7,7 @@ #include #include "backend/libinput.h" #include "util/env.h" +#include static struct wlr_libinput_backend *get_libinput_backend_from_backend( struct wlr_backend *wlr_backend) { @@ -192,7 +193,7 @@ struct wlr_backend *wlr_libinput_backend_create(struct wlr_session *session) { backend->session = session; backend->libinput_context = libinput_udev_create_context(&libinput_impl, - backend, backend->session->udev); + backend, udev_new()); if (!backend->libinput_context) { wlr_log(WLR_ERROR, "Failed to create libinput context"); wlr_backend_finish(&backend->backend); diff --git a/backend/libinput/meson.build b/backend/libinput/meson.build index 091b0e0eb..05aa9772c 100644 --- a/backend/libinput/meson.build +++ b/backend/libinput/meson.build @@ -14,6 +14,9 @@ if not (libinput.found() and features['session']) subdir_done() endif +# libinput has a hardcoded udev dependency in its API +wlr_deps += dependency('libudev') + wlr_files += files( 'backend.c', 'events.c', diff --git a/backend/meson.build b/backend/meson.build index ed977d3b6..2d0011cb0 100644 --- a/backend/meson.build +++ b/backend/meson.build @@ -1,6 +1,6 @@ wlr_files += files('backend.c') -all_backends = ['drm', 'libinput', 'x11'] +all_backends = ['drm', 'libinput', 'x11', 'wscons'] backends = get_option('backends') if 'auto' in backends and get_option('auto_features').enabled() backends = all_backends @@ -8,10 +8,10 @@ elif 'auto' in backends and get_option('auto_features').disabled() backends = [] endif -session_required = 'drm' in backends or 'libinput' in backends or get_option('session').enabled() +session_required = 'drm' in backends or 'libinput' in backends or 'wscons' in backends or get_option('session').enabled() if get_option('session').disabled() if session_required - error('Session support is required for the DRM or libinput backends') + error('Session support is required for the DRM or libinput/wscons backends') endif session_required = disabler() endif diff --git a/backend/session/meson.build b/backend/session/meson.build index 4c20ee9df..d1670bb07 100644 --- a/backend/session/meson.build +++ b/backend/session/meson.build @@ -1,17 +1,27 @@ -msg = 'Required for session support.' -udev = dependency('libudev', required: session_required, not_found_message: msg) libseat = dependency( 'libseat', version: '>=0.2.0', fallback: 'seatd', default_options: ['server=disabled', 'man-pages=disabled', 'examples=disabled'], required: session_required, - not_found_message: msg, ) -if not (udev.found() and libseat.found()) - subdir_done() + +platform = target_machine.system() +if platform == 'linux' or platform == 'freebsd' + libudev = dependency('libudev', required: session_required) + if not (libudev.found() and libseat.found()) + subdir_done() + endif + + wlr_files += files('session_libudev.c') + wlr_deps += libudev +elif platform == 'openbsd' + wlr_files += files('session_openbsd.c') +else + error('Unsupported platform') endif wlr_files += files('session.c') -wlr_deps += [udev, libseat] +wlr_deps += libseat features += { 'session': true } + diff --git a/backend/session/session.c b/backend/session/session.c index 1e587f793..f28eb9045 100644 --- a/backend/session/session.c +++ b/backend/session/session.c @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -14,6 +13,7 @@ #include #include #include +#include #include "backend/session/session.h" #include "util/time.h" @@ -146,99 +146,70 @@ static bool is_drm_card(const char *sysname) { return true; } -static void read_udev_change_event(struct wlr_device_change_event *event, - struct udev_device *udev_dev) { - const char *hotplug = udev_device_get_property_value(udev_dev, "HOTPLUG"); - if (hotplug != NULL && strcmp(hotplug, "1") == 0) { - event->type = WLR_DEVICE_HOTPLUG; - struct wlr_device_hotplug_event *hotplug = &event->hotplug; - - const char *connector = - udev_device_get_property_value(udev_dev, "CONNECTOR"); - if (connector != NULL) { - hotplug->connector_id = strtoul(connector, NULL, 10); - } - - const char *prop = - udev_device_get_property_value(udev_dev, "PROPERTY"); - if (prop != NULL) { - hotplug->prop_id = strtoul(prop, NULL, 10); - } - - return; - } - - const char *lease = udev_device_get_property_value(udev_dev, "LEASE"); - if (lease != NULL && strcmp(lease, "1") == 0) { - event->type = WLR_DEVICE_LEASE; - return; - } -} - -static int handle_udev_event(int fd, uint32_t mask, void *data) { +static int handle_device_event(int fd, uint32_t mask, void *data) { struct wlr_session *session = data; - struct udev_device *udev_dev = udev_monitor_receive_device(session->mon); - if (!udev_dev) { + struct drm_event_content ev; + if (receive_drm_device(session->drm_handle, &ev) < 0) { + return 1; + } + wlr_log(WLR_DEBUG, "drm event for %s", ev.devnode); + + if (!is_drm_card(ev.devnode)) { return 1; } - const char *sysname = udev_device_get_sysname(udev_dev); - const char *devnode = udev_device_get_devnode(udev_dev); - const char *action = udev_device_get_action(udev_dev); - wlr_log(WLR_DEBUG, "udev event for %s (%s)", sysname, action); - - if (!is_drm_card(sysname) || !action || !devnode) { - goto out; - } - - const char *seat = udev_device_get_property_value(udev_dev, "ID_SEAT"); + const char *seat = get_device_seat(session->drm_handle, ev.devnode); if (!seat) { seat = "seat0"; } if (session->seat[0] != '\0' && strcmp(session->seat, seat) != 0) { - goto out; + return 1; } - dev_t devnum = udev_device_get_devnum(udev_dev); - if (strcmp(action, "add") == 0) { - struct wlr_device *dev; + struct wlr_device *dev; + switch (ev.type) { + case DRM_EVENT_ACTION_ADD: wl_list_for_each(dev, &session->devices, link) { - if (dev->dev == devnum) { - wlr_log(WLR_DEBUG, "Skipping duplicate device %s", sysname); - goto out; + if (dev->dev == ev.devnum) { + wlr_log(WLR_DEBUG, "Skipping duplicate device %s", ev.devnode); + return 1; } } - wlr_log(WLR_DEBUG, "DRM device %s added", sysname); + wlr_log(WLR_DEBUG, "DRM device %s added", ev.devnode); struct wlr_session_add_event event = { - .path = devnode, + .path = ev.devnode, }; wl_signal_emit_mutable(&session->events.add_drm_card, &event); - } else if (strcmp(action, "change") == 0) { - struct wlr_device *dev; + break; + case DRM_EVENT_ACTION_CHANGE: wl_list_for_each(dev, &session->devices, link) { - if (dev->dev == devnum) { - wlr_log(WLR_DEBUG, "DRM device %s changed", sysname); + if (dev->dev == ev.devnum) { + wlr_log(WLR_DEBUG, "DRM device %s changed", ev.devnode); struct wlr_device_change_event event = {0}; - read_udev_change_event(&event, udev_dev); + event.hotplug.connector_id = ev.conn_id; + event.hotplug.prop_id = ev.prop_id; + event.type = ev.has_lease ? + WLR_DEVICE_LEASE : WLR_DEVICE_HOTPLUG; wl_signal_emit_mutable(&dev->events.change, &event); break; } } - } else if (strcmp(action, "remove") == 0) { - struct wlr_device *dev; + break; + case DRM_EVENT_ACTION_REMOVE: wl_list_for_each(dev, &session->devices, link) { - if (dev->dev == devnum) { - wlr_log(WLR_DEBUG, "DRM device %s removed", sysname); + if (dev->dev == ev.devnum) { + wlr_log(WLR_DEBUG, "DRM device %s removed", ev.devnode); wl_signal_emit_mutable(&dev->events.remove, NULL); break; } } + break; + case DRM_EVENT_ACTION_NONE: + wlr_log(WLR_DEBUG, "Unknown device event"); + break; } - -out: - udev_device_unref(udev_dev); return 1; } @@ -266,27 +237,17 @@ struct wlr_session *wlr_session_create(struct wl_event_loop *event_loop) { goto error_open; } - session->udev = udev_new(); - if (!session->udev) { - wlr_log_errno(WLR_ERROR, "Failed to create udev context"); + int fd = -1; + session->drm_handle = monitor_drm_events(&fd); + if (!session->drm_handle) { + wlr_log(WLR_ERROR, "Failed to create device monitor context"); goto error_session; } - session->mon = udev_monitor_new_from_netlink(session->udev, "udev"); - if (!session->mon) { - wlr_log_errno(WLR_ERROR, "Failed to create udev monitor"); - goto error_udev; - } - - udev_monitor_filter_add_match_subsystem_devtype(session->mon, "drm", NULL); - udev_monitor_enable_receiving(session->mon); - - int fd = udev_monitor_get_fd(session->mon); - - session->udev_event = wl_event_loop_add_fd(event_loop, fd, - WL_EVENT_READABLE, handle_udev_event, session); - if (!session->udev_event) { - wlr_log_errno(WLR_ERROR, "Failed to create udev event source"); + session->drm_event = wl_event_loop_add_fd(event_loop, fd, + WL_EVENT_READABLE, handle_device_event, session); + if (!session->drm_event) { + wlr_log_errno(WLR_ERROR, "Failed to create device event source"); goto error_mon; } @@ -296,9 +257,7 @@ struct wlr_session *wlr_session_create(struct wl_event_loop *event_loop) { return session; error_mon: - udev_monitor_unref(session->mon); -error_udev: - udev_unref(session->udev); + drm_event_monitor_free(session->drm_handle); error_session: libseat_session_finish(session); error_open: @@ -319,9 +278,8 @@ void wlr_session_destroy(struct wlr_session *session) { wl_list_remove(&session->event_loop_destroy.link); - wl_event_source_remove(session->udev_event); - udev_monitor_unref(session->mon); - udev_unref(session->udev); + wl_event_source_remove(session->drm_event); + drm_event_monitor_free(session->drm_handle); struct wlr_device *dev, *tmp_dev; wl_list_for_each_safe(dev, tmp_dev, &session->devices, link) { @@ -443,25 +401,6 @@ static ssize_t explicit_find_gpus(struct wlr_session *session, return i; } -static struct udev_enumerate *enumerate_drm_cards(struct udev *udev) { - struct udev_enumerate *en = udev_enumerate_new(udev); - if (!en) { - wlr_log(WLR_ERROR, "udev_enumerate_new failed"); - return NULL; - } - - udev_enumerate_add_match_subsystem(en, "drm"); - udev_enumerate_add_match_sysname(en, DRM_PRIMARY_MINOR_NAME "[0-9]*"); - - if (udev_enumerate_scan_devices(en) != 0) { - wlr_log(WLR_ERROR, "udev_enumerate_scan_devices failed"); - udev_enumerate_unref(en); - return NULL; - } - - return en; -} - struct find_gpus_add_handler { bool added; struct wl_listener listener; @@ -481,14 +420,13 @@ ssize_t wlr_session_find_gpus(struct wlr_session *session, return explicit_find_gpus(session, ret_len, ret, explicit); } - struct udev_enumerate *en = enumerate_drm_cards(session->udev); - if (!en) { + static const char *node_glob = DRM_DIR_NAME "/" DRM_PRIMARY_MINOR_NAME "[0-9]*"; + glob_t gl; + if (glob(node_glob, 0, NULL, &gl) != 0) { return -1; } - - if (udev_enumerate_get_list_entry(en) == NULL) { - udev_enumerate_unref(en); - en = NULL; + if (gl.gl_pathc == 0) { + globfree(&gl); wlr_log(WLR_INFO, "Waiting for a KMS device"); struct find_gpus_add_handler handler = {0}; @@ -513,71 +451,39 @@ ssize_t wlr_session_find_gpus(struct wlr_session *session, } wl_list_remove(&handler.listener.link); - - en = enumerate_drm_cards(session->udev); - if (!en) { + if (glob(node_glob, 0, NULL, &gl) != 0) { return -1; } } - struct udev_list_entry *entry; - size_t i = 0; - - udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(en)) { - if (i == ret_len) { - break; - } - - const char *path = udev_list_entry_get_name(entry); - struct udev_device *dev = udev_device_new_from_syspath(session->udev, path); - if (!dev) { - continue; - } - - const char *seat = udev_device_get_property_value(dev, "ID_SEAT"); + size_t ret_num = 0; + for (size_t i = 0; i < gl.gl_pathc && ret_num < ret_len; i++) { + const char *devnode = gl.gl_pathv[i]; + const char *seat = get_device_seat(session->drm_handle, devnode); if (!seat) { seat = "seat0"; } if (session->seat[0] && strcmp(session->seat, seat) != 0) { - udev_device_unref(dev); continue; } - bool is_primary = false; - const char *boot_display = udev_device_get_sysattr_value(dev, "boot_display"); - if (boot_display && strcmp(boot_display, "1") == 0) { - is_primary = true; - } else { - // This is owned by 'dev', so we don't need to free it - struct udev_device *pci = - udev_device_get_parent_with_subsystem_devtype(dev, "pci", NULL); - - if (pci) { - const char *id = udev_device_get_sysattr_value(pci, "boot_vga"); - if (id && strcmp(id, "1") == 0) { - is_primary = true; - } - } - } - + bool is_primary = is_drm_device_primary(session->drm_handle, devnode); struct wlr_device *wlr_dev = - session_open_if_kms(session, udev_device_get_devnode(dev)); - udev_device_unref(dev); + session_open_if_kms(session, devnode); if (!wlr_dev) { continue; } - ret[i] = wlr_dev; + ret[ret_num] = wlr_dev; if (is_primary) { struct wlr_device *tmp = ret[0]; - ret[0] = ret[i]; - ret[i] = tmp; + ret[0] = ret[ret_num]; + ret[ret_num] = tmp; } - ++i; + ++ret_num; } - udev_enumerate_unref(en); - - return i; + globfree(&gl); + return ret_num; } diff --git a/backend/session/session_libudev.c b/backend/session/session_libudev.c new file mode 100644 index 000000000..19b559203 --- /dev/null +++ b/backend/session/session_libudev.c @@ -0,0 +1,147 @@ +#include +#include +#include +#include +#include +#include +#include +#include "backend/session/session.h" + +struct drm_event_monitor { + struct udev *udev; + struct udev_monitor *mon; +}; + +struct drm_event_monitor *monitor_drm_events(int *fd) { + struct drm_event_monitor *ctx = calloc(1, sizeof(*ctx)); + if (!ctx) { + return NULL; + } + ctx->udev = udev_new(); + if (!ctx->udev) { + free(ctx); + return NULL; + } + ctx->mon = udev_monitor_new_from_netlink(ctx->udev, "udev"); + if (!ctx->mon) { + udev_unref(ctx->udev); + free(ctx); + return NULL; + } + udev_monitor_filter_add_match_subsystem_devtype(ctx->mon, "drm", NULL); + udev_monitor_enable_receiving(ctx->mon); + *fd = udev_monitor_get_fd(ctx->mon); + return ctx; +} + +void drm_event_monitor_free(struct drm_event_monitor *ctx) { + udev_monitor_unref(ctx->mon); + udev_unref(ctx->udev); + free(ctx); +} + +static void populate_drm_event(struct drm_event_content *ev, + struct udev_device *dev) { + memset(ev, 0, sizeof(*ev)); + + const char *devnode = udev_device_get_devnode(dev); + if (devnode) { + int len = snprintf(ev->devnode, sizeof(ev->devnode), "%s", devnode); + assert((size_t)len < sizeof(ev->devnode)); + } + ev->devnum = udev_device_get_devnum(dev); + + const char *action = udev_device_get_action(dev); + if (strcmp(action, "add") == 0) { + ev->type = DRM_EVENT_ACTION_ADD; + } else if (strcmp(action, "change") == 0) { + ev->type = DRM_EVENT_ACTION_CHANGE; + } else if (strcmp(action, "remove") == 0) { + ev->type = DRM_EVENT_ACTION_REMOVE; + } + + const char *hotplug = udev_device_get_property_value(dev, "HOTPLUG"); + if (hotplug != NULL && strcmp(hotplug, "1") == 0) { + ev->has_lease = false; + + const char *connector = + udev_device_get_property_value(dev, "CONNECTOR"); + if (connector != NULL) { + ev->conn_id = strtoul(connector, NULL, 10); + } + + const char *prop = + udev_device_get_property_value(dev, "PROPERTY"); + if (prop != NULL) { + ev->prop_id = strtoul(prop, NULL, 10); + } + + return; + } + + const char *lease = udev_device_get_property_value(dev, "LEASE"); + if (lease != NULL && strcmp(lease, "1") == 0) { + ev->has_lease = true; + } +} + +int receive_drm_device(struct drm_event_monitor *ctx, + struct drm_event_content *ev) { + struct udev_device *dev = udev_monitor_receive_device(ctx->mon); + if (!dev) { + return -1; + } + populate_drm_event(ev, dev); + udev_device_unref(dev); + return 0; +} + +static struct udev_device *get_udev_device_from_devnode(struct udev *udev, + const char *devnode) { + const char *sysname = strrchr(devnode, '/'); + if (!sysname) { + return NULL; + } + sysname += 1; + struct udev_device *dev = + udev_device_new_from_subsystem_sysname(udev, "drm", sysname); + if (!dev) { + return NULL; + } + return dev; +} + +// XXX: move it to libseat? +const char *get_device_seat(struct drm_event_monitor *ctx, const char *devnode) { + struct udev_device *dev = get_udev_device_from_devnode(ctx->udev, devnode); + if (!dev) { + return NULL; + } + const char *seat = udev_device_get_property_value(dev, "ID_SEAT"); + udev_device_unref(dev); + return seat; +} + +// XXX: use sysfs directly? +bool is_drm_device_primary(struct drm_event_monitor *ctx, const char *devnode) { + struct udev_device *dev = get_udev_device_from_devnode(ctx->udev, devnode); + if (!dev) { + return false; + } + const char *boot_display = udev_device_get_sysattr_value(dev, "boot_display"); + if (boot_display && strcmp(boot_display, "1") == 0) { + udev_device_unref(dev); + return true; + } + // This is owned by 'dev', so we don't need to free it + struct udev_device *pci = + udev_device_get_parent_with_subsystem_devtype(dev, "pci", NULL); + if (!pci) { + udev_device_unref(dev); + return false; + } + const char *id = udev_device_get_sysattr_value(pci, "boot_vga"); + bool primary = id && strcmp(id, "1") == 0; + udev_device_unref(dev); + return primary; +} diff --git a/backend/session/session_openbsd.c b/backend/session/session_openbsd.c new file mode 100644 index 000000000..282b95aa3 --- /dev/null +++ b/backend/session/session_openbsd.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include +#include "backend/session/session.h" + +struct drm_event_monitor { + int fd; +}; + +// TODO: use kqueue NOTE_CHANGE mechanism +struct drm_event_monitor *monitor_drm_events(int *fd) { + struct drm_event_monitor *ctx = calloc(1, sizeof(struct drm_event_monitor)); + if (!ctx) { + return NULL; + } + ctx->fd = open("/dev/null", O_RDONLY); + if (ctx->fd == -1) { + free(ctx); + return NULL; + } + *fd = ctx->fd; + return ctx; +} +void drm_event_monitor_free(struct drm_event_monitor *ctx) { + close(ctx->fd); + free(ctx); +} + +int receive_drm_device(struct drm_event_monitor *ctx, + struct drm_event_content *ev) { + return -1; +} + +const char *get_device_seat(struct drm_event_monitor *ctx, const char *devnode) { + return NULL; +} + +bool is_drm_device_primary(struct drm_event_monitor *ctx, const char *devnode) { + return false; +} diff --git a/backend/wscons/atKeynames.h b/backend/wscons/atKeynames.h new file mode 100644 index 000000000..2ce8b1fd6 --- /dev/null +++ b/backend/wscons/atKeynames.h @@ -0,0 +1,281 @@ +/* + * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Thomas Roell not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Thomas Roell makes no representations + * about the suitability of this software for any purpose. It is provided + * "as is" without express or implied warranty. + * + * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THOMAS ROELL BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + */ +/* + * Copyright (c) 1994-2003 by The XFree86 Project, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + +#ifndef _ATKEYNAMES_H +#define _ATKEYNAMES_H + +#define XK_TECHNICAL +#define XK_KATAKANA + +/* + * NOTE: The AT/MF keyboards can generate (via the 8042) two (MF: three) + * sets of scancodes. Set3 can only be generated by a MF keyboard. + * Set2 sends a makecode for keypress, and the same code prefixed by a + * F0 for keyrelease. This is a little bit ugly to handle. Thus we use + * here for X386 the PC/XT compatible Set1. This set uses 8bit scancodes. + * Bit 7 ist set if the key is released. The code E0 switches to a + * different meaning to add the new MF cursorkeys, while not breaking old + * applications. E1 is another special prefix. Since I assume that there + * will be further versions of PC/XT scancode compatible keyboards, we + * may be in trouble one day. + * + * IDEA: 1) Use Set2 on AT84 keyboards and translate it to MF Set3. + * 2) Use the keyboards native set and translate it to common keysyms. + */ + +/* + * definition of the AT84/MF101/MF102 Keyboard: + * ============================================================ + * Defined Key Cap Glyphs Pressed value + * Key Name Main Also (hex) (dec) + * ---------------- ---------- ------- ------ ------ + */ + +#define KEY_Escape /* Escape 0x01 */ 1 +#define KEY_1 /* 1 ! 0x02 */ 2 +#define KEY_2 /* 2 @ 0x03 */ 3 +#define KEY_3 /* 3 # 0x04 */ 4 +#define KEY_4 /* 4 $ 0x05 */ 5 +#define KEY_5 /* 5 % 0x06 */ 6 +#define KEY_6 /* 6 ^ 0x07 */ 7 +#define KEY_7 /* 7 & 0x08 */ 8 +#define KEY_8 /* 8 * 0x09 */ 9 +#define KEY_9 /* 9 ( 0x0a */ 10 +#define KEY_0 /* 0 ) 0x0b */ 11 +#define KEY_Minus /* - (Minus) _ (Under) 0x0c */ 12 +#define KEY_Equal /* = (Equal) + 0x0d */ 13 +#define KEY_BackSpace /* Back Space 0x0e */ 14 +#define KEY_Tab /* Tab 0x0f */ 15 +#define KEY_Q /* Q 0x10 */ 16 +#define KEY_W /* W 0x11 */ 17 +#define KEY_E /* E 0x12 */ 18 +#define KEY_R /* R 0x13 */ 19 +#define KEY_T /* T 0x14 */ 20 +#define KEY_Y /* Y 0x15 */ 21 +#define KEY_U /* U 0x16 */ 22 +#define KEY_I /* I 0x17 */ 23 +#define KEY_O /* O 0x18 */ 24 +#define KEY_P /* P 0x19 */ 25 +#define KEY_LBrace /* [ { 0x1a */ 26 +#define KEY_RBrace /* ] } 0x1b */ 27 +#define KEY_Enter /* Enter 0x1c */ 28 +#define KEY_LCtrl /* Ctrl(left) 0x1d */ 29 +#define KEY_A /* A 0x1e */ 30 +#define KEY_S /* S 0x1f */ 31 +#define KEY_D /* D 0x20 */ 32 +#define KEY_F /* F 0x21 */ 33 +#define KEY_G /* G 0x22 */ 34 +#define KEY_H /* H 0x23 */ 35 +#define KEY_J /* J 0x24 */ 36 +#define KEY_K /* K 0x25 */ 37 +#define KEY_L /* L 0x26 */ 38 +#define KEY_SemiColon /* ;(SemiColon) :(Colon) 0x27 */ 39 +#define KEY_Quote /* ' (Apostr) " (Quote) 0x28 */ 40 +#define KEY_Tilde /* ` (Accent) ~ (Tilde) 0x29 */ 41 +#define KEY_ShiftL /* Shift(left) 0x2a */ 42 +#define KEY_BSlash /* \(BckSlash) |(VertBar)0x2b */ 43 +#define KEY_Z /* Z 0x2c */ 44 +#define KEY_X /* X 0x2d */ 45 +#define KEY_C /* C 0x2e */ 46 +#define KEY_V /* V 0x2f */ 47 +#define KEY_B /* B 0x30 */ 48 +#define KEY_N /* N 0x31 */ 49 +#define KEY_M /* M 0x32 */ 50 +#define KEY_Comma /* , (Comma) < (Less) 0x33 */ 51 +#define KEY_Period /* . (Period) >(Greater)0x34 */ 52 +#define KEY_Slash /* / (Slash) ? 0x35 */ 53 +#define KEY_ShiftR /* Shift(right) 0x36 */ 54 +#define KEY_KP_Multiply /* * 0x37 */ 55 +#define KEY_Alt /* Alt(left) 0x38 */ 56 +#define KEY_Space /* (SpaceBar) 0x39 */ 57 +#define KEY_CapsLock /* CapsLock 0x3a */ 58 +#define KEY_F1 /* F1 0x3b */ 59 +#define KEY_F2 /* F2 0x3c */ 60 +#define KEY_F3 /* F3 0x3d */ 61 +#define KEY_F4 /* F4 0x3e */ 62 +#define KEY_F5 /* F5 0x3f */ 63 +#define KEY_F6 /* F6 0x40 */ 64 +#define KEY_F7 /* F7 0x41 */ 65 +#define KEY_F8 /* F8 0x42 */ 66 +#define KEY_F9 /* F9 0x43 */ 67 +#define KEY_F10 /* F10 0x44 */ 68 +#define KEY_NumLock /* NumLock 0x45 */ 69 +#define KEY_ScrollLock /* ScrollLock 0x46 */ 70 +#define KEY_KP_7 /* 7 Home 0x47 */ 71 +#define KEY_KP_8 /* 8 Up 0x48 */ 72 +#define KEY_KP_9 /* 9 PgUp 0x49 */ 73 +#define KEY_KP_Minus /* - (Minus) 0x4a */ 74 +#define KEY_KP_4 /* 4 Left 0x4b */ 75 +#define KEY_KP_5 /* 5 0x4c */ 76 +#define KEY_KP_6 /* 6 Right 0x4d */ 77 +#define KEY_KP_Plus /* + (Plus) 0x4e */ 78 +#define KEY_KP_1 /* 1 End 0x4f */ 79 +#define KEY_KP_2 /* 2 Down 0x50 */ 80 +#define KEY_KP_3 /* 3 PgDown 0x51 */ 81 +#define KEY_KP_0 /* 0 Insert 0x52 */ 82 +#define KEY_KP_Decimal /* . (Decimal) Delete 0x53 */ 83 +#define KEY_SysReqest /* SysReqest 0x54 */ 84 + /* NOTUSED 0x55 */ +#define KEY_Less /* < (Less) >(Greater) 0x56 */ 86 +#define KEY_F11 /* F11 0x57 */ 87 +#define KEY_F12 /* F12 0x58 */ 88 + +#define KEY_Prefix0 /* special 0x60 */ 96 +#define KEY_Prefix1 /* specail 0x61 */ 97 + +/* + * The 'scancodes' below are generated by the server, because the MF101/102 + * keyboard sends them as sequence of other scancodes + */ +#define KEY_Home /* Home 0x59 */ 89 +#define KEY_Up /* Up 0x5a */ 90 +#define KEY_PgUp /* PgUp 0x5b */ 91 +#define KEY_Left /* Left 0x5c */ 92 +#define KEY_Begin /* Begin 0x5d */ 93 +#define KEY_Right /* Right 0x5e */ 94 +#define KEY_End /* End 0x5f */ 95 +#define KEY_Down /* Down 0x60 */ 96 +#define KEY_PgDown /* PgDown 0x61 */ 97 +#define KEY_Insert /* Insert 0x62 */ 98 +#define KEY_Delete /* Delete 0x63 */ 99 +#define KEY_KP_Enter /* Enter 0x64 */ 100 +#define KEY_RCtrl /* Ctrl(right) 0x65 */ 101 +#define KEY_Pause /* Pause 0x66 */ 102 +#define KEY_Print /* Print 0x67 */ 103 +#define KEY_KP_Divide /* Divide 0x68 */ 104 +#define KEY_AltLang /* AtlLang(right) 0x69 */ 105 +#define KEY_Break /* Break 0x6a */ 106 +#define KEY_LMeta /* Left Meta 0x6b */ 107 +#define KEY_RMeta /* Right Meta 0x6c */ 108 +#define KEY_Menu /* Menu 0x6d */ 109 +#define KEY_F13 /* F13 0x6e */ 110 +#define KEY_F14 /* F14 0x6f */ 111 +#define KEY_F15 /* F15 0x70 */ 112 +#define KEY_HKTG /* Hirugana/Katakana tog 0x70 */ 112 +#define KEY_F16 /* F16 0x71 */ 113 +#define KEY_F17 /* F17 0x72 */ 114 +#define KEY_KP_DEC /* KP_DEC 0x73 */ 115 +#define KEY_BSlash2 /* \ _ 0x73 */ 115 +#define KEY_KP_Equal /* Equal (Keypad) 0x76 */ 118 +#define KEY_XFER /* Kanji Transfer 0x79 */ 121 +#define KEY_NFER /* No Kanji Transfer 0x7b */ 123 +#define KEY_Yen /* Yen 0x7d */ 125 + +#define KEY_Power /* Power Key 0x84 */ 132 +#define KEY_Mute /* Audio Mute 0x85 */ 133 +#define KEY_AudioLower /* Audio Lower 0x86 */ 134 +#define KEY_AudioRaise /* Audio Raise 0x87 */ 135 +#define KEY_Help /* Help 0x88 */ 136 +#define KEY_L1 /* Stop 0x89 */ 137 +#define KEY_L2 /* Again 0x8a */ 138 +#define KEY_L3 /* Props 0x8b */ 139 +#define KEY_L4 /* Undo 0x8c */ 140 +#define KEY_L5 /* Front 0x8d */ 141 +#define KEY_L6 /* Copy 0x8e */ 142 +#define KEY_L7 /* Open 0x8f */ 143 +#define KEY_L8 /* Paste 0x90 */ 144 +#define KEY_L9 /* Find 0x91 */ 145 +#define KEY_L10 /* Cut 0x92 */ 146 + +/* + * Fake 'scancodes' in the following ranges are generated for 2-byte + * codes not handled elsewhere. These correspond to most extended keys + * on so-called "Internet" keyboards: + * + * 0x79-0x93 + * 0x96-0xa1 + * 0xa3-0xac + * 0xb1-0xb4 + * 0xba-0xbd + * 0xc2 + * 0xcc-0xd2 + * 0xd6-0xf7 + */ + +/* + * Remapped 'scancodes' are generated for single-byte codes in the range + * 0x59-0x5f,0x62-0x76. These are used for some extra keys on some keyboards. + */ + +#define KEY_0x59 0x95 +#define KEY_0x5A 0xA2 +#define KEY_0x5B 0xAD +#define KEY_0x5C KEY_KP_EQUAL +#define KEY_0x5D 0xAE +#define KEY_0x5E 0xAF +#define KEY_0x5F 0xB0 +#define KEY_0x62 0xB5 +#define KEY_0x63 0xB6 +#define KEY_0x64 0xB7 +#define KEY_0x65 0xB8 +#define KEY_0x66 0xB9 +#define KEY_0x67 0xBE +#define KEY_0x68 0xBF +#define KEY_0x69 0xC0 +#define KEY_0x6A 0xC1 +#define KEY_0x6B 0xC3 +#define KEY_0x6C 0xC4 +#define KEY_0x6D 0xC5 +#define KEY_0x6E 0xC6 +#define KEY_0x6F 0xC7 +#define KEY_0x70 0xC8 +#define KEY_0x71 0xC9 +#define KEY_0x72 0xCA +#define KEY_0x73 0xCB +#define KEY_0x74 0xD3 +#define KEY_0x75 0xD4 +#define KEY_0x76 0xD5 +#define KEY_R_0xF4 0xF4 +#define KEY_R_0xF5 0xF5 + +/* These are for "notused" and "unknown" entries in translation maps. */ +#define KEY_NOTUSED 0 +#define KEY_UNKNOWN 255 + +#endif /* _ATKEYNAMES_H */ diff --git a/backend/wscons/backend.c b/backend/wscons/backend.c new file mode 100644 index 000000000..63a850df4 --- /dev/null +++ b/backend/wscons/backend.c @@ -0,0 +1,332 @@ +#define _BSD_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "backend/wscons.h" +#include "util/time.h" + +#include "atKeynames.h" +#include "bsd_KbdMap.h" + +static struct wlr_wscons_backend *get_wscons_backend_from_backend( + struct wlr_backend *wlr_backend) { + assert(wlr_backend_is_wscons(wlr_backend)); + struct wlr_wscons_backend *backend = wl_container_of(wlr_backend, backend, backend); + return backend; +} + +static int ws_to_xkb(unsigned type, int key) { + switch (type) { + case WSKBD_TYPE_PC_XT: + case WSKBD_TYPE_PC_AT: + return wsXtMap[key]; + case WSKBD_TYPE_USB: + return wsUsbMap[key]; + default: + wlr_log(WLR_INFO, "Unknown wskbd type %d", type); + return key; + } +} + +static int wsmouse_to_evdev(int button) { + // The right and middle mouse buttons must be swapped + switch (button) { + case 1: // Middle + return 0x112; + case 2: // Right + return 0x111; + default: + return button + 0x110; + } +} + +static void notify_key(struct wlr_keyboard *wlr_kbd, uint32_t msec, + uint32_t state, uint32_t keycode) { + struct wlr_keyboard_key_event ev; + ev.update_state = true; + ev.time_msec = msec; + ev.state = state; + ev.keycode = keycode; + + wlr_keyboard_notify_key(wlr_kbd, &ev); +} + +static void notify_button(struct wlr_pointer *wlr_ptr, uint32_t msec, + uint32_t state, uint32_t button) { + struct wlr_pointer_button_event ev; + ev.pointer = wlr_ptr; + ev.time_msec = msec; + ev.button = button; + ev.state = state; + + wlr_pointer_notify_button(wlr_ptr, &ev); + wl_signal_emit_mutable(&wlr_ptr->events.frame, wlr_ptr); +} + +static void notify_motion(struct wlr_pointer *wlr_ptr, uint32_t msec, + double x, double y) { + struct wlr_pointer_motion_event ev; + ev.pointer = wlr_ptr; + ev.time_msec = msec; + ev.delta_x = x; + ev.delta_y = y; + ev.unaccel_dx = x; + ev.unaccel_dy = y; + + wl_signal_emit_mutable(&wlr_ptr->events.motion, &ev); + wl_signal_emit_mutable(&wlr_ptr->events.frame, wlr_ptr); +} + +static void notify_axis(struct wlr_pointer *wlr_ptr, uint32_t msec, + uint32_t axis, double delta) { + struct wlr_pointer_axis_event ev; + ev.pointer = wlr_ptr; + ev.time_msec = msec; + ev.source = WL_POINTER_AXIS_SOURCE_WHEEL; + ev.relative_direction = WL_POINTER_AXIS_RELATIVE_DIRECTION_IDENTICAL; + ev.delta_discrete = 0; // XXX + ev.orientation = axis; + ev.delta = delta; + + wl_signal_emit_mutable(&wlr_ptr->events.axis, &ev); + wl_signal_emit_mutable(&wlr_ptr->events.frame, wlr_ptr); +} + +static void notify_motion_abs(struct wlr_pointer *wlr_ptr, uint32_t msec, + double x, double y) { + struct wlr_pointer_motion_absolute_event ev; + ev.pointer = wlr_ptr; + ev.time_msec = msec; + ev.x = x; + ev.y = y; + + wl_signal_emit_mutable(&wlr_ptr->events.motion_absolute, &ev); + wl_signal_emit_mutable(&wlr_ptr->events.frame, wlr_ptr); +} + +static void handle_event(struct wlr_wscons_backend *backend, struct wscons_event *ws_ev) { + struct wlr_keyboard *wlr_kbd = &backend->kbd; + struct wlr_pointer *wlr_ptr = &backend->mouse; + + uint32_t msec = timespec_to_msec(&ws_ev->time); + // TODO: make sure all types are handled + switch (ws_ev->type) { + case WSCONS_EVENT_KEY_UP: + notify_key(wlr_kbd, msec, WL_KEYBOARD_KEY_STATE_RELEASED, + ws_to_xkb(backend->kbd_type, ws_ev->value)); + break; + case WSCONS_EVENT_KEY_DOWN: + notify_key(wlr_kbd, msec, WL_KEYBOARD_KEY_STATE_PRESSED, + ws_to_xkb(backend->kbd_type, ws_ev->value)); + break; + case WSCONS_EVENT_MOUSE_UP: + notify_button(wlr_ptr, msec, WL_POINTER_BUTTON_STATE_RELEASED, + wsmouse_to_evdev(ws_ev->value)); + break; + case WSCONS_EVENT_MOUSE_DOWN: + notify_button(wlr_ptr, msec, WL_POINTER_BUTTON_STATE_PRESSED, + wsmouse_to_evdev(ws_ev->value)); + break; + case WSCONS_EVENT_MOUSE_DELTA_X: + notify_motion(wlr_ptr, msec, ws_ev->value, 0); + break; + case WSCONS_EVENT_MOUSE_DELTA_Y: + notify_motion(wlr_ptr, msec, 0, -ws_ev->value); + break; + case WSCONS_EVENT_MOUSE_DELTA_Z: + notify_axis(wlr_ptr, msec, WL_POINTER_AXIS_VERTICAL_SCROLL, + ws_ev->value * 10); + break; + case WSCONS_EVENT_MOUSE_DELTA_W: + notify_axis(wlr_ptr, msec, WL_POINTER_AXIS_HORIZONTAL_SCROLL, + ws_ev->value * 10); + break; + case WSCONS_EVENT_MOUSE_ABSOLUTE_X: + notify_motion_abs(wlr_ptr, msec, ws_ev->value, 0); + break; + case WSCONS_EVENT_MOUSE_ABSOLUTE_Y: + notify_motion_abs(wlr_ptr, msec, 0, -ws_ev->value); + break; + case WSCONS_EVENT_ALL_KEYS_UP: + case WSCONS_EVENT_WSMOUSED_ON: + case WSCONS_EVENT_WSMOUSED_OFF: + break; + default: + wlr_log(WLR_DEBUG, "Unknown wscons event type: %x", ws_ev->type); + break; + } +} + +static int handle_wscons_readable(int fd, uint32_t mask, void *_backend) { + struct wlr_wscons_backend *backend = _backend; + + while (backend->session->active) { + struct kevent kq_ev; + static const struct timespec dontblock = {0}; + if (kevent(fd, NULL, 0, &kq_ev, 1, &dontblock) <= 0) { + return 0; + } + assert(kq_ev.filter == EVFILT_READ); + int in_fd = kq_ev.ident; + + struct wscons_event ws_ev; + if (read(in_fd, &ws_ev, sizeof(ws_ev)) <= 0) { + continue; + } + handle_event(backend, &ws_ev); + } + return 0; +} + +static void keyboard_set_leds(struct wlr_keyboard *wlr_kb, uint32_t leds) { + // TODO: use WSKBDIO_SETLEDS +} + +const struct wlr_keyboard_impl wscons_keyboard_impl = { + .name = "wscons-keyboard", + .led_update = keyboard_set_leds +}; + +const struct wlr_pointer_impl wscons_pointer_impl = { + .name = "wscons-pointer", +}; + +static int init_wscons(struct wlr_wscons_backend *backend) { + struct wlr_device *mouse_dev = wlr_session_open_file(backend->session, "/dev/wsmouse"); + struct wlr_device *kbd_dev = wlr_session_open_file(backend->session, "/dev/wskbd"); + if (!mouse_dev || !kbd_dev) { + wlr_log(WLR_ERROR, "Failed to open input devices"); + return -1; + } + + if (ioctl(kbd_dev->fd, WSKBDIO_GTYPE, &backend->kbd_type) == -1) { + // TODO: free + wlr_log(WLR_ERROR, "Failed to get keyboard type"); + return -1; + } + + int kfd = kqueue1(O_CLOEXEC); + if (kfd == -1) { + // TODO: free + wlr_log(WLR_ERROR, "Failed to create kqueue fd"); + return -1; + } + struct kevent evs[2]; + EV_SET(&evs[0], mouse_dev->fd, EVFILT_READ, EV_ADD, 0, 0, NULL); + EV_SET(&evs[1], kbd_dev->fd, EVFILT_READ, EV_ADD, 0, 0, NULL); + if (kevent(kfd, evs, sizeof(evs) / sizeof(evs[0]), NULL, 0, NULL) == -1) { + // TODO: free + wlr_log(WLR_ERROR, "Failed to setup kqueue"); + return -1; + } + + backend->mouse_dev = mouse_dev; + backend->kbd_dev = kbd_dev; + + struct wlr_keyboard *wlr_kbd = &backend->kbd; + wlr_keyboard_init(wlr_kbd, &wscons_keyboard_impl, "wscons-keyboard"); + wl_signal_emit_mutable(&backend->backend.events.new_input, &wlr_kbd->base); + + struct wlr_pointer *wlr_ptr = &backend->mouse; + wlr_pointer_init(wlr_ptr, &wscons_pointer_impl, "wscons-pointer"); + wl_signal_emit_mutable(&backend->backend.events.new_input, &wlr_ptr->base); + + return kfd; +} + +static bool backend_start(struct wlr_backend *wlr_backend) { + struct wlr_wscons_backend *backend = + get_wscons_backend_from_backend(wlr_backend); + wlr_log(WLR_DEBUG, "Starting wscons backend"); + + int fd = init_wscons(backend); + if (fd < 0) { + wlr_log(WLR_ERROR, "Failed to initialize wscons backend"); + return false; + } + backend->kqueue_fd = fd; + + if (backend->input_event) { + wl_event_source_remove(backend->input_event); + } + backend->input_event = wl_event_loop_add_fd(backend->session->event_loop, fd, + WL_EVENT_READABLE, handle_wscons_readable, backend); + if (!backend->input_event) { + wlr_log(WLR_ERROR, "Failed to create input event on event loop"); + return false; + } + wlr_log(WLR_DEBUG, "wscons successfully initialized"); + return true; +} + +static void backend_destroy(struct wlr_backend *wlr_backend) { + if (!wlr_backend) { + return; + } + struct wlr_wscons_backend *backend = + get_wscons_backend_from_backend(wlr_backend); + + wlr_backend_finish(wlr_backend); + + wl_list_remove(&backend->session_destroy.link); + + if (backend->input_event) { + wl_event_source_remove(backend->input_event); + } + + close(backend->kqueue_fd); + + if (backend->mouse_dev) { + wlr_session_close_file(backend->session, backend->mouse_dev); + } + if (backend->kbd_dev) { + wlr_session_close_file(backend->session, backend->kbd_dev); + } + + free(backend); +} + +static const struct wlr_backend_impl backend_impl = { + .start = backend_start, + .destroy = backend_destroy, +}; + +bool wlr_backend_is_wscons(const struct wlr_backend *b) { + return b->impl == &backend_impl; +} + +static void handle_session_destroy(struct wl_listener *listener, void *data) { + struct wlr_wscons_backend *backend = + wl_container_of(listener, backend, session_destroy); + backend_destroy(&backend->backend); +} + +struct wlr_backend *wlr_wscons_backend_create(struct wlr_session *session) { + struct wlr_wscons_backend *backend = calloc(1, sizeof(*backend)); + if (!backend) { + wlr_log(WLR_ERROR, "Allocation failed: %s", strerror(errno)); + return NULL; + } + wlr_backend_init(&backend->backend, &backend_impl); + + backend->session = session; + backend->kqueue_fd = -1; + + backend->session_destroy.notify = handle_session_destroy; + wl_signal_add(&session->events.destroy, &backend->session_destroy); + + return &backend->backend; +} diff --git a/backend/wscons/bsd_KbdMap.h b/backend/wscons/bsd_KbdMap.h new file mode 100644 index 000000000..467c5e2c5 --- /dev/null +++ b/backend/wscons/bsd_KbdMap.h @@ -0,0 +1,485 @@ +/* + * Slightly modified xf86KbdBSD.c which is + * + * Derived from xf86Kbd.c by S_ren Schmidt (sos@login.dkuug.dk) + * which is Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany. + * and from xf86KbdCODrv.c by Holger Veit + */ + +#include + +static uint8_t wsUsbMap[] = { + /* 0 */ KEY_NOTUSED, + /* 1 */ KEY_NOTUSED, + /* 2 */ KEY_NOTUSED, + /* 3 */ KEY_NOTUSED, + /* 4 */ KEY_A, + /* 5 */ KEY_B, + /* 6 */ KEY_C, + /* 7 */ KEY_D, + /* 8 */ KEY_E, + /* 9 */ KEY_F, + /* 10 */ KEY_G, + /* 11 */ KEY_H, + /* 12 */ KEY_I, + /* 13 */ KEY_J, + /* 14 */ KEY_K, + /* 15 */ KEY_L, + /* 16 */ KEY_M, + /* 17 */ KEY_N, + /* 18 */ KEY_O, + /* 19 */ KEY_P, + /* 20 */ KEY_Q, + /* 21 */ KEY_R, + /* 22 */ KEY_S, + /* 23 */ KEY_T, + /* 24 */ KEY_U, + /* 25 */ KEY_V, + /* 26 */ KEY_W, + /* 27 */ KEY_X, + /* 28 */ KEY_Y, + /* 29 */ KEY_Z, + /* 30 */ KEY_1, /* 1 !*/ + /* 31 */ KEY_2, /* 2 @ */ + /* 32 */ KEY_3, /* 3 # */ + /* 33 */ KEY_4, /* 4 $ */ + /* 34 */ KEY_5, /* 5 % */ + /* 35 */ KEY_6, /* 6 ^ */ + /* 36 */ KEY_7, /* 7 & */ + /* 37 */ KEY_8, /* 8 * */ + /* 38 */ KEY_9, /* 9 ( */ + /* 39 */ KEY_0, /* 0 ) */ + /* 40 */ KEY_Enter, /* Return */ + /* 41 */ KEY_Escape, /* Escape */ + /* 42 */ KEY_BackSpace, /* Backspace Delete */ + /* 43 */ KEY_Tab, /* Tab */ + /* 44 */ KEY_Space, /* Space */ + /* 45 */ KEY_Minus, /* - _ */ + /* 46 */ KEY_Equal, /* = + */ + /* 47 */ KEY_LBrace, /* [ { */ + /* 48 */ KEY_RBrace, /* ] } */ + /* 49 */ KEY_BSlash, /* \ | */ + /* 50 */ KEY_BSlash, /* \ _ # ~ on some keyboards */ + /* 51 */ KEY_SemiColon, /* ; : */ + /* 52 */ KEY_Quote, /* ' " */ + /* 53 */ KEY_Tilde, /* ` ~ */ + /* 54 */ KEY_Comma, /* , < */ + /* 55 */ KEY_Period, /* . > */ + /* 56 */ KEY_Slash, /* / ? */ + /* 57 */ KEY_CapsLock, /* Caps Lock */ + /* 58 */ KEY_F1, /* F1 */ + /* 59 */ KEY_F2, /* F2 */ + /* 60 */ KEY_F3, /* F3 */ + /* 61 */ KEY_F4, /* F4 */ + /* 62 */ KEY_F5, /* F5 */ + /* 63 */ KEY_F6, /* F6 */ + /* 64 */ KEY_F7, /* F7 */ + /* 65 */ KEY_F8, /* F8 */ + /* 66 */ KEY_F9, /* F9 */ + /* 67 */ KEY_F10, /* F10 */ + /* 68 */ KEY_F11, /* F11 */ + /* 69 */ KEY_F12, /* F12 */ + /* 70 */ KEY_Print, /* PrintScrn SysReq */ + /* 71 */ KEY_ScrollLock, /* Scroll Lock */ + /* 72 */ KEY_Pause, /* Pause Break */ + /* 73 */ KEY_Insert, /* Insert XXX Help on some Mac Keyboards */ + /* 74 */ KEY_Home, /* Home */ + /* 75 */ KEY_PgUp, /* Page Up */ + /* 76 */ KEY_Delete, /* Delete */ + /* 77 */ KEY_End, /* End */ + /* 78 */ KEY_PgDown, /* Page Down */ + /* 79 */ KEY_Right, /* Right Arrow */ + /* 80 */ KEY_Left, /* Left Arrow */ + /* 81 */ KEY_Down, /* Down Arrow */ + /* 82 */ KEY_Up, /* Up Arrow */ + /* 83 */ KEY_NumLock, /* Num Lock */ + /* 84 */ KEY_KP_Divide, /* Keypad / */ + /* 85 */ KEY_KP_Multiply, /* Keypad * */ + /* 86 */ KEY_KP_Minus, /* Keypad - */ + /* 87 */ KEY_KP_Plus, /* Keypad + */ + /* 88 */ KEY_KP_Enter, /* Keypad Enter */ + /* 89 */ KEY_KP_1, /* Keypad 1 End */ + /* 90 */ KEY_KP_2, /* Keypad 2 Down */ + /* 91 */ KEY_KP_3, /* Keypad 3 Pg Down */ + /* 92 */ KEY_KP_4, /* Keypad 4 Left */ + /* 93 */ KEY_KP_5, /* Keypad 5 */ + /* 94 */ KEY_KP_6, /* Keypad 6 */ + /* 95 */ KEY_KP_7, /* Keypad 7 Home */ + /* 96 */ KEY_KP_8, /* Keypad 8 Up */ + /* 97 */ KEY_KP_9, /* KEypad 9 Pg Up */ + /* 98 */ KEY_KP_0, /* Keypad 0 Ins */ + /* 99 */ KEY_KP_Decimal, /* Keypad . Del */ + /* 100 */ KEY_Less, /* < > on some keyboards */ + /* 101 */ KEY_Menu, /* Menu */ + /* 102 */ KEY_Power, /* sleep key on Sun USB */ + /* 103 */ KEY_KP_Equal, /* Keypad = on Mac keyboards */ + /* 104 */ KEY_F13, + /* 105 */ KEY_F14, + /* 106 */ KEY_F15, + /* 107 */ KEY_F16, + /* 108 */ KEY_NOTUSED, + /* 109 */ KEY_Power, + /* 110 */ KEY_NOTUSED, + /* 111 */ KEY_NOTUSED, + /* 112 */ KEY_NOTUSED, + /* 113 */ KEY_NOTUSED, + /* 114 */ KEY_NOTUSED, + /* 115 */ KEY_NOTUSED, + /* 116 */ KEY_L7, + /* 117 */ KEY_Help, + /* 118 */ KEY_L3, + /* 119 */ KEY_L5, + /* 120 */ KEY_L1, + /* 121 */ KEY_L2, + /* 122 */ KEY_L4, + /* 123 */ KEY_L10, + /* 124 */ KEY_L6, + /* 125 */ KEY_L8, + /* 126 */ KEY_L9, + /* 127 */ KEY_Mute, + /* 128 */ KEY_AudioRaise, + /* 129 */ KEY_AudioLower, + /* 130 */ KEY_NOTUSED, + /* 131 */ KEY_NOTUSED, + /* 132 */ KEY_NOTUSED, + /* 133 */ KEY_NOTUSED, + /* 134 */ KEY_NOTUSED, +/* + * Special keycodes for Japanese keyboards + * Override atKeyname HKTG and BSlash2 code to unique values for JP106 keyboards + */ +#undef KEY_HKTG +#define KEY_HKTG 200 /* Japanese Hiragana Katakana Toggle */ +#undef KEY_BSlash2 +#define KEY_BSlash2 203 /* Japanese '\_' key */ + + /* 135 */ KEY_BSlash2, /* Japanese 106 kbd: '\_' */ + /* 136 */ KEY_HKTG, /* Japanese 106 kbd: Hiragana Katakana toggle */ + /* 137 */ KEY_Yen, /* Japanese 106 kbd: '\|' */ + /* 138 */ KEY_XFER, /* Japanese 106 kbd: Henkan */ + /* 139 */ KEY_NFER, /* Japanese 106 kbd: Muhenkan */ + /* 140 */ KEY_NOTUSED, + /* 141 */ KEY_NOTUSED, + /* 142 */ KEY_NOTUSED, + /* 143 */ KEY_NOTUSED, +/* + * Special keycodes for Korean keyboards + * Define Hangul and Hangul_Hanja unique key codes + * These keys also use KANA and EISU on some Macintosh Japanese USB keyboards + */ +#define KEY_Hangul 201 /* Also KANA Key on Mac JP USB kbd */ +#define KEY_Hangul_Hanja 202 /* Also EISU Key on Mac JP USB kbd */ + /* 144 */ KEY_Hangul, /* Korean 106 kbd: Hangul */ + /* 145 */ KEY_Hangul_Hanja, /* Korean 106 kbd: Hangul Hanja */ + /* 146 */ KEY_NOTUSED, + /* 147 */ KEY_NOTUSED, + /* 148 */ KEY_NOTUSED, + /* 149 */ KEY_NOTUSED, + /* 150 */ KEY_NOTUSED, + /* 151 */ KEY_NOTUSED, + /* 152 */ KEY_NOTUSED, + /* 153 */ KEY_NOTUSED, + /* 154 */ KEY_NOTUSED, + /* 155 */ KEY_NOTUSED, + /* 156 */ KEY_NOTUSED, + /* 157 */ KEY_NOTUSED, + /* 158 */ KEY_NOTUSED, + /* 159 */ KEY_NOTUSED, + /* 160 */ KEY_NOTUSED, + /* 161 */ KEY_NOTUSED, + /* 162 */ KEY_NOTUSED, + /* 163 */ KEY_NOTUSED, + /* 164 */ KEY_NOTUSED, + /* 165 */ KEY_NOTUSED, + /* 166 */ KEY_NOTUSED, + /* 167 */ KEY_NOTUSED, + /* 168 */ KEY_NOTUSED, + /* 169 */ KEY_NOTUSED, + /* 170 */ KEY_NOTUSED, + /* 171 */ KEY_NOTUSED, + /* 172 */ KEY_NOTUSED, + /* 173 */ KEY_NOTUSED, + /* 174 */ KEY_NOTUSED, + /* 175 */ KEY_NOTUSED, + /* 176 */ KEY_NOTUSED, + /* 177 */ KEY_NOTUSED, + /* 178 */ KEY_NOTUSED, + /* 179 */ KEY_NOTUSED, + /* 180 */ KEY_NOTUSED, + /* 181 */ KEY_NOTUSED, + /* 182 */ KEY_NOTUSED, + /* 183 */ KEY_NOTUSED, + /* 184 */ KEY_NOTUSED, + /* 185 */ KEY_NOTUSED, + /* 186 */ KEY_NOTUSED, + /* 187 */ KEY_NOTUSED, + /* 188 */ KEY_NOTUSED, + /* 189 */ KEY_NOTUSED, + /* 190 */ KEY_NOTUSED, + /* 191 */ KEY_NOTUSED, + /* 192 */ KEY_NOTUSED, + /* 193 */ KEY_NOTUSED, + /* 194 */ KEY_NOTUSED, + /* 195 */ KEY_NOTUSED, + /* 196 */ KEY_NOTUSED, + /* 197 */ KEY_NOTUSED, + /* 198 */ KEY_NOTUSED, + /* 199 */ KEY_NOTUSED, + /* 200 */ KEY_NOTUSED, + /* 201 */ KEY_NOTUSED, + /* 202 */ KEY_NOTUSED, + /* 203 */ KEY_NOTUSED, + /* 204 */ KEY_NOTUSED, + /* 205 */ KEY_NOTUSED, + /* 206 */ KEY_NOTUSED, + /* 207 */ KEY_NOTUSED, + /* 208 */ KEY_NOTUSED, + /* 209 */ KEY_NOTUSED, + /* 210 */ KEY_NOTUSED, + /* 211 */ KEY_NOTUSED, + /* 212 */ KEY_NOTUSED, + /* 213 */ KEY_NOTUSED, + /* 214 */ KEY_NOTUSED, + /* 215 */ KEY_NOTUSED, + /* 216 */ KEY_NOTUSED, + /* 217 */ KEY_NOTUSED, + /* 218 */ KEY_NOTUSED, + /* 219 */ KEY_NOTUSED, + /* 220 */ KEY_NOTUSED, + /* 221 */ KEY_NOTUSED, + /* 222 */ KEY_NOTUSED, + /* 223 */ KEY_NOTUSED, + /* 224 */ KEY_LCtrl, /* Left Control */ + /* 225 */ KEY_ShiftL, /* Left Shift */ + /* 226 */ KEY_Alt, /* Left Alt */ + /* 227 */ KEY_LMeta, /* Left Meta */ + /* 228 */ KEY_RCtrl, /* Right Control */ + /* 229 */ KEY_ShiftR, /* Right Shift */ + /* 230 */ KEY_AltLang, /* Right Alt, AKA AltGr */ + /* 231 */ KEY_LMeta, /* Right Meta XXX */ +}; + +static uint8_t wsXtMap[] = { + /* 0 */ KEY_NOTUSED, + /* 1 */ KEY_Escape, + /* 2 */ KEY_1, + /* 3 */ KEY_2, + /* 4 */ KEY_3, + /* 5 */ KEY_4, + /* 6 */ KEY_5, + /* 7 */ KEY_6, + /* 8 */ KEY_7, + /* 9 */ KEY_8, + /* 10 */ KEY_9, + /* 11 */ KEY_0, + /* 12 */ KEY_Minus, + /* 13 */ KEY_Equal, + /* 14 */ KEY_BackSpace, + /* 15 */ KEY_Tab, + /* 16 */ KEY_Q, + /* 17 */ KEY_W, + /* 18 */ KEY_E, + /* 19 */ KEY_R, + /* 20 */ KEY_T, + /* 21 */ KEY_Y, + /* 22 */ KEY_U, + /* 23 */ KEY_I, + /* 24 */ KEY_O, + /* 25 */ KEY_P, + /* 26 */ KEY_LBrace, + /* 27 */ KEY_RBrace, + /* 28 */ KEY_Enter, + /* 29 */ KEY_LCtrl, + /* 30 */ KEY_A, + /* 31 */ KEY_S, + /* 32 */ KEY_D, + /* 33 */ KEY_F, + /* 34 */ KEY_G, + /* 35 */ KEY_H, + /* 36 */ KEY_J, + /* 37 */ KEY_K, + /* 38 */ KEY_L, + /* 39 */ KEY_SemiColon, + /* 40 */ KEY_Quote, + /* 41 */ KEY_Tilde, + /* 42 */ KEY_ShiftL, + /* 43 */ KEY_BSlash, + /* 44 */ KEY_Z, + /* 45 */ KEY_X, + /* 46 */ KEY_C, + /* 47 */ KEY_V, + /* 48 */ KEY_B, + /* 49 */ KEY_N, + /* 50 */ KEY_M, + /* 51 */ KEY_Comma, + /* 52 */ KEY_Period, + /* 53 */ KEY_Slash, + /* 54 */ KEY_ShiftR, + /* 55 */ KEY_KP_Multiply, + /* 56 */ KEY_Alt, + /* 57 */ KEY_Space, + /* 58 */ KEY_CapsLock, + /* 59 */ KEY_F1, + /* 60 */ KEY_F2, + /* 61 */ KEY_F3, + /* 62 */ KEY_F4, + /* 63 */ KEY_F5, + /* 64 */ KEY_F6, + /* 65 */ KEY_F7, + /* 66 */ KEY_F8, + /* 67 */ KEY_F9, + /* 68 */ KEY_F10, + /* 69 */ KEY_NumLock, + /* 70 */ KEY_ScrollLock, + /* 71 */ KEY_KP_7, + /* 72 */ KEY_KP_8, + /* 73 */ KEY_KP_9, + /* 74 */ KEY_KP_Minus, + /* 75 */ KEY_KP_4, + /* 76 */ KEY_KP_5, + /* 77 */ KEY_KP_6, + /* 78 */ KEY_KP_Plus, + /* 79 */ KEY_KP_1, + /* 80 */ KEY_KP_2, + /* 81 */ KEY_KP_3, + /* 82 */ KEY_KP_0, + /* 83 */ KEY_KP_Decimal, + /* 84 */ KEY_NOTUSED, + /* 85 */ KEY_NOTUSED, + /* 86 */ KEY_Less, /* backslash on uk, < on german */ + /* 87 */ KEY_F11, + /* 88 */ KEY_F12, + /* 89 */ KEY_NOTUSED, + /* 90 */ KEY_NOTUSED, + /* 91 */ KEY_NOTUSED, + /* 92 */ KEY_NOTUSED, + /* 93 */ KEY_NOTUSED, + /* 94 */ KEY_NOTUSED, + /* 95 */ KEY_NOTUSED, + /* 96 */ KEY_NOTUSED, + /* 97 */ KEY_NOTUSED, + /* 98 */ KEY_NOTUSED, + /* 99 */ KEY_NOTUSED, + /* 100 */ KEY_NOTUSED, + /* 101 */ KEY_NOTUSED, + /* 102 */ KEY_NOTUSED, + /* 103 */ KEY_NOTUSED, + /* 104 */ KEY_NOTUSED, + /* 105 */ KEY_NOTUSED, + /* 106 */ KEY_NOTUSED, + /* 107 */ KEY_NOTUSED, + /* 108 */ KEY_NOTUSED, + /* 109 */ KEY_NOTUSED, + /* 110 */ KEY_NOTUSED, + /* 111 */ KEY_NOTUSED, + /* 112 */ KEY_NOTUSED, + /* 113 */ KEY_NOTUSED, + /* 114 */ KEY_NOTUSED, + /* 115 */ KEY_NOTUSED, + /* 116 */ KEY_NOTUSED, + /* 117 */ KEY_NOTUSED, + /* 118 */ KEY_NOTUSED, + /* 119 */ KEY_NOTUSED, + /* 120 */ KEY_NOTUSED, + /* 121 */ KEY_NOTUSED, + /* 122 */ KEY_NOTUSED, + /* 123 */ KEY_NOTUSED, + /* 124 */ KEY_NOTUSED, + /* 125 */ KEY_NOTUSED, + /* 126 */ KEY_NOTUSED, + /* 127 */ KEY_Pause, + /* 128 */ KEY_NOTUSED, + /* 129 */ KEY_NOTUSED, + /* 130 */ KEY_NOTUSED, + /* 131 */ KEY_NOTUSED, + /* 132 */ KEY_NOTUSED, + /* 133 */ KEY_NOTUSED, + /* 134 */ KEY_NOTUSED, + /* 135 */ KEY_NOTUSED, + /* 136 */ KEY_NOTUSED, + /* 137 */ KEY_NOTUSED, + /* 138 */ KEY_NOTUSED, + /* 139 */ KEY_NOTUSED, + /* 140 */ KEY_NOTUSED, + /* 141 */ KEY_NOTUSED, + /* 142 */ KEY_NOTUSED, + /* 143 */ KEY_NOTUSED, + /* 144 */ KEY_NOTUSED, + /* 145 */ KEY_NOTUSED, + /* 146 */ KEY_NOTUSED, + /* 147 */ KEY_NOTUSED, + /* 148 */ KEY_NOTUSED, + /* 149 */ KEY_NOTUSED, + /* 150 */ KEY_NOTUSED, + /* 151 */ KEY_NOTUSED, + /* 152 */ KEY_NOTUSED, + /* 153 */ KEY_NOTUSED, + /* 154 */ KEY_NOTUSED, + /* 155 */ KEY_NOTUSED, + /* 156 */ KEY_KP_Enter, + /* 157 */ KEY_RCtrl, + /* 158 */ KEY_NOTUSED, + /* 159 */ KEY_NOTUSED, + /* 160 */ KEY_Mute, + /* 161 */ KEY_NOTUSED, + /* 162 */ KEY_NOTUSED, + /* 163 */ KEY_NOTUSED, + /* 164 */ KEY_NOTUSED, + /* 165 */ KEY_NOTUSED, + /* 166 */ KEY_NOTUSED, + /* 167 */ KEY_NOTUSED, + /* 168 */ KEY_NOTUSED, + /* 169 */ KEY_NOTUSED, + /* 170 */ KEY_Print, + /* 171 */ KEY_NOTUSED, + /* 172 */ KEY_NOTUSED, + /* 173 */ KEY_NOTUSED, + /* 174 */ KEY_AudioLower, + /* 175 */ KEY_AudioRaise, + /* 176 */ KEY_NOTUSED, + /* 177 */ KEY_NOTUSED, + /* 178 */ KEY_NOTUSED, + /* 179 */ KEY_NOTUSED, + /* 180 */ KEY_NOTUSED, + /* 181 */ KEY_KP_Divide, + /* 182 */ KEY_NOTUSED, + /* 183 */ KEY_Print, + /* 184 */ KEY_AltLang, + /* 185 */ KEY_NOTUSED, + /* 186 */ KEY_NOTUSED, + /* 187 */ KEY_NOTUSED, + /* 188 */ KEY_NOTUSED, + /* 189 */ KEY_NOTUSED, + /* 190 */ KEY_NOTUSED, + /* 191 */ KEY_NOTUSED, + /* 192 */ KEY_NOTUSED, + /* 193 */ KEY_NOTUSED, + /* 194 */ KEY_NOTUSED, + /* 195 */ KEY_NOTUSED, + /* 196 */ KEY_NOTUSED, + /* 197 */ KEY_NOTUSED, + /* 198 */ KEY_NOTUSED, + /* 199 */ KEY_Home, + /* 200 */ KEY_Up, + /* 201 */ KEY_PgUp, + /* 202 */ KEY_NOTUSED, + /* 203 */ KEY_Left, + /* 204 */ KEY_NOTUSED, + /* 205 */ KEY_Right, + /* 206 */ KEY_NOTUSED, + /* 207 */ KEY_End, + /* 208 */ KEY_Down, + /* 209 */ KEY_PgDown, + /* 210 */ KEY_Insert, + /* 211 */ KEY_Delete, + /* 212 */ KEY_NOTUSED, + /* 213 */ KEY_NOTUSED, + /* 214 */ KEY_NOTUSED, + /* 215 */ KEY_NOTUSED, + /* 216 */ KEY_NOTUSED, + /* 217 */ KEY_NOTUSED, + /* 218 */ KEY_NOTUSED, + /* 219 */ KEY_LMeta, + /* 220 */ KEY_RMeta, + /* 221 */ KEY_Menu, +}; diff --git a/backend/wscons/meson.build b/backend/wscons/meson.build new file mode 100644 index 000000000..f4d4731e1 --- /dev/null +++ b/backend/wscons/meson.build @@ -0,0 +1,9 @@ +platform = target_machine.system() +if platform != 'openbsd' + subdir_done() +endif + +wlr_files += files('atKeynames.h') +wlr_files += files('bsd_KbdMap.h') +wlr_files += files('backend.c') +features += { 'wscons-backend': true } diff --git a/include/backend/session/session.h b/include/backend/session/session.h index f3ff9f5bd..e23e04c2e 100644 --- a/include/backend/session/session.h +++ b/include/backend/session/session.h @@ -2,6 +2,31 @@ #define BACKEND_SESSION_SESSION_H #include +#include +#include +#include + +// for some reason libdrm does not define MAX3, but has defs that depend on it +#define MAX3(a, b, c) ((a) > (b) && (a) > (c) ? (a) : \ + (b) > (c) ? (b) : (c)) + +struct drm_event_monitor; + +enum drm_event_action { + DRM_EVENT_ACTION_NONE, + DRM_EVENT_ACTION_ADD, + DRM_EVENT_ACTION_CHANGE, + DRM_EVENT_ACTION_REMOVE, +}; + +struct drm_event_content { + char devnode[DRM_NODE_NAME_MAX]; + dev_t devnum; + enum drm_event_action type; + int16_t conn_id; + int16_t prop_id; + bool has_lease; +}; struct wl_display; struct wlr_session; @@ -17,4 +42,13 @@ void session_init(struct wlr_session *session); struct wlr_device *session_open_if_kms(struct wlr_session *session, const char *path); +struct drm_event_monitor *monitor_drm_events(int *fd); +void drm_event_monitor_free(struct drm_event_monitor *ctx); + +int receive_drm_device(struct drm_event_monitor *ctx, + struct drm_event_content *ev); + +const char *get_device_seat(struct drm_event_monitor *ctx, const char *devnode); +bool is_drm_device_primary(struct drm_event_monitor *ctx, const char *devnode); + #endif diff --git a/include/backend/wscons.h b/include/backend/wscons.h new file mode 100644 index 000000000..b8c807b3b --- /dev/null +++ b/include/backend/wscons.h @@ -0,0 +1,32 @@ +#ifndef BACKEND_WSCONS_H +#define BACKEND_WSCONS_H + +#include +#include +#include +#include +#include +#include + +struct wlr_wscons_backend { + struct wlr_backend backend; + + struct wlr_device *mouse_dev; + struct wlr_device *kbd_dev; + + struct wlr_keyboard kbd; + struct wlr_pointer mouse; + + unsigned kbd_type; + int kqueue_fd; + + struct wlr_session *session; + + struct wl_event_source *input_event; + struct wl_listener session_destroy; +}; + +extern const struct wlr_keyboard_impl wscons_keyboard_impl; +extern const struct wlr_pointer_impl wscons_pointer_impl; + +#endif diff --git a/include/meson.build b/include/meson.build index 165166c33..20376e026 100644 --- a/include/meson.build +++ b/include/meson.build @@ -23,6 +23,9 @@ endif if not features.get('session') exclude_files += 'backend/session.h' endif +if not features.get('wscons-backend') + exclude_files += 'backend/wscons.h' +endif install_subdir('wlr', install_dir: get_option('includedir') / versioned_name, diff --git a/include/wlr/backend/session.h b/include/wlr/backend/session.h index a1ff0c317..2e0ee6450 100644 --- a/include/wlr/backend/session.h +++ b/include/wlr/backend/session.h @@ -6,6 +6,7 @@ #include struct libseat; +struct drm_event_monitor; /** * An opened physical device. @@ -45,9 +46,8 @@ struct wlr_session { char seat[256]; - struct udev *udev; - struct udev_monitor *mon; - struct wl_event_source *udev_event; + struct drm_event_monitor *drm_handle; + struct wl_event_source *drm_event; struct libseat *seat_handle; struct wl_event_source *libseat_event; diff --git a/include/wlr/backend/wscons.h b/include/wlr/backend/wscons.h new file mode 100644 index 000000000..817445061 --- /dev/null +++ b/include/wlr/backend/wscons.h @@ -0,0 +1,23 @@ +/* + * 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_WSCONS_H +#define WLR_BACKEND_WSCONS_H + +#include +#include +#include + +struct wlr_input_device; + +struct wlr_backend *wlr_wscons_backend_create(struct wlr_session *session); + +bool wlr_backend_is_wscons(const struct wlr_backend *backend); +bool wlr_input_device_is_wscons(struct wlr_input_device *device); + +#endif diff --git a/include/wlr/config.h.in b/include/wlr/config.h.in index 8c9f7bbde..dc5ddb48c 100644 --- a/include/wlr/config.h.in +++ b/include/wlr/config.h.in @@ -15,6 +15,13 @@ * Required for . */ #mesondefine WLR_HAS_LIBINPUT_BACKEND +/** + * Whether the wscons backend is compile-time enabled. Equivalent to the + * pkg-config "have_wscons_backend" vartiable. + * + * Required for . + */ +#mesondefine WLR_HAS_WSCONS_BACKEND /** * Whether the X11 backend is compile-time enabled. Equivalent to the * pkg-config "have_x11_backend" variable. diff --git a/meson.build b/meson.build index 90200d4e3..2250d3fec 100644 --- a/meson.build +++ b/meson.build @@ -70,6 +70,7 @@ features = { 'drm-backend': false, 'x11-backend': false, 'libinput-backend': false, + 'wscons-backend': false, 'xwayland': false, 'gles2-renderer': false, 'vulkan-renderer': false, @@ -121,7 +122,12 @@ pixman = dependency('pixman-1', default_options: ['werror=false'], ) math = cc.find_library('m') -rt = cc.find_library('rt') +platform = target_machine.system() +if platform == 'openbsd' + rt = dependency('', required: false) +else + rt = cc.find_library('rt') +endif wlr_files = [] wlr_deps = [ diff --git a/meson.options b/meson.options index d8a8ca940..7fdc21ef2 100644 --- a/meson.options +++ b/meson.options @@ -3,7 +3,7 @@ option('xwayland', type: 'feature', value: 'auto', yield: true, description: 'En option('examples', type: 'boolean', value: true, description: 'Build example applications') option('icon_directory', description: 'Location used to look for cursors (default: ${datadir}/icons)', type: 'string', value: '') option('renderers', type: 'array', choices: ['auto', 'gles2', 'vulkan'], value: ['auto'], description: 'Select built-in renderers') -option('backends', type: 'array', choices: ['auto', 'drm', 'libinput', 'x11'], value: ['auto'], description: 'Select built-in backends') +option('backends', type: 'array', choices: ['auto', 'drm', 'libinput', 'x11', 'wscons'], value: ['auto'], description: 'Select built-in backends') option('allocators', type: 'array', choices: ['auto', 'gbm', 'udmabuf'], value: ['auto'], description: 'Select built-in allocators') option('session', type: 'feature', value: 'auto', description: 'Enable session support') diff --git a/render/allocator/allocator.c b/render/allocator/allocator.c index b7dbf3d65..54a7d7b56 100644 --- a/render/allocator/allocator.c +++ b/render/allocator/allocator.c @@ -42,7 +42,7 @@ static int reopen_drm_node(int drm_fd, bool allow_render_node) { int lease_fd = drmModeCreateLease(drm_fd, NULL, 0, O_CLOEXEC, &lessee_id); if (lease_fd >= 0) { return lease_fd; - } else if (lease_fd != -EINVAL && lease_fd != -EOPNOTSUPP) { + } else if (lease_fd != -EINVAL && lease_fd != -EOPNOTSUPP && lease_fd != -ENODEV) { wlr_log_errno(WLR_ERROR, "drmModeCreateLease failed"); return -1; } diff --git a/render/drm_syncobj.c b/render/drm_syncobj.c index 15f71c536..d94721eea 100644 --- a/render/drm_syncobj.c +++ b/render/drm_syncobj.c @@ -161,7 +161,7 @@ out: bool wlr_drm_syncobj_timeline_check(struct wlr_drm_syncobj_timeline *timeline, uint64_t point, uint32_t flags, bool *result) { int etime; -#if defined(__FreeBSD__) +#if defined(__FreeBSD__) || defined(__OpenBSD__) etime = ETIMEDOUT; #else etime = ETIME; diff --git a/types/wlr_keyboard.c b/types/wlr_keyboard.c index adc705db5..a4d436c97 100644 --- a/types/wlr_keyboard.c +++ b/types/wlr_keyboard.c @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -323,6 +322,10 @@ bool wlr_keyboard_keymaps_match(struct xkb_keymap *km1, return result; } +#define BTN_LEFT 0x110 +#define BTN_RIGHT 0x111 +#define BTN_MIDDLE 0x112 + uint32_t wlr_keyboard_keysym_to_pointer_button(xkb_keysym_t keysym) { switch (keysym) { case XKB_KEY_Pointer_Button1: diff --git a/util/shm.c b/util/shm.c index 5eb87bb89..455cfe865 100644 --- a/util/shm.c +++ b/util/shm.c @@ -1,3 +1,4 @@ +#define _XOPEN_SOURCE 700 #include #include #include