Merge gitlab.freedesktop.org:wlroots/wlroots

This commit is contained in:
Christian Kröner 2022-08-30 21:25:19 +02:00
commit 26f6fab4eb
275 changed files with 7472 additions and 5463 deletions

View file

@ -17,7 +17,7 @@
#include "backend/backend.h"
#include "backend/multi.h"
#include "render/allocator/allocator.h"
#include "util/signal.h"
#include "util/env.h"
#if WLR_HAS_DRM_BACKEND
#include <wlr/backend/drm.h>
@ -36,7 +36,7 @@
void wlr_backend_init(struct wlr_backend *backend,
const struct wlr_backend_impl *impl) {
assert(backend);
memset(backend, 0, sizeof(*backend));
backend->impl = impl;
wl_signal_init(&backend->events.destroy);
wl_signal_init(&backend->events.new_input);
@ -44,7 +44,7 @@ void wlr_backend_init(struct wlr_backend *backend,
}
void wlr_backend_finish(struct wlr_backend *backend) {
wlr_signal_emit_safe(&backend->events.destroy, backend);
wl_signal_emit_mutable(&backend->events.destroy, backend);
}
bool wlr_backend_start(struct wlr_backend *backend) {
@ -365,8 +365,7 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display) {
}
wlr_multi_backend_add(backend, libinput);
#else
const char *no_devs = getenv("WLR_LIBINPUT_NO_DEVICES");
if (no_devs && strcmp(no_devs, "1") == 0) {
if (env_parse_bool("WLR_LIBINPUT_NO_DEVICES")) {
wlr_log(WLR_INFO, "WLR_LIBINPUT_NO_DEVICES is set, "
"starting without libinput backend");
} else {

View file

@ -1,4 +1,6 @@
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <stdio.h>
#include <wlr/util/log.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
@ -6,6 +8,41 @@
#include "backend/drm/iface.h"
#include "backend/drm/util.h"
static char *atomic_commit_flags_str(uint32_t flags) {
const char *const l[] = {
(flags & DRM_MODE_PAGE_FLIP_EVENT) ? "PAGE_FLIP_EVENT" : NULL,
(flags & DRM_MODE_PAGE_FLIP_ASYNC) ? "PAGE_FLIP_ASYNC" : NULL,
(flags & DRM_MODE_ATOMIC_TEST_ONLY) ? "ATOMIC_TEST_ONLY" : NULL,
(flags & DRM_MODE_ATOMIC_NONBLOCK) ? "ATOMIC_NONBLOCK" : NULL,
(flags & DRM_MODE_ATOMIC_ALLOW_MODESET) ? "ATOMIC_ALLOW_MODESET" : NULL,
};
char *buf = NULL;
size_t size = 0;
FILE *f = open_memstream(&buf, &size);
if (f == NULL) {
return NULL;
}
for (size_t i = 0; i < sizeof(l) / sizeof(l[0]); i++) {
if (l[i] == NULL) {
continue;
}
if (ftell(f) > 0) {
fprintf(f, " | ");
}
fprintf(f, "%s", l[i]);
}
if (ftell(f) == 0) {
fprintf(f, "none");
}
fclose(f);
return buf;
}
struct atomic {
drmModeAtomicReq *req;
bool failed;
@ -33,9 +70,11 @@ static bool atomic_commit(struct atomic *atom,
if (ret != 0) {
wlr_drm_conn_log_errno(conn,
(flags & DRM_MODE_ATOMIC_TEST_ONLY) ? WLR_DEBUG : WLR_ERROR,
"Atomic %s failed (%s)",
(flags & DRM_MODE_ATOMIC_TEST_ONLY) ? "test" : "commit",
(flags & DRM_MODE_ATOMIC_ALLOW_MODESET) ? "modeset" : "pageflip");
"Atomic commit failed");
char *flags_str = atomic_commit_flags_str(flags);
wlr_log(WLR_DEBUG, "(Atomic commit flags: %s)",
flags_str ? flags_str : "<error>");
free(flags_str);
return false;
}
@ -217,8 +256,10 @@ static bool atomic_crtc_commit(struct wlr_drm_connector *conn,
bool prev_vrr_enabled =
output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED;
bool vrr_enabled = prev_vrr_enabled;
if ((state->base->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) &&
drm_connector_supports_vrr(conn)) {
if ((state->base->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED)) {
if (!drm_connector_supports_vrr(conn)) {
return false;
}
vrr_enabled = state->base->adaptive_sync_enabled;
}
@ -227,7 +268,12 @@ static bool atomic_crtc_commit(struct wlr_drm_connector *conn,
}
if (modeset) {
flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
} else if (!test_only) {
} else if (!test_only && (state->base->committed & WLR_OUTPUT_STATE_BUFFER)) {
// The wlr_output API requires non-modeset commits with a new buffer to
// wait for the frame event. However compositors often perform
// non-modesets commits without a new buffer without waiting for the
// frame event. In that case we need to make the KMS commit blocking,
// otherwise the kernel will error out with EBUSY.
flags |= DRM_MODE_ATOMIC_NONBLOCK;
}
@ -238,6 +284,13 @@ static bool atomic_crtc_commit(struct wlr_drm_connector *conn,
atomic_add(&atom, conn->id, conn->props.link_status,
DRM_MODE_LINK_STATUS_GOOD);
}
if (active && conn->props.content_type != 0) {
atomic_add(&atom, conn->id, conn->props.content_type,
DRM_MODE_CONTENT_TYPE_GRAPHICS);
}
if (active && conn->props.max_bpc != 0 && conn->max_bpc > 0) {
atomic_add(&atom, conn->id, conn->props.max_bpc, conn->max_bpc);
}
atomic_add(&atom, crtc->id, crtc->props.mode_id, mode_id);
atomic_add(&atom, crtc->id, crtc->props.active, active);
if (active) {

View file

@ -1,6 +1,7 @@
#include <assert.h>
#include <errno.h>
#include <drm_fourcc.h>
#include <libudev.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -12,7 +13,6 @@
#include <wlr/util/log.h>
#include <xf86drm.h>
#include "backend/drm/drm.h"
#include "util/signal.h"
struct wlr_drm_backend *get_drm_backend_from_backend(
struct wlr_backend *wlr_backend) {
@ -58,6 +58,7 @@ static void backend_destroy(struct wlr_backend *backend) {
finish_drm_resources(drm);
udev_hwdb_unref(drm->hwdb);
free(drm->name);
wlr_session_close_file(drm->session, drm->dev);
wl_event_source_remove(drm->drm_event);
@ -172,6 +173,23 @@ static void handle_parent_destroy(struct wl_listener *listener, void *data) {
backend_destroy(&drm->backend);
}
static struct udev_hwdb *create_udev_hwdb(void) {
struct udev *udev = udev_new();
if (!udev) {
wlr_log(WLR_ERROR, "udev_new failed");
return NULL;
}
struct udev_hwdb *hwdb = udev_hwdb_new(udev);
udev_unref(udev);
if (!hwdb) {
wlr_log(WLR_ERROR, "udev_hwdb_new failed");
return NULL;
}
return hwdb;
}
struct wlr_backend *wlr_drm_backend_create(struct wl_display *display,
struct wlr_session *session, struct wlr_device *dev,
struct wlr_backend *parent) {
@ -226,6 +244,12 @@ struct wlr_backend *wlr_drm_backend_create(struct wl_display *display,
drm->session_active.notify = handle_session_active;
wl_signal_add(&session->events.active, &drm->session_active);
drm->hwdb = create_udev_hwdb();
if (!drm->hwdb) {
wlr_log(WLR_INFO, "Failed to load udev_hwdb, "
"falling back to PnP IDs instead of manufacturer names");
}
if (!check_drm_features(drm)) {
goto error_event;
}
@ -250,15 +274,17 @@ struct wlr_backend *wlr_drm_backend_create(struct wl_display *display,
goto error_mgpu_renderer;
}
// Force a linear layout. In case explicit modifiers aren't supported,
// the meaning of implicit modifiers changes from one GPU to the other.
// In case explicit modifiers are supported, we still have no guarantee
// that the buffer producer will support these, so they might fallback
// to implicit modifiers.
// Forbid implicit modifiers, because their meaning changes from one
// GPU to another.
for (size_t i = 0; i < texture_formats->len; i++) {
const struct wlr_drm_format *fmt = texture_formats->formats[i];
wlr_drm_format_set_add(&drm->mgpu_formats, fmt->format,
DRM_FORMAT_MOD_LINEAR);
for (size_t j = 0; j < fmt->len; j++) {
uint64_t mod = fmt->modifiers[j];
if (mod == DRM_FORMAT_MOD_INVALID) {
continue;
}
wlr_drm_format_set_add(&drm->mgpu_formats, fmt->format, mod);
}
}
}
@ -275,6 +301,7 @@ error_mgpu_renderer:
error_resources:
finish_drm_resources(drm);
error_event:
udev_hwdb_unref(drm->hwdb);
wl_list_remove(&drm->session_active.link);
wl_event_source_remove(drm->drm_event);
error_fd:

View file

@ -29,14 +29,18 @@
#include "render/drm_format_set.h"
#include "render/swapchain.h"
#include "render/wlr_renderer.h"
#include "util/signal.h"
#include "util/env.h"
static const uint32_t SUPPORTED_OUTPUT_STATE =
WLR_OUTPUT_STATE_BACKEND_OPTIONAL |
// Output state which needs a KMS commit to be applied
static const uint32_t COMMIT_OUTPUT_STATE =
WLR_OUTPUT_STATE_BUFFER |
WLR_OUTPUT_STATE_MODE |
WLR_OUTPUT_STATE_ENABLED |
WLR_OUTPUT_STATE_GAMMA_LUT;
WLR_OUTPUT_STATE_GAMMA_LUT |
WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED;
static const uint32_t SUPPORTED_OUTPUT_STATE =
WLR_OUTPUT_STATE_BACKEND_OPTIONAL | COMMIT_OUTPUT_STATE;
bool check_drm_features(struct wlr_drm_backend *drm) {
if (drmGetCap(drm->fd, DRM_CAP_CURSOR_WIDTH, &drm->cursor_width)) {
@ -72,8 +76,7 @@ bool check_drm_features(struct wlr_drm_backend *drm) {
return false;
}
const char *no_atomic = getenv("WLR_DRM_NO_ATOMIC");
if (no_atomic && strcmp(no_atomic, "1") == 0) {
if (env_parse_bool("WLR_DRM_NO_ATOMIC")) {
wlr_log(WLR_DEBUG,
"WLR_DRM_NO_ATOMIC set, forcing legacy DRM interface");
drm->iface = &legacy_iface;
@ -89,8 +92,7 @@ bool check_drm_features(struct wlr_drm_backend *drm) {
int ret = drmGetCap(drm->fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
drm->clock = (ret == 0 && cap == 1) ? CLOCK_MONOTONIC : CLOCK_REALTIME;
const char *no_modifiers = getenv("WLR_DRM_NO_MODIFIERS");
if (no_modifiers != NULL && strcmp(no_modifiers, "1") == 0) {
if (env_parse_bool("WLR_DRM_NO_MODIFIERS")) {
wlr_log(WLR_DEBUG, "WLR_DRM_NO_MODIFIERS set, disabling modifiers");
} else {
ret = drmGetCap(drm->fd, DRM_CAP_ADDFB2_MODIFIERS, &cap);
@ -380,6 +382,7 @@ static bool drm_crtc_page_flip(struct wlr_drm_connector *conn,
static void drm_connector_state_init(struct wlr_drm_connector_state *state,
struct wlr_drm_connector *conn,
const struct wlr_output_state *base) {
memset(state, 0, sizeof(*state));
state->base = base;
state->modeset = base->committed &
(WLR_OUTPUT_STATE_ENABLED | WLR_OUTPUT_STATE_MODE);
@ -458,37 +461,48 @@ static bool drm_connector_set_pending_fb(struct wlr_drm_connector *conn,
static bool drm_connector_alloc_crtc(struct wlr_drm_connector *conn);
static bool drm_connector_test(struct wlr_output *output) {
static bool drm_connector_test(struct wlr_output *output,
const struct wlr_output_state *state) {
struct wlr_drm_connector *conn = get_drm_connector_from_output(output);
if (!conn->backend->session->active) {
return false;
}
uint32_t unsupported = output->pending.committed & ~SUPPORTED_OUTPUT_STATE;
uint32_t unsupported = state->committed & ~SUPPORTED_OUTPUT_STATE;
if (unsupported != 0) {
wlr_log(WLR_DEBUG, "Unsupported output state fields: 0x%"PRIx32,
unsupported);
return false;
}
if ((output->pending.committed & WLR_OUTPUT_STATE_ENABLED) &&
output->pending.enabled) {
if ((state->committed & COMMIT_OUTPUT_STATE) == 0) {
// This commit doesn't change the KMS state
return true;
}
if ((state->committed & WLR_OUTPUT_STATE_ENABLED) && state->enabled) {
if (output->current_mode == NULL &&
!(output->pending.committed & WLR_OUTPUT_STATE_MODE)) {
!(state->committed & WLR_OUTPUT_STATE_MODE)) {
wlr_drm_conn_log(conn, WLR_DEBUG,
"Can't enable an output without a mode");
return false;
}
}
if ((state->committed & WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED) &&
state->adaptive_sync_enabled &&
!drm_connector_supports_vrr(conn)) {
return false;
}
struct wlr_drm_connector_state pending = {0};
drm_connector_state_init(&pending, conn, &output->pending);
drm_connector_state_init(&pending, conn, state);
if (pending.active) {
if ((output->pending.committed &
if ((state->committed &
(WLR_OUTPUT_STATE_ENABLED | WLR_OUTPUT_STATE_MODE)) &&
!(output->pending.committed & WLR_OUTPUT_STATE_BUFFER)) {
!(state->committed & WLR_OUTPUT_STATE_BUFFER)) {
wlr_drm_conn_log(conn, WLR_DEBUG,
"Can't enable an output without a buffer");
return false;
@ -513,7 +527,7 @@ static bool drm_connector_test(struct wlr_output *output) {
return true;
}
if (output->pending.committed & WLR_OUTPUT_STATE_BUFFER) {
if (state->committed & WLR_OUTPUT_STATE_BUFFER) {
if (!drm_connector_set_pending_fb(conn, pending.base)) {
return false;
}
@ -559,6 +573,11 @@ bool drm_connector_commit_state(struct wlr_drm_connector *conn,
return false;
}
if ((base->committed & COMMIT_OUTPUT_STATE) == 0) {
// This commit doesn't change the KMS state
return true;
}
struct wlr_drm_connector_state pending = {0};
drm_connector_state_init(&pending, conn, base);
@ -596,14 +615,15 @@ bool drm_connector_commit_state(struct wlr_drm_connector *conn,
return true;
}
static bool drm_connector_commit(struct wlr_output *output) {
static bool drm_connector_commit(struct wlr_output *output,
const struct wlr_output_state *state) {
struct wlr_drm_connector *conn = get_drm_connector_from_output(output);
if (!drm_connector_test(output)) {
if (!drm_connector_test(output, state)) {
return false;
}
return drm_connector_commit_state(conn, &output->pending);
return drm_connector_commit_state(conn, state);
}
size_t drm_crtc_get_gamma_lut_size(struct wlr_drm_backend *drm,
@ -692,8 +712,7 @@ static bool drm_connector_set_mode(struct wlr_drm_connector *conn,
return true;
}
if (conn->status != WLR_DRM_CONN_CONNECTED
&& conn->status != WLR_DRM_CONN_NEEDS_MODESET) {
if (conn->status != DRM_MODE_CONNECTED) {
wlr_drm_conn_log(conn, WLR_ERROR,
"Cannot modeset a disconnected output");
return false;
@ -720,7 +739,6 @@ static bool drm_connector_set_mode(struct wlr_drm_connector *conn,
return false;
}
conn->status = WLR_DRM_CONN_CONNECTED;
wlr_output_update_mode(&conn->output, wlr_mode);
wlr_output_update_enabled(&conn->output, true);
conn->desired_enabled = true;
@ -892,7 +910,7 @@ static void drm_connector_destroy_output(struct wlr_output *output) {
dealloc_crtc(conn);
conn->status = WLR_DRM_CONN_DISCONNECTED;
conn->status = DRM_MODE_DISCONNECTED;
conn->desired_enabled = false;
conn->possible_crtcs = 0;
conn->pending_page_flip_crtc = 0;
@ -1071,9 +1089,7 @@ static void realloc_crtcs(struct wlr_drm_backend *drm) {
// Only search CRTCs for user-enabled outputs (that are already
// connected or in need of a modeset)
if ((conn->status == WLR_DRM_CONN_CONNECTED ||
conn->status == WLR_DRM_CONN_NEEDS_MODESET) &&
conn->desired_enabled) {
if (conn->status == DRM_MODE_CONNECTED && conn->desired_enabled) {
connector_constraints[i] = conn->possible_crtcs;
} else {
// Will always fail to match anything
@ -1104,8 +1120,7 @@ static void realloc_crtcs(struct wlr_drm_backend *drm) {
*/
for (size_t i = 0; i < num_outputs; ++i) {
struct wlr_drm_connector *conn = connectors[i];
if (conn->status == WLR_DRM_CONN_CONNECTED &&
conn->desired_enabled &&
if (conn->status == DRM_MODE_CONNECTED && conn->output.enabled &&
connector_match[i] == -1) {
wlr_log(WLR_DEBUG, "Could not match a CRTC for previously connected output; "
"keeping old configuration");
@ -1132,7 +1147,6 @@ static void realloc_crtcs(struct wlr_drm_backend *drm) {
if (connector_match[i] == -1) {
if (prev_enabled) {
wlr_drm_conn_log(conn, WLR_DEBUG, "Output has lost its CRTC");
conn->status = WLR_DRM_CONN_NEEDS_MODESET;
wlr_output_update_enabled(&conn->output, false);
wlr_output_update_mode(&conn->output, NULL);
}
@ -1142,42 +1156,17 @@ static void realloc_crtcs(struct wlr_drm_backend *drm) {
conn->crtc = &drm->crtcs[connector_match[i]];
// Only realloc buffers if we have actually been modeset
if (conn->status != WLR_DRM_CONN_CONNECTED) {
if (conn->status != DRM_MODE_CONNECTED || !conn->output.enabled) {
continue;
}
wlr_output_damage_whole(&conn->output);
}
}
static uint32_t get_possible_crtcs(int fd, const drmModeConnector *conn) {
uint32_t possible_crtcs = 0;
for (int i = 0; i < conn->count_encoders; ++i) {
drmModeEncoder *enc = drmModeGetEncoder(fd, conn->encoders[i]);
if (!enc) {
continue;
}
possible_crtcs |= enc->possible_crtcs;
drmModeFreeEncoder(enc);
}
return possible_crtcs;
}
static void disconnect_drm_connector(struct wlr_drm_connector *conn);
void scan_drm_connectors(struct wlr_drm_backend *drm,
struct wlr_device_hotplug_event *event) {
/*
* This GPU is not really a modesetting device.
* It's just being used as a renderer.
*/
if (drm->num_crtcs == 0) {
return;
}
if (event != NULL && event->connector_id != 0) {
wlr_log(WLR_INFO, "Scanning DRM connector %"PRIu32" on %s",
event->connector_id, drm->name);
@ -1240,12 +1229,17 @@ void scan_drm_connectors(struct wlr_drm_backend *drm,
}
wlr_conn->backend = drm;
wlr_conn->status = WLR_DRM_CONN_DISCONNECTED;
wlr_conn->status = DRM_MODE_DISCONNECTED;
wlr_conn->id = drm_conn->connector_id;
const char *conn_name =
drmModeGetConnectorTypeName(drm_conn->connector_type);
if (conn_name == NULL) {
conn_name = "Unknown";
}
snprintf(wlr_conn->name, sizeof(wlr_conn->name),
"%s-%"PRIu32, conn_get_name(drm_conn->connector_type),
drm_conn->connector_type_id);
"%s-%"PRIu32, conn_name, drm_conn->connector_type_id);
wl_list_insert(drm->outputs.prev, &wlr_conn->link);
wlr_log(WLR_INFO, "Found connector '%s'", wlr_conn->name);
@ -1282,7 +1276,7 @@ void scan_drm_connectors(struct wlr_drm_backend *drm,
}
}
if (wlr_conn->status == WLR_DRM_CONN_DISCONNECTED &&
if (wlr_conn->status == DRM_MODE_DISCONNECTED &&
drm_conn->connection == DRM_MODE_CONNECTED) {
wlr_log(WLR_INFO, "'%s' connected", wlr_conn->name);
wlr_log(WLR_DEBUG, "Current CRTC: %d",
@ -1310,16 +1304,24 @@ void scan_drm_connectors(struct wlr_drm_backend *drm,
wlr_conn->output.non_desktop = non_desktop;
}
wlr_conn->max_bpc = 0;
if (wlr_conn->props.max_bpc != 0) {
if (!introspect_drm_prop_range(drm->fd, wlr_conn->props.max_bpc,
NULL, &wlr_conn->max_bpc)) {
wlr_log(WLR_ERROR, "Failed to introspect 'max bpc' property");
}
}
size_t edid_len = 0;
uint8_t *edid = get_drm_prop_blob(drm->fd,
wlr_conn->id, wlr_conn->props.edid, &edid_len);
parse_edid(&wlr_conn->output, edid_len, edid);
parse_edid(wlr_conn, edid_len, edid);
free(edid);
size_t tile_len = 0;
uint8_t *tile = get_drm_prop_blob(drm->fd,
wlr_conn->id, wlr_conn->props.tile, &tile_len);
parse_tile(&wlr_conn->output, tile_len, tile);
parse_tile(wlr_conn, tile_len, tile);
free(tile);
char *subconnector = NULL;
@ -1334,9 +1336,13 @@ void scan_drm_connectors(struct wlr_drm_backend *drm,
struct wlr_output *output = &wlr_conn->output;
char description[128];
snprintf(description, sizeof(description), "%s %s %s (%s%s%s)",
output->make, output->model, output->serial, output->name,
subconnector ? " via " : "", subconnector ? subconnector : "");
snprintf(description, sizeof(description), "%s %s%s%s (%s%s%s)",
output->make, output->model,
output->serial ? " " : "",
output->serial ? output->serial : "",
output->name,
subconnector ? " via " : "",
subconnector ? subconnector : "");
wlr_output_set_description(output, description);
free(subconnector);
@ -1371,7 +1377,8 @@ void scan_drm_connectors(struct wlr_drm_backend *drm,
wl_list_insert(wlr_conn->output.modes.prev, &mode->wlr_mode.link);
}
wlr_conn->possible_crtcs = get_possible_crtcs(drm->fd, drm_conn);
wlr_conn->possible_crtcs =
drmModeConnectorGetPossibleCrtcs(drm->fd, drm_conn);
if (wlr_conn->possible_crtcs == 0) {
wlr_drm_conn_log(wlr_conn, WLR_ERROR, "No CRTC possible");
}
@ -1381,10 +1388,9 @@ void scan_drm_connectors(struct wlr_drm_backend *drm,
wlr_output_update_enabled(&wlr_conn->output, wlr_conn->crtc != NULL);
wlr_conn->desired_enabled = true;
wlr_conn->status = WLR_DRM_CONN_NEEDS_MODESET;
wlr_conn->status = DRM_MODE_CONNECTED;
new_outputs[new_outputs_len++] = wlr_conn;
} else if ((wlr_conn->status == WLR_DRM_CONN_CONNECTED ||
wlr_conn->status == WLR_DRM_CONN_NEEDS_MODESET) &&
} else if (wlr_conn->status == DRM_MODE_CONNECTED &&
drm_conn->connection != DRM_MODE_CONNECTED) {
wlr_log(WLR_INFO, "'%s' disconnected", wlr_conn->name);
disconnect_drm_connector(wlr_conn);
@ -1416,7 +1422,7 @@ void scan_drm_connectors(struct wlr_drm_backend *drm,
struct wlr_drm_connector *conn = new_outputs[i];
wlr_drm_conn_log(conn, WLR_INFO, "Requesting modeset");
wlr_signal_emit_safe(&drm->backend.events.new_output,
wl_signal_emit_mutable(&drm->backend.events.new_output,
&conn->output);
}
}
@ -1474,7 +1480,7 @@ static void handle_page_flip(int fd, unsigned seq,
conn->pending_page_flip_crtc = 0;
if (conn->status != WLR_DRM_CONN_CONNECTED || conn->crtc == NULL) {
if (conn->status != DRM_MODE_CONNECTED || conn->crtc == NULL) {
wlr_drm_conn_log(conn, WLR_DEBUG,
"Ignoring page-flip event for disabled connector");
return;
@ -1537,7 +1543,7 @@ int handle_drm_event(int fd, uint32_t mask, void *data) {
}
static void disconnect_drm_connector(struct wlr_drm_connector *conn) {
if (conn->status == WLR_DRM_CONN_DISCONNECTED) {
if (conn->status == DRM_MODE_DISCONNECTED) {
return;
}
@ -1545,7 +1551,7 @@ static void disconnect_drm_connector(struct wlr_drm_connector *conn) {
// our wlr_drm_connector.
wlr_output_destroy(&conn->output);
assert(conn->status == WLR_DRM_CONN_DISCONNECTED);
assert(conn->status == DRM_MODE_DISCONNECTED);
}
void destroy_drm_connector(struct wlr_drm_connector *conn) {
@ -1635,7 +1641,7 @@ struct wlr_drm_lease *wlr_drm_create_lease(struct wlr_output **outputs,
wl_signal_init(&lease->events.destroy);
wlr_log(WLR_DEBUG, "Issuing DRM lease with %d objects", n_objects);
int lease_fd = drmModeCreateLease(drm->fd, objects, n_objects, 0,
int lease_fd = drmModeCreateLease(drm->fd, objects, n_objects, O_CLOEXEC,
&lease->lessee_id);
if (lease_fd < 0) {
free(lease);
@ -1669,7 +1675,7 @@ void wlr_drm_lease_terminate(struct wlr_drm_lease *lease) {
void drm_lease_destroy(struct wlr_drm_lease *lease) {
struct wlr_drm_backend *drm = lease->backend;
wlr_signal_emit_safe(&lease->events.destroy, NULL);
wl_signal_emit_mutable(&lease->events.destroy, NULL);
struct wlr_drm_connector *conn;
wl_list_for_each(conn, &drm->outputs, link) {

View file

@ -115,8 +115,10 @@ static bool legacy_crtc_commit(struct wlr_drm_connector *conn,
}
}
if ((state->base->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) &&
drm_connector_supports_vrr(conn)) {
if (state->base->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) {
if (!drm_connector_supports_vrr(conn)) {
return false;
}
if (drmModeObjectSetProperty(drm->fd, crtc->id, DRM_MODE_OBJECT_CRTC,
crtc->props.vrr_enabled,
state->base->adaptive_sync_enabled) != 0) {

View file

@ -1,4 +1,5 @@
#define _POSIX_C_SOURCE 200809L
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
@ -25,7 +26,9 @@ static const struct prop_info connector_info[] = {
{ "EDID", INDEX(edid) },
{ "PATH", INDEX(path) },
{ "TILE", INDEX(tile) },
{ "content type", INDEX(content_type) },
{ "link-status", INDEX(link_status) },
{ "max bpc", INDEX(max_bpc) },
{ "non-desktop", INDEX(non_desktop) },
{ "panel orientation", INDEX(panel_orientation) },
{ "subconnector", INDEX(subconnector) },
@ -181,3 +184,28 @@ char *get_drm_prop_enum(int fd, uint32_t obj, uint32_t prop_id) {
return str;
}
bool introspect_drm_prop_range(int fd, uint32_t prop_id,
uint64_t *min, uint64_t *max) {
drmModePropertyRes *prop = drmModeGetProperty(fd, prop_id);
if (!prop) {
return false;
}
if (drmModeGetPropertyType(prop) != DRM_MODE_PROP_RANGE) {
drmModeFreeProperty(prop);
return false;
}
assert(prop->count_values == 2);
if (min != NULL) {
*min = prop->values[0];
}
if (max != NULL) {
*max = prop->values[1];
}
drmModeFreeProperty(prop);
return true;
}

View file

@ -48,31 +48,6 @@ void finish_drm_renderer(struct wlr_drm_renderer *renderer) {
wlr_renderer_destroy(renderer->wlr_rend);
}
bool init_drm_surface(struct wlr_drm_surface *surf,
struct wlr_drm_renderer *renderer, uint32_t width, uint32_t height,
const struct wlr_drm_format *drm_format) {
if (surf->width == width && surf->height == height) {
return true;
}
surf->renderer = renderer;
surf->width = width;
surf->height = height;
wlr_swapchain_destroy(surf->swapchain);
surf->swapchain = NULL;
surf->swapchain = wlr_swapchain_create(renderer->allocator, width, height,
drm_format);
if (surf->swapchain == NULL) {
wlr_log(WLR_ERROR, "Failed to create swapchain");
memset(surf, 0, sizeof(*surf));
return false;
}
return true;
}
static void finish_drm_surface(struct wlr_drm_surface *surf) {
if (!surf || !surf->renderer) {
return;
@ -83,12 +58,34 @@ static void finish_drm_surface(struct wlr_drm_surface *surf) {
memset(surf, 0, sizeof(*surf));
}
bool init_drm_surface(struct wlr_drm_surface *surf,
struct wlr_drm_renderer *renderer, int width, int height,
const struct wlr_drm_format *drm_format) {
if (surf->swapchain != NULL && surf->swapchain->width == width &&
surf->swapchain->height == height) {
return true;
}
finish_drm_surface(surf);
surf->swapchain = wlr_swapchain_create(renderer->allocator, width, height,
drm_format);
if (surf->swapchain == NULL) {
wlr_log(WLR_ERROR, "Failed to create swapchain");
return false;
}
surf->renderer = renderer;
return true;
}
struct wlr_buffer *drm_surface_blit(struct wlr_drm_surface *surf,
struct wlr_buffer *buffer) {
struct wlr_renderer *renderer = surf->renderer->wlr_rend;
if (surf->width != (uint32_t)buffer->width ||
surf->height != (uint32_t)buffer->height) {
if (surf->swapchain->width != buffer->width ||
surf->swapchain->height != buffer->height) {
wlr_log(WLR_ERROR, "Surface size doesn't match buffer size");
return NULL;
}
@ -106,7 +103,7 @@ struct wlr_buffer *drm_surface_blit(struct wlr_drm_surface *surf,
float mat[9];
wlr_matrix_identity(mat);
wlr_matrix_scale(mat, surf->width, surf->height);
wlr_matrix_scale(mat, surf->swapchain->width, surf->swapchain->height);
if (!wlr_renderer_begin_with_buffer(renderer, dst)) {
wlr_buffer_unlock(dst);

View file

@ -1,10 +1,14 @@
#define _POSIX_C_SOURCE 200809L
#include <assert.h>
#include <drm_fourcc.h>
#include <drm_mode.h>
#include <drm.h>
#include <libudev.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wlr/util/log.h>
#include "backend/drm/drm.h"
#include "backend/drm/util.h"
int32_t calculate_refresh_rate(const drmModeModeInfo *mode) {
@ -26,125 +30,93 @@ int32_t calculate_refresh_rate(const drmModeModeInfo *mode) {
return refresh;
}
// Constructed from http://edid.tv/manufacturer
static const char *get_manufacturer(uint16_t id) {
#define ID(a, b, c) ((a & 0x1f) << 10) | ((b & 0x1f) << 5) | (c & 0x1f)
switch (id) {
case ID('A', 'A', 'A'): return "Avolites Ltd";
case ID('A', 'C', 'I'): return "Ancor Communications Inc";
case ID('A', 'C', 'R'): return "Acer Technologies";
case ID('A', 'D', 'A'): return "Addi-Data GmbH";
case ID('A', 'P', 'P'): return "Apple Computer Inc";
case ID('A', 'S', 'K'): return "Ask A/S";
case ID('A', 'V', 'T'): return "Avtek (Electronics) Pty Ltd";
case ID('B', 'N', 'O'): return "Bang & Olufsen";
case ID('B', 'N', 'Q'): return "BenQ Corporation";
case ID('C', 'M', 'N'): return "Chimei Innolux Corporation";
case ID('C', 'M', 'O'): return "Chi Mei Optoelectronics corp.";
case ID('C', 'R', 'O'): return "Extraordinary Technologies PTY Limited";
case ID('D', 'E', 'L'): return "Dell Inc.";
case ID('D', 'G', 'C'): return "Data General Corporation";
case ID('D', 'O', 'N'): return "DENON, Ltd.";
case ID('E', 'N', 'C'): return "Eizo Nanao Corporation";
case ID('E', 'P', 'H'): return "Epiphan Systems Inc.";
case ID('E', 'X', 'P'): return "Data Export Corporation";
case ID('F', 'N', 'I'): return "Funai Electric Co., Ltd.";
case ID('F', 'U', 'S'): return "Fujitsu Siemens Computers GmbH";
case ID('G', 'S', 'M'): return "Goldstar Company Ltd";
case ID('H', 'I', 'Q'): return "Kaohsiung Opto Electronics Americas, Inc.";
case ID('H', 'S', 'D'): return "HannStar Display Corp";
case ID('H', 'T', 'C'): return "Hitachi Ltd";
case ID('H', 'W', 'P'): return "Hewlett Packard";
case ID('I', 'N', 'T'): return "Interphase Corporation";
case ID('I', 'N', 'X'): return "Communications Supply Corporation (A division of WESCO)";
case ID('I', 'T', 'E'): return "Integrated Tech Express Inc";
case ID('I', 'V', 'M'): return "Iiyama North America";
case ID('L', 'E', 'N'): return "Lenovo Group Limited";
case ID('M', 'A', 'X'): return "Rogen Tech Distribution Inc";
case ID('M', 'E', 'G'): return "Abeam Tech Ltd";
case ID('M', 'E', 'I'): return "Panasonic Industry Company";
case ID('M', 'T', 'C'): return "Mars-Tech Corporation";
case ID('M', 'T', 'X'): return "Matrox";
case ID('N', 'E', 'C'): return "NEC Corporation";
case ID('N', 'E', 'X'): return "Nexgen Mediatech Inc.";
case ID('O', 'N', 'K'): return "ONKYO Corporation";
case ID('O', 'R', 'N'): return "ORION ELECTRIC CO., LTD.";
case ID('O', 'T', 'M'): return "Optoma Corporation";
case ID('O', 'V', 'R'): return "Oculus VR, Inc.";
case ID('P', 'H', 'L'): return "Philips Consumer Electronics Company";
case ID('P', 'I', 'O'): return "Pioneer Electronic Corporation";
case ID('P', 'N', 'R'): return "Planar Systems, Inc.";
case ID('Q', 'D', 'S'): return "Quanta Display Inc.";
case ID('R', 'A', 'T'): return "Rent-A-Tech";
case ID('R', 'E', 'N'): return "Renesas Technology Corp.";
case ID('S', 'A', 'M'): return "Samsung Electric Company";
case ID('S', 'A', 'N'): return "Sanyo Electric Co., Ltd.";
case ID('S', 'E', 'C'): return "Seiko Epson Corporation";
case ID('S', 'H', 'P'): return "Sharp Corporation";
case ID('S', 'I', 'I'): return "Silicon Image, Inc.";
case ID('S', 'N', 'Y'): return "Sony";
case ID('S', 'T', 'D'): return "STD Computer Inc";
case ID('S', 'V', 'S'): return "SVSI";
case ID('S', 'Y', 'N'): return "Synaptics Inc";
case ID('T', 'C', 'L'): return "Technical Concepts Ltd";
case ID('T', 'O', 'P'): return "Orion Communications Co., Ltd.";
case ID('T', 'S', 'B'): return "Toshiba America Info Systems Inc";
case ID('T', 'S', 'T'): return "Transtream Inc";
case ID('U', 'N', 'K'): return "Unknown";
case ID('V', 'E', 'S'): return "Vestel Elektronik Sanayi ve Ticaret A. S.";
case ID('V', 'I', 'T'): return "Visitech AS";
case ID('V', 'I', 'Z'): return "VIZIO, Inc";
case ID('V', 'L', 'V'): return "Valve";
case ID('V', 'S', 'C'): return "ViewSonic Corporation";
case ID('Y', 'M', 'H'): return "Yamaha Corporation";
default: return "Unknown";
static const char *get_manufacturer(struct udev_hwdb *hwdb, uint16_t code) {
static char pnp_id[4];
// The ASCII 3-letter manufacturer PnP ID is encoded in 5-bit codes
pnp_id[0] = ((code >> 10) & 0x1F) + '@';
pnp_id[1] = ((code >> 5) & 0x1F) + '@';
pnp_id[2] = ((code >> 0) & 0x1F) + '@';
pnp_id[3] = '\0';
if (hwdb == NULL) {
return pnp_id;
}
#undef ID
char query[32];
snprintf(query, sizeof(query), "acpi:%s:", pnp_id);
struct udev_list_entry *acpi_entry =
udev_hwdb_get_properties_list_entry(hwdb, query, 0);
if (acpi_entry == NULL) {
return pnp_id;
}
struct udev_list_entry *vendor_entry =
udev_list_entry_get_by_name(acpi_entry, "ID_VENDOR_FROM_DATABASE");
if (vendor_entry == NULL) {
return pnp_id;
}
return udev_list_entry_get_value(vendor_entry);
}
/* See https://en.wikipedia.org/wiki/Extended_Display_Identification_Data for layout of EDID data.
* We don't parse the EDID properly. We just expect to receive valid data.
*/
void parse_edid(struct wlr_output *restrict output, size_t len, const uint8_t *data) {
void parse_edid(struct wlr_drm_connector *conn, size_t len, const uint8_t *data) {
struct wlr_output *output = &conn->output;
free(output->make);
free(output->model);
free(output->serial);
output->make = NULL;
output->model = NULL;
output->serial = NULL;
if (!data || len < 128) {
snprintf(output->make, sizeof(output->make), "<Unknown>");
snprintf(output->model, sizeof(output->model), "<Unknown>");
return;
}
uint16_t id = (data[8] << 8) | data[9];
snprintf(output->make, sizeof(output->make), "%s", get_manufacturer(id));
output->make = strdup(get_manufacturer(conn->backend->hwdb, id));
uint16_t model = data[10] | (data[11] << 8);
snprintf(output->model, sizeof(output->model), "0x%04X", model);
char model_str[32];
snprintf(model_str, sizeof(model_str), "0x%04" PRIX16, model);
uint32_t serial = data[12] | (data[13] << 8) | (data[14] << 8) | (data[15] << 8);
snprintf(output->serial, sizeof(output->serial), "0x%08X", serial);
char serial_str[32];
if (serial != 0) {
snprintf(serial_str, sizeof(serial_str), "0x%08" PRIX32, serial);
} else {
serial_str[0] = '\0';
}
for (size_t i = 72; i <= 108; i += 18) {
uint16_t flag = (data[i] << 8) | data[i + 1];
if (flag == 0 && data[i + 3] == 0xFC) {
sprintf(output->model, "%.13s", &data[i + 5]);
snprintf(model_str, sizeof(model_str), "%.13s", &data[i + 5]);
// Monitor names are terminated by newline if they're too short
char *nl = strchr(output->model, '\n');
char *nl = strchr(model_str, '\n');
if (nl) {
*nl = '\0';
}
} else if (flag == 0 && data[i + 3] == 0xFF) {
sprintf(output->serial, "%.13s", &data[i + 5]);
snprintf(serial_str, sizeof(serial_str), "%.13s", &data[i + 5]);
// Monitor serial numbers are terminated by newline if they're too
// short
char *nl = strchr(output->serial, '\n');
char* nl = strchr(serial_str, '\n');
if (nl) {
*nl = '\0';
}
}
}
}
void parse_tile(struct wlr_output *restrict output, size_t len, const uint8_t *data) {
void parse_tile(struct wlr_drm_connector *conn, size_t len, const uint8_t *data) {
struct wlr_output *output = &conn->output;
if (len > 0) {
int ret;
ret = sscanf((char*)data, "%d:%d:%d:%d:%d:%d:%d:%d",
@ -207,6 +179,9 @@ const char *conn_get_name(uint32_t type_id) {
case DRM_MODE_CONNECTOR_USB: return "USB";
#endif
default: return "Unknown";
output->model = strdup(model_str);
if (serial_str[0] != '\0') {
output->serial = strdup(serial_str);
}
}

View file

@ -3,7 +3,6 @@
#include <wlr/interfaces/wlr_output.h>
#include <wlr/util/log.h>
#include "backend/headless.h"
#include "util/signal.h"
struct wlr_headless_backend *headless_backend_from_backend(
struct wlr_backend *wlr_backend) {
@ -20,7 +19,7 @@ static bool backend_start(struct wlr_backend *wlr_backend) {
wl_list_for_each(output, &backend->outputs, link) {
wl_event_source_timer_update(output->frame_timer, output->frame_delay);
wlr_output_update_enabled(&output->wlr_output, true);
wlr_signal_emit_safe(&backend->backend.events.new_output,
wl_signal_emit_mutable(&backend->backend.events.new_output,
&output->wlr_output);
}

View file

@ -4,7 +4,6 @@
#include <wlr/interfaces/wlr_output.h>
#include <wlr/util/log.h>
#include "backend/headless.h"
#include "util/signal.h"
static const uint32_t SUPPORTED_OUTPUT_STATE =
WLR_OUTPUT_STATE_BACKEND_OPTIONAL |
@ -29,40 +28,41 @@ static bool output_set_custom_mode(struct wlr_headless_output *output,
return true;
}
static bool output_test(struct wlr_output *wlr_output) {
uint32_t unsupported =
wlr_output->pending.committed & ~SUPPORTED_OUTPUT_STATE;
static bool output_test(struct wlr_output *wlr_output,
const struct wlr_output_state *state) {
uint32_t unsupported = state->committed & ~SUPPORTED_OUTPUT_STATE;
if (unsupported != 0) {
wlr_log(WLR_DEBUG, "Unsupported output state fields: 0x%"PRIx32,
unsupported);
return false;
}
if (wlr_output->pending.committed & WLR_OUTPUT_STATE_MODE) {
assert(wlr_output->pending.mode_type == WLR_OUTPUT_STATE_MODE_CUSTOM);
if (state->committed & WLR_OUTPUT_STATE_MODE) {
assert(state->mode_type == WLR_OUTPUT_STATE_MODE_CUSTOM);
}
return true;
}
static bool output_commit(struct wlr_output *wlr_output) {
static bool output_commit(struct wlr_output *wlr_output,
const struct wlr_output_state *state) {
struct wlr_headless_output *output =
headless_output_from_output(wlr_output);
if (!output_test(wlr_output)) {
if (!output_test(wlr_output, state)) {
return false;
}
if (wlr_output->pending.committed & WLR_OUTPUT_STATE_MODE) {
if (state->committed & WLR_OUTPUT_STATE_MODE) {
if (!output_set_custom_mode(output,
wlr_output->pending.custom_mode.width,
wlr_output->pending.custom_mode.height,
wlr_output->pending.custom_mode.refresh)) {
state->custom_mode.width,
state->custom_mode.height,
state->custom_mode.refresh)) {
return false;
}
}
if (wlr_output->pending.committed & WLR_OUTPUT_STATE_BUFFER) {
if (state->committed & WLR_OUTPUT_STATE_BUFFER) {
struct wlr_output_event_present present_event = {
.commit_seq = wlr_output->commit_seq + 1,
.presented = true,
@ -70,6 +70,8 @@ static bool output_commit(struct wlr_output *wlr_output) {
wlr_output_send_present(wlr_output, &present_event);
}
wl_event_source_timer_update(output->frame_timer, output->frame_delay);
return true;
}
@ -93,7 +95,6 @@ bool wlr_output_is_headless(struct wlr_output *wlr_output) {
static int signal_frame(void *data) {
struct wlr_headless_output *output = data;
wlr_output_send_frame(&output->wlr_output);
wl_event_source_timer_update(output->frame_timer, output->frame_delay);
return 0;
}
@ -114,8 +115,6 @@ struct wlr_output *wlr_headless_add_output(struct wlr_backend *wlr_backend,
struct wlr_output *wlr_output = &output->wlr_output;
output_set_custom_mode(output, width, height, 0);
strncpy(wlr_output->make, "headless", sizeof(wlr_output->make));
strncpy(wlr_output->model, "headless", sizeof(wlr_output->model));
char name[64];
snprintf(name, sizeof(name), "HEADLESS-%zu", ++backend->last_output_num);
@ -134,7 +133,7 @@ struct wlr_output *wlr_headless_add_output(struct wlr_backend *wlr_backend,
if (backend->started) {
wl_event_source_timer_update(output->frame_timer, output->frame_delay);
wlr_output_update_enabled(wlr_output, true);
wlr_signal_emit_safe(&backend->backend.events.new_output, wlr_output);
wl_signal_emit_mutable(&backend->backend.events.new_output, wlr_output);
}
return wlr_output;

View file

@ -6,7 +6,7 @@
#include <wlr/backend/session.h>
#include <wlr/util/log.h>
#include "backend/libinput.h"
#include "util/signal.h"
#include "util/env.h"
static struct wlr_libinput_backend *get_libinput_backend_from_backend(
struct wlr_backend *wlr_backend) {
@ -104,15 +104,10 @@ static bool backend_start(struct wlr_backend *wlr_backend) {
libinput_log_set_priority(backend->libinput_context, LIBINPUT_LOG_PRIORITY_ERROR);
int libinput_fd = libinput_get_fd(backend->libinput_context);
char *no_devs = getenv("WLR_LIBINPUT_NO_DEVICES");
if (no_devs) {
if (strcmp(no_devs, "1") != 0) {
no_devs = NULL;
}
}
if (!no_devs && backend->wlr_device_lists.size == 0) {
if (!env_parse_bool("WLR_LIBINPUT_NO_DEVICES") && wl_list_empty(&backend->devices)) {
handle_libinput_readable(libinput_fd, WL_EVENT_READABLE, backend);
if (backend->wlr_device_lists.size == 0) {
if (wl_list_empty(&backend->devices)) {
wlr_log(WLR_ERROR, "libinput initialization failed, no input devices");
wlr_log(WLR_ERROR, "Set WLR_LIBINPUT_NO_DEVICES=1 to suppress this check");
return false;
@ -141,13 +136,9 @@ static void backend_destroy(struct wlr_backend *wlr_backend) {
struct wlr_libinput_backend *backend =
get_libinput_backend_from_backend(wlr_backend);
struct wl_list **wlr_devices_ptr;
wl_array_for_each(wlr_devices_ptr, &backend->wlr_device_lists) {
struct wlr_libinput_input_device *dev, *tmp;
wl_list_for_each_safe(dev, tmp, *wlr_devices_ptr, link) {
destroy_libinput_input_device(dev);
}
free(*wlr_devices_ptr);
struct wlr_libinput_input_device *dev, *tmp;
wl_list_for_each_safe(dev, tmp, &backend->devices, link) {
destroy_libinput_input_device(dev);
}
wlr_backend_finish(wlr_backend);
@ -156,7 +147,6 @@ static void backend_destroy(struct wlr_backend *wlr_backend) {
wl_list_remove(&backend->session_destroy.link);
wl_list_remove(&backend->session_signal.link);
wl_array_release(&backend->wlr_device_lists);
if (backend->input_event) {
wl_event_source_remove(backend->input_event);
}
@ -211,7 +201,7 @@ struct wlr_backend *wlr_libinput_backend_create(struct wl_display *display,
}
wlr_backend_init(&backend->backend, &backend_impl);
wl_array_init(&backend->wlr_device_lists);
wl_list_init(&backend->devices);
backend->session = session;
backend->display = display;
@ -230,8 +220,27 @@ struct wlr_backend *wlr_libinput_backend_create(struct wl_display *display,
struct libinput_device *wlr_libinput_get_device_handle(
struct wlr_input_device *wlr_dev) {
struct wlr_libinput_input_device *dev =
(struct wlr_libinput_input_device *)wlr_dev;
struct wlr_libinput_input_device *dev = NULL;
switch (wlr_dev->type) {
case WLR_INPUT_DEVICE_KEYBOARD:
dev = device_from_keyboard(wlr_keyboard_from_input_device(wlr_dev));
break;
case WLR_INPUT_DEVICE_POINTER:
dev = device_from_pointer(wlr_pointer_from_input_device(wlr_dev));
break;
case WLR_INPUT_DEVICE_SWITCH:
dev = device_from_switch(wlr_switch_from_input_device(wlr_dev));
break;
case WLR_INPUT_DEVICE_TOUCH:
dev = device_from_touch(wlr_touch_from_input_device(wlr_dev));
break;
case WLR_INPUT_DEVICE_TABLET_TOOL:
dev = device_from_tablet(wlr_tablet_from_input_device(wlr_dev));
break;
case WLR_INPUT_DEVICE_TABLET_PAD:
dev = device_from_tablet_pad(wlr_tablet_pad_from_input_device(wlr_dev));
break;
}
return dev->handle;
}

View file

@ -1,87 +1,62 @@
#define _POSIX_C_SOURCE 200809L
#include <assert.h>
#include <libinput.h>
#include <stdlib.h>
#include <wayland-util.h>
#include <wlr/backend/session.h>
#include <wlr/interfaces/wlr_keyboard.h>
#include <wlr/interfaces/wlr_pointer.h>
#include <wlr/interfaces/wlr_touch.h>
#include <wlr/interfaces/wlr_tablet_tool.h>
#include <wlr/interfaces/wlr_tablet_pad.h>
#include <wlr/interfaces/wlr_switch.h>
#include <wlr/util/log.h>
#include "backend/libinput.h"
#include "util/array.h"
#include "util/signal.h"
struct wlr_input_device *get_appropriate_device(
enum wlr_input_device_type desired_type,
struct libinput_device *libinput_dev) {
struct wl_list *wlr_devices = libinput_device_get_user_data(libinput_dev);
if (!wlr_devices) {
return NULL;
void destroy_libinput_input_device(struct wlr_libinput_input_device *dev) {
if (dev->keyboard.impl) {
wlr_keyboard_finish(&dev->keyboard);
}
struct wlr_libinput_input_device *dev;
wl_list_for_each(dev, wlr_devices, link) {
if (dev->wlr_input_device.type == desired_type) {
return &dev->wlr_input_device;
}
if (dev->pointer.impl) {
wlr_pointer_finish(&dev->pointer);
}
return NULL;
}
void destroy_libinput_input_device(struct wlr_libinput_input_device *dev)
{
/**
* TODO remove the redundant wlr_input_device from wlr_libinput_input_device
* wlr_libinput_input_device::wlr_input_device is not owned by its input
* device type, which means we have 2 wlr_input_device to cleanup
*/
if (dev->wlr_input_device._device) {
wlr_input_device_destroy(&dev->wlr_input_device);
if (dev->switch_device.impl) {
wlr_switch_finish(&dev->switch_device);
}
if (dev->touch.impl) {
wlr_touch_finish(&dev->touch);
}
if (dev->tablet.impl) {
finish_device_tablet(dev);
}
if (dev->tablet_pad.impl) {
finish_device_tablet_pad(dev);
}
wlr_input_device_finish(&dev->wlr_input_device);
libinput_device_unref(dev->handle);
wl_list_remove(&dev->link);
free(dev);
}
static struct wlr_input_device *allocate_device(
struct wlr_libinput_backend *backend,
struct libinput_device *libinput_dev, struct wl_list *wlr_devices,
enum wlr_input_device_type type) {
const char *name = libinput_device_get_name(libinput_dev);
struct wlr_libinput_input_device *dev =
calloc(1, sizeof(struct wlr_libinput_input_device));
if (dev == NULL) {
return NULL;
}
struct wlr_input_device *wlr_dev = &dev->wlr_input_device;
libinput_device_get_size(libinput_dev,
&wlr_dev->width_mm, &wlr_dev->height_mm);
const char *output_name = libinput_device_get_output_name(libinput_dev);
if (output_name != NULL) {
wlr_dev->output_name = strdup(output_name);
}
wl_list_insert(wlr_devices, &dev->link);
dev->handle = libinput_dev;
libinput_device_ref(libinput_dev);
wlr_input_device_init(wlr_dev, type, name);
wlr_dev->vendor = libinput_device_get_id_vendor(libinput_dev);
wlr_dev->product = libinput_device_get_id_product(libinput_dev);
return wlr_dev;
}
bool wlr_input_device_is_libinput(struct wlr_input_device *wlr_dev) {
switch (wlr_dev->type) {
case WLR_INPUT_DEVICE_KEYBOARD:
return wlr_dev->keyboard->impl == &libinput_keyboard_impl;
return wlr_keyboard_from_input_device(wlr_dev)->impl ==
&libinput_keyboard_impl;
case WLR_INPUT_DEVICE_POINTER:
return wlr_dev->pointer->impl == &libinput_pointer_impl;
return wlr_pointer_from_input_device(wlr_dev)->impl ==
&libinput_pointer_impl;
case WLR_INPUT_DEVICE_TOUCH:
return wlr_dev->touch->impl == &libinput_touch_impl;
return wlr_touch_from_input_device(wlr_dev)->impl ==
&libinput_touch_impl;
case WLR_INPUT_DEVICE_TABLET_TOOL:
return wlr_dev->tablet->impl == &libinput_tablet_impl;
return wlr_tablet_from_input_device(wlr_dev)-> impl ==
&libinput_tablet_impl;
case WLR_INPUT_DEVICE_TABLET_PAD:
return wlr_dev->tablet_pad->impl == &libinput_tablet_pad_impl;
return wlr_tablet_pad_from_input_device(wlr_dev)->impl ==
&libinput_tablet_pad_impl;
case WLR_INPUT_DEVICE_SWITCH:
return wlr_dev->switch_device->impl == &libinput_switch_impl;
return wlr_switch_from_input_device(wlr_dev)->impl ==
&libinput_switch_impl;
default:
return false;
}
@ -89,165 +64,96 @@ bool wlr_input_device_is_libinput(struct wlr_input_device *wlr_dev) {
static void handle_device_added(struct wlr_libinput_backend *backend,
struct libinput_device *libinput_dev) {
/*
* Note: the wlr API exposes only devices with a single capability, because
* that meshes better with how Wayland does things and is a bit simpler.
* However, libinput devices often have multiple capabilities - in such
* cases we have to create several devices.
*/
int vendor = libinput_device_get_id_vendor(libinput_dev);
int product = libinput_device_get_id_product(libinput_dev);
const char *name = libinput_device_get_name(libinput_dev);
struct wl_list *wlr_devices = calloc(1, sizeof(struct wl_list));
if (!wlr_devices) {
wlr_log(WLR_ERROR, "Allocation failed");
wlr_log(WLR_DEBUG, "Adding %s [%d:%d]", name, vendor, product);
struct wlr_libinput_input_device *dev =
calloc(1, sizeof(struct wlr_libinput_input_device));
if (dev == NULL) {
wlr_log_errno(WLR_ERROR, "failed to allocate wlr_libinput_input_device");
return;
}
wl_list_init(wlr_devices);
wlr_log(WLR_DEBUG, "Added %s [%d:%d]", name, vendor, product);
dev->handle = libinput_dev;
libinput_device_ref(libinput_dev);
libinput_device_set_user_data(libinput_dev, dev);
wl_list_insert(&backend->devices, &dev->link);
if (libinput_device_has_capability(
libinput_dev, LIBINPUT_DEVICE_CAP_KEYBOARD)) {
struct wlr_input_device *wlr_dev = allocate_device(backend,
libinput_dev, wlr_devices, WLR_INPUT_DEVICE_KEYBOARD);
if (!wlr_dev) {
goto fail;
}
wlr_dev->keyboard = create_libinput_keyboard(libinput_dev);
if (!wlr_dev->keyboard) {
free(wlr_dev);
goto fail;
}
wlr_signal_emit_safe(&backend->backend.events.new_input, wlr_dev);
init_device_keyboard(dev);
wl_signal_emit_mutable(&backend->backend.events.new_input,
&dev->keyboard.base);
}
if (libinput_device_has_capability(
libinput_dev, LIBINPUT_DEVICE_CAP_POINTER)) {
struct wlr_input_device *wlr_dev = allocate_device(backend,
libinput_dev, wlr_devices, WLR_INPUT_DEVICE_POINTER);
if (!wlr_dev) {
goto fail;
}
wlr_dev->pointer = create_libinput_pointer(libinput_dev);
if (!wlr_dev->pointer) {
free(wlr_dev);
goto fail;
}
wlr_signal_emit_safe(&backend->backend.events.new_input, wlr_dev);
}
if (libinput_device_has_capability(
libinput_dev, LIBINPUT_DEVICE_CAP_TOUCH)) {
struct wlr_input_device *wlr_dev = allocate_device(backend,
libinput_dev, wlr_devices, WLR_INPUT_DEVICE_TOUCH);
if (!wlr_dev) {
goto fail;
}
wlr_dev->touch = create_libinput_touch(libinput_dev);
if (!wlr_dev->touch) {
free(wlr_dev);
goto fail;
}
wlr_signal_emit_safe(&backend->backend.events.new_input, wlr_dev);
}
if (libinput_device_has_capability(libinput_dev,
LIBINPUT_DEVICE_CAP_TABLET_TOOL)) {
struct wlr_input_device *wlr_dev = allocate_device(backend,
libinput_dev, wlr_devices, WLR_INPUT_DEVICE_TABLET_TOOL);
if (!wlr_dev) {
goto fail;
}
wlr_dev->tablet = create_libinput_tablet(libinput_dev);
if (!wlr_dev->tablet) {
free(wlr_dev);
goto fail;
}
wlr_signal_emit_safe(&backend->backend.events.new_input, wlr_dev);
}
if (libinput_device_has_capability(
libinput_dev, LIBINPUT_DEVICE_CAP_TABLET_PAD)) {
struct wlr_input_device *wlr_dev = allocate_device(backend,
libinput_dev, wlr_devices, WLR_INPUT_DEVICE_TABLET_PAD);
if (!wlr_dev) {
goto fail;
}
wlr_dev->tablet_pad = create_libinput_tablet_pad(libinput_dev);
if (!wlr_dev->tablet_pad) {
free(wlr_dev);
goto fail;
}
wlr_signal_emit_safe(&backend->backend.events.new_input, wlr_dev);
}
if (libinput_device_has_capability(
libinput_dev, LIBINPUT_DEVICE_CAP_GESTURE)) {
// TODO
init_device_pointer(dev);
wl_signal_emit_mutable(&backend->backend.events.new_input,
&dev->pointer.base);
}
if (libinput_device_has_capability(
libinput_dev, LIBINPUT_DEVICE_CAP_SWITCH)) {
struct wlr_input_device *wlr_dev = allocate_device(backend,
libinput_dev, wlr_devices, WLR_INPUT_DEVICE_SWITCH);
if (!wlr_dev) {
goto fail;
}
wlr_dev->switch_device = create_libinput_switch(libinput_dev);
if (!wlr_dev->switch_device) {
free(wlr_dev);
goto fail;
}
wlr_signal_emit_safe(&backend->backend.events.new_input, wlr_dev);
init_device_switch(dev);
wl_signal_emit_mutable(&backend->backend.events.new_input,
&dev->switch_device.base);
}
if (!wl_list_empty(wlr_devices)) {
struct wl_list **dst = wl_array_add(&backend->wlr_device_lists, sizeof(wlr_devices));
if (!dst) {
goto fail;
}
*dst = wlr_devices;
libinput_device_set_user_data(libinput_dev, wlr_devices);
} else {
free(wlr_devices);
if (libinput_device_has_capability(
libinput_dev, LIBINPUT_DEVICE_CAP_TOUCH)) {
init_device_touch(dev);
wl_signal_emit_mutable(&backend->backend.events.new_input,
&dev->touch.base);
}
return;
fail:
wlr_log(WLR_ERROR, "Could not allocate new device");
struct wlr_libinput_input_device *dev, *tmp_dev;
wl_list_for_each_safe(dev, tmp_dev, wlr_devices, link) {
free(dev);
if (libinput_device_has_capability(libinput_dev,
LIBINPUT_DEVICE_CAP_TABLET_TOOL)) {
init_device_tablet(dev);
wl_signal_emit_mutable(&backend->backend.events.new_input,
&dev->tablet.base);
}
if (libinput_device_has_capability(
libinput_dev, LIBINPUT_DEVICE_CAP_TABLET_PAD)) {
init_device_tablet_pad(dev);
wl_signal_emit_mutable(&backend->backend.events.new_input,
&dev->tablet_pad.base);
}
if (libinput_device_has_capability(
libinput_dev, LIBINPUT_DEVICE_CAP_GESTURE)) {
wlr_log(WLR_DEBUG, "libinput gesture not handled");
}
free(wlr_devices);
}
static void handle_device_removed(struct wlr_libinput_backend *backend,
struct libinput_device *libinput_dev) {
struct wl_list *wlr_devices = libinput_device_get_user_data(libinput_dev);
int vendor = libinput_device_get_id_vendor(libinput_dev);
int product = libinput_device_get_id_product(libinput_dev);
const char *name = libinput_device_get_name(libinput_dev);
wlr_log(WLR_DEBUG, "Removing %s [%d:%d]", name, vendor, product);
if (!wlr_devices) {
struct wlr_libinput_input_device *dev =
libinput_device_get_user_data(libinput_dev);
if (dev == NULL) {
wlr_log(WLR_ERROR, "libinput_device has no wlr_libinput_input_device");
return;
}
struct wlr_libinput_input_device *dev, *tmp_dev;
wl_list_for_each_safe(dev, tmp_dev, wlr_devices, link) {
destroy_libinput_input_device(dev);
}
size_t i = 0;
struct wl_list **ptr;
wl_array_for_each(ptr, &backend->wlr_device_lists) {
struct wl_list *iter = *ptr;
if (iter == wlr_devices) {
array_remove_at(&backend->wlr_device_lists,
i * sizeof(struct wl_list *), sizeof(struct wl_list *));
break;
}
i++;
}
free(wlr_devices);
destroy_libinput_input_device(dev);
}
void handle_libinput_event(struct wlr_libinput_backend *backend,
struct libinput_event *event) {
struct libinput_device *libinput_dev = libinput_event_get_device(event);
struct wlr_libinput_input_device *dev =
libinput_device_get_user_data(libinput_dev);
enum libinput_event_type event_type = libinput_event_get_type(event);
switch (event_type) {
case LIBINPUT_EVENT_DEVICE_ADDED:
@ -257,83 +163,100 @@ void handle_libinput_event(struct wlr_libinput_backend *backend,
handle_device_removed(backend, libinput_dev);
break;
case LIBINPUT_EVENT_KEYBOARD_KEY:
handle_keyboard_key(event, libinput_dev);
handle_keyboard_key(event, &dev->keyboard);
break;
case LIBINPUT_EVENT_POINTER_MOTION:
handle_pointer_motion(event, libinput_dev);
handle_pointer_motion(event, &dev->pointer);
break;
case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
handle_pointer_motion_abs(event, libinput_dev);
handle_pointer_motion_abs(event, &dev->pointer);
break;
case LIBINPUT_EVENT_POINTER_BUTTON:
handle_pointer_button(event, libinput_dev);
handle_pointer_button(event, &dev->pointer);
break;
case LIBINPUT_EVENT_POINTER_AXIS:
handle_pointer_axis(event, libinput_dev);
#if !LIBINPUT_HAS_SCROLL_VALUE120
/* This event must be ignored in favour of the SCROLL_* events */
handle_pointer_axis(event, &dev->pointer);
#endif
break;
#if LIBINPUT_HAS_SCROLL_VALUE120
case LIBINPUT_EVENT_POINTER_SCROLL_WHEEL:
handle_pointer_axis_value120(event, &dev->pointer,
WLR_AXIS_SOURCE_WHEEL);
break;
case LIBINPUT_EVENT_POINTER_SCROLL_FINGER:
handle_pointer_axis_value120(event, &dev->pointer,
WLR_AXIS_SOURCE_FINGER);
break;
case LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS:
handle_pointer_axis_value120(event, &dev->pointer,
WLR_AXIS_SOURCE_CONTINUOUS);
break;
#endif
case LIBINPUT_EVENT_TOUCH_DOWN:
handle_touch_down(event, libinput_dev);
handle_touch_down(event, &dev->touch);
break;
case LIBINPUT_EVENT_TOUCH_UP:
handle_touch_up(event, libinput_dev);
handle_touch_up(event, &dev->touch);
break;
case LIBINPUT_EVENT_TOUCH_MOTION:
handle_touch_motion(event, libinput_dev);
handle_touch_motion(event, &dev->touch);
break;
case LIBINPUT_EVENT_TOUCH_CANCEL:
handle_touch_cancel(event, libinput_dev);
handle_touch_cancel(event, &dev->touch);
break;
case LIBINPUT_EVENT_TOUCH_FRAME:
handle_touch_frame(event, libinput_dev);
handle_touch_frame(event, &dev->touch);
break;
case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
handle_tablet_tool_axis(event, libinput_dev);
handle_tablet_tool_axis(event, &dev->tablet);
break;
case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY:
handle_tablet_tool_proximity(event, libinput_dev);
handle_tablet_tool_proximity(event, &dev->tablet);
break;
case LIBINPUT_EVENT_TABLET_TOOL_TIP:
handle_tablet_tool_tip(event, libinput_dev);
handle_tablet_tool_tip(event, &dev->tablet);
break;
case LIBINPUT_EVENT_TABLET_TOOL_BUTTON:
handle_tablet_tool_button(event, libinput_dev);
handle_tablet_tool_button(event, &dev->tablet);
break;
case LIBINPUT_EVENT_TABLET_PAD_BUTTON:
handle_tablet_pad_button(event, libinput_dev);
handle_tablet_pad_button(event, &dev->tablet_pad);
break;
case LIBINPUT_EVENT_TABLET_PAD_RING:
handle_tablet_pad_ring(event, libinput_dev);
handle_tablet_pad_ring(event, &dev->tablet_pad);
break;
case LIBINPUT_EVENT_TABLET_PAD_STRIP:
handle_tablet_pad_strip(event, libinput_dev);
handle_tablet_pad_strip(event, &dev->tablet_pad);
break;
case LIBINPUT_EVENT_SWITCH_TOGGLE:
handle_switch_toggle(event, libinput_dev);
handle_switch_toggle(event, &dev->switch_device);
break;
case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN:
handle_pointer_swipe_begin(event, libinput_dev);
handle_pointer_swipe_begin(event, &dev->pointer);
break;
case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE:
handle_pointer_swipe_update(event, libinput_dev);
handle_pointer_swipe_update(event, &dev->pointer);
break;
case LIBINPUT_EVENT_GESTURE_SWIPE_END:
handle_pointer_swipe_end(event, libinput_dev);
handle_pointer_swipe_end(event, &dev->pointer);
break;
case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN:
handle_pointer_pinch_begin(event, libinput_dev);
handle_pointer_pinch_begin(event, &dev->pointer);
break;
case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE:
handle_pointer_pinch_update(event, libinput_dev);
handle_pointer_pinch_update(event, &dev->pointer);
break;
case LIBINPUT_EVENT_GESTURE_PINCH_END:
handle_pointer_pinch_end(event, libinput_dev);
handle_pointer_pinch_end(event, &dev->pointer);
break;
#if LIBINPUT_HAS_HOLD_GESTURES
case LIBINPUT_EVENT_GESTURE_HOLD_BEGIN:
handle_pointer_hold_begin(event, libinput_dev);
handle_pointer_hold_begin(event, &dev->pointer);
break;
case LIBINPUT_EVENT_GESTURE_HOLD_END:
handle_pointer_hold_end(event, libinput_dev);
handle_pointer_hold_end(event, &dev->pointer);
break;
#endif
default:

View file

@ -1,70 +1,42 @@
#include <assert.h>
#include <libinput.h>
#include <stdlib.h>
#include <wlr/backend/session.h>
#include <wlr/types/wlr_input_device.h>
#include <wlr/util/log.h>
#include <wlr/interfaces/wlr_keyboard.h>
#include "backend/libinput.h"
struct wlr_libinput_keyboard {
struct wlr_keyboard wlr_keyboard;
struct libinput_device *libinput_dev;
};
struct wlr_libinput_input_device *device_from_keyboard(
struct wlr_keyboard *kb) {
assert(kb->impl == &libinput_keyboard_impl);
static struct wlr_libinput_keyboard *get_libinput_keyboard_from_keyboard(
struct wlr_keyboard *wlr_kb) {
assert(wlr_kb->impl == &libinput_keyboard_impl);
return (struct wlr_libinput_keyboard *)wlr_kb;
struct wlr_libinput_input_device *dev = wl_container_of(kb, dev, keyboard);
return dev;
}
static void keyboard_set_leds(struct wlr_keyboard *wlr_kb, uint32_t leds) {
struct wlr_libinput_keyboard *kb =
get_libinput_keyboard_from_keyboard(wlr_kb);
libinput_device_led_update(kb->libinput_dev, leds);
}
static void keyboard_destroy(struct wlr_keyboard *wlr_kb) {
struct wlr_libinput_keyboard *kb =
get_libinput_keyboard_from_keyboard(wlr_kb);
libinput_device_unref(kb->libinput_dev);
free(kb);
struct wlr_libinput_input_device *dev = device_from_keyboard(wlr_kb);
libinput_device_led_update(dev->handle, leds);
}
const struct wlr_keyboard_impl libinput_keyboard_impl = {
.destroy = keyboard_destroy,
.name = "libinput-keyboard",
.led_update = keyboard_set_leds
};
struct wlr_keyboard *create_libinput_keyboard(
struct libinput_device *libinput_dev) {
struct wlr_libinput_keyboard *kb =
calloc(1, sizeof(struct wlr_libinput_keyboard));
if (kb == NULL) {
return NULL;
}
kb->libinput_dev = libinput_dev;
libinput_device_ref(libinput_dev);
libinput_device_led_update(libinput_dev, 0);
struct wlr_keyboard *wlr_kb = &kb->wlr_keyboard;
const char *name = libinput_device_get_name(libinput_dev);
void init_device_keyboard(struct wlr_libinput_input_device *dev) {
const char *name = libinput_device_get_name(dev->handle);
struct wlr_keyboard *wlr_kb = &dev->keyboard;
wlr_keyboard_init(wlr_kb, &libinput_keyboard_impl, name);
wlr_kb->base.vendor = libinput_device_get_id_vendor(libinput_dev);
wlr_kb->base.product = libinput_device_get_id_product(libinput_dev);
return wlr_kb;
wlr_kb->base.vendor = libinput_device_get_id_vendor(dev->handle);
wlr_kb->base.product = libinput_device_get_id_product(dev->handle);
libinput_device_led_update(dev->handle, 0);
}
void handle_keyboard_key(struct libinput_event *event,
struct libinput_device *libinput_dev) {
struct wlr_input_device *wlr_dev =
get_appropriate_device(WLR_INPUT_DEVICE_KEYBOARD, libinput_dev);
if (!wlr_dev) {
wlr_log(WLR_DEBUG,
"Got a keyboard event for a device with no keyboards?");
return;
}
struct wlr_keyboard *kb) {
struct libinput_event_keyboard *kbevent =
libinput_event_get_keyboard_event(event);
struct wlr_event_keyboard_key wlr_event = { 0 };
struct wlr_keyboard_key_event wlr_event = { 0 };
wlr_event.time_msec =
usec_to_msec(libinput_event_keyboard_get_time_usec(kbevent));
wlr_event.keycode = libinput_event_keyboard_get_key(kbevent);
@ -79,5 +51,5 @@ void handle_keyboard_key(struct libinput_event *event,
break;
}
wlr_event.update_state = true;
wlr_keyboard_notify_key(wlr_dev->keyboard, &wlr_event);
wlr_keyboard_notify_key(kb, &wlr_event);
}

View file

@ -28,8 +28,8 @@ wlr_files += files(
features += { 'libinput-backend': true }
wlr_deps += libinput
# libinput hold gestures are available since 1.19.0
add_project_arguments(
# libinput hold gestures and high resolution scroll are available since 1.19.0
add_project_arguments([
'-DLIBINPUT_HAS_HOLD_GESTURES=@0@'.format(libinput.version().version_compare('>=1.19.0').to_int()),
language: 'c',
)
'-DLIBINPUT_HAS_SCROLL_VALUE120=@0@'.format(libinput.version().version_compare('>=1.19.0').to_int()),
], language: 'c')

View file

@ -1,83 +1,65 @@
#include <assert.h>
#include <libinput.h>
#include <stdlib.h>
#include <wlr/backend/session.h>
#include <wlr/types/wlr_input_device.h>
#include <wlr/util/log.h>
#include <wlr/interfaces/wlr_pointer.h>
#include "backend/libinput.h"
#include "util/signal.h"
const struct wlr_pointer_impl libinput_pointer_impl = {0};
const struct wlr_pointer_impl libinput_pointer_impl = {
.name = "libinput-pointer",
};
struct wlr_pointer *create_libinput_pointer(
struct libinput_device *libinput_dev) {
assert(libinput_dev);
struct wlr_pointer *wlr_pointer = calloc(1, sizeof(struct wlr_pointer));
if (!wlr_pointer) {
wlr_log(WLR_ERROR, "Unable to allocate wlr_pointer");
return NULL;
}
const char *name = libinput_device_get_name(libinput_dev);
void init_device_pointer(struct wlr_libinput_input_device *dev) {
const char *name = libinput_device_get_name(dev->handle);
struct wlr_pointer *wlr_pointer = &dev->pointer;
wlr_pointer_init(wlr_pointer, &libinput_pointer_impl, name);
wlr_pointer->base.vendor = libinput_device_get_id_vendor(libinput_dev);
wlr_pointer->base.product = libinput_device_get_id_product(libinput_dev);
return wlr_pointer;
wlr_pointer->base.vendor = libinput_device_get_id_vendor(dev->handle);
wlr_pointer->base.product = libinput_device_get_id_product(dev->handle);
}
struct wlr_libinput_input_device *device_from_pointer(
struct wlr_pointer *wlr_pointer) {
assert(wlr_pointer->impl == &libinput_pointer_impl);
struct wlr_libinput_input_device *dev =
wl_container_of(wlr_pointer, dev, pointer);
return dev;
}
void handle_pointer_motion(struct libinput_event *event,
struct libinput_device *libinput_dev) {
struct wlr_input_device *wlr_dev =
get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev);
if (!wlr_dev) {
wlr_log(WLR_DEBUG, "Got a pointer event for a device with no pointers?");
return;
}
struct wlr_pointer *pointer) {
struct libinput_event_pointer *pevent =
libinput_event_get_pointer_event(event);
struct wlr_event_pointer_motion wlr_event = { 0 };
wlr_event.device = wlr_dev;
struct wlr_pointer_motion_event wlr_event = { 0 };
wlr_event.pointer = pointer;
wlr_event.time_msec =
usec_to_msec(libinput_event_pointer_get_time_usec(pevent));
wlr_event.delta_x = libinput_event_pointer_get_dx(pevent);
wlr_event.delta_y = libinput_event_pointer_get_dy(pevent);
wlr_event.unaccel_dx = libinput_event_pointer_get_dx_unaccelerated(pevent);
wlr_event.unaccel_dy = libinput_event_pointer_get_dy_unaccelerated(pevent);
wlr_signal_emit_safe(&wlr_dev->pointer->events.motion, &wlr_event);
wlr_signal_emit_safe(&wlr_dev->pointer->events.frame, wlr_dev->pointer);
wl_signal_emit_mutable(&pointer->events.motion, &wlr_event);
wl_signal_emit_mutable(&pointer->events.frame, pointer);
}
void handle_pointer_motion_abs(struct libinput_event *event,
struct libinput_device *libinput_dev) {
struct wlr_input_device *wlr_dev =
get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev);
if (!wlr_dev) {
wlr_log(WLR_DEBUG, "Got a pointer event for a device with no pointers?");
return;
}
struct wlr_pointer *pointer) {
struct libinput_event_pointer *pevent =
libinput_event_get_pointer_event(event);
struct wlr_event_pointer_motion_absolute wlr_event = { 0 };
wlr_event.device = wlr_dev;
struct wlr_pointer_motion_absolute_event wlr_event = { 0 };
wlr_event.pointer = pointer;
wlr_event.time_msec =
usec_to_msec(libinput_event_pointer_get_time_usec(pevent));
wlr_event.x = libinput_event_pointer_get_absolute_x_transformed(pevent, 1);
wlr_event.y = libinput_event_pointer_get_absolute_y_transformed(pevent, 1);
wlr_signal_emit_safe(&wlr_dev->pointer->events.motion_absolute, &wlr_event);
wlr_signal_emit_safe(&wlr_dev->pointer->events.frame, wlr_dev->pointer);
wl_signal_emit_mutable(&pointer->events.motion_absolute, &wlr_event);
wl_signal_emit_mutable(&pointer->events.frame, pointer);
}
void handle_pointer_button(struct libinput_event *event,
struct libinput_device *libinput_dev) {
struct wlr_input_device *wlr_dev =
get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev);
if (!wlr_dev) {
wlr_log(WLR_DEBUG, "Got a pointer event for a device with no pointers?");
return;
}
struct wlr_pointer *pointer) {
struct libinput_event_pointer *pevent =
libinput_event_get_pointer_event(event);
struct wlr_event_pointer_button wlr_event = { 0 };
wlr_event.device = wlr_dev;
struct wlr_pointer_button_event wlr_event = { 0 };
wlr_event.pointer = pointer;
wlr_event.time_msec =
usec_to_msec(libinput_event_pointer_get_time_usec(pevent));
wlr_event.button = libinput_event_pointer_get_button(pevent);
@ -89,22 +71,16 @@ void handle_pointer_button(struct libinput_event *event,
wlr_event.state = WLR_BUTTON_RELEASED;
break;
}
wlr_signal_emit_safe(&wlr_dev->pointer->events.button, &wlr_event);
wlr_signal_emit_safe(&wlr_dev->pointer->events.frame, wlr_dev->pointer);
wl_signal_emit_mutable(&pointer->events.button, &wlr_event);
wl_signal_emit_mutable(&pointer->events.frame, pointer);
}
void handle_pointer_axis(struct libinput_event *event,
struct libinput_device *libinput_dev) {
struct wlr_input_device *wlr_dev =
get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev);
if (!wlr_dev) {
wlr_log(WLR_DEBUG, "Got a pointer event for a device with no pointers?");
return;
}
struct wlr_pointer *pointer) {
struct libinput_event_pointer *pevent =
libinput_event_get_pointer_event(event);
struct wlr_event_pointer_axis wlr_event = { 0 };
wlr_event.device = wlr_dev;
struct wlr_pointer_axis_event wlr_event = { 0 };
wlr_event.pointer = pointer;
wlr_event.time_msec =
usec_to_msec(libinput_event_pointer_get_time_usec(pevent));
switch (libinput_event_pointer_get_axis_source(pevent)) {
@ -126,115 +102,127 @@ void handle_pointer_axis(struct libinput_event *event,
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL,
};
for (size_t i = 0; i < sizeof(axes) / sizeof(axes[0]); ++i) {
if (libinput_event_pointer_has_axis(pevent, axes[i])) {
switch (axes[i]) {
case LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL:
wlr_event.orientation = WLR_AXIS_ORIENTATION_VERTICAL;
break;
case LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL:
wlr_event.orientation = WLR_AXIS_ORIENTATION_HORIZONTAL;
break;
}
wlr_event.delta =
libinput_event_pointer_get_axis_value(pevent, axes[i]);
wlr_event.delta_discrete =
libinput_event_pointer_get_axis_value_discrete(pevent, axes[i]);
wlr_signal_emit_safe(&wlr_dev->pointer->events.axis, &wlr_event);
if (!libinput_event_pointer_has_axis(pevent, axes[i])) {
continue;
}
switch (axes[i]) {
case LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL:
wlr_event.orientation = WLR_AXIS_ORIENTATION_VERTICAL;
break;
case LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL:
wlr_event.orientation = WLR_AXIS_ORIENTATION_HORIZONTAL;
break;
}
wlr_event.delta =
libinput_event_pointer_get_axis_value(pevent, axes[i]);
wlr_event.delta_discrete =
libinput_event_pointer_get_axis_value_discrete(pevent, axes[i]);
wlr_event.delta_discrete *= WLR_POINTER_AXIS_DISCRETE_STEP;
wl_signal_emit_mutable(&pointer->events.axis, &wlr_event);
}
wlr_signal_emit_safe(&wlr_dev->pointer->events.frame, wlr_dev->pointer);
wl_signal_emit_mutable(&pointer->events.frame, pointer);
}
void handle_pointer_swipe_begin(struct libinput_event *event,
struct libinput_device *libinput_dev) {
struct wlr_input_device *wlr_dev =
get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev);
if (!wlr_dev) {
wlr_log(WLR_DEBUG, "Got a pointer gesture event for a device with no pointers?");
return;
#if LIBINPUT_HAS_SCROLL_VALUE120
void handle_pointer_axis_value120(struct libinput_event *event,
struct wlr_pointer *pointer, enum wlr_axis_source source) {
struct libinput_event_pointer *pevent =
libinput_event_get_pointer_event(event);
struct wlr_pointer_axis_event wlr_event = { 0 };
wlr_event.pointer = pointer;
wlr_event.time_msec =
usec_to_msec(libinput_event_pointer_get_time_usec(pevent));
wlr_event.source = source;
const enum libinput_pointer_axis axes[] = {
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL,
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL,
};
for (size_t i = 0; i < sizeof(axes) / sizeof(axes[0]); ++i) {
if (!libinput_event_pointer_has_axis(pevent, axes[i])) {
continue;
}
switch (axes[i]) {
case LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL:
wlr_event.orientation = WLR_AXIS_ORIENTATION_VERTICAL;
break;
case LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL:
wlr_event.orientation = WLR_AXIS_ORIENTATION_HORIZONTAL;
break;
}
wlr_event.delta =
libinput_event_pointer_get_scroll_value(pevent, axes[i]);
if (source == WLR_AXIS_SOURCE_WHEEL) {
wlr_event.delta_discrete =
libinput_event_pointer_get_scroll_value_v120(pevent, axes[i]);
}
wl_signal_emit_mutable(&pointer->events.axis, &wlr_event);
}
wl_signal_emit_mutable(&pointer->events.frame, pointer);
}
#endif
void handle_pointer_swipe_begin(struct libinput_event *event,
struct wlr_pointer *pointer) {
struct libinput_event_gesture *gevent =
libinput_event_get_gesture_event(event);
struct wlr_event_pointer_swipe_begin wlr_event = {
.device = wlr_dev,
struct wlr_pointer_swipe_begin_event wlr_event = {
.pointer = pointer,
.time_msec =
usec_to_msec(libinput_event_gesture_get_time_usec(gevent)),
.fingers = libinput_event_gesture_get_finger_count(gevent),
};
wlr_signal_emit_safe(&wlr_dev->pointer->events.swipe_begin, &wlr_event);
wl_signal_emit_mutable(&pointer->events.swipe_begin, &wlr_event);
}
void handle_pointer_swipe_update(struct libinput_event *event,
struct libinput_device *libinput_dev) {
struct wlr_input_device *wlr_dev =
get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev);
if (!wlr_dev) {
wlr_log(WLR_DEBUG, "Got a pointer gesture event for a device with no pointers?");
return;
}
struct wlr_pointer *pointer) {
struct libinput_event_gesture *gevent =
libinput_event_get_gesture_event(event);
struct wlr_event_pointer_swipe_update wlr_event = {
.device = wlr_dev,
struct wlr_pointer_swipe_update_event wlr_event = {
.pointer = pointer,
.time_msec =
usec_to_msec(libinput_event_gesture_get_time_usec(gevent)),
.fingers = libinput_event_gesture_get_finger_count(gevent),
.dx = libinput_event_gesture_get_dx(gevent),
.dy = libinput_event_gesture_get_dy(gevent),
};
wlr_signal_emit_safe(&wlr_dev->pointer->events.swipe_update, &wlr_event);
wl_signal_emit_mutable(&pointer->events.swipe_update, &wlr_event);
}
void handle_pointer_swipe_end(struct libinput_event *event,
struct libinput_device *libinput_dev) {
struct wlr_input_device *wlr_dev =
get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev);
if (!wlr_dev) {
wlr_log(WLR_DEBUG, "Got a pointer gesture event for a device with no pointers?");
return;
}
struct wlr_pointer *pointer) {
struct libinput_event_gesture *gevent =
libinput_event_get_gesture_event(event);
struct wlr_event_pointer_swipe_end wlr_event = {
.device = wlr_dev,
struct wlr_pointer_swipe_end_event wlr_event = {
.pointer = pointer,
.time_msec =
usec_to_msec(libinput_event_gesture_get_time_usec(gevent)),
.cancelled = libinput_event_gesture_get_cancelled(gevent),
};
wlr_signal_emit_safe(&wlr_dev->pointer->events.swipe_end, &wlr_event);
wl_signal_emit_mutable(&pointer->events.swipe_end, &wlr_event);
}
void handle_pointer_pinch_begin(struct libinput_event *event,
struct libinput_device *libinput_dev) {
struct wlr_input_device *wlr_dev =
get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev);
if (!wlr_dev) {
wlr_log(WLR_DEBUG, "Got a pointer gesture event for a device with no pointers?");
return;
}
struct wlr_pointer *pointer) {
struct libinput_event_gesture *gevent =
libinput_event_get_gesture_event(event);
struct wlr_event_pointer_pinch_begin wlr_event = {
.device = wlr_dev,
struct wlr_pointer_pinch_begin_event wlr_event = {
.pointer = pointer,
.time_msec =
usec_to_msec(libinput_event_gesture_get_time_usec(gevent)),
.fingers = libinput_event_gesture_get_finger_count(gevent),
};
wlr_signal_emit_safe(&wlr_dev->pointer->events.pinch_begin, &wlr_event);
wl_signal_emit_mutable(&pointer->events.pinch_begin, &wlr_event);
}
void handle_pointer_pinch_update(struct libinput_event *event,
struct libinput_device *libinput_dev) {
struct wlr_input_device *wlr_dev =
get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev);
if (!wlr_dev) {
wlr_log(WLR_DEBUG, "Got a pointer gesture event for a device with no pointers?");
return;
}
struct wlr_pointer *pointer) {
struct libinput_event_gesture *gevent =
libinput_event_get_gesture_event(event);
struct wlr_event_pointer_pinch_update wlr_event = {
.device = wlr_dev,
struct wlr_pointer_pinch_update_event wlr_event = {
.pointer = pointer,
.time_msec =
usec_to_msec(libinput_event_gesture_get_time_usec(gevent)),
.fingers = libinput_event_gesture_get_finger_count(gevent),
@ -243,62 +231,44 @@ void handle_pointer_pinch_update(struct libinput_event *event,
.scale = libinput_event_gesture_get_scale(gevent),
.rotation = libinput_event_gesture_get_angle_delta(gevent),
};
wlr_signal_emit_safe(&wlr_dev->pointer->events.pinch_update, &wlr_event);
wl_signal_emit_mutable(&pointer->events.pinch_update, &wlr_event);
}
void handle_pointer_pinch_end(struct libinput_event *event,
struct libinput_device *libinput_dev) {
struct wlr_input_device *wlr_dev =
get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev);
if (!wlr_dev) {
wlr_log(WLR_DEBUG, "Got a pointer gesture event for a device with no pointers?");
return;
}
struct wlr_pointer *pointer) {
struct libinput_event_gesture *gevent =
libinput_event_get_gesture_event(event);
struct wlr_event_pointer_pinch_end wlr_event = {
.device = wlr_dev,
struct wlr_pointer_pinch_end_event wlr_event = {
.pointer = pointer,
.time_msec =
usec_to_msec(libinput_event_gesture_get_time_usec(gevent)),
.cancelled = libinput_event_gesture_get_cancelled(gevent),
};
wlr_signal_emit_safe(&wlr_dev->pointer->events.pinch_end, &wlr_event);
wl_signal_emit_mutable(&pointer->events.pinch_end, &wlr_event);
}
void handle_pointer_hold_begin(struct libinput_event *event,
struct libinput_device *libinput_dev) {
struct wlr_input_device *wlr_dev =
get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev);
if (!wlr_dev) {
wlr_log(WLR_DEBUG, "Got a pointer gesture event for a device with no pointers?");
return;
}
struct wlr_pointer *pointer) {
struct libinput_event_gesture *gevent =
libinput_event_get_gesture_event(event);
struct wlr_event_pointer_hold_begin wlr_event = {
.device = wlr_dev,
struct wlr_pointer_hold_begin_event wlr_event = {
.pointer = pointer,
.time_msec =
usec_to_msec(libinput_event_gesture_get_time_usec(gevent)),
.fingers = libinput_event_gesture_get_finger_count(gevent),
};
wlr_signal_emit_safe(&wlr_dev->pointer->events.hold_begin, &wlr_event);
wl_signal_emit_mutable(&pointer->events.hold_begin, &wlr_event);
}
void handle_pointer_hold_end(struct libinput_event *event,
struct libinput_device *libinput_dev) {
struct wlr_input_device *wlr_dev =
get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev);
if (!wlr_dev) {
wlr_log(WLR_DEBUG, "Got a pointer gesture event for a device with no pointers?");
return;
}
struct wlr_pointer *pointer) {
struct libinput_event_gesture *gevent =
libinput_event_get_gesture_event(event);
struct wlr_event_pointer_hold_end wlr_event = {
.device = wlr_dev,
struct wlr_pointer_hold_end_event wlr_event = {
.pointer = pointer,
.time_msec =
usec_to_msec(libinput_event_gesture_get_time_usec(gevent)),
.cancelled = libinput_event_gesture_get_cancelled(gevent),
};
wlr_signal_emit_safe(&wlr_dev->pointer->events.hold_end, &wlr_event);
wl_signal_emit_mutable(&pointer->events.hold_end, &wlr_event);
}

View file

@ -1,43 +1,34 @@
#include <assert.h>
#include <libinput.h>
#include <stdlib.h>
#include <wlr/backend/session.h>
#include <wlr/interfaces/wlr_switch.h>
#include <wlr/types/wlr_input_device.h>
#include <wlr/util/log.h>
#include "backend/libinput.h"
#include "util/signal.h"
const struct wlr_switch_impl libinput_switch_impl;
const struct wlr_switch_impl libinput_switch_impl = {
.name = "libinput-switch",
};
struct wlr_switch *create_libinput_switch(
struct libinput_device *libinput_dev) {
assert(libinput_dev);
struct wlr_switch *wlr_switch = calloc(1, sizeof(struct wlr_switch));
if (!wlr_switch) {
wlr_log(WLR_ERROR, "Unable to allocate wlr_switch");
return NULL;
}
const char *name = libinput_device_get_name(libinput_dev);
void init_device_switch(struct wlr_libinput_input_device *dev) {
const char *name = libinput_device_get_name(dev->handle);
struct wlr_switch *wlr_switch = &dev->switch_device;
wlr_switch_init(wlr_switch, &libinput_switch_impl, name);
wlr_log(WLR_DEBUG, "Created switch for device %s", name);
wlr_switch->base.vendor = libinput_device_get_id_vendor(libinput_dev);
wlr_switch->base.product = libinput_device_get_id_product(libinput_dev);
return wlr_switch;
wlr_switch->base.vendor = libinput_device_get_id_vendor(dev->handle);
wlr_switch->base.product = libinput_device_get_id_product(dev->handle);
}
struct wlr_libinput_input_device *device_from_switch(
struct wlr_switch *wlr_switch) {
assert(wlr_switch->impl == &libinput_switch_impl);
struct wlr_libinput_input_device *dev =
wl_container_of(wlr_switch, dev, switch_device);
return dev;
}
void handle_switch_toggle(struct libinput_event *event,
struct libinput_device *libinput_dev) {
struct wlr_input_device *wlr_dev =
get_appropriate_device(WLR_INPUT_DEVICE_SWITCH, libinput_dev);
if (!wlr_dev) {
wlr_log(WLR_DEBUG, "Got a switch event for a device with no switch?");
return;
}
struct wlr_switch *wlr_switch) {
struct libinput_event_switch *sevent =
libinput_event_get_switch_event (event);
struct wlr_event_switch_toggle wlr_event = { 0 };
wlr_event.device = wlr_dev;
struct wlr_switch_toggle_event wlr_event = { 0 };
switch (libinput_event_switch_get_switch(sevent)) {
case LIBINPUT_SWITCH_LID:
wlr_event.switch_type = WLR_SWITCH_TYPE_LID;
@ -56,5 +47,5 @@ void handle_switch_toggle(struct libinput_event *event,
}
wlr_event.time_msec =
usec_to_msec(libinput_event_switch_get_time_usec(sevent));
wlr_signal_emit_safe(&wlr_dev->switch_device->events.toggle, &wlr_event);
wl_signal_emit_mutable(&wlr_switch->events.toggle, &wlr_event);
}

View file

@ -1,18 +1,23 @@
#ifndef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 200809L
#endif
#include <assert.h>
#include <string.h>
#include <libinput.h>
#include <stdlib.h>
#include <wlr/backend/session.h>
#include <wlr/interfaces/wlr_tablet_pad.h>
#include <wlr/types/wlr_input_device.h>
#include <wlr/util/log.h>
#include "backend/libinput.h"
#include "util/signal.h"
// FIXME: Decide on how to alloc/count here
const struct wlr_tablet_pad_impl libinput_tablet_pad_impl = {
.name = "libinput-tablet-pad",
};
static void group_destroy(struct wlr_tablet_pad_group *group) {
free(group->buttons);
free(group->strips);
free(group->rings);
free(group);
}
static void add_pad_group_from_libinput(struct wlr_tablet_pad *pad,
struct libinput_device *device, unsigned int index) {
struct libinput_tablet_pad_mode_group *li_group =
@ -20,6 +25,7 @@ static void add_pad_group_from_libinput(struct wlr_tablet_pad *pad,
struct wlr_tablet_pad_group *group =
calloc(1, sizeof(struct wlr_tablet_pad_group));
if (!group) {
wlr_log_errno(WLR_ERROR, "failed to allocate wlr_tablet_pad_group");
return;
}
@ -29,6 +35,10 @@ static void add_pad_group_from_libinput(struct wlr_tablet_pad *pad,
}
}
group->rings = calloc(sizeof(unsigned int), group->ring_count);
if (group->rings == NULL) {
goto group_fail;
}
size_t ring = 0;
for (size_t i = 0; i < pad->ring_count; ++i) {
if (libinput_tablet_pad_mode_group_has_ring(li_group, i)) {
@ -42,6 +52,9 @@ static void add_pad_group_from_libinput(struct wlr_tablet_pad *pad,
}
}
group->strips = calloc(sizeof(unsigned int), group->strip_count);
if (group->strips == NULL) {
goto group_fail;
}
size_t strip = 0;
for (size_t i = 0; i < pad->strip_count; ++i) {
if (libinput_tablet_pad_mode_group_has_strip(li_group, i)) {
@ -55,6 +68,9 @@ static void add_pad_group_from_libinput(struct wlr_tablet_pad *pad,
}
}
group->buttons = calloc(sizeof(unsigned int), group->button_count);
if (group->buttons == NULL) {
goto group_fail;
}
size_t button = 0;
for (size_t i = 0; i < pad->button_count; ++i) {
if (libinput_tablet_pad_mode_group_has_button(li_group, i)) {
@ -63,56 +79,72 @@ static void add_pad_group_from_libinput(struct wlr_tablet_pad *pad,
}
group->mode_count = libinput_tablet_pad_mode_group_get_num_modes(li_group);
libinput_tablet_pad_mode_group_ref(li_group);
wl_list_insert(&pad->groups, &group->link);
return;
group_fail:
wlr_log(WLR_ERROR, "failed to configure wlr_tablet_pad_group");
group_destroy(group);
}
const struct wlr_tablet_pad_impl libinput_tablet_pad_impl;
struct wlr_tablet_pad *create_libinput_tablet_pad(
struct libinput_device *libinput_dev) {
assert(libinput_dev);
struct wlr_tablet_pad *wlr_tablet_pad =
calloc(1, sizeof(struct wlr_tablet_pad));
if (!wlr_tablet_pad) {
wlr_log(WLR_ERROR, "Unable to allocate wlr_tablet_pad");
return NULL;
}
const char *name = libinput_device_get_name(libinput_dev);
void init_device_tablet_pad(struct wlr_libinput_input_device *dev) {
struct libinput_device *handle = dev->handle;
const char *name = libinput_device_get_name(handle);
struct wlr_tablet_pad *wlr_tablet_pad = &dev->tablet_pad;
wlr_tablet_pad_init(wlr_tablet_pad, &libinput_tablet_pad_impl, name);
wlr_tablet_pad->base.vendor = libinput_device_get_id_vendor(libinput_dev);
wlr_tablet_pad->base.product = libinput_device_get_id_product(libinput_dev);
wlr_tablet_pad->base.vendor = libinput_device_get_id_vendor(handle);
wlr_tablet_pad->base.product = libinput_device_get_id_product(handle);
wlr_tablet_pad->button_count =
libinput_device_tablet_pad_get_num_buttons(libinput_dev);
libinput_device_tablet_pad_get_num_buttons(handle);
wlr_tablet_pad->ring_count =
libinput_device_tablet_pad_get_num_rings(libinput_dev);
libinput_device_tablet_pad_get_num_rings(handle);
wlr_tablet_pad->strip_count =
libinput_device_tablet_pad_get_num_strips(libinput_dev);
libinput_device_tablet_pad_get_num_strips(handle);
struct udev_device *udev = libinput_device_get_udev_device(libinput_dev);
struct udev_device *udev = libinput_device_get_udev_device(handle);
char **dst = wl_array_add(&wlr_tablet_pad->paths, sizeof(char *));
*dst = strdup(udev_device_get_syspath(udev));
int groups = libinput_device_tablet_pad_get_num_mode_groups(libinput_dev);
int groups = libinput_device_tablet_pad_get_num_mode_groups(handle);
for (int i = 0; i < groups; ++i) {
add_pad_group_from_libinput(wlr_tablet_pad, libinput_dev, i);
add_pad_group_from_libinput(wlr_tablet_pad, handle, i);
}
}
void finish_device_tablet_pad(struct wlr_libinput_input_device *dev) {
struct wlr_tablet_pad_group *group, *tmp;
wl_list_for_each_safe(group, tmp, &dev->tablet_pad.groups, link) {
group_destroy(group);
}
return wlr_tablet_pad;
wlr_tablet_pad_finish(&dev->tablet_pad);
int groups = libinput_device_tablet_pad_get_num_mode_groups(dev->handle);
for (int i = 0; i < groups; ++i) {
struct libinput_tablet_pad_mode_group *li_group =
libinput_device_tablet_pad_get_mode_group(dev->handle, i);
libinput_tablet_pad_mode_group_unref(li_group);
}
}
struct wlr_libinput_input_device *device_from_tablet_pad(
struct wlr_tablet_pad *wlr_tablet_pad) {
assert(wlr_tablet_pad->impl == &libinput_tablet_pad_impl);
struct wlr_libinput_input_device *dev =
wl_container_of(wlr_tablet_pad, dev, tablet_pad);
return dev;
}
void handle_tablet_pad_button(struct libinput_event *event,
struct libinput_device *libinput_dev) {
struct wlr_input_device *wlr_dev =
get_appropriate_device(WLR_INPUT_DEVICE_TABLET_PAD, libinput_dev);
if (!wlr_dev) {
wlr_log(WLR_DEBUG,
"Got a tablet pad event for a device with no tablet pad?");
return;
}
struct wlr_tablet_pad *tablet_pad) {
struct libinput_event_tablet_pad *pevent =
libinput_event_get_tablet_pad_event(event);
struct wlr_event_tablet_pad_button wlr_event = { 0 };
struct wlr_tablet_pad_button_event wlr_event = { 0 };
wlr_event.time_msec =
usec_to_msec(libinput_event_tablet_pad_get_time_usec(pevent));
wlr_event.button = libinput_event_tablet_pad_get_button_number(pevent);
@ -127,21 +159,14 @@ void handle_tablet_pad_button(struct libinput_event *event,
wlr_event.state = WLR_BUTTON_RELEASED;
break;
}
wlr_signal_emit_safe(&wlr_dev->tablet_pad->events.button, &wlr_event);
wl_signal_emit_mutable(&tablet_pad->events.button, &wlr_event);
}
void handle_tablet_pad_ring(struct libinput_event *event,
struct libinput_device *libinput_dev) {
struct wlr_input_device *wlr_dev =
get_appropriate_device(WLR_INPUT_DEVICE_TABLET_PAD, libinput_dev);
if (!wlr_dev) {
wlr_log(WLR_DEBUG,
"Got a tablet pad event for a device with no tablet pad?");
return;
}
struct wlr_tablet_pad *tablet_pad) {
struct libinput_event_tablet_pad *pevent =
libinput_event_get_tablet_pad_event(event);
struct wlr_event_tablet_pad_ring wlr_event = { 0 };
struct wlr_tablet_pad_ring_event wlr_event = { 0 };
wlr_event.time_msec =
usec_to_msec(libinput_event_tablet_pad_get_time_usec(pevent));
wlr_event.ring = libinput_event_tablet_pad_get_ring_number(pevent);
@ -155,21 +180,14 @@ void handle_tablet_pad_ring(struct libinput_event *event,
wlr_event.source = WLR_TABLET_PAD_RING_SOURCE_FINGER;
break;
}
wlr_signal_emit_safe(&wlr_dev->tablet_pad->events.ring, &wlr_event);
wl_signal_emit_mutable(&tablet_pad->events.ring, &wlr_event);
}
void handle_tablet_pad_strip(struct libinput_event *event,
struct libinput_device *libinput_dev) {
struct wlr_input_device *wlr_dev =
get_appropriate_device(WLR_INPUT_DEVICE_TABLET_PAD, libinput_dev);
if (!wlr_dev) {
wlr_log(WLR_DEBUG,
"Got a tablet pad event for a device with no tablet pad?");
return;
}
struct wlr_tablet_pad *tablet_pad) {
struct libinput_event_tablet_pad *pevent =
libinput_event_get_tablet_pad_event(event);
struct wlr_event_tablet_pad_strip wlr_event = { 0 };
struct wlr_tablet_pad_strip_event wlr_event = { 0 };
wlr_event.time_msec =
usec_to_msec(libinput_event_tablet_pad_get_time_usec(pevent));
wlr_event.strip = libinput_event_tablet_pad_get_strip_number(pevent);
@ -183,5 +201,5 @@ void handle_tablet_pad_strip(struct libinput_event *event,
wlr_event.source = WLR_TABLET_PAD_STRIP_SOURCE_FINGER;
break;
}
wlr_signal_emit_safe(&wlr_dev->tablet_pad->events.strip, &wlr_event);
wl_signal_emit_mutable(&tablet_pad->events.strip, &wlr_event);
}

View file

@ -1,92 +1,63 @@
#ifndef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 200809L
#endif
#include <string.h>
#include <assert.h>
#include <libinput.h>
#include <stdlib.h>
#include <wayland-util.h>
#include <wlr/backend/session.h>
#include <wlr/interfaces/wlr_tablet_tool.h>
#include <wlr/types/wlr_input_device.h>
#include <wlr/util/log.h>
#include "backend/libinput.h"
#include "util/array.h"
#include "util/signal.h"
static bool tablet_is_libinput(struct wlr_tablet *tablet) {
return tablet->impl == &libinput_tablet_impl;
}
struct wlr_libinput_tablet_tool {
struct tablet_tool {
struct wlr_tablet_tool wlr_tool;
struct libinput_tablet_tool *libinput_tool;
bool unique;
// Refcount for destroy + release
size_t pad_refs;
struct libinput_tablet_tool *handle;
struct wl_list link; // wlr_libinput_input_device::tablet_tools
};
struct wlr_libinput_tablet {
struct wlr_tablet wlr_tablet;
struct wl_array tools; // struct wlr_libinput_tablet_tool *
};
static void destroy_tool(struct wlr_libinput_tablet_tool *tool) {
wlr_signal_emit_safe(&tool->wlr_tool.events.destroy, &tool->wlr_tool);
libinput_tablet_tool_ref(tool->libinput_tool);
libinput_tablet_tool_set_user_data(tool->libinput_tool, NULL);
free(tool);
}
static void destroy_tablet(struct wlr_tablet *wlr_tablet) {
assert(tablet_is_libinput(wlr_tablet));
struct wlr_libinput_tablet *tablet =
wl_container_of(wlr_tablet, tablet, wlr_tablet);
struct wlr_libinput_tablet_tool **tool_ptr;
wl_array_for_each(tool_ptr, &tablet->tools) {
struct wlr_libinput_tablet_tool *tool = *tool_ptr;
if (--tool->pad_refs == 0) {
destroy_tool(tool);
}
}
wl_array_release(&tablet->tools);
free(tablet);
}
const struct wlr_tablet_impl libinput_tablet_impl = {
.destroy = destroy_tablet,
.name = "libinput-tablet-tool",
};
struct wlr_tablet *create_libinput_tablet(
struct libinput_device *libinput_dev) {
assert(libinput_dev);
struct wlr_libinput_tablet *libinput_tablet =
calloc(1, sizeof(struct wlr_libinput_tablet));
if (!libinput_tablet) {
wlr_log(WLR_ERROR, "Unable to allocate wlr_tablet_tool");
return NULL;
}
struct wlr_tablet *wlr_tablet = &libinput_tablet->wlr_tablet;
const char *name = libinput_device_get_name(libinput_dev);
void init_device_tablet(struct wlr_libinput_input_device *dev) {
const char *name = libinput_device_get_name(dev->handle);
struct wlr_tablet *wlr_tablet = &dev->tablet;
wlr_tablet_init(wlr_tablet, &libinput_tablet_impl, name);
wlr_tablet->base.vendor = libinput_device_get_id_vendor(libinput_dev);
wlr_tablet->base.product = libinput_device_get_id_product(libinput_dev);
wlr_tablet->base.vendor = libinput_device_get_id_vendor(dev->handle);
wlr_tablet->base.product = libinput_device_get_id_product(dev->handle);
struct udev_device *udev = libinput_device_get_udev_device(libinput_dev);
libinput_device_get_size(dev->handle, &wlr_tablet->width_mm,
&wlr_tablet->height_mm);
struct udev_device *udev = libinput_device_get_udev_device(dev->handle);
char **dst = wl_array_add(&wlr_tablet->paths, sizeof(char *));
*dst = strdup(udev_device_get_syspath(udev));
wlr_tablet->name = strdup(libinput_device_get_name(libinput_dev));
wl_list_init(&dev->tablet_tools);
}
wl_array_init(&libinput_tablet->tools);
static void tool_destroy(struct tablet_tool *tool) {
wl_signal_emit_mutable(&tool->wlr_tool.events.destroy, &tool->wlr_tool);
libinput_tablet_tool_unref(tool->handle);
libinput_tablet_tool_set_user_data(tool->handle, NULL);
wl_list_remove(&tool->link);
free(tool);
}
return wlr_tablet;
void finish_device_tablet(struct wlr_libinput_input_device *dev) {
struct tablet_tool *tool, *tmp;
wl_list_for_each_safe(tool, tmp, &dev->tablet_tools, link) {
tool_destroy(tool);
}
wlr_tablet_finish(&dev->tablet);
}
struct wlr_libinput_input_device *device_from_tablet(
struct wlr_tablet *wlr_tablet) {
assert(wlr_tablet->impl == &libinput_tablet_impl);
struct wlr_libinput_input_device *dev =
wl_container_of(wlr_tablet, dev, tablet);
return dev;
}
static enum wlr_tablet_tool_type wlr_type_from_libinput_type(
@ -112,87 +83,54 @@ static enum wlr_tablet_tool_type wlr_type_from_libinput_type(
abort(); // unreachable
}
static struct wlr_libinput_tablet_tool *get_wlr_tablet_tool(
struct libinput_tablet_tool *tool) {
struct wlr_libinput_tablet_tool *ret =
libinput_tablet_tool_get_user_data(tool);
if (ret) {
return ret;
static struct tablet_tool *get_tablet_tool(
struct wlr_libinput_input_device *dev,
struct libinput_tablet_tool *libinput_tool) {
struct tablet_tool *tool =
libinput_tablet_tool_get_user_data(libinput_tool);
if (tool) {
return tool;
}
ret = calloc(1, sizeof(struct wlr_libinput_tablet_tool));
if (!ret) {
tool = calloc(1, sizeof(struct tablet_tool));
if (tool == NULL) {
wlr_log_errno(WLR_ERROR, "failed to allocate wlr_libinput_tablet_tool");
return NULL;
}
ret->libinput_tool = libinput_tablet_tool_ref(tool);
ret->wlr_tool.pressure = libinput_tablet_tool_has_pressure(tool);
ret->wlr_tool.distance = libinput_tablet_tool_has_distance(tool);
ret->wlr_tool.tilt = libinput_tablet_tool_has_tilt(tool);
ret->wlr_tool.rotation = libinput_tablet_tool_has_rotation(tool);
ret->wlr_tool.slider = libinput_tablet_tool_has_slider(tool);
ret->wlr_tool.wheel = libinput_tablet_tool_has_wheel(tool);
tool->wlr_tool.type = wlr_type_from_libinput_type(
libinput_tablet_tool_get_type(libinput_tool));
tool->wlr_tool.hardware_serial =
libinput_tablet_tool_get_serial(libinput_tool);
tool->wlr_tool.hardware_wacom =
libinput_tablet_tool_get_tool_id(libinput_tool);
ret->wlr_tool.hardware_serial = libinput_tablet_tool_get_serial(tool);
ret->wlr_tool.hardware_wacom = libinput_tablet_tool_get_tool_id(tool);
ret->wlr_tool.type = wlr_type_from_libinput_type(
libinput_tablet_tool_get_type(tool));
tool->wlr_tool.pressure = libinput_tablet_tool_has_pressure(libinput_tool);
tool->wlr_tool.distance = libinput_tablet_tool_has_distance(libinput_tool);
tool->wlr_tool.tilt = libinput_tablet_tool_has_tilt(libinput_tool);
tool->wlr_tool.rotation = libinput_tablet_tool_has_rotation(libinput_tool);
tool->wlr_tool.slider = libinput_tablet_tool_has_slider(libinput_tool);
tool->wlr_tool.wheel = libinput_tablet_tool_has_wheel(libinput_tool);
ret->unique = libinput_tablet_tool_is_unique(tool);
wl_signal_init(&tool->wlr_tool.events.destroy);
wl_signal_init(&ret->wlr_tool.events.destroy);
tool->handle = libinput_tablet_tool_ref(libinput_tool);
libinput_tablet_tool_set_user_data(libinput_tool, tool);
libinput_tablet_tool_set_user_data(tool, ret);
return ret;
}
static void ensure_tool_reference(struct wlr_libinput_tablet_tool *tool,
struct wlr_tablet *wlr_dev) {
assert(tablet_is_libinput(wlr_dev));
struct wlr_libinput_tablet *tablet =
wl_container_of(wlr_dev, tablet, wlr_tablet);
struct wlr_libinput_tablet_tool **tool_ptr;
wl_array_for_each(tool_ptr, &tablet->tools) {
if (*tool_ptr == tool) { // We already have a ref
// XXX: We *could* optimize the tool to the front of
// the list here, since we will probably get the next
// couple of events from the same tool.
// BUT the list should always be rather short (probably
// single digit amount of tools) so it might be more
// work than it saves
return;
}
}
struct wlr_libinput_tablet_tool **dst =
wl_array_add(&tablet->tools, sizeof(tool));
if (!dst) {
wlr_log(WLR_ERROR, "Failed to allocate memory for tracking tablet tool");
return;
}
*dst = tool;
++tool->pad_refs;
wl_list_insert(&dev->tablet_tools, &tool->link);
return tool;
}
void handle_tablet_tool_axis(struct libinput_event *event,
struct libinput_device *libinput_dev) {
struct wlr_input_device *wlr_dev =
get_appropriate_device(WLR_INPUT_DEVICE_TABLET_TOOL, libinput_dev);
if (!wlr_dev) {
wlr_log(WLR_DEBUG,
"Got a tablet tool event for a device with no tablet tools?");
return;
}
struct wlr_tablet *wlr_tablet) {
struct libinput_event_tablet_tool *tevent =
libinput_event_get_tablet_tool_event(event);
struct wlr_event_tablet_tool_axis wlr_event = { 0 };
struct wlr_libinput_tablet_tool *tool = get_wlr_tablet_tool(
libinput_event_tablet_tool_get_tool(tevent));
ensure_tool_reference(tool, wlr_dev->tablet);
struct wlr_libinput_input_device *dev = device_from_tablet(wlr_tablet);
struct tablet_tool *tool =
get_tablet_tool(dev, libinput_event_tablet_tool_get_tool(tevent));
wlr_event.device = wlr_dev;
struct wlr_tablet_tool_axis_event wlr_event = { 0 };
wlr_event.tablet = wlr_tablet;
wlr_event.tool = &tool->wlr_tool;
wlr_event.time_msec =
usec_to_msec(libinput_event_tablet_tool_get_time_usec(tevent));
@ -234,27 +172,20 @@ void handle_tablet_tool_axis(struct libinput_event *event,
wlr_event.updated_axes |= WLR_TABLET_TOOL_AXIS_WHEEL;
wlr_event.wheel_delta = libinput_event_tablet_tool_get_wheel_delta(tevent);
}
wlr_signal_emit_safe(&wlr_dev->tablet->events.axis, &wlr_event);
wl_signal_emit_mutable(&wlr_tablet->events.axis, &wlr_event);
}
void handle_tablet_tool_proximity(struct libinput_event *event,
struct libinput_device *libinput_dev) {
struct wlr_input_device *wlr_dev =
get_appropriate_device(WLR_INPUT_DEVICE_TABLET_TOOL, libinput_dev);
if (!wlr_dev) {
wlr_log(WLR_DEBUG,
"Got a tablet tool event for a device with no tablet tools?");
return;
}
struct wlr_tablet *wlr_tablet) {
struct libinput_event_tablet_tool *tevent =
libinput_event_get_tablet_tool_event(event);
struct wlr_event_tablet_tool_proximity wlr_event = { 0 };
struct wlr_libinput_tablet_tool *tool = get_wlr_tablet_tool(
libinput_event_tablet_tool_get_tool(tevent));
ensure_tool_reference(tool, wlr_dev->tablet);
struct wlr_libinput_input_device *dev = device_from_tablet(wlr_tablet);
struct tablet_tool *tool =
get_tablet_tool(dev, libinput_event_tablet_tool_get_tool(tevent));
struct wlr_tablet_tool_proximity_event wlr_event = { 0 };
wlr_event.tablet = wlr_tablet;
wlr_event.tool = &tool->wlr_tool;
wlr_event.device = wlr_dev;
wlr_event.time_msec =
usec_to_msec(libinput_event_tablet_tool_get_time_usec(tevent));
wlr_event.x = libinput_event_tablet_tool_get_x_transformed(tevent, 1);
@ -268,56 +199,34 @@ void handle_tablet_tool_proximity(struct libinput_event *event,
wlr_event.state = WLR_TABLET_TOOL_PROXIMITY_IN;
break;
}
wlr_signal_emit_safe(&wlr_dev->tablet->events.proximity, &wlr_event);
wl_signal_emit_mutable(&wlr_tablet->events.proximity, &wlr_event);
if (libinput_event_tablet_tool_get_proximity_state(tevent) ==
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN) {
handle_tablet_tool_axis(event, libinput_dev);
handle_tablet_tool_axis(event, wlr_tablet);
}
// If the tool is not unique, libinput will not find it again after the
// proximity out, so we should destroy it
if (!tool->unique &&
libinput_event_tablet_tool_get_proximity_state(tevent) ==
if (!libinput_tablet_tool_is_unique(tool->handle)
&& libinput_event_tablet_tool_get_proximity_state(tevent) ==
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT) {
// The tool isn't unique, it can't be on multiple tablets
assert(tool->pad_refs == 1);
assert(tablet_is_libinput(wlr_dev->tablet));
struct wlr_libinput_tablet *tablet =
wl_container_of(wlr_dev->tablet, tablet, wlr_tablet);
size_t i = 0;
struct wlr_libinput_tablet_tool **tool_ptr;
wl_array_for_each(tool_ptr, &tablet->tools) {
if (*tool_ptr == tool) {
array_remove_at(&tablet->tools, i * sizeof(tool), sizeof(tool));
break;
}
i++;
}
destroy_tool(tool);
tool_destroy(tool);
}
}
void handle_tablet_tool_tip(struct libinput_event *event,
struct libinput_device *libinput_dev) {
struct wlr_input_device *wlr_dev =
get_appropriate_device(WLR_INPUT_DEVICE_TABLET_TOOL, libinput_dev);
if (!wlr_dev) {
wlr_log(WLR_DEBUG,
"Got a tablet tool event for a device with no tablet tools?");
return;
}
handle_tablet_tool_axis(event, libinput_dev);
struct wlr_tablet *wlr_tablet) {
handle_tablet_tool_axis(event, wlr_tablet);
struct libinput_event_tablet_tool *tevent =
libinput_event_get_tablet_tool_event(event);
struct wlr_event_tablet_tool_tip wlr_event = { 0 };
struct wlr_libinput_tablet_tool *tool = get_wlr_tablet_tool(
libinput_event_tablet_tool_get_tool(tevent));
ensure_tool_reference(tool, wlr_dev->tablet);
struct wlr_libinput_input_device *dev = device_from_tablet(wlr_tablet);
struct tablet_tool *tool =
get_tablet_tool(dev, libinput_event_tablet_tool_get_tool(tevent));
wlr_event.device = wlr_dev;
struct wlr_tablet_tool_tip_event wlr_event = { 0 };
wlr_event.tablet = wlr_tablet;
wlr_event.tool = &tool->wlr_tool;
wlr_event.time_msec =
usec_to_msec(libinput_event_tablet_tool_get_time_usec(tevent));
@ -332,27 +241,20 @@ void handle_tablet_tool_tip(struct libinput_event *event,
wlr_event.state = WLR_TABLET_TOOL_TIP_DOWN;
break;
}
wlr_signal_emit_safe(&wlr_dev->tablet->events.tip, &wlr_event);
wl_signal_emit_mutable(&wlr_tablet->events.tip, &wlr_event);
}
void handle_tablet_tool_button(struct libinput_event *event,
struct libinput_device *libinput_dev) {
struct wlr_input_device *wlr_dev =
get_appropriate_device(WLR_INPUT_DEVICE_TABLET_TOOL, libinput_dev);
if (!wlr_dev) {
wlr_log(WLR_DEBUG,
"Got a tablet tool event for a device with no tablet tools?");
return;
}
handle_tablet_tool_axis(event, libinput_dev);
struct wlr_tablet *wlr_tablet) {
handle_tablet_tool_axis(event, wlr_tablet);
struct libinput_event_tablet_tool *tevent =
libinput_event_get_tablet_tool_event(event);
struct wlr_event_tablet_tool_button wlr_event = { 0 };
struct wlr_libinput_tablet_tool *tool = get_wlr_tablet_tool(
libinput_event_tablet_tool_get_tool(tevent));
ensure_tool_reference(tool, wlr_dev->tablet);
struct wlr_libinput_input_device *dev = device_from_tablet(wlr_tablet);
struct tablet_tool *tool =
get_tablet_tool(dev, libinput_event_tablet_tool_get_tool(tevent));
wlr_event.device = wlr_dev;
struct wlr_tablet_tool_button_event wlr_event = { 0 };
wlr_event.tablet = wlr_tablet;
wlr_event.tool = &tool->wlr_tool;
wlr_event.time_msec =
usec_to_msec(libinput_event_tablet_tool_get_time_usec(tevent));
@ -365,5 +267,5 @@ void handle_tablet_tool_button(struct libinput_event *event,
wlr_event.state = WLR_BUTTON_PRESSED;
break;
}
wlr_signal_emit_safe(&wlr_dev->tablet->events.button, &wlr_event);
wl_signal_emit_mutable(&wlr_tablet->events.button, &wlr_event);
}

View file

@ -1,113 +1,85 @@
#include <assert.h>
#include <libinput.h>
#include <stdlib.h>
#include <wlr/backend/session.h>
#include <wlr/interfaces/wlr_touch.h>
#include <wlr/types/wlr_input_device.h>
#include <wlr/util/log.h>
#include "backend/libinput.h"
#include "util/signal.h"
const struct wlr_touch_impl libinput_touch_impl;
const struct wlr_touch_impl libinput_touch_impl = {
.name = "libinput-touch",
};
struct wlr_touch *create_libinput_touch(
struct libinput_device *libinput_dev) {
assert(libinput_dev);
struct wlr_touch *wlr_touch = calloc(1, sizeof(struct wlr_touch));
if (!wlr_touch) {
wlr_log(WLR_ERROR, "Unable to allocate wlr_touch");
return NULL;
}
const char *name = libinput_device_get_name(libinput_dev);
void init_device_touch(struct wlr_libinput_input_device *dev) {
const char *name = libinput_device_get_name(dev->handle);
struct wlr_touch *wlr_touch = &dev->touch;
wlr_touch_init(wlr_touch, &libinput_touch_impl, name);
wlr_touch->base.vendor = libinput_device_get_id_vendor(libinput_dev);
wlr_touch->base.product = libinput_device_get_id_product(libinput_dev);
return wlr_touch;
wlr_touch->base.vendor = libinput_device_get_id_vendor(dev->handle);
wlr_touch->base.product = libinput_device_get_id_product(dev->handle);
libinput_device_get_size(dev->handle, &wlr_touch->width_mm,
&wlr_touch->height_mm);
}
struct wlr_libinput_input_device *device_from_touch(
struct wlr_touch *wlr_touch) {
assert(wlr_touch->impl == &libinput_touch_impl);
struct wlr_libinput_input_device *dev =
wl_container_of(wlr_touch, dev, touch);
return dev;
}
void handle_touch_down(struct libinput_event *event,
struct libinput_device *libinput_dev) {
struct wlr_input_device *wlr_dev =
get_appropriate_device(WLR_INPUT_DEVICE_TOUCH, libinput_dev);
if (!wlr_dev) {
wlr_log(WLR_DEBUG, "Got a touch event for a device with no touch?");
return;
}
struct wlr_touch *touch) {
struct libinput_event_touch *tevent =
libinput_event_get_touch_event(event);
struct wlr_event_touch_down wlr_event = { 0 };
wlr_event.device = wlr_dev;
struct wlr_touch_down_event wlr_event = { 0 };
wlr_event.touch = touch;
wlr_event.time_msec =
usec_to_msec(libinput_event_touch_get_time_usec(tevent));
wlr_event.touch_id = libinput_event_touch_get_seat_slot(tevent);
wlr_event.x = libinput_event_touch_get_x_transformed(tevent, 1);
wlr_event.y = libinput_event_touch_get_y_transformed(tevent, 1);
wlr_signal_emit_safe(&wlr_dev->touch->events.down, &wlr_event);
wl_signal_emit_mutable(&touch->events.down, &wlr_event);
}
void handle_touch_up(struct libinput_event *event,
struct libinput_device *libinput_dev) {
struct wlr_input_device *wlr_dev =
get_appropriate_device(WLR_INPUT_DEVICE_TOUCH, libinput_dev);
if (!wlr_dev) {
wlr_log(WLR_DEBUG, "Got a touch event for a device with no touch?");
return;
}
struct wlr_touch *touch) {
struct libinput_event_touch *tevent =
libinput_event_get_touch_event(event);
struct wlr_event_touch_up wlr_event = { 0 };
wlr_event.device = wlr_dev;
struct wlr_touch_up_event wlr_event = { 0 };
wlr_event.touch = touch;
wlr_event.time_msec =
usec_to_msec(libinput_event_touch_get_time_usec(tevent));
wlr_event.touch_id = libinput_event_touch_get_seat_slot(tevent);
wlr_signal_emit_safe(&wlr_dev->touch->events.up, &wlr_event);
wl_signal_emit_mutable(&touch->events.up, &wlr_event);
}
void handle_touch_motion(struct libinput_event *event,
struct libinput_device *libinput_dev) {
struct wlr_input_device *wlr_dev =
get_appropriate_device(WLR_INPUT_DEVICE_TOUCH, libinput_dev);
if (!wlr_dev) {
wlr_log(WLR_DEBUG, "Got a touch event for a device with no touch?");
return;
}
struct wlr_touch *touch) {
struct libinput_event_touch *tevent =
libinput_event_get_touch_event(event);
struct wlr_event_touch_motion wlr_event = { 0 };
wlr_event.device = wlr_dev;
struct wlr_touch_motion_event wlr_event = { 0 };
wlr_event.touch = touch;
wlr_event.time_msec =
usec_to_msec(libinput_event_touch_get_time_usec(tevent));
wlr_event.touch_id = libinput_event_touch_get_seat_slot(tevent);
wlr_event.x = libinput_event_touch_get_x_transformed(tevent, 1);
wlr_event.y = libinput_event_touch_get_y_transformed(tevent, 1);
wlr_signal_emit_safe(&wlr_dev->touch->events.motion, &wlr_event);
wl_signal_emit_mutable(&touch->events.motion, &wlr_event);
}
void handle_touch_cancel(struct libinput_event *event,
struct libinput_device *libinput_dev) {
struct wlr_input_device *wlr_dev =
get_appropriate_device(WLR_INPUT_DEVICE_TOUCH, libinput_dev);
if (!wlr_dev) {
wlr_log(WLR_DEBUG, "Got a touch event for a device with no touch?");
return;
}
struct wlr_touch *touch) {
struct libinput_event_touch *tevent =
libinput_event_get_touch_event(event);
struct wlr_event_touch_cancel wlr_event = { 0 };
wlr_event.device = wlr_dev;
struct wlr_touch_cancel_event wlr_event = { 0 };
wlr_event.touch = touch;
wlr_event.time_msec =
usec_to_msec(libinput_event_touch_get_time_usec(tevent));
wlr_event.touch_id = libinput_event_touch_get_seat_slot(tevent);
wlr_signal_emit_safe(&wlr_dev->touch->events.cancel, &wlr_event);
wl_signal_emit_mutable(&touch->events.cancel, &wlr_event);
}
void handle_touch_frame(struct libinput_event *event,
struct libinput_device *libinput_dev) {
struct wlr_input_device *wlr_dev =
get_appropriate_device(WLR_INPUT_DEVICE_TOUCH, libinput_dev);
if (!wlr_dev) {
wlr_log(WLR_DEBUG, "Got a touch event for a device with no touch?");
return;
}
wlr_signal_emit_safe(&wlr_dev->touch->events.frame, NULL);
struct wlr_touch *touch) {
wl_signal_emit_mutable(&touch->events.frame, NULL);
}

View file

@ -9,7 +9,6 @@
#include <wlr/util/log.h>
#include "backend/backend.h"
#include "backend/multi.h"
#include "util/signal.h"
struct subbackend_state {
struct wlr_backend *backend;
@ -161,13 +160,13 @@ bool wlr_backend_is_multi(struct wlr_backend *b) {
static void new_input_reemit(struct wl_listener *listener, void *data) {
struct subbackend_state *state = wl_container_of(listener,
state, new_input);
wlr_signal_emit_safe(&state->container->events.new_input, data);
wl_signal_emit_mutable(&state->container->events.new_input, data);
}
static void new_output_reemit(struct wl_listener *listener, void *data) {
struct subbackend_state *state = wl_container_of(listener,
state, new_output);
wlr_signal_emit_safe(&state->container->events.new_output, data);
wl_signal_emit_mutable(&state->container->events.new_output, data);
}
static void handle_subbackend_destroy(struct wl_listener *listener,
@ -218,7 +217,7 @@ bool wlr_multi_backend_add(struct wlr_backend *_multi,
wl_signal_add(&backend->events.new_output, &sub->new_output);
sub->new_output.notify = new_output_reemit;
wlr_signal_emit_safe(&multi->events.backend_add, backend);
wl_signal_emit_mutable(&multi->events.backend_add, backend);
return true;
}
@ -230,7 +229,7 @@ void wlr_multi_backend_remove(struct wlr_backend *_multi,
multi_backend_get_subbackend(multi, backend);
if (sub) {
wlr_signal_emit_safe(&multi->events.backend_remove, backend);
wl_signal_emit_mutable(&multi->events.backend_remove, backend);
subbackend_state_destroy(sub);
}
}

View file

@ -17,7 +17,6 @@
#include <xf86drm.h>
#include <xf86drmMode.h>
#include "backend/session/session.h"
#include "util/signal.h"
#include <libseat.h>
@ -26,13 +25,13 @@
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);
wl_signal_emit_mutable(&session->events.active, 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);
wl_signal_emit_mutable(&session->events.active, NULL);
libseat_disable_seat(session->seat_handle);
}
@ -198,7 +197,7 @@ static int handle_udev_event(int fd, uint32_t mask, void *data) {
struct wlr_session_add_event event = {
.path = devnode,
};
wlr_signal_emit_safe(&session->events.add_drm_card, &event);
wl_signal_emit_mutable(&session->events.add_drm_card, &event);
} else if (strcmp(action, "change") == 0 || strcmp(action, "remove") == 0) {
dev_t devnum = udev_device_get_devnum(udev_dev);
struct wlr_device *dev;
@ -211,10 +210,10 @@ static int handle_udev_event(int fd, uint32_t mask, void *data) {
wlr_log(WLR_DEBUG, "DRM device %s changed", sysname);
struct wlr_device_change_event event = {0};
read_udev_change_event(&event, udev_dev);
wlr_signal_emit_safe(&dev->events.change, &event);
wl_signal_emit_mutable(&dev->events.change, &event);
} else if (strcmp(action, "remove") == 0) {
wlr_log(WLR_DEBUG, "DRM device %s removed", sysname);
wlr_signal_emit_safe(&dev->events.remove, NULL);
wl_signal_emit_mutable(&dev->events.remove, NULL);
} else {
assert(0);
}
@ -298,7 +297,7 @@ void wlr_session_destroy(struct wlr_session *session) {
return;
}
wlr_signal_emit_safe(&session->events.destroy, session);
wl_signal_emit_mutable(&session->events.destroy, session);
wl_list_remove(&session->display_destroy.link);
wl_event_source_remove(session->udev_event);

View file

@ -19,7 +19,6 @@
#include "backend/wayland.h"
#include "render/drm_format_set.h"
#include "render/pixel_format.h"
#include "util/signal.h"
#include "drm-client-protocol.h"
#include "linux-dmabuf-unstable-v1-client-protocol.h"
@ -346,8 +345,15 @@ static void registry_global(void *data, struct wl_registry *registry,
wl->compositor = wl_registry_bind(registry, name,
&wl_compositor_interface, 4);
} else if (strcmp(iface, wl_seat_interface.name) == 0) {
uint32_t target_version = version;
if (version < 5) {
target_version = 5;
}
if (version > 8) {
target_version = 8;
}
struct wl_seat *wl_seat = wl_registry_bind(registry, name,
&wl_seat_interface, 5);
&wl_seat_interface, target_version);
if (!create_wl_seat(wl_seat, wl)) {
wl_seat_destroy(wl_seat);
}
@ -413,12 +419,16 @@ static bool backend_start(struct wlr_backend *backend) {
struct wlr_wl_seat *seat;
wl_list_for_each(seat, &wl->seats, link) {
if (seat->keyboard) {
create_wl_keyboard(seat);
if (seat->wl_keyboard) {
init_seat_keyboard(seat);
}
if (seat->wl_touch) {
init_seat_touch(seat);
}
if (wl->tablet_manager) {
wl_add_tablet_seat(wl->tablet_manager, seat);
init_seat_tablet(seat);
}
}
@ -441,11 +451,6 @@ static void backend_destroy(struct wlr_backend *backend) {
wlr_output_destroy(&output->wlr_output);
}
struct wlr_wl_input_device *input_device, *tmp_input_device;
wl_list_for_each_safe(input_device, tmp_input_device, &wl->devices, link) {
destroy_wl_input_device(input_device);
}
struct wlr_wl_buffer *buffer, *tmp_buffer;
wl_list_for_each_safe(buffer, tmp_buffer, &wl->buffers, link) {
destroy_wl_buffer(buffer);
@ -538,7 +543,6 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display,
wlr_backend_init(&wl->backend, &backend_impl);
wl->local_display = display;
wl_list_init(&wl->devices);
wl_list_init(&wl->outputs);
wl_list_init(&wl->seats);
wl_list_init(&wl->buffers);

View file

@ -8,6 +8,7 @@ wlr_files += files(
'backend.c',
'output.c',
'seat.c',
'pointer.c',
'tablet_v2.c',
)

View file

@ -19,7 +19,6 @@
#include "render/pixel_format.h"
#include "render/swapchain.h"
#include "render/wlr_renderer.h"
#include "util/signal.h"
#include "linux-dmabuf-unstable-v1-client-protocol.h"
#include "presentation-time-client-protocol.h"
@ -30,7 +29,8 @@
static const uint32_t SUPPORTED_OUTPUT_STATE =
WLR_OUTPUT_STATE_BACKEND_OPTIONAL |
WLR_OUTPUT_STATE_BUFFER |
WLR_OUTPUT_STATE_MODE;
WLR_OUTPUT_STATE_MODE |
WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED;
static struct wlr_wl_output *get_wl_output_from_output(
struct wlr_output *wlr_output) {
@ -240,48 +240,59 @@ static struct wlr_wl_buffer *get_or_create_wl_buffer(struct wlr_wl_backend *wl,
return create_wl_buffer(wl, wlr_buffer);
}
static bool output_test(struct wlr_output *wlr_output) {
static bool output_test(struct wlr_output *wlr_output,
const struct wlr_output_state *state) {
struct wlr_wl_output *output =
get_wl_output_from_output(wlr_output);
uint32_t unsupported =
wlr_output->pending.committed & ~SUPPORTED_OUTPUT_STATE;
uint32_t unsupported = state->committed & ~SUPPORTED_OUTPUT_STATE;
if (unsupported != 0) {
wlr_log(WLR_DEBUG, "Unsupported output state fields: 0x%"PRIx32,
unsupported);
return false;
}
if (wlr_output->pending.committed & WLR_OUTPUT_STATE_MODE) {
assert(wlr_output->pending.mode_type == WLR_OUTPUT_STATE_MODE_CUSTOM);
// Adaptive sync is effectively always enabled when using the Wayland
// backend. This is not something we have control over, so we set the state
// to enabled on creating the output and never allow changing it.
assert(wlr_output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED);
if (state->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) {
if (!state->adaptive_sync_enabled) {
return false;
}
}
if ((wlr_output->pending.committed & WLR_OUTPUT_STATE_BUFFER) &&
!test_buffer(output->backend, wlr_output->pending.buffer)) {
if (state->committed & WLR_OUTPUT_STATE_MODE) {
assert(state->mode_type == WLR_OUTPUT_STATE_MODE_CUSTOM);
}
if ((state->committed & WLR_OUTPUT_STATE_BUFFER) &&
!test_buffer(output->backend, state->buffer)) {
return false;
}
return true;
}
static bool output_commit(struct wlr_output *wlr_output) {
static bool output_commit(struct wlr_output *wlr_output,
const struct wlr_output_state *state) {
struct wlr_wl_output *output =
get_wl_output_from_output(wlr_output);
if (!output_test(wlr_output)) {
if (!output_test(wlr_output, state)) {
return false;
}
if (wlr_output->pending.committed & WLR_OUTPUT_STATE_MODE) {
if (state->committed & WLR_OUTPUT_STATE_MODE) {
if (!output_set_custom_mode(wlr_output,
wlr_output->pending.custom_mode.width,
wlr_output->pending.custom_mode.height,
wlr_output->pending.custom_mode.refresh)) {
state->custom_mode.width,
state->custom_mode.height,
state->custom_mode.refresh)) {
return false;
}
}
if (wlr_output->pending.committed & WLR_OUTPUT_STATE_BUFFER) {
if (state->committed & WLR_OUTPUT_STATE_BUFFER) {
struct wp_presentation_feedback *wp_feedback = NULL;
if (output->backend->presentation != NULL) {
wp_feedback = wp_presentation_feedback(output->backend->presentation,
@ -289,8 +300,8 @@ static bool output_commit(struct wlr_output *wlr_output) {
}
pixman_region32_t *damage = NULL;
if (wlr_output->pending.committed & WLR_OUTPUT_STATE_DAMAGE) {
damage = &wlr_output->pending.damage;
if (state->committed & WLR_OUTPUT_STATE_DAMAGE) {
damage = (pixman_region32_t *) &state->damage;
}
if (output->frame_callback != NULL) {
@ -301,7 +312,7 @@ static bool output_commit(struct wlr_output *wlr_output) {
output->frame_callback = wl_surface_frame(output->surface);
wl_callback_add_listener(output->frame_callback, &frame_listener, output);
struct wlr_buffer *wlr_buffer = wlr_output->pending.buffer;
struct wlr_buffer *wlr_buffer = state->buffer;
struct wlr_wl_buffer *buffer =
get_or_create_wl_buffer(output->backend, wlr_buffer);
if (buffer == NULL) {
@ -436,7 +447,9 @@ void update_wl_output_cursor(struct wlr_wl_output *output) {
if (pointer) {
assert(pointer->output == output);
assert(output->enter_serial);
wl_pointer_set_cursor(pointer->wl_pointer, output->enter_serial,
struct wlr_wl_seat *seat = pointer->seat;
wl_pointer_set_cursor(seat->wl_pointer, output->enter_serial,
output->cursor.surface, output->cursor.hotspot_x,
output->cursor.hotspot_y);
}
@ -518,8 +531,8 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend *wlr_backend) {
struct wlr_output *wlr_output = &output->wlr_output;
wlr_output_update_custom_mode(wlr_output, 1280, 720, 0);
strncpy(wlr_output->make, "wayland", sizeof(wlr_output->make));
strncpy(wlr_output->model, "wayland", sizeof(wlr_output->model));
wlr_output->adaptive_sync_status = WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED;
char name[64];
snprintf(name, sizeof(name), "WL-%zu", ++backend->last_output_num);
@ -578,12 +591,12 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend *wlr_backend) {
wl_list_insert(&backend->outputs, &output->link);
wlr_output_update_enabled(wlr_output, true);
wlr_signal_emit_safe(&backend->backend.events.new_output, wlr_output);
wl_signal_emit_mutable(&backend->backend.events.new_output, wlr_output);
struct wlr_wl_seat *seat;
wl_list_for_each(seat, &backend->seats, link) {
if (seat->pointer) {
create_wl_pointer(seat, output);
if (seat->wl_pointer) {
create_pointer(seat, output);
}
}

541
backend/wayland/pointer.c Normal file
View file

@ -0,0 +1,541 @@
#define _POSIX_C_SOURCE 200809L
#include <assert.h>
#include <stdlib.h>
#include <wayland-client.h>
#include <wlr/interfaces/wlr_pointer.h>
#include <wlr/util/log.h>
#include "backend/wayland.h"
#include "pointer-gestures-unstable-v1-client-protocol.h"
#include "relative-pointer-unstable-v1-client-protocol.h"
static struct wlr_wl_pointer *output_get_pointer(struct wlr_wl_output *output,
const struct wl_pointer *wl_pointer) {
struct wlr_wl_seat *seat;
wl_list_for_each(seat, &output->backend->seats, link) {
if (seat->wl_pointer != wl_pointer) {
continue;
}
struct wlr_wl_pointer *pointer;
wl_list_for_each(pointer, &seat->pointers, link) {
if (pointer->output == output) {
return pointer;
}
}
}
return NULL;
}
static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer,
uint32_t serial, struct wl_surface *surface, wl_fixed_t sx,
wl_fixed_t sy) {
struct wlr_wl_seat *seat = data;
if (surface == NULL) {
return;
}
struct wlr_wl_output *output = wl_surface_get_user_data(surface);
assert(output);
struct wlr_wl_pointer *pointer = output_get_pointer(output, wl_pointer);
seat->active_pointer = pointer;
// Manage cursor icon/rendering on output
struct wlr_wl_pointer *current = output->cursor.pointer;
if (current && current != pointer) {
wlr_log(WLR_INFO, "Ignoring seat '%s' pointer in favor of seat '%s'",
seat->name, current->seat->name);
return;
}
output->enter_serial = serial;
output->cursor.pointer = pointer;
update_wl_output_cursor(output);
}
static void pointer_handle_leave(void *data, struct wl_pointer *wl_pointer,
uint32_t serial, struct wl_surface *surface) {
struct wlr_wl_seat *seat = data;
if (surface == NULL) {
return;
}
struct wlr_wl_output *output = wl_surface_get_user_data(surface);
assert(output);
if (seat->active_pointer != NULL &&
seat->active_pointer->output == output) {
seat->active_pointer = NULL;
}
if (output->cursor.pointer == seat->active_pointer) {
output->enter_serial = 0;
output->cursor.pointer = NULL;
}
}
static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer,
uint32_t time, wl_fixed_t sx, wl_fixed_t sy) {
struct wlr_wl_seat *seat = data;
struct wlr_wl_pointer *pointer = seat->active_pointer;
if (pointer == NULL) {
return;
}
struct wlr_output *wlr_output = &pointer->output->wlr_output;
struct wlr_pointer_motion_absolute_event event = {
.pointer = &pointer->wlr_pointer,
.time_msec = time,
.x = wl_fixed_to_double(sx) / wlr_output->width,
.y = wl_fixed_to_double(sy) / wlr_output->height,
};
wl_signal_emit_mutable(&pointer->wlr_pointer.events.motion_absolute, &event);
}
static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
uint32_t serial, uint32_t time, uint32_t button, uint32_t state) {
struct wlr_wl_seat *seat = data;
struct wlr_wl_pointer *pointer = seat->active_pointer;
if (pointer == NULL) {
return;
}
struct wlr_pointer_button_event event = {
.pointer = &pointer->wlr_pointer,
.button = button,
.state = state,
.time_msec = time,
};
wl_signal_emit_mutable(&pointer->wlr_pointer.events.button, &event);
}
static void pointer_handle_axis(void *data, struct wl_pointer *wl_pointer,
uint32_t time, uint32_t axis, wl_fixed_t value) {
struct wlr_wl_seat *seat = data;
struct wlr_wl_pointer *pointer = seat->active_pointer;
if (pointer == NULL) {
return;
}
struct wlr_pointer_axis_event event = {
.pointer = &pointer->wlr_pointer,
.delta = wl_fixed_to_double(value),
.delta_discrete = pointer->axis_discrete,
.orientation = axis,
.time_msec = time,
.source = pointer->axis_source,
};
wl_signal_emit_mutable(&pointer->wlr_pointer.events.axis, &event);
pointer->axis_discrete = 0;
}
static void pointer_handle_frame(void *data, struct wl_pointer *wl_pointer) {
struct wlr_wl_seat *seat = data;
struct wlr_wl_pointer *pointer = seat->active_pointer;
if (pointer == NULL) {
return;
}
wl_signal_emit_mutable(&pointer->wlr_pointer.events.frame,
&pointer->wlr_pointer);
}
static void pointer_handle_axis_source(void *data,
struct wl_pointer *wl_pointer, uint32_t axis_source) {
struct wlr_wl_seat *seat = data;
struct wlr_wl_pointer *pointer = seat->active_pointer;
if (pointer == NULL) {
return;
}
pointer->axis_source = axis_source;
}
static void pointer_handle_axis_stop(void *data, struct wl_pointer *wl_pointer,
uint32_t time, uint32_t axis) {
struct wlr_wl_seat *seat = data;
struct wlr_wl_pointer *pointer = seat->active_pointer;
if (pointer == NULL) {
return;
}
struct wlr_pointer_axis_event event = {
.pointer = &pointer->wlr_pointer,
.delta = 0,
.delta_discrete = 0,
.orientation = axis,
.time_msec = time,
.source = pointer->axis_source,
};
wl_signal_emit_mutable(&pointer->wlr_pointer.events.axis, &event);
}
static void pointer_handle_axis_discrete(void *data,
struct wl_pointer *wl_pointer, uint32_t axis, int32_t discrete) {
struct wlr_wl_seat *seat = data;
struct wlr_wl_pointer *pointer = seat->active_pointer;
if (pointer == NULL) {
return;
}
pointer->axis_discrete = discrete * WLR_POINTER_AXIS_DISCRETE_STEP;
}
static void pointer_handle_axis_value120(void *data,
struct wl_pointer *wl_pointer, uint32_t axis, int32_t value120) {
struct wlr_wl_seat *seat = data;
struct wlr_wl_pointer *pointer = seat->active_pointer;
if (pointer == NULL) {
return;
}
pointer->axis_discrete = value120;
}
static const struct wl_pointer_listener pointer_listener = {
.enter = pointer_handle_enter,
.leave = pointer_handle_leave,
.motion = pointer_handle_motion,
.button = pointer_handle_button,
.axis = pointer_handle_axis,
.frame = pointer_handle_frame,
.axis_source = pointer_handle_axis_source,
.axis_stop = pointer_handle_axis_stop,
.axis_discrete = pointer_handle_axis_discrete,
.axis_value120 = pointer_handle_axis_value120,
};
static void gesture_swipe_begin(void *data,
struct zwp_pointer_gesture_swipe_v1 *zwp_pointer_gesture_swipe_v1,
uint32_t serial, uint32_t time, struct wl_surface *surface,
uint32_t fingers) {
struct wlr_wl_seat *seat = data;
struct wlr_wl_pointer *pointer = seat->active_pointer;
if (pointer == NULL) {
return;
}
pointer->fingers = fingers;
struct wlr_pointer_swipe_begin_event wlr_event = {
.pointer = &pointer->wlr_pointer,
.time_msec = time,
.fingers = fingers,
};
wl_signal_emit_mutable(&pointer->wlr_pointer.events.swipe_begin, &wlr_event);
}
static void gesture_swipe_update(void *data,
struct zwp_pointer_gesture_swipe_v1 *zwp_pointer_gesture_swipe_v1,
uint32_t time, wl_fixed_t dx, wl_fixed_t dy) {
struct wlr_wl_seat *seat = data;
struct wlr_wl_pointer *pointer = seat->active_pointer;
if (pointer == NULL) {
return;
}
struct wlr_pointer_swipe_update_event wlr_event = {
.pointer = &pointer->wlr_pointer,
.time_msec = time,
.fingers = pointer->fingers,
.dx = wl_fixed_to_double(dx),
.dy = wl_fixed_to_double(dy),
};
wl_signal_emit_mutable(&pointer->wlr_pointer.events.swipe_update, &wlr_event);
}
static void gesture_swipe_end(void *data,
struct zwp_pointer_gesture_swipe_v1 *zwp_pointer_gesture_swipe_v1,
uint32_t serial, uint32_t time, int32_t cancelled) {
struct wlr_wl_seat *seat = data;
struct wlr_wl_pointer *pointer = seat->active_pointer;
if (pointer == NULL) {
return;
}
struct wlr_pointer_swipe_end_event wlr_event = {
.pointer = &pointer->wlr_pointer,
.time_msec = time,
.cancelled = cancelled,
};
wl_signal_emit_mutable(&pointer->wlr_pointer.events.swipe_end, &wlr_event);
}
static const struct zwp_pointer_gesture_swipe_v1_listener gesture_swipe_impl = {
.begin = gesture_swipe_begin,
.update = gesture_swipe_update,
.end = gesture_swipe_end,
};
static void gesture_pinch_begin(void *data,
struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1,
uint32_t serial, uint32_t time, struct wl_surface *surface,
uint32_t fingers) {
struct wlr_wl_seat *seat = data;
struct wlr_wl_pointer *pointer = seat->active_pointer;
if (pointer == NULL) {
return;
}
pointer->fingers = fingers;
struct wlr_pointer_pinch_begin_event wlr_event = {
.pointer = &pointer->wlr_pointer,
.time_msec = time,
.fingers = pointer->fingers,
};
wl_signal_emit_mutable(&pointer->wlr_pointer.events.pinch_begin, &wlr_event);
}
static void gesture_pinch_update(void *data,
struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1,
uint32_t time, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t scale,
wl_fixed_t rotation) {
struct wlr_wl_seat *seat = data;
struct wlr_wl_pointer *pointer = seat->active_pointer;
if (pointer == NULL) {
return;
}
struct wlr_pointer_pinch_update_event wlr_event = {
.pointer = &pointer->wlr_pointer,
.time_msec = time,
.fingers = pointer->fingers,
.dx = wl_fixed_to_double(dx),
.dy = wl_fixed_to_double(dy),
.scale = wl_fixed_to_double(scale),
.rotation = wl_fixed_to_double(rotation),
};
wl_signal_emit_mutable(&pointer->wlr_pointer.events.pinch_update, &wlr_event);
}
static void gesture_pinch_end(void *data,
struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1,
uint32_t serial, uint32_t time, int32_t cancelled) {
struct wlr_wl_seat *seat = data;
struct wlr_wl_pointer *pointer = seat->active_pointer;
if (pointer == NULL) {
return;
}
struct wlr_pointer_pinch_end_event wlr_event = {
.pointer = &pointer->wlr_pointer,
.time_msec = time,
.cancelled = cancelled,
};
wl_signal_emit_mutable(&pointer->wlr_pointer.events.pinch_end, &wlr_event);
}
static const struct zwp_pointer_gesture_pinch_v1_listener gesture_pinch_impl = {
.begin = gesture_pinch_begin,
.update = gesture_pinch_update,
.end = gesture_pinch_end,
};
static void gesture_hold_begin(void *data,
struct zwp_pointer_gesture_hold_v1 *zwp_pointer_gesture_hold_v1,
uint32_t serial, uint32_t time, struct wl_surface *surface,
uint32_t fingers) {
struct wlr_wl_seat *seat = data;
struct wlr_wl_pointer *pointer = seat->active_pointer;
if (pointer == NULL) {
return;
}
pointer->fingers = fingers;
struct wlr_pointer_hold_begin_event wlr_event = {
.pointer = &pointer->wlr_pointer,
.time_msec = time,
.fingers = fingers,
};
wl_signal_emit_mutable(&pointer->wlr_pointer.events.hold_begin, &wlr_event);
}
static void gesture_hold_end(void *data,
struct zwp_pointer_gesture_hold_v1 *zwp_pointer_gesture_hold_v1,
uint32_t serial, uint32_t time, int32_t cancelled) {
struct wlr_wl_seat *seat = data;
struct wlr_wl_pointer *pointer = seat->active_pointer;
if (pointer == NULL) {
return;
}
struct wlr_pointer_hold_end_event wlr_event = {
.pointer = &pointer->wlr_pointer,
.time_msec = time,
.cancelled = cancelled,
};
wl_signal_emit_mutable(&pointer->wlr_pointer.events.hold_end, &wlr_event);
}
static const struct zwp_pointer_gesture_hold_v1_listener gesture_hold_impl = {
.begin = gesture_hold_begin,
.end = gesture_hold_end,
};
static void relative_pointer_handle_relative_motion(void *data,
struct zwp_relative_pointer_v1 *relative_pointer, uint32_t utime_hi,
uint32_t utime_lo, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t dx_unaccel,
wl_fixed_t dy_unaccel) {
struct wlr_wl_seat *seat = data;
struct wlr_wl_pointer *pointer = seat->active_pointer;
if (pointer == NULL) {
return;
}
uint64_t time_usec = (uint64_t)utime_hi << 32 | utime_lo;
struct wlr_pointer_motion_event wlr_event = {
.pointer = &pointer->wlr_pointer,
.time_msec = (uint32_t)(time_usec / 1000),
.delta_x = wl_fixed_to_double(dx),
.delta_y = wl_fixed_to_double(dy),
.unaccel_dx = wl_fixed_to_double(dx_unaccel),
.unaccel_dy = wl_fixed_to_double(dy_unaccel),
};
wl_signal_emit_mutable(&pointer->wlr_pointer.events.motion, &wlr_event);
}
static const struct zwp_relative_pointer_v1_listener relative_pointer_listener = {
.relative_motion = relative_pointer_handle_relative_motion,
};
const struct wlr_pointer_impl wl_pointer_impl = {
.name = "wl-pointer",
};
static void destroy_pointer(struct wlr_wl_pointer *pointer) {
if (pointer->output->cursor.pointer == pointer) {
pointer->output->cursor.pointer = NULL;
}
if (pointer->seat->active_pointer == pointer) {
pointer->seat->active_pointer = NULL;
}
wlr_pointer_finish(&pointer->wlr_pointer);
wl_list_remove(&pointer->output_destroy.link);
wl_list_remove(&pointer->link);
free(pointer);
}
static void pointer_output_destroy(struct wl_listener *listener, void *data) {
struct wlr_wl_pointer *pointer =
wl_container_of(listener, pointer, output_destroy);
destroy_pointer(pointer);
}
void create_pointer(struct wlr_wl_seat *seat, struct wlr_wl_output *output) {
assert(seat->wl_pointer);
if (output_get_pointer(output, seat->wl_pointer)) {
wlr_log(WLR_DEBUG,
"pointer for output '%s' from seat '%s' already exists",
output->wlr_output.name, seat->name);
return;
}
wlr_log(WLR_DEBUG, "creating pointer for output '%s' from seat '%s'",
output->wlr_output.name, seat->name);
struct wlr_wl_pointer *pointer = calloc(1, sizeof(struct wlr_wl_pointer));
if (pointer == NULL) {
wlr_log(WLR_ERROR, "failed to allocate wlr_wl_pointer");
return;
}
char name[64] = {0};
snprintf(name, sizeof(name), "wayland-pointer-%s", seat->name);
wlr_pointer_init(&pointer->wlr_pointer, &wl_pointer_impl, name);
pointer->wlr_pointer.output_name = strdup(output->wlr_output.name);
pointer->seat = seat;
pointer->output = output;
wl_signal_add(&output->wlr_output.events.destroy, &pointer->output_destroy);
pointer->output_destroy.notify = pointer_output_destroy;
wl_signal_emit_mutable(&seat->backend->backend.events.new_input,
&pointer->wlr_pointer.base);
wl_list_insert(&seat->pointers, &pointer->link);
}
void init_seat_pointer(struct wlr_wl_seat *seat) {
assert(seat->wl_pointer);
struct wlr_wl_backend *backend = seat->backend;
wl_list_init(&seat->pointers);
struct wlr_wl_output *output;
wl_list_for_each(output, &backend->outputs, link) {
create_pointer(seat, output);
}
if (backend->zwp_pointer_gestures_v1) {
uint32_t version = zwp_pointer_gestures_v1_get_version(
backend->zwp_pointer_gestures_v1);
seat->gesture_swipe = zwp_pointer_gestures_v1_get_swipe_gesture(
backend->zwp_pointer_gestures_v1, seat->wl_pointer);
zwp_pointer_gesture_swipe_v1_add_listener(seat->gesture_swipe,
&gesture_swipe_impl, seat);
seat->gesture_pinch = zwp_pointer_gestures_v1_get_pinch_gesture(
backend->zwp_pointer_gestures_v1, seat->wl_pointer);
zwp_pointer_gesture_pinch_v1_add_listener(seat->gesture_pinch,
&gesture_pinch_impl, seat);
if (version >= ZWP_POINTER_GESTURES_V1_GET_HOLD_GESTURE) {
seat->gesture_hold = zwp_pointer_gestures_v1_get_hold_gesture(
backend->zwp_pointer_gestures_v1, seat->wl_pointer);
zwp_pointer_gesture_hold_v1_add_listener(seat->gesture_hold,
&gesture_hold_impl, seat);
}
}
if (backend->zwp_relative_pointer_manager_v1) {
seat->relative_pointer =
zwp_relative_pointer_manager_v1_get_relative_pointer(
backend->zwp_relative_pointer_manager_v1, seat->wl_pointer);
zwp_relative_pointer_v1_add_listener(seat->relative_pointer,
&relative_pointer_listener, seat);
}
wl_pointer_add_listener(seat->wl_pointer, &pointer_listener, seat);
}
void finish_seat_pointer(struct wlr_wl_seat *seat) {
assert(seat->wl_pointer);
wl_pointer_release(seat->wl_pointer);
struct wlr_wl_pointer *pointer, *tmp;
wl_list_for_each_safe(pointer, tmp, &seat->pointers, link) {
destroy_pointer(pointer);
}
if (seat->gesture_swipe != NULL) {
zwp_pointer_gesture_swipe_v1_destroy(seat->gesture_swipe);
}
if (seat->gesture_pinch != NULL) {
zwp_pointer_gesture_pinch_v1_destroy(seat->gesture_pinch);
}
if (seat->gesture_hold != NULL) {
zwp_pointer_gesture_hold_v1_destroy(seat->gesture_hold);
}
if (seat->relative_pointer != NULL) {
zwp_relative_pointer_v1_destroy(seat->relative_pointer);
}
seat->wl_pointer = NULL;
seat->active_pointer = NULL;
}

File diff suppressed because it is too large Load diff

View file

@ -1,35 +1,24 @@
#ifndef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 200809L
#endif
#include <wayland-util.h>
#include <assert.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <wlr/interfaces/wlr_tablet_pad.h>
#include <wlr/interfaces/wlr_tablet_tool.h>
#include <wlr/types/wlr_input_device.h>
#include "util/signal.h"
#include "util/time.h"
#include "wlr/util/log.h"
#include "tablet-unstable-v2-client-protocol.h"
#include <wlr/util/log.h>
#include "backend/wayland.h"
#include "util/time.h"
struct wlr_wl_tablet_seat {
struct zwp_tablet_seat_v2 *tablet_seat;
};
#include "tablet-unstable-v2-client-protocol.h"
struct wlr_wl_tablet_tool {
struct tablet_tool {
/* static */
struct zwp_tablet_tool_v2 *tool;
struct wlr_tablet_tool wlr_tool;
struct wlr_wl_seat *seat;
/* semi-static */
struct wlr_wl_output *output;
struct wlr_wl_input_device *tablet;
double pre_x, pre_y;
/* per frame */
@ -49,11 +38,11 @@ struct wlr_wl_tablet_tool {
bool is_down;
};
struct wlr_wl_tablet_pad_ring {
struct wl_list link; // wlr_wl_tablet_pad_group::rings
struct tablet_pad_ring {
struct wl_list link; // tablet_pad_group::rings
/* static */
struct zwp_tablet_pad_ring_v2 *ring;
struct wlr_wl_tablet_pad_group *group;
struct tablet_pad_group *group;
size_t index;
/* per frame */
@ -62,10 +51,10 @@ struct wlr_wl_tablet_pad_ring {
bool stopped;
};
struct wlr_wl_tablet_pad_strip {
struct wl_list link; // wlr_wl_tablet_pad_group::strips
struct tablet_pad_strip {
struct wl_list link; // tablet_pad_group::strips
struct zwp_tablet_pad_strip_v2 *strip;
struct wlr_wl_tablet_pad_group *group;
struct tablet_pad_group *group;
size_t index;
enum wlr_tablet_pad_strip_source source;
@ -73,43 +62,43 @@ struct wlr_wl_tablet_pad_strip {
bool stopped;
};
struct wlr_wl_tablet_pad_group {
struct tablet_pad_group {
struct zwp_tablet_pad_group_v2 *pad_group;
struct wlr_tablet_pad *pad;
unsigned int mode;
struct wlr_tablet_pad_group group;
struct wl_list rings; // wlr_wl_tablet_pad_ring::link
struct wl_list strips; // wlr_wl_tablet_pad_strips::link
struct wl_list rings; // tablet_pad_ring::link
struct wl_list strips; // tablet_pad_strips::link
};
static void handle_tablet_pad_ring_source(void *data,
struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2,
uint32_t source) {
struct wlr_wl_tablet_pad_ring *ring = data;
struct tablet_pad_ring *ring = data;
ring->source = source;
}
static void handle_tablet_pad_ring_angle(void *data,
struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2,
wl_fixed_t degrees) {
struct wlr_wl_tablet_pad_ring *ring = data;
struct tablet_pad_ring *ring = data;
ring->angle = wl_fixed_to_double(degrees);
}
static void handle_tablet_pad_ring_stop(void *data,
struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2) {
struct wlr_wl_tablet_pad_ring *ring = data;
struct tablet_pad_ring *ring = data;
ring->stopped = true;
}
static void handle_tablet_pad_ring_frame(void *data,
struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2,
uint32_t time) {
struct wlr_wl_tablet_pad_ring *ring = data;
struct tablet_pad_ring *ring = data;
struct wlr_event_tablet_pad_ring evt = {
struct wlr_tablet_pad_ring_event evt = {
.time_msec = time,
.source = ring->source,
.ring = ring->index,
@ -118,11 +107,11 @@ static void handle_tablet_pad_ring_frame(void *data,
};
if (ring->angle >= 0) {
wlr_signal_emit_safe(&ring->group->pad->events.ring, &evt);
wl_signal_emit_mutable(&ring->group->pad->events.ring, &evt);
}
if (ring->stopped) {
evt.position = -1;
wlr_signal_emit_safe(&ring->group->pad->events.ring, &evt);
wl_signal_emit_mutable(&ring->group->pad->events.ring, &evt);
}
ring->angle = -1;
@ -140,29 +129,29 @@ static const struct zwp_tablet_pad_ring_v2_listener tablet_pad_ring_listener = {
static void handle_tablet_pad_strip_source(void *data,
struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2,
uint32_t source) {
struct wlr_wl_tablet_pad_strip *strip = data;
struct tablet_pad_strip *strip = data;
strip->source = source;
}
static void handle_tablet_pad_strip_position(void *data,
struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2,
uint32_t position) {
struct wlr_wl_tablet_pad_strip *strip = data;
struct tablet_pad_strip *strip = data;
strip->position = (double) position / 65536.0;
}
static void handle_tablet_pad_strip_stop(void *data,
struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2) {
struct wlr_wl_tablet_pad_strip *strip = data;
struct tablet_pad_strip *strip = data;
strip->stopped = true;
}
static void handle_tablet_pad_strip_frame(void *data,
struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2,
uint32_t time) {
struct wlr_wl_tablet_pad_strip *strip = data;
struct tablet_pad_strip *strip = data;
struct wlr_event_tablet_pad_strip evt = {
struct wlr_tablet_pad_strip_event evt = {
.time_msec = time,
.source = strip->source,
.strip = strip->index,
@ -171,11 +160,11 @@ static void handle_tablet_pad_strip_frame(void *data,
};
if (strip->position >= 0) {
wlr_signal_emit_safe(&strip->group->pad->events.strip, &evt);
wl_signal_emit_mutable(&strip->group->pad->events.strip, &evt);
}
if (strip->stopped) {
evt.position = -1;
wlr_signal_emit_safe(&strip->group->pad->events.strip, &evt);
wl_signal_emit_mutable(&strip->group->pad->events.strip, &evt);
}
strip->position = -1;
@ -193,7 +182,7 @@ static const struct zwp_tablet_pad_strip_v2_listener tablet_pad_strip_listener =
static void handle_tablet_pad_group_buttons(void *data,
struct zwp_tablet_pad_group_v2 *pad_group,
struct wl_array *buttons) {
struct wlr_wl_tablet_pad_group *group = data;
struct tablet_pad_group *group = data;
free(group->group.buttons);
group->group.buttons = calloc(1, buttons->size);
@ -208,7 +197,7 @@ static void handle_tablet_pad_group_buttons(void *data,
static void handle_tablet_pad_group_modes(void *data,
struct zwp_tablet_pad_group_v2 *pad_group, uint32_t modes) {
struct wlr_wl_tablet_pad_group *group = data;
struct tablet_pad_group *group = data;
group->group.mode_count = modes;
}
@ -216,9 +205,9 @@ static void handle_tablet_pad_group_modes(void *data,
static void handle_tablet_pad_group_ring(void *data,
struct zwp_tablet_pad_group_v2 *pad_group,
struct zwp_tablet_pad_ring_v2 *ring) {
struct wlr_wl_tablet_pad_group *group = data;
struct wlr_wl_tablet_pad_ring *tablet_ring =
calloc(1, sizeof(struct wlr_wl_tablet_pad_ring));
struct tablet_pad_group *group = data;
struct tablet_pad_ring *tablet_ring =
calloc(1, sizeof(struct tablet_pad_ring));
if (!tablet_ring) {
zwp_tablet_pad_ring_v2_destroy(ring);
return;
@ -237,9 +226,9 @@ static void handle_tablet_pad_group_ring(void *data,
static void handle_tablet_pad_group_strip(void *data,
struct zwp_tablet_pad_group_v2 *pad_group,
struct zwp_tablet_pad_strip_v2 *strip) {
struct wlr_wl_tablet_pad_group *group = data;
struct wlr_wl_tablet_pad_strip *tablet_strip =
calloc(1, sizeof(struct wlr_wl_tablet_pad_strip));
struct tablet_pad_group *group = data;
struct tablet_pad_strip *tablet_strip =
calloc(1, sizeof(struct tablet_pad_strip));
if (!tablet_strip) {
zwp_tablet_pad_strip_v2_destroy(strip);
return;
@ -263,25 +252,20 @@ static void handle_tablet_pad_group_done(void *data,
static void handle_tablet_pad_group_mode_switch(void *data,
struct zwp_tablet_pad_group_v2 *pad_group,
uint32_t time, uint32_t serial, uint32_t mode) {
struct wlr_wl_tablet_pad_group *group = data;
struct tablet_pad_group *group = data;
group->mode = mode;
}
/* This isn't in the listener, but keep the naming scheme around since the
* other removed functions work like this, and pad sub-resources are just a bit
* special */
static void handle_tablet_pad_group_removed(
struct wlr_wl_tablet_pad_group *group) {
static void destroy_tablet_pad_group(struct tablet_pad_group *group) {
/* No need to remove the ::link on strips rings as long as we do *not*
* wl_list_remove on the wl_groups ring/strip attributes here */
struct wlr_wl_tablet_pad_ring *ring, *tmp_ring;
struct tablet_pad_ring *ring, *tmp_ring;
wl_list_for_each_safe(ring, tmp_ring, &group->rings, link) {
zwp_tablet_pad_ring_v2_destroy(ring->ring);
free(ring);
}
struct wlr_wl_tablet_pad_strip *strip, *tmp_strip;
struct tablet_pad_strip *strip, *tmp_strip;
wl_list_for_each_safe(strip, tmp_strip, &group->strips, link) {
zwp_tablet_pad_strip_v2_destroy(strip->strip);
free(strip);
@ -289,10 +273,11 @@ static void handle_tablet_pad_group_removed(
zwp_tablet_pad_group_v2_destroy(group->pad_group);
/* While I'm pretty sure we have control over this as well, it's
* outside the scope of a single function, so better be safe than
* sorry */
free(group->group.buttons);
free(group->group.strips);
free(group->group.rings);
wl_list_remove(&group->group.link);
free(group);
}
@ -308,12 +293,13 @@ static const struct zwp_tablet_pad_group_v2_listener tablet_pad_group_listener =
static void handle_tablet_pad_group(void *data,
struct zwp_tablet_pad_v2 *zwp_tablet_pad,
struct zwp_tablet_pad_group_v2 *pad_group) {
struct wlr_wl_input_device *dev = data;
struct wlr_tablet_pad *pad = dev->wlr_input_device.tablet_pad;
struct wlr_wl_seat *seat = data;
struct wlr_tablet_pad *pad = &seat->wlr_tablet_pad;
struct wlr_wl_tablet_pad_group *group =
calloc(1, sizeof(struct wlr_wl_tablet_pad_group));
struct tablet_pad_group *group =
calloc(1, sizeof(struct tablet_pad_group));
if (!group) {
wlr_log_errno(WLR_ERROR, "failed to allocate tablet_pad_group");
zwp_tablet_pad_group_v2_destroy(pad_group);
return;
}
@ -330,20 +316,18 @@ static void handle_tablet_pad_group(void *data,
}
static void handle_tablet_pad_path(void *data,
struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2,
const char *path) {
struct wlr_wl_input_device *dev = data;
struct wlr_tablet_pad *tablet_pad = dev->wlr_input_device.tablet_pad;
struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, const char *path) {
struct wlr_wl_seat *seat = data;
struct wlr_tablet_pad *tablet_pad = &seat->wlr_tablet_pad;
char **dst = wl_array_add(&tablet_pad->paths, sizeof(char *));
*dst = strdup(path);
}
static void handle_tablet_pad_buttons(void *data,
struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2,
uint32_t buttons) {
struct wlr_wl_input_device *dev = data;
struct wlr_tablet_pad *tablet_pad = dev->wlr_input_device.tablet_pad;
struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, uint32_t buttons) {
struct wlr_wl_seat *seat = data;
struct wlr_tablet_pad *tablet_pad = &seat->wlr_tablet_pad;
tablet_pad->button_count = buttons;
}
@ -351,10 +335,8 @@ static void handle_tablet_pad_buttons(void *data,
static void handle_tablet_pad_button(void *data,
struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2,
uint32_t time, uint32_t button, uint32_t state) {
struct wlr_wl_input_device *dev = data;
struct wlr_tablet_pad *tablet_pad = dev->wlr_input_device.tablet_pad;
struct wlr_event_tablet_pad_button evt = {
struct wlr_wl_seat *seat = data;
struct wlr_tablet_pad_button_event evt = {
.time_msec = time,
.button = button,
.state = state,
@ -362,28 +344,25 @@ static void handle_tablet_pad_button(void *data,
.group = 0,
};
wlr_signal_emit_safe(&tablet_pad->events.button, &evt);
wl_signal_emit_mutable(&seat->wlr_tablet_pad.events.button, &evt);
}
static void handle_tablet_pad_done(void *data,
struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2) {
struct wlr_wl_input_device *dev = data;
wlr_signal_emit_safe(&dev->backend->backend.events.new_input,
&dev->wlr_input_device);
struct wlr_wl_seat *seat = data;
wl_signal_emit_mutable(&seat->backend->backend.events.new_input,
&seat->wlr_tablet_pad.base);
}
static void handle_tablet_pad_enter(void *data,
struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2,
uint32_t serial, struct zwp_tablet_v2 *tablet_p,
struct wl_surface *surface) {
struct wlr_wl_input_device *dev = data;
struct wlr_tablet_pad *tablet_pad = dev->wlr_input_device.tablet_pad;
struct wlr_wl_input_device *tab_dev = zwp_tablet_v2_get_user_data(tablet_p);
struct wlr_input_device *tablet = &tab_dev->wlr_input_device;
wlr_log(WLR_DEBUG, "Tablet: %p\n", tablet);
struct wlr_wl_seat *seat = data;
assert(seat->zwp_tablet_v2 == tablet_p);
wlr_signal_emit_safe(&tablet_pad->events.attach_tablet, tablet);
wl_signal_emit_mutable(&seat->wlr_tablet_pad.events.attach_tablet,
&seat->wlr_tablet_tool);
}
static void handle_tablet_pad_leave(void *data,
@ -395,23 +374,17 @@ static void handle_tablet_pad_leave(void *data,
static void handle_tablet_pad_removed(void *data,
struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2) {
struct wlr_wl_input_device *dev = data;
struct wlr_tablet_pad *tablet_pad = dev->wlr_input_device.tablet_pad;
struct wlr_wl_seat *seat = data;
/* This doesn't free anything, but emits the destroy signal */
wlr_input_device_destroy(&dev->wlr_input_device);
/* This is a bit ugly, but we need to remove it from our list */
wl_list_remove(&dev->link);
struct wlr_wl_tablet_pad_group *group, *it;
struct wlr_tablet_pad *tablet_pad = &seat->wlr_tablet_pad;
struct tablet_pad_group *group, *it;
wl_list_for_each_safe(group, it, &tablet_pad->groups, group.link) {
handle_tablet_pad_group_removed(group);
destroy_tablet_pad_group(group);
}
/* This frees */
wlr_tablet_pad_destroy(tablet_pad);
zwp_tablet_pad_v2_destroy(dev->resource);
free(dev);
wlr_tablet_pad_finish(tablet_pad);
zwp_tablet_pad_v2_destroy(seat->zwp_tablet_pad_v2);
seat->zwp_tablet_pad_v2 = NULL;
}
static const struct zwp_tablet_pad_v2_listener tablet_pad_listener = {
@ -425,37 +398,25 @@ static const struct zwp_tablet_pad_v2_listener tablet_pad_listener = {
.removed = handle_tablet_pad_removed,
};
const struct wlr_tablet_pad_impl tablet_pad_impl = {0};
const struct wlr_tablet_pad_impl wl_tablet_pad_impl = {
.name = "wl-tablet-pad",
};
static void handle_pad_added(void *data,
struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2,
struct zwp_tablet_pad_v2 *id) {
wlr_log(WLR_DEBUG, "New tablet pad");
struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2) {
struct wlr_wl_seat *seat = data;
struct wlr_wl_input_device *dev = create_wl_input_device(
seat, WLR_INPUT_DEVICE_TABLET_PAD);
if (!dev) {
/* This leaks a couple of server-sent resource ids. iirc this
* shouldn't ever be a problem, but it isn't exactly nice
* either. */
zwp_tablet_pad_v2_destroy(id);
if (seat->zwp_tablet_pad_v2 != NULL) {
wlr_log(WLR_ERROR, "zwp_tablet_pad_v2 is already present");
return;
}
dev->resource = id;
struct wlr_input_device *wlr_dev = &dev->wlr_input_device;
wlr_dev->tablet_pad = calloc(1, sizeof(*wlr_dev->tablet_pad));
seat->zwp_tablet_pad_v2 = zwp_tablet_pad_v2;
zwp_tablet_pad_v2_add_listener(zwp_tablet_pad_v2, &tablet_pad_listener,
seat);
if (!wlr_dev->tablet_pad) {
/* This leaks a couple of server-sent resource ids. iirc this
* shouldn't ever be a problem, but it isn't exactly nice
* either. */
free(dev);
zwp_tablet_pad_v2_destroy(id);
return;
}
wlr_tablet_pad_init(wlr_dev->tablet_pad, &tablet_pad_impl, wlr_dev->name);
zwp_tablet_pad_v2_add_listener(id, &tablet_pad_listener, dev);
wlr_tablet_pad_init(&seat->wlr_tablet_pad, &wl_tablet_pad_impl,
"wlr_tablet_v2");
}
static void handle_tablet_tool_done(void *data,
@ -463,7 +424,8 @@ static void handle_tablet_tool_done(void *data,
/* empty */
}
static enum wlr_tablet_tool_type tablet_type_to_wlr_type(enum zwp_tablet_tool_v2_type type) {
static enum wlr_tablet_tool_type tablet_type_to_wlr_type(
enum zwp_tablet_tool_v2_type type) {
switch (type) {
case ZWP_TABLET_TOOL_V2_TYPE_PEN:
return WLR_TABLET_TOOL_TYPE_PEN;
@ -488,94 +450,85 @@ static enum wlr_tablet_tool_type tablet_type_to_wlr_type(enum zwp_tablet_tool_v2
}
static void handle_tablet_tool_type(void *data,
struct zwp_tablet_tool_v2 *id,
uint32_t tool_type) {
struct wlr_wl_tablet_tool *tool = data;
tool->wlr_tool.type = tablet_type_to_wlr_type(tool_type);
struct zwp_tablet_tool_v2 *id, uint32_t tool_type) {
struct tablet_tool *tool = data;
struct wlr_tablet_tool *wlr_tool = &tool->seat->wlr_tablet_tool;
wlr_tool->type = tablet_type_to_wlr_type(tool_type);
}
static void handle_tablet_tool_serial(void *data,
struct zwp_tablet_tool_v2 *id,
uint32_t high, uint32_t low) {
struct wlr_wl_tablet_tool *tool = data;
tool->wlr_tool.hardware_serial =
((uint64_t) high) << 32 | (uint64_t) low;
struct zwp_tablet_tool_v2 *id, uint32_t high, uint32_t low) {
struct tablet_tool *tool = data;
struct wlr_tablet_tool *wlr_tool = &tool->seat->wlr_tablet_tool;
wlr_tool->hardware_serial = ((uint64_t) high) << 32 | (uint64_t) low;
}
static void handle_tablet_tool_id_wacom(void *data,
struct zwp_tablet_tool_v2 *id,
uint32_t high, uint32_t low) {
struct wlr_wl_tablet_tool *tool = data;
tool->wlr_tool.hardware_wacom =
((uint64_t) high) << 32 | (uint64_t) low;
struct zwp_tablet_tool_v2 *id, uint32_t high, uint32_t low) {
struct tablet_tool *tool = data;
struct wlr_tablet_tool *wlr_tool = &tool->seat->wlr_tablet_tool;
wlr_tool->hardware_wacom = ((uint64_t) high) << 32 | (uint64_t) low;
}
static void handle_tablet_tool_capability(void *data,
struct zwp_tablet_tool_v2 *id,
uint32_t capability) {
struct wlr_wl_tablet_tool *tool = data;
struct zwp_tablet_tool_v2 *id, uint32_t capability) {
struct tablet_tool *tool = data;
struct wlr_tablet_tool *wlr_tool = &tool->seat->wlr_tablet_tool;
enum zwp_tablet_tool_v2_capability cap = capability;
switch (cap) {
/* One event is sent for each capability */
switch (capability) {
case ZWP_TABLET_TOOL_V2_CAPABILITY_TILT:
tool->wlr_tool.tilt = true;
wlr_tool->tilt = true;
break;
case ZWP_TABLET_TOOL_V2_CAPABILITY_PRESSURE:
tool->wlr_tool.pressure = true;
wlr_tool->pressure = true;
break;
case ZWP_TABLET_TOOL_V2_CAPABILITY_DISTANCE:
tool->wlr_tool.distance = true;
wlr_tool->distance = true;
break;
case ZWP_TABLET_TOOL_V2_CAPABILITY_ROTATION:
tool->wlr_tool.rotation = true;
wlr_tool->rotation = true;
break;
case ZWP_TABLET_TOOL_V2_CAPABILITY_SLIDER:
tool->wlr_tool.slider = true;
wlr_tool->slider = true;
break;
case ZWP_TABLET_TOOL_V2_CAPABILITY_WHEEL:
tool->wlr_tool.wheel = true;
wlr_tool->wheel = true;
break;
}
}
static void handle_tablet_tool_proximity_in(void *data,
struct zwp_tablet_tool_v2 *id, uint32_t serial,
struct zwp_tablet_v2 *tablet_id,
struct wl_surface *surface) {
struct wlr_wl_tablet_tool *tool = data;
struct zwp_tablet_v2 *tablet_id, struct wl_surface *surface) {
struct tablet_tool *tool = data;
assert(tablet_id == tool->seat->zwp_tablet_v2);
tool->is_in = true;
tool->tablet = zwp_tablet_v2_get_user_data(tablet_id);
tool->output = wl_surface_get_user_data(surface);
}
static void handle_tablet_tool_proximity_out(void *data,
struct zwp_tablet_tool_v2 *id) {
struct wlr_wl_tablet_tool *tool = data;
struct tablet_tool *tool = data;
tool->is_out = true;
tool->output = NULL;
}
static void handle_tablet_tool_down(void *data,
struct zwp_tablet_tool_v2 *id,
static void handle_tablet_tool_down(void *data, struct zwp_tablet_tool_v2 *id,
unsigned int serial) {
struct wlr_wl_tablet_tool *tool = data;
struct tablet_tool *tool = data;
tool->is_down = true;
}
static void handle_tablet_tool_up(void *data,
struct zwp_tablet_tool_v2 *id) {
struct wlr_wl_tablet_tool *tool = data;
static void handle_tablet_tool_up(void *data, struct zwp_tablet_tool_v2 *id) {
struct tablet_tool *tool = data;
tool->is_up = true;
}
static void handle_tablet_tool_motion(void *data,
struct zwp_tablet_tool_v2 *id,
static void handle_tablet_tool_motion(void *data, struct zwp_tablet_tool_v2 *id,
wl_fixed_t x, wl_fixed_t y) {
struct wlr_wl_tablet_tool *tool = data;
struct tablet_tool *tool = data;
struct wlr_wl_output *output = tool->output;
assert(output);
@ -584,68 +537,63 @@ static void handle_tablet_tool_motion(void *data,
}
static void handle_tablet_tool_pressure(void *data,
struct zwp_tablet_tool_v2 *id,
uint32_t pressure) {
struct wlr_wl_tablet_tool *tool = data;
struct zwp_tablet_tool_v2 *id, uint32_t pressure) {
struct tablet_tool *tool = data;
tool->pressure = (double) pressure / 65535.0;
}
static void handle_tablet_tool_distance(void *data,
struct zwp_tablet_tool_v2 *id,
uint32_t distance) {
struct wlr_wl_tablet_tool *tool = data;
struct zwp_tablet_tool_v2 *id, uint32_t distance) {
struct tablet_tool *tool = data;
tool->distance = (double) distance / 65535.0;
}
static void handle_tablet_tool_tilt(void *data,
struct zwp_tablet_tool_v2 *id,
static void handle_tablet_tool_tilt(void *data, struct zwp_tablet_tool_v2 *id,
wl_fixed_t x, wl_fixed_t y) {
struct wlr_wl_tablet_tool *tool = data;
struct tablet_tool *tool = data;
tool->tilt_x = wl_fixed_to_double(x);
tool->tilt_y = wl_fixed_to_double(y);
}
static void handle_tablet_tool_rotation(void *data,
struct zwp_tablet_tool_v2 *id,
wl_fixed_t rotation) {
struct wlr_wl_tablet_tool *tool = data;
struct zwp_tablet_tool_v2 *id, wl_fixed_t rotation) {
struct tablet_tool *tool = data;
tool->rotation = wl_fixed_to_double(rotation);
}
static void handle_tablet_tool_slider(void *data,
struct zwp_tablet_tool_v2 *id,
static void handle_tablet_tool_slider(void *data, struct zwp_tablet_tool_v2 *id,
int slider) {
struct wlr_wl_tablet_tool *tool = data;
struct tablet_tool *tool = data;
tool->slider = (double) slider / 65535.0;;
}
// TODO: This looks wrong :/
static void handle_tablet_tool_wheel(void *data,
struct zwp_tablet_tool_v2 *id,
static void handle_tablet_tool_wheel(void *data, struct zwp_tablet_tool_v2 *id,
wl_fixed_t degree, int clicks) {
struct wlr_wl_tablet_tool *tool = data;
struct tablet_tool *tool = data;
tool->wheel_delta = wl_fixed_to_double(degree);
}
static void handle_tablet_tool_button(void *data,
struct zwp_tablet_tool_v2 *id,
uint32_t serial, uint32_t button, uint32_t state) {
struct wlr_wl_tablet_tool *tool = data;
struct wlr_tablet *tablet = tool->tablet->wlr_input_device.tablet;
struct tablet_tool *tool = data;
struct wlr_wl_seat *seat = tool->seat;
struct wlr_tablet *tablet = &seat->wlr_tablet;
struct wlr_event_tablet_tool_button evt = {
.device = &tool->tablet->wlr_input_device,
.tool = &tool->wlr_tool,
struct wlr_tablet_tool_button_event evt = {
.tablet = tablet,
.tool = &seat->wlr_tablet_tool,
.time_msec = get_current_time_msec(),
.button = button,
.state = state == ZWP_TABLET_TOOL_V2_BUTTON_STATE_RELEASED ?
WLR_BUTTON_RELEASED : WLR_BUTTON_PRESSED,
};
wlr_signal_emit_safe(&tablet->events.button, &evt);
wl_signal_emit_mutable(&tablet->events.button, &evt);
}
static void clear_tablet_tool_values(struct wlr_wl_tablet_tool *tool) {
static void clear_tablet_tool_values(struct tablet_tool *tool) {
tool->is_out = tool->is_in = false;
tool->is_up = tool->is_down = false;
tool->x = tool->y = NAN;
@ -660,31 +608,33 @@ static void clear_tablet_tool_values(struct wlr_wl_tablet_tool *tool) {
static void handle_tablet_tool_frame(void *data,
struct zwp_tablet_tool_v2 *id,
uint32_t time) {
struct wlr_wl_tablet_tool *tool = data;
struct tablet_tool *tool = data;
struct wlr_wl_seat *seat = tool->seat;
if (tool->is_out && tool->is_in) {
/* we got a tablet tool coming in and out of proximity before
* we could process it. Just ignore anything it did */
goto clear_values;
}
struct wlr_tablet *tablet = tool->tablet->wlr_input_device.tablet;
struct wlr_tablet *tablet = &seat->wlr_tablet;
if (tool->is_in) {
struct wlr_event_tablet_tool_proximity evt = {
.device = &tool->tablet->wlr_input_device,
.tool = &tool->wlr_tool,
struct wlr_tablet_tool_proximity_event evt = {
.tablet = tablet,
.tool = &seat->wlr_tablet_tool,
.time_msec = time,
.x = tool->x,
.y = tool->y,
.state = WLR_TABLET_TOOL_PROXIMITY_IN,
};
wlr_signal_emit_safe(&tablet->events.proximity, &evt);
wl_signal_emit_mutable(&tablet->events.proximity, &evt);
}
{
struct wlr_event_tablet_tool_axis evt = {
.device = &tool->tablet->wlr_input_device,
.tool = &tool->wlr_tool,
struct wlr_tablet_tool_axis_event evt = {
.tablet = tablet,
.tool = &seat->wlr_tablet_tool,
.time_msec = time,
.updated_axes = 0,
};
@ -735,7 +685,7 @@ static void handle_tablet_tool_frame(void *data,
}
if (evt.updated_axes) {
wlr_signal_emit_safe(&tablet->events.axis, &evt);
wl_signal_emit_mutable(&tablet->events.axis, &evt);
}
}
@ -745,42 +695,42 @@ static void handle_tablet_tool_frame(void *data,
* Downside: Here we have the frame time, if we sent right away, we
* need to generate the time */
if (tool->is_down) {
struct wlr_event_tablet_tool_tip evt = {
.device = &tool->tablet->wlr_input_device,
.tool = &tool->wlr_tool,
struct wlr_tablet_tool_tip_event evt = {
.tablet = tablet,
.tool = &seat->wlr_tablet_tool,
.time_msec = time,
.x = tool->x,
.y = tool->y,
.state = WLR_TABLET_TOOL_TIP_DOWN,
};
wlr_signal_emit_safe(&tablet->events.tip, &evt);
wl_signal_emit_mutable(&tablet->events.tip, &evt);
}
if (tool->is_up) {
struct wlr_event_tablet_tool_tip evt = {
.device = &tool->tablet->wlr_input_device,
.tool = &tool->wlr_tool,
struct wlr_tablet_tool_tip_event evt = {
.tablet = tablet,
.tool = &seat->wlr_tablet_tool,
.time_msec = time,
.x = tool->x,
.y = tool->y,
.state = WLR_TABLET_TOOL_TIP_UP,
};
wlr_signal_emit_safe(&tablet->events.tip, &evt);
wl_signal_emit_mutable(&tablet->events.tip, &evt);
}
if (tool->is_out) {
struct wlr_event_tablet_tool_proximity evt = {
.device = &tool->tablet->wlr_input_device,
.tool = &tool->wlr_tool,
struct wlr_tablet_tool_proximity_event evt = {
.tablet = tablet,
.tool = &seat->wlr_tablet_tool,
.time_msec = time,
.x = tool->x,
.y = tool->y,
.state = WLR_TABLET_TOOL_PROXIMITY_OUT,
};
wlr_signal_emit_safe(&tablet->events.proximity, &evt);
wl_signal_emit_mutable(&tablet->events.proximity, &evt);
}
clear_values:
@ -789,10 +739,12 @@ clear_values:
static void handle_tablet_tool_removed(void *data,
struct zwp_tablet_tool_v2 *id) {
struct wlr_wl_tablet_tool *tool = data;
struct tablet_tool *tool = data;
struct wlr_wl_seat *seat = tool->seat;
zwp_tablet_tool_v2_destroy(seat->zwp_tablet_tool_v2);
seat->zwp_tablet_tool_v2 = NULL;
zwp_tablet_tool_v2_destroy(tool->tool);
wlr_signal_emit_safe(&tool->wlr_tool.events.destroy, &tool->wlr_tool);
free(tool);
}
@ -822,62 +774,71 @@ static const struct zwp_tablet_tool_v2_listener tablet_tool_listener = {
static void handle_tool_added(void *data,
struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2,
struct zwp_tablet_tool_v2 *id) {
wlr_log(WLR_DEBUG, "New tablet tool");
struct wlr_wl_tablet_tool *tool = calloc(1, sizeof(*tool));
if (!tool) {
zwp_tablet_tool_v2_destroy(id);
struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2) {
struct wlr_wl_seat *seat = data;
if (seat->zwp_tablet_tool_v2 != NULL) {
wlr_log(WLR_ERROR, "zwp_tablet_tool_v2 already present");
return;
}
tool->tool = id;
wl_signal_init(&seat->wlr_tablet_tool.events.destroy);
struct tablet_tool *tool = calloc(1, sizeof(struct tablet_tool));
if (tool == NULL) {
wlr_log_errno(WLR_ERROR, "failed to allocate tablet_tool");
zwp_tablet_tool_v2_destroy(zwp_tablet_tool_v2);
return;
}
tool->seat = seat;
clear_tablet_tool_values(tool);
wl_signal_init(&tool->wlr_tool.events.destroy);
zwp_tablet_tool_v2_add_listener(id, &tablet_tool_listener, tool);
seat->zwp_tablet_tool_v2 = zwp_tablet_tool_v2;
zwp_tablet_tool_v2_add_listener(seat->zwp_tablet_tool_v2, &tablet_tool_listener,
tool);
}
static void handle_tablet_name(void *data, struct zwp_tablet_v2 *zwp_tablet_v2,
const char *name) {
struct wlr_wl_input_device *dev = data;
struct wlr_tablet *tablet = dev->wlr_input_device.tablet;
struct wlr_wl_seat *seat = data;
struct wlr_tablet *tablet = &seat->wlr_tablet;
free(tablet->name);
tablet->name = strdup(name);
free(tablet->base.name);
tablet->base.name = strdup(name);
}
static void handle_tablet_id(void *data, struct zwp_tablet_v2 *zwp_tablet_v2,
uint32_t vid, uint32_t pid) {
struct wlr_wl_input_device *dev = data;
dev->wlr_input_device.vendor = vid;
dev->wlr_input_device.product = pid;
struct wlr_wl_seat *seat = data;
struct wlr_tablet *tablet = &seat->wlr_tablet;
tablet->base.vendor = vid;
tablet->base.product = pid;
}
static void handle_tablet_path(void *data, struct zwp_tablet_v2 *zwp_tablet_v2,
const char *path) {
struct wlr_wl_input_device *dev = data;
struct wlr_tablet *tablet = dev->wlr_input_device.tablet;
struct wlr_wl_seat *seat = data;
struct wlr_tablet *tablet = &seat->wlr_tablet;
char **dst = wl_array_add(&tablet->paths, sizeof(char *));
*dst = strdup(path);
}
static void handle_tablet_done(void *data, struct zwp_tablet_v2 *zwp_tablet_v2) {
struct wlr_wl_input_device *dev = data;
struct wlr_wl_seat *seat = data;
wlr_signal_emit_safe(&dev->backend->backend.events.new_input,
&dev->wlr_input_device);
wl_signal_emit_mutable(&seat->backend->backend.events.new_input,
&seat->wlr_tablet.base);
}
static void handle_tablet_removed(void *data,
struct zwp_tablet_v2 *zwp_tablet_v2) {
struct wlr_wl_input_device *dev = data;
struct wlr_wl_seat *seat = data;
/* This doesn't free anything, but emits the destroy signal */
wlr_input_device_destroy(&dev->wlr_input_device);
/* This is a bit ugly, but we need to remove it from our list */
wl_list_remove(&dev->link);
zwp_tablet_v2_destroy(dev->resource);
free(dev);
wlr_tablet_finish(&seat->wlr_tablet);
zwp_tablet_v2_destroy(seat->zwp_tablet_v2);
seat->zwp_tablet_v2 = NULL;
}
static const struct zwp_tablet_v2_listener tablet_listener = {
@ -888,32 +849,23 @@ static const struct zwp_tablet_v2_listener tablet_listener = {
.removed = handle_tablet_removed,
};
const struct wlr_tablet_impl tablet_impl = {0};
const struct wlr_tablet_impl wl_tablet_impl = {
.name = "wl-tablet-tool",
};
static void handle_tab_added(void *data,
struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2,
struct zwp_tablet_v2 *id) {
wlr_log(WLR_DEBUG, "New tablet");
struct zwp_tablet_v2 *zwp_tablet_v2) {
struct wlr_wl_seat *seat = data;
struct wlr_wl_input_device *dev = create_wl_input_device(
seat, WLR_INPUT_DEVICE_TABLET_TOOL);
if (!dev) {
zwp_tablet_v2_destroy(id);
if (seat->zwp_tablet_v2 != NULL) {
wlr_log(WLR_ERROR, "zwp_tablet_v2 already present");
return;
}
dev->resource = id;
struct wlr_input_device *wlr_dev = &dev->wlr_input_device;
wlr_dev->tablet = calloc(1, sizeof(*wlr_dev->tablet));
seat->zwp_tablet_v2 = zwp_tablet_v2;
zwp_tablet_v2_add_listener(zwp_tablet_v2, &tablet_listener, seat);
if (!wlr_dev->tablet) {
zwp_tablet_v2_destroy(id);
return;
}
zwp_tablet_v2_set_user_data(id, wlr_dev->tablet);
wlr_tablet_init(wlr_dev->tablet, &tablet_impl, wlr_dev->name);
zwp_tablet_v2_add_listener(id, &tablet_listener, dev);
wlr_tablet_init(&seat->wlr_tablet, &wl_tablet_impl, "wlr_tablet_v2");
}
static const struct zwp_tablet_seat_v2_listener tablet_seat_listener = {
@ -922,20 +874,55 @@ static const struct zwp_tablet_seat_v2_listener tablet_seat_listener = {
.pad_added = handle_pad_added,
};
struct wlr_wl_tablet_seat *wl_add_tablet_seat(
struct zwp_tablet_manager_v2 *manager,
struct wlr_wl_seat *seat) {
struct wlr_wl_tablet_seat *ret =
calloc(1, sizeof(struct wlr_wl_tablet_seat));
void init_seat_tablet(struct wlr_wl_seat *seat) {
struct zwp_tablet_manager_v2 *manager = seat->backend->tablet_manager;
assert(manager);
if (!(ret->tablet_seat =
zwp_tablet_manager_v2_get_tablet_seat(manager, seat->wl_seat))) {
free(ret);
return NULL;
/**
* TODO: multi tablet support
* The wlr_wl_seat should support multiple tablet_v2 devices, but for
* the sake of simplicity, it supports only one device of each.
* If this is a feature you want/need, please open an issue on the wlroots
* tracker here https://gitlab.freedesktop.org/wlroots/wlroots/-/issues
*/
seat->zwp_tablet_seat_v2 =
zwp_tablet_manager_v2_get_tablet_seat(manager, seat->wl_seat);
if (seat->zwp_tablet_seat_v2 == NULL) {
wlr_log(WLR_ERROR, "failed to get zwp_tablet_manager_v2 from seat '%s'",
seat->name);
return;
}
zwp_tablet_seat_v2_add_listener(ret->tablet_seat,
zwp_tablet_seat_v2_add_listener(seat->zwp_tablet_seat_v2,
&tablet_seat_listener, seat);
return ret;
}
void finish_seat_tablet(struct wlr_wl_seat *seat) {
if (seat->zwp_tablet_v2 != NULL) {
wlr_tablet_finish(&seat->wlr_tablet);
zwp_tablet_v2_destroy(seat->zwp_tablet_v2);
}
if (seat->zwp_tablet_tool_v2 != NULL) {
struct tablet_tool *tool =
zwp_tablet_tool_v2_get_user_data(seat->zwp_tablet_tool_v2);
free(tool);
zwp_tablet_tool_v2_destroy(seat->zwp_tablet_tool_v2);
}
if (seat->zwp_tablet_pad_v2 != NULL) {
struct wlr_tablet_pad *tablet_pad = &seat->wlr_tablet_pad;
struct tablet_pad_group *group, *it;
wl_list_for_each_safe(group, it, &tablet_pad->groups, group.link) {
destroy_tablet_pad_group(group);
}
wlr_tablet_pad_finish(tablet_pad);
zwp_tablet_pad_v2_destroy(seat->zwp_tablet_pad_v2);
}
zwp_tablet_seat_v2_destroy(seat->zwp_tablet_seat_v2);
seat->zwp_tablet_seat_v2 = NULL;
}

View file

@ -30,7 +30,6 @@
#include "backend/x11.h"
#include "render/drm_format_set.h"
#include "util/signal.h"
// See dri2_format_for_depth in mesa
const struct wlr_x11_format formats[] = {
@ -164,7 +163,7 @@ static bool backend_start(struct wlr_backend *backend) {
wlr_log(WLR_INFO, "Starting X11 backend");
wlr_signal_emit_safe(&x11->backend.events.new_input, &x11->keyboard.base);
wl_signal_emit_mutable(&x11->backend.events.new_input, &x11->keyboard.base);
for (size_t i = 0; i < x11->requested_outputs; ++i) {
wlr_x11_output_create(&x11->backend);
@ -185,7 +184,7 @@ static void backend_destroy(struct wlr_backend *backend) {
wlr_output_destroy(&output->wlr_output);
}
wlr_keyboard_destroy(&x11->keyboard);
wlr_keyboard_finish(&x11->keyboard);
wlr_backend_finish(backend);
@ -637,7 +636,8 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_display *display,
}
#endif
wlr_keyboard_init(&x11->keyboard, &x11_keyboard_impl, "x11-keyboard");
wlr_keyboard_init(&x11->keyboard, &x11_keyboard_impl,
x11_keyboard_impl.name);
x11->display_destroy.notify = handle_display_destroy;
wl_display_add_destroy_listener(display, &x11->display_destroy);

View file

@ -16,11 +16,10 @@
#include <wlr/util/log.h>
#include "backend/x11.h"
#include "util/signal.h"
static void send_key_event(struct wlr_x11_backend *x11, uint32_t key,
enum wl_keyboard_key_state st, xcb_timestamp_t time) {
struct wlr_event_keyboard_key ev = {
struct wlr_keyboard_key_event ev = {
.time_msec = time,
.keycode = key,
.state = st,
@ -31,20 +30,20 @@ static void send_key_event(struct wlr_x11_backend *x11, uint32_t key,
static void send_button_event(struct wlr_x11_output *output, uint32_t key,
enum wlr_button_state st, xcb_timestamp_t time) {
struct wlr_event_pointer_button ev = {
.device = &output->pointer.base,
struct wlr_pointer_button_event ev = {
.pointer = &output->pointer,
.time_msec = time,
.button = key,
.state = st,
};
wlr_signal_emit_safe(&output->pointer.events.button, &ev);
wlr_signal_emit_safe(&output->pointer.events.frame, &output->pointer);
wl_signal_emit_mutable(&output->pointer.events.button, &ev);
wl_signal_emit_mutable(&output->pointer.events.frame, &output->pointer);
}
static void send_axis_event(struct wlr_x11_output *output, int32_t delta,
xcb_timestamp_t time) {
struct wlr_event_pointer_axis ev = {
.device = &output->pointer.base,
struct wlr_pointer_axis_event ev = {
.pointer = &output->pointer,
.time_msec = time,
.source = WLR_AXIS_SOURCE_WHEEL,
.orientation = WLR_AXIS_ORIENTATION_VERTICAL,
@ -52,57 +51,57 @@ static void send_axis_event(struct wlr_x11_output *output, int32_t delta,
.delta = delta * 15,
.delta_discrete = delta,
};
wlr_signal_emit_safe(&output->pointer.events.axis, &ev);
wlr_signal_emit_safe(&output->pointer.events.frame, &output->pointer);
wl_signal_emit_mutable(&output->pointer.events.axis, &ev);
wl_signal_emit_mutable(&output->pointer.events.frame, &output->pointer);
}
static void send_pointer_position_event(struct wlr_x11_output *output,
int16_t x, int16_t y, xcb_timestamp_t time) {
struct wlr_event_pointer_motion_absolute ev = {
.device = &output->pointer.base,
struct wlr_pointer_motion_absolute_event ev = {
.pointer = &output->pointer,
.time_msec = time,
.x = (double)x / output->wlr_output.width,
.y = (double)y / output->wlr_output.height,
};
wlr_signal_emit_safe(&output->pointer.events.motion_absolute, &ev);
wlr_signal_emit_safe(&output->pointer.events.frame, &output->pointer);
wl_signal_emit_mutable(&output->pointer.events.motion_absolute, &ev);
wl_signal_emit_mutable(&output->pointer.events.frame, &output->pointer);
}
static void send_touch_down_event(struct wlr_x11_output *output,
int16_t x, int16_t y, int32_t touch_id, xcb_timestamp_t time) {
struct wlr_event_touch_down ev = {
.device = &output->touch.base,
struct wlr_touch_down_event ev = {
.touch = &output->touch,
.time_msec = time,
.x = (double)x / output->wlr_output.width,
.y = (double)y / output->wlr_output.height,
.touch_id = touch_id,
};
wlr_signal_emit_safe(&output->touch.events.down, &ev);
wlr_signal_emit_safe(&output->touch.events.frame, NULL);
wl_signal_emit_mutable(&output->touch.events.down, &ev);
wl_signal_emit_mutable(&output->touch.events.frame, NULL);
}
static void send_touch_motion_event(struct wlr_x11_output *output,
int16_t x, int16_t y, int32_t touch_id, xcb_timestamp_t time) {
struct wlr_event_touch_motion ev = {
.device = &output->touch.base,
struct wlr_touch_motion_event ev = {
.touch = &output->touch,
.time_msec = time,
.x = (double)x / output->wlr_output.width,
.y = (double)y / output->wlr_output.height,
.touch_id = touch_id,
};
wlr_signal_emit_safe(&output->touch.events.motion, &ev);
wlr_signal_emit_safe(&output->touch.events.frame, NULL);
wl_signal_emit_mutable(&output->touch.events.motion, &ev);
wl_signal_emit_mutable(&output->touch.events.frame, NULL);
}
static void send_touch_up_event(struct wlr_x11_output *output,
int32_t touch_id, xcb_timestamp_t time) {
struct wlr_event_touch_up ev = {
.device = &output->touch.base,
struct wlr_touch_up_event ev = {
.touch = &output->touch,
.time_msec = time,
.touch_id = touch_id,
};
wlr_signal_emit_safe(&output->touch.events.up, &ev);
wlr_signal_emit_safe(&output->touch.events.frame, NULL);
wl_signal_emit_mutable(&output->touch.events.up, &ev);
wl_signal_emit_mutable(&output->touch.events.frame, NULL);
}
static struct wlr_x11_touchpoint *get_touchpoint_from_x11_touch_id(
@ -285,28 +284,16 @@ void handle_x11_xinput_event(struct wlr_x11_backend *x11,
}
}
static void keyboard_destroy(struct wlr_keyboard *wlr_keyboard) {
// Don't free the keyboard, it's on the stack
}
const struct wlr_keyboard_impl x11_keyboard_impl = {
.destroy = keyboard_destroy,
.name = "x11-keyboard",
};
static void pointer_destroy(struct wlr_pointer *wlr_pointer) {
// Don't free the pointer, it's on the stack
}
const struct wlr_pointer_impl x11_pointer_impl = {
.destroy = pointer_destroy,
.name = "x11-pointer",
};
static void touch_destroy(struct wlr_touch *wlr_touch) {
// Don't free the touch, it's on the stack
}
const struct wlr_touch_impl x11_touch_impl = {
.destroy = touch_destroy,
.name = "x11-touch",
};
void update_x11_pointer_position(struct wlr_x11_output *output,
@ -329,11 +316,11 @@ void update_x11_pointer_position(struct wlr_x11_output *output,
bool wlr_input_device_is_x11(struct wlr_input_device *wlr_dev) {
switch (wlr_dev->type) {
case WLR_INPUT_DEVICE_KEYBOARD:
return wlr_dev->keyboard->impl == &x11_keyboard_impl;
return wlr_keyboard_from_input_device(wlr_dev)->impl == &x11_keyboard_impl;
case WLR_INPUT_DEVICE_POINTER:
return wlr_dev->pointer->impl == &x11_pointer_impl;
return wlr_pointer_from_input_device(wlr_dev)->impl == &x11_pointer_impl;
case WLR_INPUT_DEVICE_TOUCH:
return wlr_dev->touch->impl == &x11_touch_impl;
return wlr_touch_from_input_device(wlr_dev)->impl == &x11_touch_impl;
default:
return false;
}

View file

@ -21,24 +21,31 @@
#include <wlr/util/log.h>
#include "backend/x11.h"
#include "util/signal.h"
#include "util/time.h"
static const uint32_t SUPPORTED_OUTPUT_STATE =
WLR_OUTPUT_STATE_BACKEND_OPTIONAL |
WLR_OUTPUT_STATE_BUFFER |
WLR_OUTPUT_STATE_MODE;
WLR_OUTPUT_STATE_MODE |
WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED;
static void parse_xcb_setup(struct wlr_output *output,
xcb_connection_t *xcb) {
const xcb_setup_t *xcb_setup = xcb_get_setup(xcb);
snprintf(output->make, sizeof(output->make), "%.*s",
xcb_setup_vendor_length(xcb_setup),
xcb_setup_vendor(xcb_setup));
snprintf(output->model, sizeof(output->model), "%"PRIu16".%"PRIu16,
xcb_setup->protocol_major_version,
xcb_setup->protocol_minor_version);
output->make = calloc(1, xcb_setup_vendor_length(xcb_setup) + 1);
if (output->make == NULL) {
wlr_log_errno(WLR_ERROR, "Allocation failed");
return;
}
memcpy(output->make, xcb_setup_vendor(xcb_setup),
xcb_setup_vendor_length(xcb_setup));
char model[64];
snprintf(model, sizeof(model), "%"PRIu16".%"PRIu16,
xcb_setup->protocol_major_version,
xcb_setup->protocol_minor_version);
output->model = strdup(model);
}
static struct wlr_x11_output *get_x11_output_from_output(
@ -76,8 +83,8 @@ static void output_destroy(struct wlr_output *wlr_output) {
pixman_region32_fini(&output->exposed);
wlr_pointer_destroy(&output->pointer);
wlr_touch_destroy(&output->touch);
wlr_pointer_finish(&output->pointer);
wlr_touch_finish(&output->touch);
struct wlr_x11_buffer *buffer, *buffer_tmp;
wl_list_for_each_safe(buffer, buffer_tmp, &output->buffers, link) {
@ -97,17 +104,28 @@ static void output_destroy(struct wlr_output *wlr_output) {
free(output);
}
static bool output_test(struct wlr_output *wlr_output) {
uint32_t unsupported =
wlr_output->pending.committed & ~SUPPORTED_OUTPUT_STATE;
static bool output_test(struct wlr_output *wlr_output,
const struct wlr_output_state *state) {
uint32_t unsupported = state->committed & ~SUPPORTED_OUTPUT_STATE;
if (unsupported != 0) {
wlr_log(WLR_DEBUG, "Unsupported output state fields: 0x%"PRIx32,
unsupported);
return false;
}
if (wlr_output->pending.committed & WLR_OUTPUT_STATE_MODE) {
assert(wlr_output->pending.mode_type == WLR_OUTPUT_STATE_MODE_CUSTOM);
// All we can do to influence adaptive sync on the X11 backend is set the
// _VARIABLE_REFRESH window property like mesa automatically does. We don't
// have any control beyond that, so we set the state to enabled on creating
// the output and never allow changing it (just like the Wayland backend).
assert(wlr_output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED);
if (state->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) {
if (!state->adaptive_sync_enabled) {
return false;
}
}
if (state->committed & WLR_OUTPUT_STATE_MODE) {
assert(state->mode_type == WLR_OUTPUT_STATE_MODE_CUSTOM);
}
return true;
@ -250,10 +268,11 @@ static struct wlr_x11_buffer *get_or_create_x11_buffer(
return create_x11_buffer(output, wlr_buffer);
}
static bool output_commit_buffer(struct wlr_x11_output *output) {
static bool output_commit_buffer(struct wlr_x11_output *output,
const struct wlr_output_state *state) {
struct wlr_x11_backend *x11 = output->x11;
struct wlr_buffer *buffer = output->wlr_output.pending.buffer;
struct wlr_buffer *buffer = state->buffer;
struct wlr_x11_buffer *x11_buffer =
get_or_create_x11_buffer(output, buffer);
if (!x11_buffer) {
@ -261,8 +280,9 @@ static bool output_commit_buffer(struct wlr_x11_output *output) {
}
xcb_xfixes_region_t region = XCB_NONE;
if (output->wlr_output.pending.committed & WLR_OUTPUT_STATE_DAMAGE) {
pixman_region32_union(&output->exposed, &output->exposed, &output->wlr_output.pending.damage);
if (state->committed & WLR_OUTPUT_STATE_DAMAGE) {
pixman_region32_union(&output->exposed, &output->exposed,
(pixman_region32_t *) &state->damage);
int rects_len = 0;
pixman_box32_t *rects = pixman_region32_rectangles(&output->exposed, &rects_len);
@ -308,40 +328,26 @@ error:
return false;
}
static bool output_commit(struct wlr_output *wlr_output) {
static bool output_commit(struct wlr_output *wlr_output,
const struct wlr_output_state *state) {
struct wlr_x11_output *output = get_x11_output_from_output(wlr_output);
struct wlr_x11_backend *x11 = output->x11;
if (!output_test(wlr_output)) {
if (!output_test(wlr_output, state)) {
return false;
}
if (wlr_output->pending.committed & WLR_OUTPUT_STATE_MODE) {
if (state->committed & WLR_OUTPUT_STATE_MODE) {
if (!output_set_custom_mode(wlr_output,
wlr_output->pending.custom_mode.width,
wlr_output->pending.custom_mode.height,
wlr_output->pending.custom_mode.refresh)) {
state->custom_mode.width,
state->custom_mode.height,
state->custom_mode.refresh)) {
return false;
}
}
if (wlr_output->pending.committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED &&
x11->atoms.variable_refresh != XCB_ATOM_NONE) {
if (wlr_output->pending.adaptive_sync_enabled) {
uint32_t enabled = 1;
xcb_change_property(x11->xcb, XCB_PROP_MODE_REPLACE, output->win,
x11->atoms.variable_refresh, XCB_ATOM_CARDINAL, 32, 1,
&enabled);
wlr_output->adaptive_sync_status = WLR_OUTPUT_ADAPTIVE_SYNC_UNKNOWN;
} else {
xcb_delete_property(x11->xcb, output->win,
x11->atoms.variable_refresh);
wlr_output->adaptive_sync_status = WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED;
}
}
if (wlr_output->pending.committed & WLR_OUTPUT_STATE_BUFFER) {
if (!output_commit_buffer(output)) {
if (state->committed & WLR_OUTPUT_STATE_BUFFER) {
if (!output_commit_buffer(output, state)) {
return false;
}
}
@ -564,6 +570,12 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend) {
x11->atoms.wm_protocols, XCB_ATOM_ATOM, 32, 1,
&x11->atoms.wm_delete_window);
uint32_t enabled = 1;
xcb_change_property(x11->xcb, XCB_PROP_MODE_REPLACE, output->win,
x11->atoms.variable_refresh, XCB_ATOM_CARDINAL, 32, 1,
&enabled);
wlr_output->adaptive_sync_status = WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED;
wlr_x11_output_set_title(wlr_output, NULL);
xcb_map_window(x11->xcb, output->win);
@ -574,15 +586,15 @@ struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend) {
wlr_output_update_enabled(wlr_output, true);
wlr_pointer_init(&output->pointer, &x11_pointer_impl, "x11-pointer");
output->pointer.base.output_name = strdup(wlr_output->name);
output->pointer.output_name = strdup(wlr_output->name);
wlr_touch_init(&output->touch, &x11_touch_impl, "x11-touch");
output->touch.base.output_name = strdup(wlr_output->name);
output->touch.output_name = strdup(wlr_output->name);
wl_list_init(&output->touchpoints);
wlr_signal_emit_safe(&x11->backend.events.new_output, wlr_output);
wlr_signal_emit_safe(&x11->backend.events.new_input, &output->pointer.base);
wlr_signal_emit_safe(&x11->backend.events.new_input, &output->touch.base);
wl_signal_emit_mutable(&x11->backend.events.new_output, wlr_output);
wl_signal_emit_mutable(&x11->backend.events.new_input, &output->pointer.base);
wl_signal_emit_mutable(&x11->backend.events.new_input, &output->touch.base);
// Start the rendering loop by requesting the compositor to render a frame
wlr_output_schedule_frame(wlr_output);