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

10
.gitignore vendored
View file

@ -1,9 +1 @@
.clang_complete /subprojects/
*.o
*.a
bin/
test/
build/
build-*/
wayland-*-protocol.*
wlr-example.ini

View file

@ -13,7 +13,7 @@ If you already have your own merge request habits, feel free to use them. If you
don't, however, allow me to make a suggestion: feature branches pulled from don't, however, allow me to make a suggestion: feature branches pulled from
upstream. Try this: upstream. Try this:
1. Fork wlroots 1. Fork wlroots (make the fork public to allow the CI to run)
2. `git clone git@gitlab.freedesktop.org:<username>/wlroots.git && cd wlroots` 2. `git clone git@gitlab.freedesktop.org:<username>/wlroots.git && cd wlroots`
3. `git remote add upstream https://gitlab.freedesktop.org/wlroots/wlroots.git` 3. `git remote add upstream https://gitlab.freedesktop.org/wlroots/wlroots.git`
@ -167,7 +167,6 @@ if (condition1 && condition2 && ...
Try to break the line in the place which you think is the most appropriate. Try to break the line in the place which you think is the most appropriate.
### Line Length ### Line Length
Try to keep your lines under 80 columns, but you can go up to 100 if it Try to keep your lines under 80 columns, but you can go up to 100 if it
@ -190,16 +189,18 @@ Functions that are responsible for constructing objects should take one of the
two following forms: two following forms:
* `init`: for functions which accept a pointer to a pre-allocated object (e.g. * `init`: for functions which accept a pointer to a pre-allocated object (e.g.
a member of a struct) and initialize it. a member of a struct) and initialize it. Such functions must call `memset()`
to zero out the memory before initializing it to avoid leaving unset fields.
* `create`: for functions which allocate the memory for an object, initialize * `create`: for functions which allocate the memory for an object, initialize
it, and return a pointer. it, and return a pointer. Such functions should allocate the memory with
`calloc()` to avoid leaving unset fields.
Likewise, functions that are responsible for destructing objects should take Likewise, functions that are responsible for destructing objects should take
one of the two following forms: one of the two following forms:
* `finish`: for functions which accept a pointer to an object and deinitialize * `finish`: for functions which accept a pointer to an object and deinitialize
it. Such functions should always be able to accept an already deinitialized it. If a finished object isn't destroyed but kept for future use, it must be
object. reinitialized to be used again.
* `destroy`: for functions which accept a pointer to an object, deinitialize * `destroy`: for functions which accept a pointer to an object, deinitialize
it, and free the memory. Such functions should always be able to accept a NULL it, and free the memory. Such functions should always be able to accept a NULL
pointer. pointer.
@ -215,6 +216,19 @@ Try to keep the use of macros to a minimum, especially if a function can do the
job. If you do need to use them, try to keep them close to where they're being job. If you do need to use them, try to keep them close to where they're being
used and `#undef` them after. used and `#undef` them after.
### Documentation
* Documentation comments for declarations start with `/**` and end with `*/`.
* Cross-reference other declarations by ending function names with `()`, and
writing `struct`, `union`, `enum` or `typedef` before types.
* Document fields which can be NULL with a `// may be NULL` comment, optionally
with more details describing when this can happen.
* Document the bits of a bitfield with a `// enum bar` comment.
* Document the `data` argument of a `struct wl_signal` with a `// struct foo`
comment.
* Document the contents and container of a `struct wl_list` with a
`// content.link` and `// container.list` comment.
### Example ### Example
```c ```c

View file

@ -45,7 +45,7 @@ Install dependencies:
* EGL and GLESv2 (optional, for the GLES2 renderer) * EGL and GLESv2 (optional, for the GLES2 renderer)
* Vulkan loader, headers and glslang (optional, for the Vulkan renderer) * Vulkan loader, headers and glslang (optional, for the Vulkan renderer)
* libdrm * libdrm
* GBM * GBM (optional, for the GBM allocator)
* libinput (optional, for the libinput backend) * libinput (optional, for the libinput backend)
* xkbcommon * xkbcommon
* udev * udev

View file

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

View file

@ -1,4 +1,6 @@
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include <xf86drm.h> #include <xf86drm.h>
#include <xf86drmMode.h> #include <xf86drmMode.h>
@ -6,6 +8,41 @@
#include "backend/drm/iface.h" #include "backend/drm/iface.h"
#include "backend/drm/util.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 { struct atomic {
drmModeAtomicReq *req; drmModeAtomicReq *req;
bool failed; bool failed;
@ -33,9 +70,11 @@ static bool atomic_commit(struct atomic *atom,
if (ret != 0) { if (ret != 0) {
wlr_drm_conn_log_errno(conn, wlr_drm_conn_log_errno(conn,
(flags & DRM_MODE_ATOMIC_TEST_ONLY) ? WLR_DEBUG : WLR_ERROR, (flags & DRM_MODE_ATOMIC_TEST_ONLY) ? WLR_DEBUG : WLR_ERROR,
"Atomic %s failed (%s)", "Atomic commit failed");
(flags & DRM_MODE_ATOMIC_TEST_ONLY) ? "test" : "commit", char *flags_str = atomic_commit_flags_str(flags);
(flags & DRM_MODE_ATOMIC_ALLOW_MODESET) ? "modeset" : "pageflip"); wlr_log(WLR_DEBUG, "(Atomic commit flags: %s)",
flags_str ? flags_str : "<error>");
free(flags_str);
return false; return false;
} }
@ -217,8 +256,10 @@ static bool atomic_crtc_commit(struct wlr_drm_connector *conn,
bool prev_vrr_enabled = bool prev_vrr_enabled =
output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED; output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED;
bool vrr_enabled = prev_vrr_enabled; bool vrr_enabled = prev_vrr_enabled;
if ((state->base->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) && if ((state->base->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED)) {
drm_connector_supports_vrr(conn)) { if (!drm_connector_supports_vrr(conn)) {
return false;
}
vrr_enabled = state->base->adaptive_sync_enabled; vrr_enabled = state->base->adaptive_sync_enabled;
} }
@ -227,7 +268,12 @@ static bool atomic_crtc_commit(struct wlr_drm_connector *conn,
} }
if (modeset) { if (modeset) {
flags |= DRM_MODE_ATOMIC_ALLOW_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; 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, atomic_add(&atom, conn->id, conn->props.link_status,
DRM_MODE_LINK_STATUS_GOOD); 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.mode_id, mode_id);
atomic_add(&atom, crtc->id, crtc->props.active, active); atomic_add(&atom, crtc->id, crtc->props.active, active);
if (active) { if (active) {

View file

@ -1,6 +1,7 @@
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
#include <drm_fourcc.h> #include <drm_fourcc.h>
#include <libudev.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -12,7 +13,6 @@
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include <xf86drm.h> #include <xf86drm.h>
#include "backend/drm/drm.h" #include "backend/drm/drm.h"
#include "util/signal.h"
struct wlr_drm_backend *get_drm_backend_from_backend( struct wlr_drm_backend *get_drm_backend_from_backend(
struct wlr_backend *wlr_backend) { struct wlr_backend *wlr_backend) {
@ -58,6 +58,7 @@ static void backend_destroy(struct wlr_backend *backend) {
finish_drm_resources(drm); finish_drm_resources(drm);
udev_hwdb_unref(drm->hwdb);
free(drm->name); free(drm->name);
wlr_session_close_file(drm->session, drm->dev); wlr_session_close_file(drm->session, drm->dev);
wl_event_source_remove(drm->drm_event); 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); 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_backend *wlr_drm_backend_create(struct wl_display *display,
struct wlr_session *session, struct wlr_device *dev, struct wlr_session *session, struct wlr_device *dev,
struct wlr_backend *parent) { 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; drm->session_active.notify = handle_session_active;
wl_signal_add(&session->events.active, &drm->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)) { if (!check_drm_features(drm)) {
goto error_event; goto error_event;
} }
@ -250,15 +274,17 @@ struct wlr_backend *wlr_drm_backend_create(struct wl_display *display,
goto error_mgpu_renderer; goto error_mgpu_renderer;
} }
// Force a linear layout. In case explicit modifiers aren't supported, // Forbid implicit modifiers, because their meaning changes from one
// the meaning of implicit modifiers changes from one GPU to the other. // GPU to another.
// 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.
for (size_t i = 0; i < texture_formats->len; i++) { for (size_t i = 0; i < texture_formats->len; i++) {
const struct wlr_drm_format *fmt = texture_formats->formats[i]; const struct wlr_drm_format *fmt = texture_formats->formats[i];
wlr_drm_format_set_add(&drm->mgpu_formats, fmt->format, for (size_t j = 0; j < fmt->len; j++) {
DRM_FORMAT_MOD_LINEAR); 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: error_resources:
finish_drm_resources(drm); finish_drm_resources(drm);
error_event: error_event:
udev_hwdb_unref(drm->hwdb);
wl_list_remove(&drm->session_active.link); wl_list_remove(&drm->session_active.link);
wl_event_source_remove(drm->drm_event); wl_event_source_remove(drm->drm_event);
error_fd: error_fd:

View file

@ -29,14 +29,18 @@
#include "render/drm_format_set.h" #include "render/drm_format_set.h"
#include "render/swapchain.h" #include "render/swapchain.h"
#include "render/wlr_renderer.h" #include "render/wlr_renderer.h"
#include "util/signal.h" #include "util/env.h"
static const uint32_t SUPPORTED_OUTPUT_STATE = // Output state which needs a KMS commit to be applied
WLR_OUTPUT_STATE_BACKEND_OPTIONAL | static const uint32_t COMMIT_OUTPUT_STATE =
WLR_OUTPUT_STATE_BUFFER | WLR_OUTPUT_STATE_BUFFER |
WLR_OUTPUT_STATE_MODE | WLR_OUTPUT_STATE_MODE |
WLR_OUTPUT_STATE_ENABLED | 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) { bool check_drm_features(struct wlr_drm_backend *drm) {
if (drmGetCap(drm->fd, DRM_CAP_CURSOR_WIDTH, &drm->cursor_width)) { 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; return false;
} }
const char *no_atomic = getenv("WLR_DRM_NO_ATOMIC"); if (env_parse_bool("WLR_DRM_NO_ATOMIC")) {
if (no_atomic && strcmp(no_atomic, "1") == 0) {
wlr_log(WLR_DEBUG, wlr_log(WLR_DEBUG,
"WLR_DRM_NO_ATOMIC set, forcing legacy DRM interface"); "WLR_DRM_NO_ATOMIC set, forcing legacy DRM interface");
drm->iface = &legacy_iface; 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); int ret = drmGetCap(drm->fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
drm->clock = (ret == 0 && cap == 1) ? CLOCK_MONOTONIC : CLOCK_REALTIME; drm->clock = (ret == 0 && cap == 1) ? CLOCK_MONOTONIC : CLOCK_REALTIME;
const char *no_modifiers = getenv("WLR_DRM_NO_MODIFIERS"); if (env_parse_bool("WLR_DRM_NO_MODIFIERS")) {
if (no_modifiers != NULL && strcmp(no_modifiers, "1") == 0) {
wlr_log(WLR_DEBUG, "WLR_DRM_NO_MODIFIERS set, disabling modifiers"); wlr_log(WLR_DEBUG, "WLR_DRM_NO_MODIFIERS set, disabling modifiers");
} else { } else {
ret = drmGetCap(drm->fd, DRM_CAP_ADDFB2_MODIFIERS, &cap); 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, static void drm_connector_state_init(struct wlr_drm_connector_state *state,
struct wlr_drm_connector *conn, struct wlr_drm_connector *conn,
const struct wlr_output_state *base) { const struct wlr_output_state *base) {
memset(state, 0, sizeof(*state));
state->base = base; state->base = base;
state->modeset = base->committed & state->modeset = base->committed &
(WLR_OUTPUT_STATE_ENABLED | WLR_OUTPUT_STATE_MODE); (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_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); struct wlr_drm_connector *conn = get_drm_connector_from_output(output);
if (!conn->backend->session->active) { if (!conn->backend->session->active) {
return false; return false;
} }
uint32_t unsupported = output->pending.committed & ~SUPPORTED_OUTPUT_STATE; uint32_t unsupported = state->committed & ~SUPPORTED_OUTPUT_STATE;
if (unsupported != 0) { if (unsupported != 0) {
wlr_log(WLR_DEBUG, "Unsupported output state fields: 0x%"PRIx32, wlr_log(WLR_DEBUG, "Unsupported output state fields: 0x%"PRIx32,
unsupported); unsupported);
return false; return false;
} }
if ((output->pending.committed & WLR_OUTPUT_STATE_ENABLED) && if ((state->committed & COMMIT_OUTPUT_STATE) == 0) {
output->pending.enabled) { // This commit doesn't change the KMS state
return true;
}
if ((state->committed & WLR_OUTPUT_STATE_ENABLED) && state->enabled) {
if (output->current_mode == NULL && 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, wlr_drm_conn_log(conn, WLR_DEBUG,
"Can't enable an output without a mode"); "Can't enable an output without a mode");
return false; 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}; 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 (pending.active) {
if ((output->pending.committed & if ((state->committed &
(WLR_OUTPUT_STATE_ENABLED | WLR_OUTPUT_STATE_MODE)) && (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, wlr_drm_conn_log(conn, WLR_DEBUG,
"Can't enable an output without a buffer"); "Can't enable an output without a buffer");
return false; return false;
@ -513,7 +527,7 @@ static bool drm_connector_test(struct wlr_output *output) {
return true; 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)) { if (!drm_connector_set_pending_fb(conn, pending.base)) {
return false; return false;
} }
@ -559,6 +573,11 @@ bool drm_connector_commit_state(struct wlr_drm_connector *conn,
return false; 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}; struct wlr_drm_connector_state pending = {0};
drm_connector_state_init(&pending, conn, base); drm_connector_state_init(&pending, conn, base);
@ -596,14 +615,15 @@ bool drm_connector_commit_state(struct wlr_drm_connector *conn,
return true; 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); 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 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, 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; return true;
} }
if (conn->status != WLR_DRM_CONN_CONNECTED if (conn->status != DRM_MODE_CONNECTED) {
&& conn->status != WLR_DRM_CONN_NEEDS_MODESET) {
wlr_drm_conn_log(conn, WLR_ERROR, wlr_drm_conn_log(conn, WLR_ERROR,
"Cannot modeset a disconnected output"); "Cannot modeset a disconnected output");
return false; return false;
@ -720,7 +739,6 @@ static bool drm_connector_set_mode(struct wlr_drm_connector *conn,
return false; return false;
} }
conn->status = WLR_DRM_CONN_CONNECTED;
wlr_output_update_mode(&conn->output, wlr_mode); wlr_output_update_mode(&conn->output, wlr_mode);
wlr_output_update_enabled(&conn->output, true); wlr_output_update_enabled(&conn->output, true);
conn->desired_enabled = true; conn->desired_enabled = true;
@ -892,7 +910,7 @@ static void drm_connector_destroy_output(struct wlr_output *output) {
dealloc_crtc(conn); dealloc_crtc(conn);
conn->status = WLR_DRM_CONN_DISCONNECTED; conn->status = DRM_MODE_DISCONNECTED;
conn->desired_enabled = false; conn->desired_enabled = false;
conn->possible_crtcs = 0; conn->possible_crtcs = 0;
conn->pending_page_flip_crtc = 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 // Only search CRTCs for user-enabled outputs (that are already
// connected or in need of a modeset) // connected or in need of a modeset)
if ((conn->status == WLR_DRM_CONN_CONNECTED || if (conn->status == DRM_MODE_CONNECTED && conn->desired_enabled) {
conn->status == WLR_DRM_CONN_NEEDS_MODESET) &&
conn->desired_enabled) {
connector_constraints[i] = conn->possible_crtcs; connector_constraints[i] = conn->possible_crtcs;
} else { } else {
// Will always fail to match anything // 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) { for (size_t i = 0; i < num_outputs; ++i) {
struct wlr_drm_connector *conn = connectors[i]; struct wlr_drm_connector *conn = connectors[i];
if (conn->status == WLR_DRM_CONN_CONNECTED && if (conn->status == DRM_MODE_CONNECTED && conn->output.enabled &&
conn->desired_enabled &&
connector_match[i] == -1) { connector_match[i] == -1) {
wlr_log(WLR_DEBUG, "Could not match a CRTC for previously connected output; " wlr_log(WLR_DEBUG, "Could not match a CRTC for previously connected output; "
"keeping old configuration"); "keeping old configuration");
@ -1132,7 +1147,6 @@ static void realloc_crtcs(struct wlr_drm_backend *drm) {
if (connector_match[i] == -1) { if (connector_match[i] == -1) {
if (prev_enabled) { if (prev_enabled) {
wlr_drm_conn_log(conn, WLR_DEBUG, "Output has lost its CRTC"); 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_enabled(&conn->output, false);
wlr_output_update_mode(&conn->output, NULL); 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]]; conn->crtc = &drm->crtcs[connector_match[i]];
// Only realloc buffers if we have actually been modeset // 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; continue;
} }
wlr_output_damage_whole(&conn->output); 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); static void disconnect_drm_connector(struct wlr_drm_connector *conn);
void scan_drm_connectors(struct wlr_drm_backend *drm, void scan_drm_connectors(struct wlr_drm_backend *drm,
struct wlr_device_hotplug_event *event) { 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) { if (event != NULL && event->connector_id != 0) {
wlr_log(WLR_INFO, "Scanning DRM connector %"PRIu32" on %s", wlr_log(WLR_INFO, "Scanning DRM connector %"PRIu32" on %s",
event->connector_id, drm->name); event->connector_id, drm->name);
@ -1240,12 +1229,17 @@ void scan_drm_connectors(struct wlr_drm_backend *drm,
} }
wlr_conn->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; 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), snprintf(wlr_conn->name, sizeof(wlr_conn->name),
"%s-%"PRIu32, conn_get_name(drm_conn->connector_type), "%s-%"PRIu32, conn_name, drm_conn->connector_type_id);
drm_conn->connector_type_id);
wl_list_insert(drm->outputs.prev, &wlr_conn->link); wl_list_insert(drm->outputs.prev, &wlr_conn->link);
wlr_log(WLR_INFO, "Found connector '%s'", wlr_conn->name); 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) { drm_conn->connection == DRM_MODE_CONNECTED) {
wlr_log(WLR_INFO, "'%s' connected", wlr_conn->name); wlr_log(WLR_INFO, "'%s' connected", wlr_conn->name);
wlr_log(WLR_DEBUG, "Current CRTC: %d", 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->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; size_t edid_len = 0;
uint8_t *edid = get_drm_prop_blob(drm->fd, uint8_t *edid = get_drm_prop_blob(drm->fd,
wlr_conn->id, wlr_conn->props.edid, &edid_len); 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); free(edid);
size_t tile_len = 0; size_t tile_len = 0;
uint8_t *tile = get_drm_prop_blob(drm->fd, uint8_t *tile = get_drm_prop_blob(drm->fd,
wlr_conn->id, wlr_conn->props.tile, &tile_len); 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); free(tile);
char *subconnector = NULL; char *subconnector = NULL;
@ -1334,9 +1336,13 @@ void scan_drm_connectors(struct wlr_drm_backend *drm,
struct wlr_output *output = &wlr_conn->output; struct wlr_output *output = &wlr_conn->output;
char description[128]; char description[128];
snprintf(description, sizeof(description), "%s %s %s (%s%s%s)", snprintf(description, sizeof(description), "%s %s%s%s (%s%s%s)",
output->make, output->model, output->serial, output->name, output->make, output->model,
subconnector ? " via " : "", subconnector ? subconnector : ""); output->serial ? " " : "",
output->serial ? output->serial : "",
output->name,
subconnector ? " via " : "",
subconnector ? subconnector : "");
wlr_output_set_description(output, description); wlr_output_set_description(output, description);
free(subconnector); 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); 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) { if (wlr_conn->possible_crtcs == 0) {
wlr_drm_conn_log(wlr_conn, WLR_ERROR, "No CRTC possible"); 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_output_update_enabled(&wlr_conn->output, wlr_conn->crtc != NULL);
wlr_conn->desired_enabled = true; 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; new_outputs[new_outputs_len++] = wlr_conn;
} else if ((wlr_conn->status == WLR_DRM_CONN_CONNECTED || } else if (wlr_conn->status == DRM_MODE_CONNECTED &&
wlr_conn->status == WLR_DRM_CONN_NEEDS_MODESET) &&
drm_conn->connection != DRM_MODE_CONNECTED) { drm_conn->connection != DRM_MODE_CONNECTED) {
wlr_log(WLR_INFO, "'%s' disconnected", wlr_conn->name); wlr_log(WLR_INFO, "'%s' disconnected", wlr_conn->name);
disconnect_drm_connector(wlr_conn); 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]; struct wlr_drm_connector *conn = new_outputs[i];
wlr_drm_conn_log(conn, WLR_INFO, "Requesting modeset"); 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); &conn->output);
} }
} }
@ -1474,7 +1480,7 @@ static void handle_page_flip(int fd, unsigned seq,
conn->pending_page_flip_crtc = 0; 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, wlr_drm_conn_log(conn, WLR_DEBUG,
"Ignoring page-flip event for disabled connector"); "Ignoring page-flip event for disabled connector");
return; 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) { static void disconnect_drm_connector(struct wlr_drm_connector *conn) {
if (conn->status == WLR_DRM_CONN_DISCONNECTED) { if (conn->status == DRM_MODE_DISCONNECTED) {
return; return;
} }
@ -1545,7 +1551,7 @@ static void disconnect_drm_connector(struct wlr_drm_connector *conn) {
// our wlr_drm_connector. // our wlr_drm_connector.
wlr_output_destroy(&conn->output); 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) { 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); wl_signal_init(&lease->events.destroy);
wlr_log(WLR_DEBUG, "Issuing DRM lease with %d objects", n_objects); 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); &lease->lessee_id);
if (lease_fd < 0) { if (lease_fd < 0) {
free(lease); 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) { void drm_lease_destroy(struct wlr_drm_lease *lease) {
struct wlr_drm_backend *drm = lease->backend; 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; struct wlr_drm_connector *conn;
wl_list_for_each(conn, &drm->outputs, link) { 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) && if (state->base->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) {
drm_connector_supports_vrr(conn)) { if (!drm_connector_supports_vrr(conn)) {
return false;
}
if (drmModeObjectSetProperty(drm->fd, crtc->id, DRM_MODE_OBJECT_CRTC, if (drmModeObjectSetProperty(drm->fd, crtc->id, DRM_MODE_OBJECT_CRTC,
crtc->props.vrr_enabled, crtc->props.vrr_enabled,
state->base->adaptive_sync_enabled) != 0) { state->base->adaptive_sync_enabled) != 0) {

View file

@ -1,4 +1,5 @@
#define _POSIX_C_SOURCE 200809L #define _POSIX_C_SOURCE 200809L
#include <assert.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
@ -25,7 +26,9 @@ static const struct prop_info connector_info[] = {
{ "EDID", INDEX(edid) }, { "EDID", INDEX(edid) },
{ "PATH", INDEX(path) }, { "PATH", INDEX(path) },
{ "TILE", INDEX(tile) }, { "TILE", INDEX(tile) },
{ "content type", INDEX(content_type) },
{ "link-status", INDEX(link_status) }, { "link-status", INDEX(link_status) },
{ "max bpc", INDEX(max_bpc) },
{ "non-desktop", INDEX(non_desktop) }, { "non-desktop", INDEX(non_desktop) },
{ "panel orientation", INDEX(panel_orientation) }, { "panel orientation", INDEX(panel_orientation) },
{ "subconnector", INDEX(subconnector) }, { "subconnector", INDEX(subconnector) },
@ -181,3 +184,28 @@ char *get_drm_prop_enum(int fd, uint32_t obj, uint32_t prop_id) {
return str; 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); 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) { static void finish_drm_surface(struct wlr_drm_surface *surf) {
if (!surf || !surf->renderer) { if (!surf || !surf->renderer) {
return; return;
@ -83,12 +58,34 @@ static void finish_drm_surface(struct wlr_drm_surface *surf) {
memset(surf, 0, sizeof(*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 *drm_surface_blit(struct wlr_drm_surface *surf,
struct wlr_buffer *buffer) { struct wlr_buffer *buffer) {
struct wlr_renderer *renderer = surf->renderer->wlr_rend; struct wlr_renderer *renderer = surf->renderer->wlr_rend;
if (surf->width != (uint32_t)buffer->width || if (surf->swapchain->width != buffer->width ||
surf->height != (uint32_t)buffer->height) { surf->swapchain->height != buffer->height) {
wlr_log(WLR_ERROR, "Surface size doesn't match buffer size"); wlr_log(WLR_ERROR, "Surface size doesn't match buffer size");
return NULL; return NULL;
} }
@ -106,7 +103,7 @@ struct wlr_buffer *drm_surface_blit(struct wlr_drm_surface *surf,
float mat[9]; float mat[9];
wlr_matrix_identity(mat); 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)) { if (!wlr_renderer_begin_with_buffer(renderer, dst)) {
wlr_buffer_unlock(dst); wlr_buffer_unlock(dst);

View file

@ -1,10 +1,14 @@
#define _POSIX_C_SOURCE 200809L
#include <assert.h> #include <assert.h>
#include <drm_fourcc.h> #include <drm_fourcc.h>
#include <drm_mode.h> #include <drm_mode.h>
#include <drm.h> #include <drm.h>
#include <libudev.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include "backend/drm/drm.h"
#include "backend/drm/util.h" #include "backend/drm/util.h"
int32_t calculate_refresh_rate(const drmModeModeInfo *mode) { int32_t calculate_refresh_rate(const drmModeModeInfo *mode) {
@ -26,125 +30,93 @@ int32_t calculate_refresh_rate(const drmModeModeInfo *mode) {
return refresh; return refresh;
} }
// Constructed from http://edid.tv/manufacturer static const char *get_manufacturer(struct udev_hwdb *hwdb, uint16_t code) {
static const char *get_manufacturer(uint16_t id) { static char pnp_id[4];
#define ID(a, b, c) ((a & 0x1f) << 10) | ((b & 0x1f) << 5) | (c & 0x1f)
switch (id) { // The ASCII 3-letter manufacturer PnP ID is encoded in 5-bit codes
case ID('A', 'A', 'A'): return "Avolites Ltd"; pnp_id[0] = ((code >> 10) & 0x1F) + '@';
case ID('A', 'C', 'I'): return "Ancor Communications Inc"; pnp_id[1] = ((code >> 5) & 0x1F) + '@';
case ID('A', 'C', 'R'): return "Acer Technologies"; pnp_id[2] = ((code >> 0) & 0x1F) + '@';
case ID('A', 'D', 'A'): return "Addi-Data GmbH"; pnp_id[3] = '\0';
case ID('A', 'P', 'P'): return "Apple Computer Inc";
case ID('A', 'S', 'K'): return "Ask A/S"; if (hwdb == NULL) {
case ID('A', 'V', 'T'): return "Avtek (Electronics) Pty Ltd"; return pnp_id;
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";
} }
#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. /* 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. * 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) { if (!data || len < 128) {
snprintf(output->make, sizeof(output->make), "<Unknown>");
snprintf(output->model, sizeof(output->model), "<Unknown>");
return; return;
} }
uint16_t id = (data[8] << 8) | data[9]; 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); 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); 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) { for (size_t i = 72; i <= 108; i += 18) {
uint16_t flag = (data[i] << 8) | data[i + 1]; uint16_t flag = (data[i] << 8) | data[i + 1];
if (flag == 0 && data[i + 3] == 0xFC) { 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 // 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) { if (nl) {
*nl = '\0'; *nl = '\0';
} }
} else if (flag == 0 && data[i + 3] == 0xFF) { } 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 // Monitor serial numbers are terminated by newline if they're too
// short // short
char *nl = strchr(output->serial, '\n'); char* nl = strchr(serial_str, '\n');
if (nl) { if (nl) {
*nl = '\0'; *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) { if (len > 0) {
int ret; int ret;
ret = sscanf((char*)data, "%d:%d:%d:%d:%d:%d:%d:%d", 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"; case DRM_MODE_CONNECTOR_USB: return "USB";
#endif #endif
default: return "Unknown"; 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/interfaces/wlr_output.h>
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include "backend/headless.h" #include "backend/headless.h"
#include "util/signal.h"
struct wlr_headless_backend *headless_backend_from_backend( struct wlr_headless_backend *headless_backend_from_backend(
struct wlr_backend *wlr_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_list_for_each(output, &backend->outputs, link) {
wl_event_source_timer_update(output->frame_timer, output->frame_delay); wl_event_source_timer_update(output->frame_timer, output->frame_delay);
wlr_output_update_enabled(&output->wlr_output, true); 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); &output->wlr_output);
} }

View file

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

View file

@ -6,7 +6,7 @@
#include <wlr/backend/session.h> #include <wlr/backend/session.h>
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include "backend/libinput.h" #include "backend/libinput.h"
#include "util/signal.h" #include "util/env.h"
static struct wlr_libinput_backend *get_libinput_backend_from_backend( static struct wlr_libinput_backend *get_libinput_backend_from_backend(
struct wlr_backend *wlr_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); libinput_log_set_priority(backend->libinput_context, LIBINPUT_LOG_PRIORITY_ERROR);
int libinput_fd = libinput_get_fd(backend->libinput_context); int libinput_fd = libinput_get_fd(backend->libinput_context);
char *no_devs = getenv("WLR_LIBINPUT_NO_DEVICES");
if (no_devs) { if (!env_parse_bool("WLR_LIBINPUT_NO_DEVICES") && wl_list_empty(&backend->devices)) {
if (strcmp(no_devs, "1") != 0) {
no_devs = NULL;
}
}
if (!no_devs && backend->wlr_device_lists.size == 0) {
handle_libinput_readable(libinput_fd, WL_EVENT_READABLE, backend); 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, "libinput initialization failed, no input devices");
wlr_log(WLR_ERROR, "Set WLR_LIBINPUT_NO_DEVICES=1 to suppress this check"); wlr_log(WLR_ERROR, "Set WLR_LIBINPUT_NO_DEVICES=1 to suppress this check");
return false; return false;
@ -141,13 +136,9 @@ static void backend_destroy(struct wlr_backend *wlr_backend) {
struct wlr_libinput_backend *backend = struct wlr_libinput_backend *backend =
get_libinput_backend_from_backend(wlr_backend); get_libinput_backend_from_backend(wlr_backend);
struct wl_list **wlr_devices_ptr; struct wlr_libinput_input_device *dev, *tmp;
wl_array_for_each(wlr_devices_ptr, &backend->wlr_device_lists) { wl_list_for_each_safe(dev, tmp, &backend->devices, link) {
struct wlr_libinput_input_device *dev, *tmp; destroy_libinput_input_device(dev);
wl_list_for_each_safe(dev, tmp, *wlr_devices_ptr, link) {
destroy_libinput_input_device(dev);
}
free(*wlr_devices_ptr);
} }
wlr_backend_finish(wlr_backend); 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_destroy.link);
wl_list_remove(&backend->session_signal.link); wl_list_remove(&backend->session_signal.link);
wl_array_release(&backend->wlr_device_lists);
if (backend->input_event) { if (backend->input_event) {
wl_event_source_remove(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); wlr_backend_init(&backend->backend, &backend_impl);
wl_array_init(&backend->wlr_device_lists); wl_list_init(&backend->devices);
backend->session = session; backend->session = session;
backend->display = display; 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 libinput_device *wlr_libinput_get_device_handle(
struct wlr_input_device *wlr_dev) { struct wlr_input_device *wlr_dev) {
struct wlr_libinput_input_device *dev = struct wlr_libinput_input_device *dev = NULL;
(struct wlr_libinput_input_device *)wlr_dev; 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; return dev->handle;
} }

View file

@ -1,87 +1,62 @@
#define _POSIX_C_SOURCE 200809L #define _POSIX_C_SOURCE 200809L
#include <assert.h>
#include <libinput.h> #include <libinput.h>
#include <stdlib.h> #include <stdlib.h>
#include <wayland-util.h>
#include <wlr/backend/session.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 <wlr/util/log.h>
#include "backend/libinput.h" #include "backend/libinput.h"
#include "util/array.h"
#include "util/signal.h"
struct wlr_input_device *get_appropriate_device( void destroy_libinput_input_device(struct wlr_libinput_input_device *dev) {
enum wlr_input_device_type desired_type, if (dev->keyboard.impl) {
struct libinput_device *libinput_dev) { wlr_keyboard_finish(&dev->keyboard);
struct wl_list *wlr_devices = libinput_device_get_user_data(libinput_dev);
if (!wlr_devices) {
return NULL;
} }
struct wlr_libinput_input_device *dev; if (dev->pointer.impl) {
wl_list_for_each(dev, wlr_devices, link) { wlr_pointer_finish(&dev->pointer);
if (dev->wlr_input_device.type == desired_type) {
return &dev->wlr_input_device;
}
} }
return NULL; if (dev->switch_device.impl) {
} wlr_switch_finish(&dev->switch_device);
}
void destroy_libinput_input_device(struct wlr_libinput_input_device *dev) if (dev->touch.impl) {
{ wlr_touch_finish(&dev->touch);
/** }
* TODO remove the redundant wlr_input_device from wlr_libinput_input_device if (dev->tablet.impl) {
* wlr_libinput_input_device::wlr_input_device is not owned by its input finish_device_tablet(dev);
* device type, which means we have 2 wlr_input_device to cleanup }
*/ if (dev->tablet_pad.impl) {
if (dev->wlr_input_device._device) { finish_device_tablet_pad(dev);
wlr_input_device_destroy(&dev->wlr_input_device);
} }
wlr_input_device_finish(&dev->wlr_input_device);
libinput_device_unref(dev->handle); libinput_device_unref(dev->handle);
wl_list_remove(&dev->link); wl_list_remove(&dev->link);
free(dev); 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) { bool wlr_input_device_is_libinput(struct wlr_input_device *wlr_dev) {
switch (wlr_dev->type) { switch (wlr_dev->type) {
case WLR_INPUT_DEVICE_KEYBOARD: 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: 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: 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: 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: 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: 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: default:
return false; 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, static void handle_device_added(struct wlr_libinput_backend *backend,
struct libinput_device *libinput_dev) { 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 vendor = libinput_device_get_id_vendor(libinput_dev);
int product = libinput_device_get_id_product(libinput_dev); int product = libinput_device_get_id_product(libinput_dev);
const char *name = libinput_device_get_name(libinput_dev); const char *name = libinput_device_get_name(libinput_dev);
struct wl_list *wlr_devices = calloc(1, sizeof(struct wl_list)); wlr_log(WLR_DEBUG, "Adding %s [%d:%d]", name, vendor, product);
if (!wlr_devices) {
wlr_log(WLR_ERROR, "Allocation failed"); 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; 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( if (libinput_device_has_capability(
libinput_dev, LIBINPUT_DEVICE_CAP_KEYBOARD)) { libinput_dev, LIBINPUT_DEVICE_CAP_KEYBOARD)) {
struct wlr_input_device *wlr_dev = allocate_device(backend, init_device_keyboard(dev);
libinput_dev, wlr_devices, WLR_INPUT_DEVICE_KEYBOARD);
if (!wlr_dev) { wl_signal_emit_mutable(&backend->backend.events.new_input,
goto fail; &dev->keyboard.base);
}
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);
} }
if (libinput_device_has_capability( if (libinput_device_has_capability(
libinput_dev, LIBINPUT_DEVICE_CAP_POINTER)) { libinput_dev, LIBINPUT_DEVICE_CAP_POINTER)) {
struct wlr_input_device *wlr_dev = allocate_device(backend, init_device_pointer(dev);
libinput_dev, wlr_devices, WLR_INPUT_DEVICE_POINTER);
if (!wlr_dev) { wl_signal_emit_mutable(&backend->backend.events.new_input,
goto fail; &dev->pointer.base);
}
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
} }
if (libinput_device_has_capability( if (libinput_device_has_capability(
libinput_dev, LIBINPUT_DEVICE_CAP_SWITCH)) { libinput_dev, LIBINPUT_DEVICE_CAP_SWITCH)) {
struct wlr_input_device *wlr_dev = allocate_device(backend, init_device_switch(dev);
libinput_dev, wlr_devices, WLR_INPUT_DEVICE_SWITCH); wl_signal_emit_mutable(&backend->backend.events.new_input,
if (!wlr_dev) { &dev->switch_device.base);
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);
} }
if (!wl_list_empty(wlr_devices)) { if (libinput_device_has_capability(
struct wl_list **dst = wl_array_add(&backend->wlr_device_lists, sizeof(wlr_devices)); libinput_dev, LIBINPUT_DEVICE_CAP_TOUCH)) {
if (!dst) { init_device_touch(dev);
goto fail; wl_signal_emit_mutable(&backend->backend.events.new_input,
} &dev->touch.base);
*dst = wlr_devices;
libinput_device_set_user_data(libinput_dev, wlr_devices);
} else {
free(wlr_devices);
} }
return;
fail: if (libinput_device_has_capability(libinput_dev,
wlr_log(WLR_ERROR, "Could not allocate new device"); LIBINPUT_DEVICE_CAP_TABLET_TOOL)) {
struct wlr_libinput_input_device *dev, *tmp_dev; init_device_tablet(dev);
wl_list_for_each_safe(dev, tmp_dev, wlr_devices, link) { wl_signal_emit_mutable(&backend->backend.events.new_input,
free(dev); &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, static void handle_device_removed(struct wlr_libinput_backend *backend,
struct libinput_device *libinput_dev) { 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 vendor = libinput_device_get_id_vendor(libinput_dev);
int product = libinput_device_get_id_product(libinput_dev); int product = libinput_device_get_id_product(libinput_dev);
const char *name = libinput_device_get_name(libinput_dev); const char *name = libinput_device_get_name(libinput_dev);
wlr_log(WLR_DEBUG, "Removing %s [%d:%d]", name, vendor, product); 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; 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);
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);
} }
void handle_libinput_event(struct wlr_libinput_backend *backend, void handle_libinput_event(struct wlr_libinput_backend *backend,
struct libinput_event *event) { struct libinput_event *event) {
struct libinput_device *libinput_dev = libinput_event_get_device(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); enum libinput_event_type event_type = libinput_event_get_type(event);
switch (event_type) { switch (event_type) {
case LIBINPUT_EVENT_DEVICE_ADDED: case LIBINPUT_EVENT_DEVICE_ADDED:
@ -257,83 +163,100 @@ void handle_libinput_event(struct wlr_libinput_backend *backend,
handle_device_removed(backend, libinput_dev); handle_device_removed(backend, libinput_dev);
break; break;
case LIBINPUT_EVENT_KEYBOARD_KEY: case LIBINPUT_EVENT_KEYBOARD_KEY:
handle_keyboard_key(event, libinput_dev); handle_keyboard_key(event, &dev->keyboard);
break; break;
case LIBINPUT_EVENT_POINTER_MOTION: case LIBINPUT_EVENT_POINTER_MOTION:
handle_pointer_motion(event, libinput_dev); handle_pointer_motion(event, &dev->pointer);
break; break;
case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE: case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
handle_pointer_motion_abs(event, libinput_dev); handle_pointer_motion_abs(event, &dev->pointer);
break; break;
case LIBINPUT_EVENT_POINTER_BUTTON: case LIBINPUT_EVENT_POINTER_BUTTON:
handle_pointer_button(event, libinput_dev); handle_pointer_button(event, &dev->pointer);
break; break;
case LIBINPUT_EVENT_POINTER_AXIS: 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; 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: case LIBINPUT_EVENT_TOUCH_DOWN:
handle_touch_down(event, libinput_dev); handle_touch_down(event, &dev->touch);
break; break;
case LIBINPUT_EVENT_TOUCH_UP: case LIBINPUT_EVENT_TOUCH_UP:
handle_touch_up(event, libinput_dev); handle_touch_up(event, &dev->touch);
break; break;
case LIBINPUT_EVENT_TOUCH_MOTION: case LIBINPUT_EVENT_TOUCH_MOTION:
handle_touch_motion(event, libinput_dev); handle_touch_motion(event, &dev->touch);
break; break;
case LIBINPUT_EVENT_TOUCH_CANCEL: case LIBINPUT_EVENT_TOUCH_CANCEL:
handle_touch_cancel(event, libinput_dev); handle_touch_cancel(event, &dev->touch);
break; break;
case LIBINPUT_EVENT_TOUCH_FRAME: case LIBINPUT_EVENT_TOUCH_FRAME:
handle_touch_frame(event, libinput_dev); handle_touch_frame(event, &dev->touch);
break; break;
case LIBINPUT_EVENT_TABLET_TOOL_AXIS: case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
handle_tablet_tool_axis(event, libinput_dev); handle_tablet_tool_axis(event, &dev->tablet);
break; break;
case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY: case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY:
handle_tablet_tool_proximity(event, libinput_dev); handle_tablet_tool_proximity(event, &dev->tablet);
break; break;
case LIBINPUT_EVENT_TABLET_TOOL_TIP: case LIBINPUT_EVENT_TABLET_TOOL_TIP:
handle_tablet_tool_tip(event, libinput_dev); handle_tablet_tool_tip(event, &dev->tablet);
break; break;
case LIBINPUT_EVENT_TABLET_TOOL_BUTTON: case LIBINPUT_EVENT_TABLET_TOOL_BUTTON:
handle_tablet_tool_button(event, libinput_dev); handle_tablet_tool_button(event, &dev->tablet);
break; break;
case LIBINPUT_EVENT_TABLET_PAD_BUTTON: case LIBINPUT_EVENT_TABLET_PAD_BUTTON:
handle_tablet_pad_button(event, libinput_dev); handle_tablet_pad_button(event, &dev->tablet_pad);
break; break;
case LIBINPUT_EVENT_TABLET_PAD_RING: case LIBINPUT_EVENT_TABLET_PAD_RING:
handle_tablet_pad_ring(event, libinput_dev); handle_tablet_pad_ring(event, &dev->tablet_pad);
break; break;
case LIBINPUT_EVENT_TABLET_PAD_STRIP: case LIBINPUT_EVENT_TABLET_PAD_STRIP:
handle_tablet_pad_strip(event, libinput_dev); handle_tablet_pad_strip(event, &dev->tablet_pad);
break; break;
case LIBINPUT_EVENT_SWITCH_TOGGLE: case LIBINPUT_EVENT_SWITCH_TOGGLE:
handle_switch_toggle(event, libinput_dev); handle_switch_toggle(event, &dev->switch_device);
break; break;
case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN: case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN:
handle_pointer_swipe_begin(event, libinput_dev); handle_pointer_swipe_begin(event, &dev->pointer);
break; break;
case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE: case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE:
handle_pointer_swipe_update(event, libinput_dev); handle_pointer_swipe_update(event, &dev->pointer);
break; break;
case LIBINPUT_EVENT_GESTURE_SWIPE_END: case LIBINPUT_EVENT_GESTURE_SWIPE_END:
handle_pointer_swipe_end(event, libinput_dev); handle_pointer_swipe_end(event, &dev->pointer);
break; break;
case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN: case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN:
handle_pointer_pinch_begin(event, libinput_dev); handle_pointer_pinch_begin(event, &dev->pointer);
break; break;
case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE: case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE:
handle_pointer_pinch_update(event, libinput_dev); handle_pointer_pinch_update(event, &dev->pointer);
break; break;
case LIBINPUT_EVENT_GESTURE_PINCH_END: case LIBINPUT_EVENT_GESTURE_PINCH_END:
handle_pointer_pinch_end(event, libinput_dev); handle_pointer_pinch_end(event, &dev->pointer);
break; break;
#if LIBINPUT_HAS_HOLD_GESTURES #if LIBINPUT_HAS_HOLD_GESTURES
case LIBINPUT_EVENT_GESTURE_HOLD_BEGIN: case LIBINPUT_EVENT_GESTURE_HOLD_BEGIN:
handle_pointer_hold_begin(event, libinput_dev); handle_pointer_hold_begin(event, &dev->pointer);
break; break;
case LIBINPUT_EVENT_GESTURE_HOLD_END: case LIBINPUT_EVENT_GESTURE_HOLD_END:
handle_pointer_hold_end(event, libinput_dev); handle_pointer_hold_end(event, &dev->pointer);
break; break;
#endif #endif
default: default:

View file

@ -1,70 +1,42 @@
#include <assert.h> #include <assert.h>
#include <libinput.h> #include <libinput.h>
#include <stdlib.h> #include <stdlib.h>
#include <wlr/backend/session.h> #include <wlr/interfaces/wlr_keyboard.h>
#include <wlr/types/wlr_input_device.h>
#include <wlr/util/log.h>
#include "backend/libinput.h" #include "backend/libinput.h"
struct wlr_libinput_keyboard { struct wlr_libinput_input_device *device_from_keyboard(
struct wlr_keyboard wlr_keyboard; struct wlr_keyboard *kb) {
struct libinput_device *libinput_dev; assert(kb->impl == &libinput_keyboard_impl);
};
static struct wlr_libinput_keyboard *get_libinput_keyboard_from_keyboard( struct wlr_libinput_input_device *dev = wl_container_of(kb, dev, keyboard);
struct wlr_keyboard *wlr_kb) { return dev;
assert(wlr_kb->impl == &libinput_keyboard_impl);
return (struct wlr_libinput_keyboard *)wlr_kb;
} }
static void keyboard_set_leds(struct wlr_keyboard *wlr_kb, uint32_t leds) { static void keyboard_set_leds(struct wlr_keyboard *wlr_kb, uint32_t leds) {
struct wlr_libinput_keyboard *kb = struct wlr_libinput_input_device *dev = device_from_keyboard(wlr_kb);
get_libinput_keyboard_from_keyboard(wlr_kb); libinput_device_led_update(dev->handle, leds);
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);
} }
const struct wlr_keyboard_impl libinput_keyboard_impl = { const struct wlr_keyboard_impl libinput_keyboard_impl = {
.destroy = keyboard_destroy, .name = "libinput-keyboard",
.led_update = keyboard_set_leds .led_update = keyboard_set_leds
}; };
struct wlr_keyboard *create_libinput_keyboard( void init_device_keyboard(struct wlr_libinput_input_device *dev) {
struct libinput_device *libinput_dev) { const char *name = libinput_device_get_name(dev->handle);
struct wlr_libinput_keyboard *kb = struct wlr_keyboard *wlr_kb = &dev->keyboard;
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);
wlr_keyboard_init(wlr_kb, &libinput_keyboard_impl, name); wlr_keyboard_init(wlr_kb, &libinput_keyboard_impl, name);
wlr_kb->base.vendor = libinput_device_get_id_vendor(libinput_dev); wlr_kb->base.vendor = libinput_device_get_id_vendor(dev->handle);
wlr_kb->base.product = libinput_device_get_id_product(libinput_dev); wlr_kb->base.product = libinput_device_get_id_product(dev->handle);
return wlr_kb;
libinput_device_led_update(dev->handle, 0);
} }
void handle_keyboard_key(struct libinput_event *event, void handle_keyboard_key(struct libinput_event *event,
struct libinput_device *libinput_dev) { struct wlr_keyboard *kb) {
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 libinput_event_keyboard *kbevent = struct libinput_event_keyboard *kbevent =
libinput_event_get_keyboard_event(event); 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 = wlr_event.time_msec =
usec_to_msec(libinput_event_keyboard_get_time_usec(kbevent)); usec_to_msec(libinput_event_keyboard_get_time_usec(kbevent));
wlr_event.keycode = libinput_event_keyboard_get_key(kbevent); wlr_event.keycode = libinput_event_keyboard_get_key(kbevent);
@ -79,5 +51,5 @@ void handle_keyboard_key(struct libinput_event *event,
break; break;
} }
wlr_event.update_state = true; 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 } features += { 'libinput-backend': true }
wlr_deps += libinput wlr_deps += libinput
# libinput hold gestures are available since 1.19.0 # libinput hold gestures and high resolution scroll are available since 1.19.0
add_project_arguments( add_project_arguments([
'-DLIBINPUT_HAS_HOLD_GESTURES=@0@'.format(libinput.version().version_compare('>=1.19.0').to_int()), '-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 <assert.h>
#include <libinput.h> #include <libinput.h>
#include <stdlib.h> #include <wlr/interfaces/wlr_pointer.h>
#include <wlr/backend/session.h>
#include <wlr/types/wlr_input_device.h>
#include <wlr/util/log.h>
#include "backend/libinput.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( void init_device_pointer(struct wlr_libinput_input_device *dev) {
struct libinput_device *libinput_dev) { const char *name = libinput_device_get_name(dev->handle);
assert(libinput_dev); struct wlr_pointer *wlr_pointer = &dev->pointer;
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);
wlr_pointer_init(wlr_pointer, &libinput_pointer_impl, name); wlr_pointer_init(wlr_pointer, &libinput_pointer_impl, name);
wlr_pointer->base.vendor = libinput_device_get_id_vendor(libinput_dev); wlr_pointer->base.vendor = libinput_device_get_id_vendor(dev->handle);
wlr_pointer->base.product = libinput_device_get_id_product(libinput_dev); wlr_pointer->base.product = libinput_device_get_id_product(dev->handle);
return wlr_pointer; }
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, void handle_pointer_motion(struct libinput_event *event,
struct libinput_device *libinput_dev) { struct wlr_pointer *pointer) {
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 libinput_event_pointer *pevent = struct libinput_event_pointer *pevent =
libinput_event_get_pointer_event(event); libinput_event_get_pointer_event(event);
struct wlr_event_pointer_motion wlr_event = { 0 }; struct wlr_pointer_motion_event wlr_event = { 0 };
wlr_event.device = wlr_dev; wlr_event.pointer = pointer;
wlr_event.time_msec = wlr_event.time_msec =
usec_to_msec(libinput_event_pointer_get_time_usec(pevent)); usec_to_msec(libinput_event_pointer_get_time_usec(pevent));
wlr_event.delta_x = libinput_event_pointer_get_dx(pevent); wlr_event.delta_x = libinput_event_pointer_get_dx(pevent);
wlr_event.delta_y = libinput_event_pointer_get_dy(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_dx = libinput_event_pointer_get_dx_unaccelerated(pevent);
wlr_event.unaccel_dy = libinput_event_pointer_get_dy_unaccelerated(pevent); wlr_event.unaccel_dy = libinput_event_pointer_get_dy_unaccelerated(pevent);
wlr_signal_emit_safe(&wlr_dev->pointer->events.motion, &wlr_event); wl_signal_emit_mutable(&pointer->events.motion, &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_motion_abs(struct libinput_event *event, void handle_pointer_motion_abs(struct libinput_event *event,
struct libinput_device *libinput_dev) { struct wlr_pointer *pointer) {
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 libinput_event_pointer *pevent = struct libinput_event_pointer *pevent =
libinput_event_get_pointer_event(event); libinput_event_get_pointer_event(event);
struct wlr_event_pointer_motion_absolute wlr_event = { 0 }; struct wlr_pointer_motion_absolute_event wlr_event = { 0 };
wlr_event.device = wlr_dev; wlr_event.pointer = pointer;
wlr_event.time_msec = wlr_event.time_msec =
usec_to_msec(libinput_event_pointer_get_time_usec(pevent)); usec_to_msec(libinput_event_pointer_get_time_usec(pevent));
wlr_event.x = libinput_event_pointer_get_absolute_x_transformed(pevent, 1); 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_event.y = libinput_event_pointer_get_absolute_y_transformed(pevent, 1);
wlr_signal_emit_safe(&wlr_dev->pointer->events.motion_absolute, &wlr_event); wl_signal_emit_mutable(&pointer->events.motion_absolute, &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_button(struct libinput_event *event, void handle_pointer_button(struct libinput_event *event,
struct libinput_device *libinput_dev) { struct wlr_pointer *pointer) {
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 libinput_event_pointer *pevent = struct libinput_event_pointer *pevent =
libinput_event_get_pointer_event(event); libinput_event_get_pointer_event(event);
struct wlr_event_pointer_button wlr_event = { 0 }; struct wlr_pointer_button_event wlr_event = { 0 };
wlr_event.device = wlr_dev; wlr_event.pointer = pointer;
wlr_event.time_msec = wlr_event.time_msec =
usec_to_msec(libinput_event_pointer_get_time_usec(pevent)); usec_to_msec(libinput_event_pointer_get_time_usec(pevent));
wlr_event.button = libinput_event_pointer_get_button(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; wlr_event.state = WLR_BUTTON_RELEASED;
break; break;
} }
wlr_signal_emit_safe(&wlr_dev->pointer->events.button, &wlr_event); wl_signal_emit_mutable(&pointer->events.button, &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_axis(struct libinput_event *event, void handle_pointer_axis(struct libinput_event *event,
struct libinput_device *libinput_dev) { struct wlr_pointer *pointer) {
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 libinput_event_pointer *pevent = struct libinput_event_pointer *pevent =
libinput_event_get_pointer_event(event); libinput_event_get_pointer_event(event);
struct wlr_event_pointer_axis wlr_event = { 0 }; struct wlr_pointer_axis_event wlr_event = { 0 };
wlr_event.device = wlr_dev; wlr_event.pointer = pointer;
wlr_event.time_msec = wlr_event.time_msec =
usec_to_msec(libinput_event_pointer_get_time_usec(pevent)); usec_to_msec(libinput_event_pointer_get_time_usec(pevent));
switch (libinput_event_pointer_get_axis_source(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, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL,
}; };
for (size_t i = 0; i < sizeof(axes) / sizeof(axes[0]); ++i) { for (size_t i = 0; i < sizeof(axes) / sizeof(axes[0]); ++i) {
if (libinput_event_pointer_has_axis(pevent, axes[i])) { if (!libinput_event_pointer_has_axis(pevent, axes[i])) {
switch (axes[i]) { continue;
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);
} }
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, #if LIBINPUT_HAS_SCROLL_VALUE120
struct libinput_device *libinput_dev) { void handle_pointer_axis_value120(struct libinput_event *event,
struct wlr_input_device *wlr_dev = struct wlr_pointer *pointer, enum wlr_axis_source source) {
get_appropriate_device(WLR_INPUT_DEVICE_POINTER, libinput_dev); struct libinput_event_pointer *pevent =
if (!wlr_dev) { libinput_event_get_pointer_event(event);
wlr_log(WLR_DEBUG, "Got a pointer gesture event for a device with no pointers?"); struct wlr_pointer_axis_event wlr_event = { 0 };
return; 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 = struct libinput_event_gesture *gevent =
libinput_event_get_gesture_event(event); libinput_event_get_gesture_event(event);
struct wlr_event_pointer_swipe_begin wlr_event = { struct wlr_pointer_swipe_begin_event wlr_event = {
.device = wlr_dev, .pointer = pointer,
.time_msec = .time_msec =
usec_to_msec(libinput_event_gesture_get_time_usec(gevent)), usec_to_msec(libinput_event_gesture_get_time_usec(gevent)),
.fingers = libinput_event_gesture_get_finger_count(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, void handle_pointer_swipe_update(struct libinput_event *event,
struct libinput_device *libinput_dev) { struct wlr_pointer *pointer) {
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 libinput_event_gesture *gevent = struct libinput_event_gesture *gevent =
libinput_event_get_gesture_event(event); libinput_event_get_gesture_event(event);
struct wlr_event_pointer_swipe_update wlr_event = { struct wlr_pointer_swipe_update_event wlr_event = {
.device = wlr_dev, .pointer = pointer,
.time_msec = .time_msec =
usec_to_msec(libinput_event_gesture_get_time_usec(gevent)), usec_to_msec(libinput_event_gesture_get_time_usec(gevent)),
.fingers = libinput_event_gesture_get_finger_count(gevent), .fingers = libinput_event_gesture_get_finger_count(gevent),
.dx = libinput_event_gesture_get_dx(gevent), .dx = libinput_event_gesture_get_dx(gevent),
.dy = libinput_event_gesture_get_dy(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, void handle_pointer_swipe_end(struct libinput_event *event,
struct libinput_device *libinput_dev) { struct wlr_pointer *pointer) {
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 libinput_event_gesture *gevent = struct libinput_event_gesture *gevent =
libinput_event_get_gesture_event(event); libinput_event_get_gesture_event(event);
struct wlr_event_pointer_swipe_end wlr_event = { struct wlr_pointer_swipe_end_event wlr_event = {
.device = wlr_dev, .pointer = pointer,
.time_msec = .time_msec =
usec_to_msec(libinput_event_gesture_get_time_usec(gevent)), usec_to_msec(libinput_event_gesture_get_time_usec(gevent)),
.cancelled = libinput_event_gesture_get_cancelled(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, void handle_pointer_pinch_begin(struct libinput_event *event,
struct libinput_device *libinput_dev) { struct wlr_pointer *pointer) {
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 libinput_event_gesture *gevent = struct libinput_event_gesture *gevent =
libinput_event_get_gesture_event(event); libinput_event_get_gesture_event(event);
struct wlr_event_pointer_pinch_begin wlr_event = { struct wlr_pointer_pinch_begin_event wlr_event = {
.device = wlr_dev, .pointer = pointer,
.time_msec = .time_msec =
usec_to_msec(libinput_event_gesture_get_time_usec(gevent)), usec_to_msec(libinput_event_gesture_get_time_usec(gevent)),
.fingers = libinput_event_gesture_get_finger_count(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, void handle_pointer_pinch_update(struct libinput_event *event,
struct libinput_device *libinput_dev) { struct wlr_pointer *pointer) {
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 libinput_event_gesture *gevent = struct libinput_event_gesture *gevent =
libinput_event_get_gesture_event(event); libinput_event_get_gesture_event(event);
struct wlr_event_pointer_pinch_update wlr_event = { struct wlr_pointer_pinch_update_event wlr_event = {
.device = wlr_dev, .pointer = pointer,
.time_msec = .time_msec =
usec_to_msec(libinput_event_gesture_get_time_usec(gevent)), usec_to_msec(libinput_event_gesture_get_time_usec(gevent)),
.fingers = libinput_event_gesture_get_finger_count(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), .scale = libinput_event_gesture_get_scale(gevent),
.rotation = libinput_event_gesture_get_angle_delta(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, void handle_pointer_pinch_end(struct libinput_event *event,
struct libinput_device *libinput_dev) { struct wlr_pointer *pointer) {
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 libinput_event_gesture *gevent = struct libinput_event_gesture *gevent =
libinput_event_get_gesture_event(event); libinput_event_get_gesture_event(event);
struct wlr_event_pointer_pinch_end wlr_event = { struct wlr_pointer_pinch_end_event wlr_event = {
.device = wlr_dev, .pointer = pointer,
.time_msec = .time_msec =
usec_to_msec(libinput_event_gesture_get_time_usec(gevent)), usec_to_msec(libinput_event_gesture_get_time_usec(gevent)),
.cancelled = libinput_event_gesture_get_cancelled(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, void handle_pointer_hold_begin(struct libinput_event *event,
struct libinput_device *libinput_dev) { struct wlr_pointer *pointer) {
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 libinput_event_gesture *gevent = struct libinput_event_gesture *gevent =
libinput_event_get_gesture_event(event); libinput_event_get_gesture_event(event);
struct wlr_event_pointer_hold_begin wlr_event = { struct wlr_pointer_hold_begin_event wlr_event = {
.device = wlr_dev, .pointer = pointer,
.time_msec = .time_msec =
usec_to_msec(libinput_event_gesture_get_time_usec(gevent)), usec_to_msec(libinput_event_gesture_get_time_usec(gevent)),
.fingers = libinput_event_gesture_get_finger_count(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, void handle_pointer_hold_end(struct libinput_event *event,
struct libinput_device *libinput_dev) { struct wlr_pointer *pointer) {
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 libinput_event_gesture *gevent = struct libinput_event_gesture *gevent =
libinput_event_get_gesture_event(event); libinput_event_get_gesture_event(event);
struct wlr_event_pointer_hold_end wlr_event = { struct wlr_pointer_hold_end_event wlr_event = {
.device = wlr_dev, .pointer = pointer,
.time_msec = .time_msec =
usec_to_msec(libinput_event_gesture_get_time_usec(gevent)), usec_to_msec(libinput_event_gesture_get_time_usec(gevent)),
.cancelled = libinput_event_gesture_get_cancelled(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 <assert.h>
#include <libinput.h> #include <libinput.h>
#include <stdlib.h>
#include <wlr/backend/session.h>
#include <wlr/interfaces/wlr_switch.h> #include <wlr/interfaces/wlr_switch.h>
#include <wlr/types/wlr_input_device.h>
#include <wlr/util/log.h>
#include "backend/libinput.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( void init_device_switch(struct wlr_libinput_input_device *dev) {
struct libinput_device *libinput_dev) { const char *name = libinput_device_get_name(dev->handle);
assert(libinput_dev); struct wlr_switch *wlr_switch = &dev->switch_device;
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);
wlr_switch_init(wlr_switch, &libinput_switch_impl, name); 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(dev->handle);
wlr_switch->base.vendor = libinput_device_get_id_vendor(libinput_dev); wlr_switch->base.product = libinput_device_get_id_product(dev->handle);
wlr_switch->base.product = libinput_device_get_id_product(libinput_dev); }
return wlr_switch;
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, void handle_switch_toggle(struct libinput_event *event,
struct libinput_device *libinput_dev) { struct wlr_switch *wlr_switch) {
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 libinput_event_switch *sevent = struct libinput_event_switch *sevent =
libinput_event_get_switch_event (event); libinput_event_get_switch_event (event);
struct wlr_event_switch_toggle wlr_event = { 0 }; struct wlr_switch_toggle_event wlr_event = { 0 };
wlr_event.device = wlr_dev;
switch (libinput_event_switch_get_switch(sevent)) { switch (libinput_event_switch_get_switch(sevent)) {
case LIBINPUT_SWITCH_LID: case LIBINPUT_SWITCH_LID:
wlr_event.switch_type = WLR_SWITCH_TYPE_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 = wlr_event.time_msec =
usec_to_msec(libinput_event_switch_get_time_usec(sevent)); 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 #define _POSIX_C_SOURCE 200809L
#endif
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#include <libinput.h> #include <libinput.h>
#include <stdlib.h> #include <stdlib.h>
#include <wlr/backend/session.h>
#include <wlr/interfaces/wlr_tablet_pad.h> #include <wlr/interfaces/wlr_tablet_pad.h>
#include <wlr/types/wlr_input_device.h>
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include "backend/libinput.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, static void add_pad_group_from_libinput(struct wlr_tablet_pad *pad,
struct libinput_device *device, unsigned int index) { struct libinput_device *device, unsigned int index) {
struct libinput_tablet_pad_mode_group *li_group = 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 = struct wlr_tablet_pad_group *group =
calloc(1, sizeof(struct wlr_tablet_pad_group)); calloc(1, sizeof(struct wlr_tablet_pad_group));
if (!group) { if (!group) {
wlr_log_errno(WLR_ERROR, "failed to allocate wlr_tablet_pad_group");
return; 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); group->rings = calloc(sizeof(unsigned int), group->ring_count);
if (group->rings == NULL) {
goto group_fail;
}
size_t ring = 0; size_t ring = 0;
for (size_t i = 0; i < pad->ring_count; ++i) { for (size_t i = 0; i < pad->ring_count; ++i) {
if (libinput_tablet_pad_mode_group_has_ring(li_group, 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); group->strips = calloc(sizeof(unsigned int), group->strip_count);
if (group->strips == NULL) {
goto group_fail;
}
size_t strip = 0; size_t strip = 0;
for (size_t i = 0; i < pad->strip_count; ++i) { for (size_t i = 0; i < pad->strip_count; ++i) {
if (libinput_tablet_pad_mode_group_has_strip(li_group, 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); group->buttons = calloc(sizeof(unsigned int), group->button_count);
if (group->buttons == NULL) {
goto group_fail;
}
size_t button = 0; size_t button = 0;
for (size_t i = 0; i < pad->button_count; ++i) { for (size_t i = 0; i < pad->button_count; ++i) {
if (libinput_tablet_pad_mode_group_has_button(li_group, 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); 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); 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; void init_device_tablet_pad(struct wlr_libinput_input_device *dev) {
struct libinput_device *handle = dev->handle;
struct wlr_tablet_pad *create_libinput_tablet_pad( const char *name = libinput_device_get_name(handle);
struct libinput_device *libinput_dev) { struct wlr_tablet_pad *wlr_tablet_pad = &dev->tablet_pad;
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);
wlr_tablet_pad_init(wlr_tablet_pad, &libinput_tablet_pad_impl, name); 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.vendor = libinput_device_get_id_vendor(handle);
wlr_tablet_pad->base.product = libinput_device_get_id_product(libinput_dev); wlr_tablet_pad->base.product = libinput_device_get_id_product(handle);
wlr_tablet_pad->button_count = 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 = 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 = 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 *)); char **dst = wl_array_add(&wlr_tablet_pad->paths, sizeof(char *));
*dst = strdup(udev_device_get_syspath(udev)); *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) { 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, void handle_tablet_pad_button(struct libinput_event *event,
struct libinput_device *libinput_dev) { struct wlr_tablet_pad *tablet_pad) {
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 libinput_event_tablet_pad *pevent = struct libinput_event_tablet_pad *pevent =
libinput_event_get_tablet_pad_event(event); 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 = wlr_event.time_msec =
usec_to_msec(libinput_event_tablet_pad_get_time_usec(pevent)); usec_to_msec(libinput_event_tablet_pad_get_time_usec(pevent));
wlr_event.button = libinput_event_tablet_pad_get_button_number(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; wlr_event.state = WLR_BUTTON_RELEASED;
break; 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, void handle_tablet_pad_ring(struct libinput_event *event,
struct libinput_device *libinput_dev) { struct wlr_tablet_pad *tablet_pad) {
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 libinput_event_tablet_pad *pevent = struct libinput_event_tablet_pad *pevent =
libinput_event_get_tablet_pad_event(event); 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 = wlr_event.time_msec =
usec_to_msec(libinput_event_tablet_pad_get_time_usec(pevent)); usec_to_msec(libinput_event_tablet_pad_get_time_usec(pevent));
wlr_event.ring = libinput_event_tablet_pad_get_ring_number(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; wlr_event.source = WLR_TABLET_PAD_RING_SOURCE_FINGER;
break; 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, void handle_tablet_pad_strip(struct libinput_event *event,
struct libinput_device *libinput_dev) { struct wlr_tablet_pad *tablet_pad) {
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 libinput_event_tablet_pad *pevent = struct libinput_event_tablet_pad *pevent =
libinput_event_get_tablet_pad_event(event); 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 = wlr_event.time_msec =
usec_to_msec(libinput_event_tablet_pad_get_time_usec(pevent)); usec_to_msec(libinput_event_tablet_pad_get_time_usec(pevent));
wlr_event.strip = libinput_event_tablet_pad_get_strip_number(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; wlr_event.source = WLR_TABLET_PAD_STRIP_SOURCE_FINGER;
break; 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 #define _POSIX_C_SOURCE 200809L
#endif
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include <libinput.h> #include <libinput.h>
#include <stdlib.h> #include <stdlib.h>
#include <wayland-util.h>
#include <wlr/backend/session.h>
#include <wlr/interfaces/wlr_tablet_tool.h> #include <wlr/interfaces/wlr_tablet_tool.h>
#include <wlr/types/wlr_input_device.h>
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include "backend/libinput.h" #include "backend/libinput.h"
#include "util/array.h"
#include "util/signal.h"
static bool tablet_is_libinput(struct wlr_tablet *tablet) { struct tablet_tool {
return tablet->impl == &libinput_tablet_impl;
}
struct wlr_libinput_tablet_tool {
struct wlr_tablet_tool wlr_tool; struct wlr_tablet_tool wlr_tool;
struct libinput_tablet_tool *handle;
struct libinput_tablet_tool *libinput_tool; struct wl_list link; // wlr_libinput_input_device::tablet_tools
bool unique;
// Refcount for destroy + release
size_t pad_refs;
}; };
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 = { const struct wlr_tablet_impl libinput_tablet_impl = {
.destroy = destroy_tablet, .name = "libinput-tablet-tool",
}; };
struct wlr_tablet *create_libinput_tablet( void init_device_tablet(struct wlr_libinput_input_device *dev) {
struct libinput_device *libinput_dev) { const char *name = libinput_device_get_name(dev->handle);
assert(libinput_dev); struct wlr_tablet *wlr_tablet = &dev->tablet;
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);
wlr_tablet_init(wlr_tablet, &libinput_tablet_impl, name); wlr_tablet_init(wlr_tablet, &libinput_tablet_impl, name);
wlr_tablet->base.vendor = libinput_device_get_id_vendor(libinput_dev); wlr_tablet->base.vendor = libinput_device_get_id_vendor(dev->handle);
wlr_tablet->base.product = libinput_device_get_id_product(libinput_dev); 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 *)); char **dst = wl_array_add(&wlr_tablet->paths, sizeof(char *));
*dst = strdup(udev_device_get_syspath(udev)); *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( 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 abort(); // unreachable
} }
static struct wlr_libinput_tablet_tool *get_wlr_tablet_tool( static struct tablet_tool *get_tablet_tool(
struct libinput_tablet_tool *tool) { struct wlr_libinput_input_device *dev,
struct wlr_libinput_tablet_tool *ret = struct libinput_tablet_tool *libinput_tool) {
libinput_tablet_tool_get_user_data(tool); struct tablet_tool *tool =
libinput_tablet_tool_get_user_data(libinput_tool);
if (ret) { if (tool) {
return ret; return tool;
} }
ret = calloc(1, sizeof(struct wlr_libinput_tablet_tool)); tool = calloc(1, sizeof(struct tablet_tool));
if (!ret) { if (tool == NULL) {
wlr_log_errno(WLR_ERROR, "failed to allocate wlr_libinput_tablet_tool");
return NULL; return NULL;
} }
ret->libinput_tool = libinput_tablet_tool_ref(tool); tool->wlr_tool.type = wlr_type_from_libinput_type(
ret->wlr_tool.pressure = libinput_tablet_tool_has_pressure(tool); libinput_tablet_tool_get_type(libinput_tool));
ret->wlr_tool.distance = libinput_tablet_tool_has_distance(tool); tool->wlr_tool.hardware_serial =
ret->wlr_tool.tilt = libinput_tablet_tool_has_tilt(tool); libinput_tablet_tool_get_serial(libinput_tool);
ret->wlr_tool.rotation = libinput_tablet_tool_has_rotation(tool); tool->wlr_tool.hardware_wacom =
ret->wlr_tool.slider = libinput_tablet_tool_has_slider(tool); libinput_tablet_tool_get_tool_id(libinput_tool);
ret->wlr_tool.wheel = libinput_tablet_tool_has_wheel(tool);
ret->wlr_tool.hardware_serial = libinput_tablet_tool_get_serial(tool); tool->wlr_tool.pressure = libinput_tablet_tool_has_pressure(libinput_tool);
ret->wlr_tool.hardware_wacom = libinput_tablet_tool_get_tool_id(tool); tool->wlr_tool.distance = libinput_tablet_tool_has_distance(libinput_tool);
ret->wlr_tool.type = wlr_type_from_libinput_type( tool->wlr_tool.tilt = libinput_tablet_tool_has_tilt(libinput_tool);
libinput_tablet_tool_get_type(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); wl_list_insert(&dev->tablet_tools, &tool->link);
return ret; return tool;
}
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;
} }
void handle_tablet_tool_axis(struct libinput_event *event, void handle_tablet_tool_axis(struct libinput_event *event,
struct libinput_device *libinput_dev) { struct wlr_tablet *wlr_tablet) {
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 libinput_event_tablet_tool *tevent = struct libinput_event_tablet_tool *tevent =
libinput_event_get_tablet_tool_event(event); libinput_event_get_tablet_tool_event(event);
struct wlr_event_tablet_tool_axis wlr_event = { 0 }; struct wlr_libinput_input_device *dev = device_from_tablet(wlr_tablet);
struct wlr_libinput_tablet_tool *tool = get_wlr_tablet_tool( struct tablet_tool *tool =
libinput_event_tablet_tool_get_tool(tevent)); get_tablet_tool(dev, libinput_event_tablet_tool_get_tool(tevent));
ensure_tool_reference(tool, wlr_dev->tablet);
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.tool = &tool->wlr_tool;
wlr_event.time_msec = wlr_event.time_msec =
usec_to_msec(libinput_event_tablet_tool_get_time_usec(tevent)); 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.updated_axes |= WLR_TABLET_TOOL_AXIS_WHEEL;
wlr_event.wheel_delta = libinput_event_tablet_tool_get_wheel_delta(tevent); 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, void handle_tablet_tool_proximity(struct libinput_event *event,
struct libinput_device *libinput_dev) { struct wlr_tablet *wlr_tablet) {
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 libinput_event_tablet_tool *tevent = struct libinput_event_tablet_tool *tevent =
libinput_event_get_tablet_tool_event(event); libinput_event_get_tablet_tool_event(event);
struct wlr_event_tablet_tool_proximity wlr_event = { 0 }; struct wlr_libinput_input_device *dev = device_from_tablet(wlr_tablet);
struct wlr_libinput_tablet_tool *tool = get_wlr_tablet_tool( struct tablet_tool *tool =
libinput_event_tablet_tool_get_tool(tevent)); get_tablet_tool(dev, libinput_event_tablet_tool_get_tool(tevent));
ensure_tool_reference(tool, wlr_dev->tablet);
struct wlr_tablet_tool_proximity_event wlr_event = { 0 };
wlr_event.tablet = wlr_tablet;
wlr_event.tool = &tool->wlr_tool; wlr_event.tool = &tool->wlr_tool;
wlr_event.device = wlr_dev;
wlr_event.time_msec = wlr_event.time_msec =
usec_to_msec(libinput_event_tablet_tool_get_time_usec(tevent)); usec_to_msec(libinput_event_tablet_tool_get_time_usec(tevent));
wlr_event.x = libinput_event_tablet_tool_get_x_transformed(tevent, 1); 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; wlr_event.state = WLR_TABLET_TOOL_PROXIMITY_IN;
break; 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) == if (libinput_event_tablet_tool_get_proximity_state(tevent) ==
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN) { 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 // If the tool is not unique, libinput will not find it again after the
// proximity out, so we should destroy it // proximity out, so we should destroy it
if (!tool->unique && if (!libinput_tablet_tool_is_unique(tool->handle)
libinput_event_tablet_tool_get_proximity_state(tevent) == && libinput_event_tablet_tool_get_proximity_state(tevent) ==
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT) { LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT) {
// The tool isn't unique, it can't be on multiple tablets // The tool isn't unique, it can't be on multiple tablets
assert(tool->pad_refs == 1); tool_destroy(tool);
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);
} }
} }
void handle_tablet_tool_tip(struct libinput_event *event, void handle_tablet_tool_tip(struct libinput_event *event,
struct libinput_device *libinput_dev) { struct wlr_tablet *wlr_tablet) {
struct wlr_input_device *wlr_dev = handle_tablet_tool_axis(event, wlr_tablet);
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 libinput_event_tablet_tool *tevent = struct libinput_event_tablet_tool *tevent =
libinput_event_get_tablet_tool_event(event); libinput_event_get_tablet_tool_event(event);
struct wlr_event_tablet_tool_tip wlr_event = { 0 }; struct wlr_libinput_input_device *dev = device_from_tablet(wlr_tablet);
struct wlr_libinput_tablet_tool *tool = get_wlr_tablet_tool( struct tablet_tool *tool =
libinput_event_tablet_tool_get_tool(tevent)); get_tablet_tool(dev, libinput_event_tablet_tool_get_tool(tevent));
ensure_tool_reference(tool, wlr_dev->tablet);
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.tool = &tool->wlr_tool;
wlr_event.time_msec = wlr_event.time_msec =
usec_to_msec(libinput_event_tablet_tool_get_time_usec(tevent)); 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; wlr_event.state = WLR_TABLET_TOOL_TIP_DOWN;
break; 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, void handle_tablet_tool_button(struct libinput_event *event,
struct libinput_device *libinput_dev) { struct wlr_tablet *wlr_tablet) {
struct wlr_input_device *wlr_dev = handle_tablet_tool_axis(event, wlr_tablet);
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 libinput_event_tablet_tool *tevent = struct libinput_event_tablet_tool *tevent =
libinput_event_get_tablet_tool_event(event); libinput_event_get_tablet_tool_event(event);
struct wlr_event_tablet_tool_button wlr_event = { 0 }; struct wlr_libinput_input_device *dev = device_from_tablet(wlr_tablet);
struct wlr_libinput_tablet_tool *tool = get_wlr_tablet_tool( struct tablet_tool *tool =
libinput_event_tablet_tool_get_tool(tevent)); get_tablet_tool(dev, libinput_event_tablet_tool_get_tool(tevent));
ensure_tool_reference(tool, wlr_dev->tablet);
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.tool = &tool->wlr_tool;
wlr_event.time_msec = wlr_event.time_msec =
usec_to_msec(libinput_event_tablet_tool_get_time_usec(tevent)); 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; wlr_event.state = WLR_BUTTON_PRESSED;
break; 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 <assert.h>
#include <libinput.h> #include <libinput.h>
#include <stdlib.h>
#include <wlr/backend/session.h>
#include <wlr/interfaces/wlr_touch.h> #include <wlr/interfaces/wlr_touch.h>
#include <wlr/types/wlr_input_device.h>
#include <wlr/util/log.h>
#include "backend/libinput.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( void init_device_touch(struct wlr_libinput_input_device *dev) {
struct libinput_device *libinput_dev) { const char *name = libinput_device_get_name(dev->handle);
assert(libinput_dev); struct wlr_touch *wlr_touch = &dev->touch;
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);
wlr_touch_init(wlr_touch, &libinput_touch_impl, name); wlr_touch_init(wlr_touch, &libinput_touch_impl, name);
wlr_touch->base.vendor = libinput_device_get_id_vendor(libinput_dev); wlr_touch->base.vendor = libinput_device_get_id_vendor(dev->handle);
wlr_touch->base.product = libinput_device_get_id_product(libinput_dev); wlr_touch->base.product = libinput_device_get_id_product(dev->handle);
return wlr_touch;
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, void handle_touch_down(struct libinput_event *event,
struct libinput_device *libinput_dev) { struct wlr_touch *touch) {
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 libinput_event_touch *tevent = struct libinput_event_touch *tevent =
libinput_event_get_touch_event(event); libinput_event_get_touch_event(event);
struct wlr_event_touch_down wlr_event = { 0 }; struct wlr_touch_down_event wlr_event = { 0 };
wlr_event.device = wlr_dev; wlr_event.touch = touch;
wlr_event.time_msec = wlr_event.time_msec =
usec_to_msec(libinput_event_touch_get_time_usec(tevent)); usec_to_msec(libinput_event_touch_get_time_usec(tevent));
wlr_event.touch_id = libinput_event_touch_get_seat_slot(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.x = libinput_event_touch_get_x_transformed(tevent, 1);
wlr_event.y = libinput_event_touch_get_y_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, void handle_touch_up(struct libinput_event *event,
struct libinput_device *libinput_dev) { struct wlr_touch *touch) {
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 libinput_event_touch *tevent = struct libinput_event_touch *tevent =
libinput_event_get_touch_event(event); libinput_event_get_touch_event(event);
struct wlr_event_touch_up wlr_event = { 0 }; struct wlr_touch_up_event wlr_event = { 0 };
wlr_event.device = wlr_dev; wlr_event.touch = touch;
wlr_event.time_msec = wlr_event.time_msec =
usec_to_msec(libinput_event_touch_get_time_usec(tevent)); usec_to_msec(libinput_event_touch_get_time_usec(tevent));
wlr_event.touch_id = libinput_event_touch_get_seat_slot(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, void handle_touch_motion(struct libinput_event *event,
struct libinput_device *libinput_dev) { struct wlr_touch *touch) {
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 libinput_event_touch *tevent = struct libinput_event_touch *tevent =
libinput_event_get_touch_event(event); libinput_event_get_touch_event(event);
struct wlr_event_touch_motion wlr_event = { 0 }; struct wlr_touch_motion_event wlr_event = { 0 };
wlr_event.device = wlr_dev; wlr_event.touch = touch;
wlr_event.time_msec = wlr_event.time_msec =
usec_to_msec(libinput_event_touch_get_time_usec(tevent)); usec_to_msec(libinput_event_touch_get_time_usec(tevent));
wlr_event.touch_id = libinput_event_touch_get_seat_slot(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.x = libinput_event_touch_get_x_transformed(tevent, 1);
wlr_event.y = libinput_event_touch_get_y_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, void handle_touch_cancel(struct libinput_event *event,
struct libinput_device *libinput_dev) { struct wlr_touch *touch) {
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 libinput_event_touch *tevent = struct libinput_event_touch *tevent =
libinput_event_get_touch_event(event); libinput_event_get_touch_event(event);
struct wlr_event_touch_cancel wlr_event = { 0 }; struct wlr_touch_cancel_event wlr_event = { 0 };
wlr_event.device = wlr_dev; wlr_event.touch = touch;
wlr_event.time_msec = wlr_event.time_msec =
usec_to_msec(libinput_event_touch_get_time_usec(tevent)); usec_to_msec(libinput_event_touch_get_time_usec(tevent));
wlr_event.touch_id = libinput_event_touch_get_seat_slot(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, void handle_touch_frame(struct libinput_event *event,
struct libinput_device *libinput_dev) { struct wlr_touch *touch) {
struct wlr_input_device *wlr_dev = wl_signal_emit_mutable(&touch->events.frame, NULL);
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);
} }

View file

@ -9,7 +9,6 @@
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include "backend/backend.h" #include "backend/backend.h"
#include "backend/multi.h" #include "backend/multi.h"
#include "util/signal.h"
struct subbackend_state { struct subbackend_state {
struct wlr_backend *backend; 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) { static void new_input_reemit(struct wl_listener *listener, void *data) {
struct subbackend_state *state = wl_container_of(listener, struct subbackend_state *state = wl_container_of(listener,
state, new_input); 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) { static void new_output_reemit(struct wl_listener *listener, void *data) {
struct subbackend_state *state = wl_container_of(listener, struct subbackend_state *state = wl_container_of(listener,
state, new_output); 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, 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); wl_signal_add(&backend->events.new_output, &sub->new_output);
sub->new_output.notify = new_output_reemit; 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; return true;
} }
@ -230,7 +229,7 @@ void wlr_multi_backend_remove(struct wlr_backend *_multi,
multi_backend_get_subbackend(multi, backend); multi_backend_get_subbackend(multi, backend);
if (sub) { if (sub) {
wlr_signal_emit_safe(&multi->events.backend_remove, backend); wl_signal_emit_mutable(&multi->events.backend_remove, backend);
subbackend_state_destroy(sub); subbackend_state_destroy(sub);
} }
} }

View file

@ -17,7 +17,6 @@
#include <xf86drm.h> #include <xf86drm.h>
#include <xf86drmMode.h> #include <xf86drmMode.h>
#include "backend/session/session.h" #include "backend/session/session.h"
#include "util/signal.h"
#include <libseat.h> #include <libseat.h>
@ -26,13 +25,13 @@
static void handle_enable_seat(struct libseat *seat, void *data) { static void handle_enable_seat(struct libseat *seat, void *data) {
struct wlr_session *session = data; struct wlr_session *session = data;
session->active = true; 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) { static void handle_disable_seat(struct libseat *seat, void *data) {
struct wlr_session *session = data; struct wlr_session *session = data;
session->active = false; 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); 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 = { struct wlr_session_add_event event = {
.path = devnode, .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) { } else if (strcmp(action, "change") == 0 || strcmp(action, "remove") == 0) {
dev_t devnum = udev_device_get_devnum(udev_dev); dev_t devnum = udev_device_get_devnum(udev_dev);
struct wlr_device *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); wlr_log(WLR_DEBUG, "DRM device %s changed", sysname);
struct wlr_device_change_event event = {0}; struct wlr_device_change_event event = {0};
read_udev_change_event(&event, udev_dev); 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) { } else if (strcmp(action, "remove") == 0) {
wlr_log(WLR_DEBUG, "DRM device %s removed", sysname); 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 { } else {
assert(0); assert(0);
} }
@ -298,7 +297,7 @@ void wlr_session_destroy(struct wlr_session *session) {
return; 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_list_remove(&session->display_destroy.link);
wl_event_source_remove(session->udev_event); wl_event_source_remove(session->udev_event);

View file

@ -19,7 +19,6 @@
#include "backend/wayland.h" #include "backend/wayland.h"
#include "render/drm_format_set.h" #include "render/drm_format_set.h"
#include "render/pixel_format.h" #include "render/pixel_format.h"
#include "util/signal.h"
#include "drm-client-protocol.h" #include "drm-client-protocol.h"
#include "linux-dmabuf-unstable-v1-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 = wl_registry_bind(registry, name,
&wl_compositor_interface, 4); &wl_compositor_interface, 4);
} else if (strcmp(iface, wl_seat_interface.name) == 0) { } 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, 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)) { if (!create_wl_seat(wl_seat, wl)) {
wl_seat_destroy(wl_seat); wl_seat_destroy(wl_seat);
} }
@ -413,12 +419,16 @@ static bool backend_start(struct wlr_backend *backend) {
struct wlr_wl_seat *seat; struct wlr_wl_seat *seat;
wl_list_for_each(seat, &wl->seats, link) { wl_list_for_each(seat, &wl->seats, link) {
if (seat->keyboard) { if (seat->wl_keyboard) {
create_wl_keyboard(seat); init_seat_keyboard(seat);
}
if (seat->wl_touch) {
init_seat_touch(seat);
} }
if (wl->tablet_manager) { 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); 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; struct wlr_wl_buffer *buffer, *tmp_buffer;
wl_list_for_each_safe(buffer, tmp_buffer, &wl->buffers, link) { wl_list_for_each_safe(buffer, tmp_buffer, &wl->buffers, link) {
destroy_wl_buffer(buffer); 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); wlr_backend_init(&wl->backend, &backend_impl);
wl->local_display = display; wl->local_display = display;
wl_list_init(&wl->devices);
wl_list_init(&wl->outputs); wl_list_init(&wl->outputs);
wl_list_init(&wl->seats); wl_list_init(&wl->seats);
wl_list_init(&wl->buffers); wl_list_init(&wl->buffers);

View file

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

View file

@ -19,7 +19,6 @@
#include "render/pixel_format.h" #include "render/pixel_format.h"
#include "render/swapchain.h" #include "render/swapchain.h"
#include "render/wlr_renderer.h" #include "render/wlr_renderer.h"
#include "util/signal.h"
#include "linux-dmabuf-unstable-v1-client-protocol.h" #include "linux-dmabuf-unstable-v1-client-protocol.h"
#include "presentation-time-client-protocol.h" #include "presentation-time-client-protocol.h"
@ -30,7 +29,8 @@
static const uint32_t SUPPORTED_OUTPUT_STATE = static const uint32_t SUPPORTED_OUTPUT_STATE =
WLR_OUTPUT_STATE_BACKEND_OPTIONAL | WLR_OUTPUT_STATE_BACKEND_OPTIONAL |
WLR_OUTPUT_STATE_BUFFER | 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( static struct wlr_wl_output *get_wl_output_from_output(
struct wlr_output *wlr_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); 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 = struct wlr_wl_output *output =
get_wl_output_from_output(wlr_output); get_wl_output_from_output(wlr_output);
uint32_t unsupported = uint32_t unsupported = state->committed & ~SUPPORTED_OUTPUT_STATE;
wlr_output->pending.committed & ~SUPPORTED_OUTPUT_STATE;
if (unsupported != 0) { if (unsupported != 0) {
wlr_log(WLR_DEBUG, "Unsupported output state fields: 0x%"PRIx32, wlr_log(WLR_DEBUG, "Unsupported output state fields: 0x%"PRIx32,
unsupported); unsupported);
return false; return false;
} }
if (wlr_output->pending.committed & WLR_OUTPUT_STATE_MODE) { // Adaptive sync is effectively always enabled when using the Wayland
assert(wlr_output->pending.mode_type == WLR_OUTPUT_STATE_MODE_CUSTOM); // 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) && if (state->committed & WLR_OUTPUT_STATE_MODE) {
!test_buffer(output->backend, wlr_output->pending.buffer)) { 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 false;
} }
return true; 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 = struct wlr_wl_output *output =
get_wl_output_from_output(wlr_output); get_wl_output_from_output(wlr_output);
if (!output_test(wlr_output)) { if (!output_test(wlr_output, state)) {
return false; 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, if (!output_set_custom_mode(wlr_output,
wlr_output->pending.custom_mode.width, state->custom_mode.width,
wlr_output->pending.custom_mode.height, state->custom_mode.height,
wlr_output->pending.custom_mode.refresh)) { state->custom_mode.refresh)) {
return false; 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; struct wp_presentation_feedback *wp_feedback = NULL;
if (output->backend->presentation != NULL) { if (output->backend->presentation != NULL) {
wp_feedback = wp_presentation_feedback(output->backend->presentation, 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; pixman_region32_t *damage = NULL;
if (wlr_output->pending.committed & WLR_OUTPUT_STATE_DAMAGE) { if (state->committed & WLR_OUTPUT_STATE_DAMAGE) {
damage = &wlr_output->pending.damage; damage = (pixman_region32_t *) &state->damage;
} }
if (output->frame_callback != NULL) { 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); output->frame_callback = wl_surface_frame(output->surface);
wl_callback_add_listener(output->frame_callback, &frame_listener, output); 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 = struct wlr_wl_buffer *buffer =
get_or_create_wl_buffer(output->backend, wlr_buffer); get_or_create_wl_buffer(output->backend, wlr_buffer);
if (buffer == NULL) { if (buffer == NULL) {
@ -436,7 +447,9 @@ void update_wl_output_cursor(struct wlr_wl_output *output) {
if (pointer) { if (pointer) {
assert(pointer->output == output); assert(pointer->output == output);
assert(output->enter_serial); 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.surface, output->cursor.hotspot_x,
output->cursor.hotspot_y); 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; struct wlr_output *wlr_output = &output->wlr_output;
wlr_output_update_custom_mode(wlr_output, 1280, 720, 0); 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]; char name[64];
snprintf(name, sizeof(name), "WL-%zu", ++backend->last_output_num); 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); wl_list_insert(&backend->outputs, &output->link);
wlr_output_update_enabled(wlr_output, true); 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; struct wlr_wl_seat *seat;
wl_list_for_each(seat, &backend->seats, link) { wl_list_for_each(seat, &backend->seats, link) {
if (seat->pointer) { if (seat->wl_pointer) {
create_wl_pointer(seat, output); 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 #define _POSIX_C_SOURCE 200809L
#endif
#include <wayland-util.h>
#include <assert.h> #include <assert.h>
#include <math.h> #include <math.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <wlr/interfaces/wlr_tablet_pad.h> #include <wlr/interfaces/wlr_tablet_pad.h>
#include <wlr/interfaces/wlr_tablet_tool.h> #include <wlr/interfaces/wlr_tablet_tool.h>
#include <wlr/types/wlr_input_device.h> #include <wlr/util/log.h>
#include "util/signal.h"
#include "util/time.h"
#include "wlr/util/log.h"
#include "tablet-unstable-v2-client-protocol.h"
#include "backend/wayland.h" #include "backend/wayland.h"
#include "util/time.h"
struct wlr_wl_tablet_seat { #include "tablet-unstable-v2-client-protocol.h"
struct zwp_tablet_seat_v2 *tablet_seat;
};
struct wlr_wl_tablet_tool { struct tablet_tool {
/* static */ /* static */
struct zwp_tablet_tool_v2 *tool; struct wlr_wl_seat *seat;
struct wlr_tablet_tool wlr_tool;
/* semi-static */ /* semi-static */
struct wlr_wl_output *output; struct wlr_wl_output *output;
struct wlr_wl_input_device *tablet;
double pre_x, pre_y; double pre_x, pre_y;
/* per frame */ /* per frame */
@ -49,11 +38,11 @@ struct wlr_wl_tablet_tool {
bool is_down; bool is_down;
}; };
struct wlr_wl_tablet_pad_ring { struct tablet_pad_ring {
struct wl_list link; // wlr_wl_tablet_pad_group::rings struct wl_list link; // tablet_pad_group::rings
/* static */ /* static */
struct zwp_tablet_pad_ring_v2 *ring; struct zwp_tablet_pad_ring_v2 *ring;
struct wlr_wl_tablet_pad_group *group; struct tablet_pad_group *group;
size_t index; size_t index;
/* per frame */ /* per frame */
@ -62,10 +51,10 @@ struct wlr_wl_tablet_pad_ring {
bool stopped; bool stopped;
}; };
struct wlr_wl_tablet_pad_strip { struct tablet_pad_strip {
struct wl_list link; // wlr_wl_tablet_pad_group::strips struct wl_list link; // tablet_pad_group::strips
struct zwp_tablet_pad_strip_v2 *strip; struct zwp_tablet_pad_strip_v2 *strip;
struct wlr_wl_tablet_pad_group *group; struct tablet_pad_group *group;
size_t index; size_t index;
enum wlr_tablet_pad_strip_source source; enum wlr_tablet_pad_strip_source source;
@ -73,43 +62,43 @@ struct wlr_wl_tablet_pad_strip {
bool stopped; bool stopped;
}; };
struct wlr_wl_tablet_pad_group { struct tablet_pad_group {
struct zwp_tablet_pad_group_v2 *pad_group; struct zwp_tablet_pad_group_v2 *pad_group;
struct wlr_tablet_pad *pad; struct wlr_tablet_pad *pad;
unsigned int mode; unsigned int mode;
struct wlr_tablet_pad_group group; struct wlr_tablet_pad_group group;
struct wl_list rings; // wlr_wl_tablet_pad_ring::link struct wl_list rings; // tablet_pad_ring::link
struct wl_list strips; // wlr_wl_tablet_pad_strips::link struct wl_list strips; // tablet_pad_strips::link
}; };
static void handle_tablet_pad_ring_source(void *data, static void handle_tablet_pad_ring_source(void *data,
struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2, struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2,
uint32_t source) { uint32_t source) {
struct wlr_wl_tablet_pad_ring *ring = data; struct tablet_pad_ring *ring = data;
ring->source = source; ring->source = source;
} }
static void handle_tablet_pad_ring_angle(void *data, static void handle_tablet_pad_ring_angle(void *data,
struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2, struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2,
wl_fixed_t degrees) { 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); ring->angle = wl_fixed_to_double(degrees);
} }
static void handle_tablet_pad_ring_stop(void *data, static void handle_tablet_pad_ring_stop(void *data,
struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2) { 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; ring->stopped = true;
} }
static void handle_tablet_pad_ring_frame(void *data, static void handle_tablet_pad_ring_frame(void *data,
struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2, struct zwp_tablet_pad_ring_v2 *zwp_tablet_pad_ring_v2,
uint32_t time) { 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, .time_msec = time,
.source = ring->source, .source = ring->source,
.ring = ring->index, .ring = ring->index,
@ -118,11 +107,11 @@ static void handle_tablet_pad_ring_frame(void *data,
}; };
if (ring->angle >= 0) { 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) { if (ring->stopped) {
evt.position = -1; 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; 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, static void handle_tablet_pad_strip_source(void *data,
struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2, struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2,
uint32_t source) { uint32_t source) {
struct wlr_wl_tablet_pad_strip *strip = data; struct tablet_pad_strip *strip = data;
strip->source = source; strip->source = source;
} }
static void handle_tablet_pad_strip_position(void *data, static void handle_tablet_pad_strip_position(void *data,
struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2, struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2,
uint32_t position) { uint32_t position) {
struct wlr_wl_tablet_pad_strip *strip = data; struct tablet_pad_strip *strip = data;
strip->position = (double) position / 65536.0; strip->position = (double) position / 65536.0;
} }
static void handle_tablet_pad_strip_stop(void *data, static void handle_tablet_pad_strip_stop(void *data,
struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2) { 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; strip->stopped = true;
} }
static void handle_tablet_pad_strip_frame(void *data, static void handle_tablet_pad_strip_frame(void *data,
struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2, struct zwp_tablet_pad_strip_v2 *zwp_tablet_pad_strip_v2,
uint32_t time) { 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, .time_msec = time,
.source = strip->source, .source = strip->source,
.strip = strip->index, .strip = strip->index,
@ -171,11 +160,11 @@ static void handle_tablet_pad_strip_frame(void *data,
}; };
if (strip->position >= 0) { 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) { if (strip->stopped) {
evt.position = -1; 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; 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, static void handle_tablet_pad_group_buttons(void *data,
struct zwp_tablet_pad_group_v2 *pad_group, struct zwp_tablet_pad_group_v2 *pad_group,
struct wl_array *buttons) { struct wl_array *buttons) {
struct wlr_wl_tablet_pad_group *group = data; struct tablet_pad_group *group = data;
free(group->group.buttons); free(group->group.buttons);
group->group.buttons = calloc(1, buttons->size); 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, static void handle_tablet_pad_group_modes(void *data,
struct zwp_tablet_pad_group_v2 *pad_group, uint32_t modes) { 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; 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, static void handle_tablet_pad_group_ring(void *data,
struct zwp_tablet_pad_group_v2 *pad_group, struct zwp_tablet_pad_group_v2 *pad_group,
struct zwp_tablet_pad_ring_v2 *ring) { struct zwp_tablet_pad_ring_v2 *ring) {
struct wlr_wl_tablet_pad_group *group = data; struct tablet_pad_group *group = data;
struct wlr_wl_tablet_pad_ring *tablet_ring = struct tablet_pad_ring *tablet_ring =
calloc(1, sizeof(struct wlr_wl_tablet_pad_ring)); calloc(1, sizeof(struct tablet_pad_ring));
if (!tablet_ring) { if (!tablet_ring) {
zwp_tablet_pad_ring_v2_destroy(ring); zwp_tablet_pad_ring_v2_destroy(ring);
return; return;
@ -237,9 +226,9 @@ static void handle_tablet_pad_group_ring(void *data,
static void handle_tablet_pad_group_strip(void *data, static void handle_tablet_pad_group_strip(void *data,
struct zwp_tablet_pad_group_v2 *pad_group, struct zwp_tablet_pad_group_v2 *pad_group,
struct zwp_tablet_pad_strip_v2 *strip) { struct zwp_tablet_pad_strip_v2 *strip) {
struct wlr_wl_tablet_pad_group *group = data; struct tablet_pad_group *group = data;
struct wlr_wl_tablet_pad_strip *tablet_strip = struct tablet_pad_strip *tablet_strip =
calloc(1, sizeof(struct wlr_wl_tablet_pad_strip)); calloc(1, sizeof(struct tablet_pad_strip));
if (!tablet_strip) { if (!tablet_strip) {
zwp_tablet_pad_strip_v2_destroy(strip); zwp_tablet_pad_strip_v2_destroy(strip);
return; return;
@ -263,25 +252,20 @@ static void handle_tablet_pad_group_done(void *data,
static void handle_tablet_pad_group_mode_switch(void *data, static void handle_tablet_pad_group_mode_switch(void *data,
struct zwp_tablet_pad_group_v2 *pad_group, struct zwp_tablet_pad_group_v2 *pad_group,
uint32_t time, uint32_t serial, uint32_t mode) { 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; group->mode = mode;
} }
/* This isn't in the listener, but keep the naming scheme around since the static void destroy_tablet_pad_group(struct tablet_pad_group *group) {
* 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) {
/* No need to remove the ::link on strips rings as long as we do *not* /* 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 */ * 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) { wl_list_for_each_safe(ring, tmp_ring, &group->rings, link) {
zwp_tablet_pad_ring_v2_destroy(ring->ring); zwp_tablet_pad_ring_v2_destroy(ring->ring);
free(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) { wl_list_for_each_safe(strip, tmp_strip, &group->strips, link) {
zwp_tablet_pad_strip_v2_destroy(strip->strip); zwp_tablet_pad_strip_v2_destroy(strip->strip);
free(strip); free(strip);
@ -289,10 +273,11 @@ static void handle_tablet_pad_group_removed(
zwp_tablet_pad_group_v2_destroy(group->pad_group); zwp_tablet_pad_group_v2_destroy(group->pad_group);
/* While I'm pretty sure we have control over this as well, it's free(group->group.buttons);
* outside the scope of a single function, so better be safe than free(group->group.strips);
* sorry */ free(group->group.rings);
wl_list_remove(&group->group.link); wl_list_remove(&group->group.link);
free(group); 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, static void handle_tablet_pad_group(void *data,
struct zwp_tablet_pad_v2 *zwp_tablet_pad, struct zwp_tablet_pad_v2 *zwp_tablet_pad,
struct zwp_tablet_pad_group_v2 *pad_group) { struct zwp_tablet_pad_group_v2 *pad_group) {
struct wlr_wl_input_device *dev = data; struct wlr_wl_seat *seat = data;
struct wlr_tablet_pad *pad = dev->wlr_input_device.tablet_pad; struct wlr_tablet_pad *pad = &seat->wlr_tablet_pad;
struct wlr_wl_tablet_pad_group *group = struct tablet_pad_group *group =
calloc(1, sizeof(struct wlr_wl_tablet_pad_group)); calloc(1, sizeof(struct tablet_pad_group));
if (!group) { if (!group) {
wlr_log_errno(WLR_ERROR, "failed to allocate tablet_pad_group");
zwp_tablet_pad_group_v2_destroy(pad_group); zwp_tablet_pad_group_v2_destroy(pad_group);
return; return;
} }
@ -330,20 +316,18 @@ static void handle_tablet_pad_group(void *data,
} }
static void handle_tablet_pad_path(void *data, static void handle_tablet_pad_path(void *data,
struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, const char *path) {
const char *path) { struct wlr_wl_seat *seat = data;
struct wlr_wl_input_device *dev = data; struct wlr_tablet_pad *tablet_pad = &seat->wlr_tablet_pad;
struct wlr_tablet_pad *tablet_pad = dev->wlr_input_device.tablet_pad;
char **dst = wl_array_add(&tablet_pad->paths, sizeof(char *)); char **dst = wl_array_add(&tablet_pad->paths, sizeof(char *));
*dst = strdup(path); *dst = strdup(path);
} }
static void handle_tablet_pad_buttons(void *data, static void handle_tablet_pad_buttons(void *data,
struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, uint32_t buttons) {
uint32_t buttons) { struct wlr_wl_seat *seat = data;
struct wlr_wl_input_device *dev = data; struct wlr_tablet_pad *tablet_pad = &seat->wlr_tablet_pad;
struct wlr_tablet_pad *tablet_pad = dev->wlr_input_device.tablet_pad;
tablet_pad->button_count = buttons; 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, static void handle_tablet_pad_button(void *data,
struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2,
uint32_t time, uint32_t button, uint32_t state) { uint32_t time, uint32_t button, uint32_t state) {
struct wlr_wl_input_device *dev = data; struct wlr_wl_seat *seat = data;
struct wlr_tablet_pad *tablet_pad = dev->wlr_input_device.tablet_pad; struct wlr_tablet_pad_button_event evt = {
struct wlr_event_tablet_pad_button evt = {
.time_msec = time, .time_msec = time,
.button = button, .button = button,
.state = state, .state = state,
@ -362,28 +344,25 @@ static void handle_tablet_pad_button(void *data,
.group = 0, .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, static void handle_tablet_pad_done(void *data,
struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2) { struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2) {
struct wlr_wl_input_device *dev = data; struct wlr_wl_seat *seat = data;
wl_signal_emit_mutable(&seat->backend->backend.events.new_input,
wlr_signal_emit_safe(&dev->backend->backend.events.new_input, &seat->wlr_tablet_pad.base);
&dev->wlr_input_device);
} }
static void handle_tablet_pad_enter(void *data, static void handle_tablet_pad_enter(void *data,
struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2, struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2,
uint32_t serial, struct zwp_tablet_v2 *tablet_p, uint32_t serial, struct zwp_tablet_v2 *tablet_p,
struct wl_surface *surface) { struct wl_surface *surface) {
struct wlr_wl_input_device *dev = data; struct wlr_wl_seat *seat = data;
struct wlr_tablet_pad *tablet_pad = dev->wlr_input_device.tablet_pad; assert(seat->zwp_tablet_v2 == tablet_p);
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);
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, 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, static void handle_tablet_pad_removed(void *data,
struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2) { struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2) {
struct wlr_wl_input_device *dev = data; struct wlr_wl_seat *seat = data;
struct wlr_tablet_pad *tablet_pad = dev->wlr_input_device.tablet_pad;
/* This doesn't free anything, but emits the destroy signal */ struct wlr_tablet_pad *tablet_pad = &seat->wlr_tablet_pad;
wlr_input_device_destroy(&dev->wlr_input_device); struct tablet_pad_group *group, *it;
/* 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;
wl_list_for_each_safe(group, it, &tablet_pad->groups, group.link) { 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_finish(tablet_pad);
wlr_tablet_pad_destroy(tablet_pad); zwp_tablet_pad_v2_destroy(seat->zwp_tablet_pad_v2);
zwp_tablet_pad_v2_destroy(dev->resource); seat->zwp_tablet_pad_v2 = NULL;
free(dev);
} }
static const struct zwp_tablet_pad_v2_listener tablet_pad_listener = { 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, .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, static void handle_pad_added(void *data,
struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2,
struct zwp_tablet_pad_v2 *id) { struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2) {
wlr_log(WLR_DEBUG, "New tablet pad");
struct wlr_wl_seat *seat = data; struct wlr_wl_seat *seat = data;
struct wlr_wl_input_device *dev = create_wl_input_device( if (seat->zwp_tablet_pad_v2 != NULL) {
seat, WLR_INPUT_DEVICE_TABLET_PAD); wlr_log(WLR_ERROR, "zwp_tablet_pad_v2 is already present");
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);
return; return;
} }
dev->resource = id; seat->zwp_tablet_pad_v2 = zwp_tablet_pad_v2;
struct wlr_input_device *wlr_dev = &dev->wlr_input_device; zwp_tablet_pad_v2_add_listener(zwp_tablet_pad_v2, &tablet_pad_listener,
wlr_dev->tablet_pad = calloc(1, sizeof(*wlr_dev->tablet_pad)); seat);
if (!wlr_dev->tablet_pad) { wlr_tablet_pad_init(&seat->wlr_tablet_pad, &wl_tablet_pad_impl,
/* This leaks a couple of server-sent resource ids. iirc this "wlr_tablet_v2");
* 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);
} }
static void handle_tablet_tool_done(void *data, static void handle_tablet_tool_done(void *data,
@ -463,7 +424,8 @@ static void handle_tablet_tool_done(void *data,
/* empty */ /* 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) { switch (type) {
case ZWP_TABLET_TOOL_V2_TYPE_PEN: case ZWP_TABLET_TOOL_V2_TYPE_PEN:
return WLR_TABLET_TOOL_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, static void handle_tablet_tool_type(void *data,
struct zwp_tablet_tool_v2 *id, struct zwp_tablet_tool_v2 *id, uint32_t tool_type) {
uint32_t tool_type) { struct tablet_tool *tool = data;
struct wlr_wl_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);
tool->wlr_tool.type = tablet_type_to_wlr_type(tool_type);
} }
static void handle_tablet_tool_serial(void *data, static void handle_tablet_tool_serial(void *data,
struct zwp_tablet_tool_v2 *id, struct zwp_tablet_tool_v2 *id, uint32_t high, uint32_t low) {
uint32_t high, uint32_t low) { struct tablet_tool *tool = data;
struct wlr_wl_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;
tool->wlr_tool.hardware_serial =
((uint64_t) high) << 32 | (uint64_t) low;
} }
static void handle_tablet_tool_id_wacom(void *data, static void handle_tablet_tool_id_wacom(void *data,
struct zwp_tablet_tool_v2 *id, struct zwp_tablet_tool_v2 *id, uint32_t high, uint32_t low) {
uint32_t high, uint32_t low) { struct tablet_tool *tool = data;
struct wlr_wl_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;
tool->wlr_tool.hardware_wacom =
((uint64_t) high) << 32 | (uint64_t) low;
} }
static void handle_tablet_tool_capability(void *data, static void handle_tablet_tool_capability(void *data,
struct zwp_tablet_tool_v2 *id, struct zwp_tablet_tool_v2 *id, uint32_t capability) {
uint32_t capability) { struct tablet_tool *tool = data;
struct wlr_wl_tablet_tool *tool = data; struct wlr_tablet_tool *wlr_tool = &tool->seat->wlr_tablet_tool;
enum zwp_tablet_tool_v2_capability cap = capability; /* One event is sent for each capability */
switch (capability) {
switch (cap) {
case ZWP_TABLET_TOOL_V2_CAPABILITY_TILT: case ZWP_TABLET_TOOL_V2_CAPABILITY_TILT:
tool->wlr_tool.tilt = true; wlr_tool->tilt = true;
break; break;
case ZWP_TABLET_TOOL_V2_CAPABILITY_PRESSURE: case ZWP_TABLET_TOOL_V2_CAPABILITY_PRESSURE:
tool->wlr_tool.pressure = true; wlr_tool->pressure = true;
break; break;
case ZWP_TABLET_TOOL_V2_CAPABILITY_DISTANCE: case ZWP_TABLET_TOOL_V2_CAPABILITY_DISTANCE:
tool->wlr_tool.distance = true; wlr_tool->distance = true;
break; break;
case ZWP_TABLET_TOOL_V2_CAPABILITY_ROTATION: case ZWP_TABLET_TOOL_V2_CAPABILITY_ROTATION:
tool->wlr_tool.rotation = true; wlr_tool->rotation = true;
break; break;
case ZWP_TABLET_TOOL_V2_CAPABILITY_SLIDER: case ZWP_TABLET_TOOL_V2_CAPABILITY_SLIDER:
tool->wlr_tool.slider = true; wlr_tool->slider = true;
break; break;
case ZWP_TABLET_TOOL_V2_CAPABILITY_WHEEL: case ZWP_TABLET_TOOL_V2_CAPABILITY_WHEEL:
tool->wlr_tool.wheel = true; wlr_tool->wheel = true;
break; break;
} }
} }
static void handle_tablet_tool_proximity_in(void *data, static void handle_tablet_tool_proximity_in(void *data,
struct zwp_tablet_tool_v2 *id, uint32_t serial, struct zwp_tablet_tool_v2 *id, uint32_t serial,
struct zwp_tablet_v2 *tablet_id, struct zwp_tablet_v2 *tablet_id, struct wl_surface *surface) {
struct wl_surface *surface) { struct tablet_tool *tool = data;
struct wlr_wl_tablet_tool *tool = data; assert(tablet_id == tool->seat->zwp_tablet_v2);
tool->is_in = true; tool->is_in = true;
tool->tablet = zwp_tablet_v2_get_user_data(tablet_id);
tool->output = wl_surface_get_user_data(surface); tool->output = wl_surface_get_user_data(surface);
} }
static void handle_tablet_tool_proximity_out(void *data, static void handle_tablet_tool_proximity_out(void *data,
struct zwp_tablet_tool_v2 *id) { struct zwp_tablet_tool_v2 *id) {
struct wlr_wl_tablet_tool *tool = data; struct tablet_tool *tool = data;
tool->is_out = true; tool->is_out = true;
tool->output = NULL; tool->output = NULL;
} }
static void handle_tablet_tool_down(void *data, static void handle_tablet_tool_down(void *data, struct zwp_tablet_tool_v2 *id,
struct zwp_tablet_tool_v2 *id,
unsigned int serial) { unsigned int serial) {
struct wlr_wl_tablet_tool *tool = data; struct tablet_tool *tool = data;
tool->is_down = true; tool->is_down = true;
} }
static void handle_tablet_tool_up(void *data, static void handle_tablet_tool_up(void *data, struct zwp_tablet_tool_v2 *id) {
struct zwp_tablet_tool_v2 *id) { struct tablet_tool *tool = data;
struct wlr_wl_tablet_tool *tool = data;
tool->is_up = true; tool->is_up = true;
} }
static void handle_tablet_tool_motion(void *data, static void handle_tablet_tool_motion(void *data, struct zwp_tablet_tool_v2 *id,
struct zwp_tablet_tool_v2 *id,
wl_fixed_t x, wl_fixed_t y) { 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; struct wlr_wl_output *output = tool->output;
assert(output); assert(output);
@ -584,68 +537,63 @@ static void handle_tablet_tool_motion(void *data,
} }
static void handle_tablet_tool_pressure(void *data, static void handle_tablet_tool_pressure(void *data,
struct zwp_tablet_tool_v2 *id, struct zwp_tablet_tool_v2 *id, uint32_t pressure) {
uint32_t pressure) { struct tablet_tool *tool = data;
struct wlr_wl_tablet_tool *tool = data;
tool->pressure = (double) pressure / 65535.0; tool->pressure = (double) pressure / 65535.0;
} }
static void handle_tablet_tool_distance(void *data, static void handle_tablet_tool_distance(void *data,
struct zwp_tablet_tool_v2 *id, struct zwp_tablet_tool_v2 *id, uint32_t distance) {
uint32_t distance) { struct tablet_tool *tool = data;
struct wlr_wl_tablet_tool *tool = data;
tool->distance = (double) distance / 65535.0; tool->distance = (double) distance / 65535.0;
} }
static void handle_tablet_tool_tilt(void *data, static void handle_tablet_tool_tilt(void *data, struct zwp_tablet_tool_v2 *id,
struct zwp_tablet_tool_v2 *id,
wl_fixed_t x, wl_fixed_t y) { 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_x = wl_fixed_to_double(x);
tool->tilt_y = wl_fixed_to_double(y); tool->tilt_y = wl_fixed_to_double(y);
} }
static void handle_tablet_tool_rotation(void *data, static void handle_tablet_tool_rotation(void *data,
struct zwp_tablet_tool_v2 *id, struct zwp_tablet_tool_v2 *id, wl_fixed_t rotation) {
wl_fixed_t rotation) { struct tablet_tool *tool = data;
struct wlr_wl_tablet_tool *tool = data;
tool->rotation = wl_fixed_to_double(rotation); tool->rotation = wl_fixed_to_double(rotation);
} }
static void handle_tablet_tool_slider(void *data, static void handle_tablet_tool_slider(void *data, struct zwp_tablet_tool_v2 *id,
struct zwp_tablet_tool_v2 *id,
int slider) { int slider) {
struct wlr_wl_tablet_tool *tool = data; struct tablet_tool *tool = data;
tool->slider = (double) slider / 65535.0;; tool->slider = (double) slider / 65535.0;;
} }
// TODO: This looks wrong :/ // TODO: This looks wrong :/
static void handle_tablet_tool_wheel(void *data, static void handle_tablet_tool_wheel(void *data, struct zwp_tablet_tool_v2 *id,
struct zwp_tablet_tool_v2 *id,
wl_fixed_t degree, int clicks) { 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); tool->wheel_delta = wl_fixed_to_double(degree);
} }
static void handle_tablet_tool_button(void *data, static void handle_tablet_tool_button(void *data,
struct zwp_tablet_tool_v2 *id, struct zwp_tablet_tool_v2 *id,
uint32_t serial, uint32_t button, uint32_t state) { uint32_t serial, uint32_t button, uint32_t state) {
struct wlr_wl_tablet_tool *tool = data; struct tablet_tool *tool = data;
struct wlr_tablet *tablet = tool->tablet->wlr_input_device.tablet; struct wlr_wl_seat *seat = tool->seat;
struct wlr_tablet *tablet = &seat->wlr_tablet;
struct wlr_event_tablet_tool_button evt = { struct wlr_tablet_tool_button_event evt = {
.device = &tool->tablet->wlr_input_device, .tablet = tablet,
.tool = &tool->wlr_tool, .tool = &seat->wlr_tablet_tool,
.time_msec = get_current_time_msec(), .time_msec = get_current_time_msec(),
.button = button, .button = button,
.state = state == ZWP_TABLET_TOOL_V2_BUTTON_STATE_RELEASED ? .state = state == ZWP_TABLET_TOOL_V2_BUTTON_STATE_RELEASED ?
WLR_BUTTON_RELEASED : WLR_BUTTON_PRESSED, 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_out = tool->is_in = false;
tool->is_up = tool->is_down = false; tool->is_up = tool->is_down = false;
tool->x = tool->y = NAN; 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, static void handle_tablet_tool_frame(void *data,
struct zwp_tablet_tool_v2 *id, struct zwp_tablet_tool_v2 *id,
uint32_t time) { 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) { if (tool->is_out && tool->is_in) {
/* we got a tablet tool coming in and out of proximity before /* we got a tablet tool coming in and out of proximity before
* we could process it. Just ignore anything it did */ * we could process it. Just ignore anything it did */
goto clear_values; goto clear_values;
} }
struct wlr_tablet *tablet = tool->tablet->wlr_input_device.tablet; struct wlr_tablet *tablet = &seat->wlr_tablet;
if (tool->is_in) { if (tool->is_in) {
struct wlr_event_tablet_tool_proximity evt = { struct wlr_tablet_tool_proximity_event evt = {
.device = &tool->tablet->wlr_input_device, .tablet = tablet,
.tool = &tool->wlr_tool, .tool = &seat->wlr_tablet_tool,
.time_msec = time, .time_msec = time,
.x = tool->x, .x = tool->x,
.y = tool->y, .y = tool->y,
.state = WLR_TABLET_TOOL_PROXIMITY_IN, .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 = { struct wlr_tablet_tool_axis_event evt = {
.device = &tool->tablet->wlr_input_device, .tablet = tablet,
.tool = &tool->wlr_tool, .tool = &seat->wlr_tablet_tool,
.time_msec = time, .time_msec = time,
.updated_axes = 0, .updated_axes = 0,
}; };
@ -735,7 +685,7 @@ static void handle_tablet_tool_frame(void *data,
} }
if (evt.updated_axes) { 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 * Downside: Here we have the frame time, if we sent right away, we
* need to generate the time */ * need to generate the time */
if (tool->is_down) { if (tool->is_down) {
struct wlr_event_tablet_tool_tip evt = { struct wlr_tablet_tool_tip_event evt = {
.device = &tool->tablet->wlr_input_device, .tablet = tablet,
.tool = &tool->wlr_tool, .tool = &seat->wlr_tablet_tool,
.time_msec = time, .time_msec = time,
.x = tool->x, .x = tool->x,
.y = tool->y, .y = tool->y,
.state = WLR_TABLET_TOOL_TIP_DOWN, .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) { if (tool->is_up) {
struct wlr_event_tablet_tool_tip evt = { struct wlr_tablet_tool_tip_event evt = {
.device = &tool->tablet->wlr_input_device, .tablet = tablet,
.tool = &tool->wlr_tool, .tool = &seat->wlr_tablet_tool,
.time_msec = time, .time_msec = time,
.x = tool->x, .x = tool->x,
.y = tool->y, .y = tool->y,
.state = WLR_TABLET_TOOL_TIP_UP, .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) { if (tool->is_out) {
struct wlr_event_tablet_tool_proximity evt = { struct wlr_tablet_tool_proximity_event evt = {
.device = &tool->tablet->wlr_input_device, .tablet = tablet,
.tool = &tool->wlr_tool, .tool = &seat->wlr_tablet_tool,
.time_msec = time, .time_msec = time,
.x = tool->x, .x = tool->x,
.y = tool->y, .y = tool->y,
.state = WLR_TABLET_TOOL_PROXIMITY_OUT, .state = WLR_TABLET_TOOL_PROXIMITY_OUT,
}; };
wlr_signal_emit_safe(&tablet->events.proximity, &evt); wl_signal_emit_mutable(&tablet->events.proximity, &evt);
} }
clear_values: clear_values:
@ -789,10 +739,12 @@ clear_values:
static void handle_tablet_tool_removed(void *data, static void handle_tablet_tool_removed(void *data,
struct zwp_tablet_tool_v2 *id) { 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); free(tool);
} }
@ -822,62 +774,71 @@ static const struct zwp_tablet_tool_v2_listener tablet_tool_listener = {
static void handle_tool_added(void *data, static void handle_tool_added(void *data,
struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2,
struct zwp_tablet_tool_v2 *id) { struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2) {
wlr_log(WLR_DEBUG, "New tablet tool"); struct wlr_wl_seat *seat = data;
struct wlr_wl_tablet_tool *tool = calloc(1, sizeof(*tool)); if (seat->zwp_tablet_tool_v2 != NULL) {
if (!tool) { wlr_log(WLR_ERROR, "zwp_tablet_tool_v2 already present");
zwp_tablet_tool_v2_destroy(id);
return; 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); 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, static void handle_tablet_name(void *data, struct zwp_tablet_v2 *zwp_tablet_v2,
const char *name) { const char *name) {
struct wlr_wl_input_device *dev = data; struct wlr_wl_seat *seat = data;
struct wlr_tablet *tablet = dev->wlr_input_device.tablet; struct wlr_tablet *tablet = &seat->wlr_tablet;
free(tablet->name); free(tablet->base.name);
tablet->name = strdup(name); tablet->base.name = strdup(name);
} }
static void handle_tablet_id(void *data, struct zwp_tablet_v2 *zwp_tablet_v2, static void handle_tablet_id(void *data, struct zwp_tablet_v2 *zwp_tablet_v2,
uint32_t vid, uint32_t pid) { uint32_t vid, uint32_t pid) {
struct wlr_wl_input_device *dev = data; struct wlr_wl_seat *seat = data;
dev->wlr_input_device.vendor = vid; struct wlr_tablet *tablet = &seat->wlr_tablet;
dev->wlr_input_device.product = pid;
tablet->base.vendor = vid;
tablet->base.product = pid;
} }
static void handle_tablet_path(void *data, struct zwp_tablet_v2 *zwp_tablet_v2, static void handle_tablet_path(void *data, struct zwp_tablet_v2 *zwp_tablet_v2,
const char *path) { const char *path) {
struct wlr_wl_input_device *dev = data; struct wlr_wl_seat *seat = data;
struct wlr_tablet *tablet = dev->wlr_input_device.tablet; struct wlr_tablet *tablet = &seat->wlr_tablet;
char **dst = wl_array_add(&tablet->paths, sizeof(char *)); char **dst = wl_array_add(&tablet->paths, sizeof(char *));
*dst = strdup(path); *dst = strdup(path);
} }
static void handle_tablet_done(void *data, struct zwp_tablet_v2 *zwp_tablet_v2) { 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, wl_signal_emit_mutable(&seat->backend->backend.events.new_input,
&dev->wlr_input_device); &seat->wlr_tablet.base);
} }
static void handle_tablet_removed(void *data, static void handle_tablet_removed(void *data,
struct zwp_tablet_v2 *zwp_tablet_v2) { 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_tablet_finish(&seat->wlr_tablet);
wlr_input_device_destroy(&dev->wlr_input_device); zwp_tablet_v2_destroy(seat->zwp_tablet_v2);
/* This is a bit ugly, but we need to remove it from our list */ seat->zwp_tablet_v2 = NULL;
wl_list_remove(&dev->link);
zwp_tablet_v2_destroy(dev->resource);
free(dev);
} }
static const struct zwp_tablet_v2_listener tablet_listener = { 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, .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, static void handle_tab_added(void *data,
struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2, struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2,
struct zwp_tablet_v2 *id) { struct zwp_tablet_v2 *zwp_tablet_v2) {
wlr_log(WLR_DEBUG, "New tablet");
struct wlr_wl_seat *seat = data; struct wlr_wl_seat *seat = data;
struct wlr_wl_input_device *dev = create_wl_input_device( if (seat->zwp_tablet_v2 != NULL) {
seat, WLR_INPUT_DEVICE_TABLET_TOOL); wlr_log(WLR_ERROR, "zwp_tablet_v2 already present");
if (!dev) {
zwp_tablet_v2_destroy(id);
return; return;
} }
dev->resource = id;
struct wlr_input_device *wlr_dev = &dev->wlr_input_device; seat->zwp_tablet_v2 = zwp_tablet_v2;
wlr_dev->tablet = calloc(1, sizeof(*wlr_dev->tablet)); zwp_tablet_v2_add_listener(zwp_tablet_v2, &tablet_listener, seat);
if (!wlr_dev->tablet) { wlr_tablet_init(&seat->wlr_tablet, &wl_tablet_impl, "wlr_tablet_v2");
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);
} }
static const struct zwp_tablet_seat_v2_listener tablet_seat_listener = { 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, .pad_added = handle_pad_added,
}; };
struct wlr_wl_tablet_seat *wl_add_tablet_seat( void init_seat_tablet(struct wlr_wl_seat *seat) {
struct zwp_tablet_manager_v2 *manager, struct zwp_tablet_manager_v2 *manager = seat->backend->tablet_manager;
struct wlr_wl_seat *seat) { assert(manager);
struct wlr_wl_tablet_seat *ret =
calloc(1, sizeof(struct wlr_wl_tablet_seat));
if (!(ret->tablet_seat = /**
zwp_tablet_manager_v2_get_tablet_seat(manager, seat->wl_seat))) { * TODO: multi tablet support
free(ret); * The wlr_wl_seat should support multiple tablet_v2 devices, but for
return NULL; * 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); &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 "backend/x11.h"
#include "render/drm_format_set.h" #include "render/drm_format_set.h"
#include "util/signal.h"
// See dri2_format_for_depth in mesa // See dri2_format_for_depth in mesa
const struct wlr_x11_format formats[] = { 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_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) { for (size_t i = 0; i < x11->requested_outputs; ++i) {
wlr_x11_output_create(&x11->backend); 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_output_destroy(&output->wlr_output);
} }
wlr_keyboard_destroy(&x11->keyboard); wlr_keyboard_finish(&x11->keyboard);
wlr_backend_finish(backend); wlr_backend_finish(backend);
@ -637,7 +636,8 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_display *display,
} }
#endif #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; x11->display_destroy.notify = handle_display_destroy;
wl_display_add_destroy_listener(display, &x11->display_destroy); wl_display_add_destroy_listener(display, &x11->display_destroy);

View file

@ -16,11 +16,10 @@
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include "backend/x11.h" #include "backend/x11.h"
#include "util/signal.h"
static void send_key_event(struct wlr_x11_backend *x11, uint32_t key, static void send_key_event(struct wlr_x11_backend *x11, uint32_t key,
enum wl_keyboard_key_state st, xcb_timestamp_t time) { 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, .time_msec = time,
.keycode = key, .keycode = key,
.state = st, .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, static void send_button_event(struct wlr_x11_output *output, uint32_t key,
enum wlr_button_state st, xcb_timestamp_t time) { enum wlr_button_state st, xcb_timestamp_t time) {
struct wlr_event_pointer_button ev = { struct wlr_pointer_button_event ev = {
.device = &output->pointer.base, .pointer = &output->pointer,
.time_msec = time, .time_msec = time,
.button = key, .button = key,
.state = st, .state = st,
}; };
wlr_signal_emit_safe(&output->pointer.events.button, &ev); wl_signal_emit_mutable(&output->pointer.events.button, &ev);
wlr_signal_emit_safe(&output->pointer.events.frame, &output->pointer); wl_signal_emit_mutable(&output->pointer.events.frame, &output->pointer);
} }
static void send_axis_event(struct wlr_x11_output *output, int32_t delta, static void send_axis_event(struct wlr_x11_output *output, int32_t delta,
xcb_timestamp_t time) { xcb_timestamp_t time) {
struct wlr_event_pointer_axis ev = { struct wlr_pointer_axis_event ev = {
.device = &output->pointer.base, .pointer = &output->pointer,
.time_msec = time, .time_msec = time,
.source = WLR_AXIS_SOURCE_WHEEL, .source = WLR_AXIS_SOURCE_WHEEL,
.orientation = WLR_AXIS_ORIENTATION_VERTICAL, .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 = delta * 15,
.delta_discrete = delta, .delta_discrete = delta,
}; };
wlr_signal_emit_safe(&output->pointer.events.axis, &ev); wl_signal_emit_mutable(&output->pointer.events.axis, &ev);
wlr_signal_emit_safe(&output->pointer.events.frame, &output->pointer); wl_signal_emit_mutable(&output->pointer.events.frame, &output->pointer);
} }
static void send_pointer_position_event(struct wlr_x11_output *output, static void send_pointer_position_event(struct wlr_x11_output *output,
int16_t x, int16_t y, xcb_timestamp_t time) { int16_t x, int16_t y, xcb_timestamp_t time) {
struct wlr_event_pointer_motion_absolute ev = { struct wlr_pointer_motion_absolute_event ev = {
.device = &output->pointer.base, .pointer = &output->pointer,
.time_msec = time, .time_msec = time,
.x = (double)x / output->wlr_output.width, .x = (double)x / output->wlr_output.width,
.y = (double)y / output->wlr_output.height, .y = (double)y / output->wlr_output.height,
}; };
wlr_signal_emit_safe(&output->pointer.events.motion_absolute, &ev); wl_signal_emit_mutable(&output->pointer.events.motion_absolute, &ev);
wlr_signal_emit_safe(&output->pointer.events.frame, &output->pointer); wl_signal_emit_mutable(&output->pointer.events.frame, &output->pointer);
} }
static void send_touch_down_event(struct wlr_x11_output *output, 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) { int16_t x, int16_t y, int32_t touch_id, xcb_timestamp_t time) {
struct wlr_event_touch_down ev = { struct wlr_touch_down_event ev = {
.device = &output->touch.base, .touch = &output->touch,
.time_msec = time, .time_msec = time,
.x = (double)x / output->wlr_output.width, .x = (double)x / output->wlr_output.width,
.y = (double)y / output->wlr_output.height, .y = (double)y / output->wlr_output.height,
.touch_id = touch_id, .touch_id = touch_id,
}; };
wlr_signal_emit_safe(&output->touch.events.down, &ev); wl_signal_emit_mutable(&output->touch.events.down, &ev);
wlr_signal_emit_safe(&output->touch.events.frame, NULL); wl_signal_emit_mutable(&output->touch.events.frame, NULL);
} }
static void send_touch_motion_event(struct wlr_x11_output *output, 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) { int16_t x, int16_t y, int32_t touch_id, xcb_timestamp_t time) {
struct wlr_event_touch_motion ev = { struct wlr_touch_motion_event ev = {
.device = &output->touch.base, .touch = &output->touch,
.time_msec = time, .time_msec = time,
.x = (double)x / output->wlr_output.width, .x = (double)x / output->wlr_output.width,
.y = (double)y / output->wlr_output.height, .y = (double)y / output->wlr_output.height,
.touch_id = touch_id, .touch_id = touch_id,
}; };
wlr_signal_emit_safe(&output->touch.events.motion, &ev); wl_signal_emit_mutable(&output->touch.events.motion, &ev);
wlr_signal_emit_safe(&output->touch.events.frame, NULL); wl_signal_emit_mutable(&output->touch.events.frame, NULL);
} }
static void send_touch_up_event(struct wlr_x11_output *output, static void send_touch_up_event(struct wlr_x11_output *output,
int32_t touch_id, xcb_timestamp_t time) { int32_t touch_id, xcb_timestamp_t time) {
struct wlr_event_touch_up ev = { struct wlr_touch_up_event ev = {
.device = &output->touch.base, .touch = &output->touch,
.time_msec = time, .time_msec = time,
.touch_id = touch_id, .touch_id = touch_id,
}; };
wlr_signal_emit_safe(&output->touch.events.up, &ev); wl_signal_emit_mutable(&output->touch.events.up, &ev);
wlr_signal_emit_safe(&output->touch.events.frame, NULL); wl_signal_emit_mutable(&output->touch.events.frame, NULL);
} }
static struct wlr_x11_touchpoint *get_touchpoint_from_x11_touch_id( 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 = { 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 = { 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 = { const struct wlr_touch_impl x11_touch_impl = {
.destroy = touch_destroy, .name = "x11-touch",
}; };
void update_x11_pointer_position(struct wlr_x11_output *output, 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) { bool wlr_input_device_is_x11(struct wlr_input_device *wlr_dev) {
switch (wlr_dev->type) { switch (wlr_dev->type) {
case WLR_INPUT_DEVICE_KEYBOARD: 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: 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: 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: default:
return false; return false;
} }

View file

@ -21,24 +21,31 @@
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include "backend/x11.h" #include "backend/x11.h"
#include "util/signal.h"
#include "util/time.h" #include "util/time.h"
static const uint32_t SUPPORTED_OUTPUT_STATE = static const uint32_t SUPPORTED_OUTPUT_STATE =
WLR_OUTPUT_STATE_BACKEND_OPTIONAL | WLR_OUTPUT_STATE_BACKEND_OPTIONAL |
WLR_OUTPUT_STATE_BUFFER | 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, static void parse_xcb_setup(struct wlr_output *output,
xcb_connection_t *xcb) { xcb_connection_t *xcb) {
const xcb_setup_t *xcb_setup = xcb_get_setup(xcb); const xcb_setup_t *xcb_setup = xcb_get_setup(xcb);
snprintf(output->make, sizeof(output->make), "%.*s", output->make = calloc(1, xcb_setup_vendor_length(xcb_setup) + 1);
xcb_setup_vendor_length(xcb_setup), if (output->make == NULL) {
xcb_setup_vendor(xcb_setup)); wlr_log_errno(WLR_ERROR, "Allocation failed");
snprintf(output->model, sizeof(output->model), "%"PRIu16".%"PRIu16, return;
xcb_setup->protocol_major_version, }
xcb_setup->protocol_minor_version); 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( 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); pixman_region32_fini(&output->exposed);
wlr_pointer_destroy(&output->pointer); wlr_pointer_finish(&output->pointer);
wlr_touch_destroy(&output->touch); wlr_touch_finish(&output->touch);
struct wlr_x11_buffer *buffer, *buffer_tmp; struct wlr_x11_buffer *buffer, *buffer_tmp;
wl_list_for_each_safe(buffer, buffer_tmp, &output->buffers, link) { 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); free(output);
} }
static bool output_test(struct wlr_output *wlr_output) { static bool output_test(struct wlr_output *wlr_output,
uint32_t unsupported = const struct wlr_output_state *state) {
wlr_output->pending.committed & ~SUPPORTED_OUTPUT_STATE; uint32_t unsupported = state->committed & ~SUPPORTED_OUTPUT_STATE;
if (unsupported != 0) { if (unsupported != 0) {
wlr_log(WLR_DEBUG, "Unsupported output state fields: 0x%"PRIx32, wlr_log(WLR_DEBUG, "Unsupported output state fields: 0x%"PRIx32,
unsupported); unsupported);
return false; return false;
} }
if (wlr_output->pending.committed & WLR_OUTPUT_STATE_MODE) { // All we can do to influence adaptive sync on the X11 backend is set the
assert(wlr_output->pending.mode_type == WLR_OUTPUT_STATE_MODE_CUSTOM); // _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; return true;
@ -250,10 +268,11 @@ static struct wlr_x11_buffer *get_or_create_x11_buffer(
return create_x11_buffer(output, wlr_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_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 = struct wlr_x11_buffer *x11_buffer =
get_or_create_x11_buffer(output, buffer); get_or_create_x11_buffer(output, buffer);
if (!x11_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; xcb_xfixes_region_t region = XCB_NONE;
if (output->wlr_output.pending.committed & WLR_OUTPUT_STATE_DAMAGE) { if (state->committed & WLR_OUTPUT_STATE_DAMAGE) {
pixman_region32_union(&output->exposed, &output->exposed, &output->wlr_output.pending.damage); pixman_region32_union(&output->exposed, &output->exposed,
(pixman_region32_t *) &state->damage);
int rects_len = 0; int rects_len = 0;
pixman_box32_t *rects = pixman_region32_rectangles(&output->exposed, &rects_len); pixman_box32_t *rects = pixman_region32_rectangles(&output->exposed, &rects_len);
@ -308,40 +328,26 @@ error:
return false; 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_output *output = get_x11_output_from_output(wlr_output);
struct wlr_x11_backend *x11 = output->x11; struct wlr_x11_backend *x11 = output->x11;
if (!output_test(wlr_output)) { if (!output_test(wlr_output, state)) {
return false; 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, if (!output_set_custom_mode(wlr_output,
wlr_output->pending.custom_mode.width, state->custom_mode.width,
wlr_output->pending.custom_mode.height, state->custom_mode.height,
wlr_output->pending.custom_mode.refresh)) { state->custom_mode.refresh)) {
return false; return false;
} }
} }
if (wlr_output->pending.committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED && if (state->committed & WLR_OUTPUT_STATE_BUFFER) {
x11->atoms.variable_refresh != XCB_ATOM_NONE) { if (!output_commit_buffer(output, state)) {
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)) {
return false; 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_protocols, XCB_ATOM_ATOM, 32, 1,
&x11->atoms.wm_delete_window); &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); wlr_x11_output_set_title(wlr_output, NULL);
xcb_map_window(x11->xcb, output->win); 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_output_update_enabled(wlr_output, true);
wlr_pointer_init(&output->pointer, &x11_pointer_impl, "x11-pointer"); 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"); 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); wl_list_init(&output->touchpoints);
wlr_signal_emit_safe(&x11->backend.events.new_output, wlr_output); wl_signal_emit_mutable(&x11->backend.events.new_output, wlr_output);
wlr_signal_emit_safe(&x11->backend.events.new_input, &output->pointer.base); wl_signal_emit_mutable(&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_input, &output->touch.base);
// Start the rendering loop by requesting the compositor to render a frame // Start the rendering loop by requesting the compositor to render a frame
wlr_output_schedule_frame(wlr_output); wlr_output_schedule_frame(wlr_output);

View file

@ -45,6 +45,16 @@ wlroots reads these environment variables
* *WLR_RENDERER_ALLOW_SOFTWARE*: allows the gles2 renderer to use software * *WLR_RENDERER_ALLOW_SOFTWARE*: allows the gles2 renderer to use software
rendering rendering
## scenes
* *WLR_SCENE_DEBUG_DAMAGE*: specifies debug options for screen damage related
tasks for compositors that use scenes (available options: none, rerender,
highlight)
* *WLR_SCENE_DISABLE_DIRECT_SCANOUT*: disables direct scan-out for debugging.
* *WLR_SCENE_DISABLE_VISIBILITY*: If set to 1, the visibility of all scene nodes
will be considered to be the full node. Intelligent visibility canculations will
be disabled.
# Generic # Generic
* *DISPLAY*: if set probe X11 backend in `wlr_backend_autocreate` * *DISPLAY*: if set probe X11 backend in `wlr_backend_autocreate`

View file

@ -20,10 +20,10 @@ PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC eglCreatePlatformWindowSurfaceEXT;
const EGLint config_attribs[] = { const EGLint config_attribs[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RED_SIZE, 1, EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 1, EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 1, EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 1, EGL_ALPHA_SIZE, 8,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_NONE, EGL_NONE,
}; };

View file

@ -194,7 +194,7 @@ static void do_updates(void) {
update_stage++; update_stage++;
break; break;
case 2: case 2:
if (strcmp(current.surrounding.text, "_Commit_") != 0) { if (current.surrounding.text && strcmp(current.surrounding.text, "_Commit_") != 0) {
return; return;
} }
zwp_input_method_v2_commit_string(input_method, "_CommitNoPreed_"); zwp_input_method_v2_commit_string(input_method, "_CommitNoPreed_");
@ -203,7 +203,7 @@ static void do_updates(void) {
update_stage++; update_stage++;
break; break;
case 3: case 3:
if (strcmp(current.surrounding.text, "_Commit__CommitNoPreed_") != 0) { if (current.surrounding.text && strcmp(current.surrounding.text, "_Commit__CommitNoPreed_") != 0) {
return; return;
} }
zwp_input_method_v2_commit_string(input_method, "_WaitNo_"); zwp_input_method_v2_commit_string(input_method, "_WaitNo_");
@ -212,7 +212,7 @@ static void do_updates(void) {
update_stage++; update_stage++;
break; break;
case 4: case 4:
if (strcmp(current.surrounding.text, "_Commit__WaitNo_") != 0) { if (current.surrounding.text && strcmp(current.surrounding.text, "_Commit__WaitNo_") != 0) {
return; return;
} }
zwp_input_method_v2_set_preedit_string(input_method, "PreedWithDel", strlen("Preed"), strlen("Preed")); zwp_input_method_v2_set_preedit_string(input_method, "PreedWithDel", strlen("Preed"), strlen("Preed"));
@ -221,7 +221,7 @@ static void do_updates(void) {
update_stage++; update_stage++;
break; break;
case 5: case 5:
if (strcmp(current.surrounding.text, "_Commit_") != 0) { if (current.surrounding.text && strcmp(current.surrounding.text, "_Commit_") != 0) {
return; return;
} }
zwp_input_method_v2_delete_surrounding_text(input_method, strlen("mit_"), 0); zwp_input_method_v2_delete_surrounding_text(input_method, strlen("mit_"), 0);
@ -229,7 +229,7 @@ static void do_updates(void) {
update_stage++; update_stage++;
break; break;
case 6: case 6:
if (strcmp(current.surrounding.text, "_Com") != 0) { if (current.surrounding.text && strcmp(current.surrounding.text, "_Com") != 0) {
printf("Failed\n"); printf("Failed\n");
} }
update_stage++; update_stage++;

View file

@ -124,9 +124,10 @@ static void draw(void) {
glViewport(0, 0, width, height); glViewport(0, 0, width, height);
if (buttons) { if (buttons) {
glClearColor(1, 1, 1, alpha); glClearColor(alpha, alpha, alpha, alpha);
} else { } else {
glClearColor(demo.color[0], demo.color[1], demo.color[2], alpha); glClearColor(demo.color[0] * alpha, demo.color[1] * alpha,
demo.color[2] * alpha, alpha);
} }
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
@ -151,7 +152,8 @@ static void draw_popup(void) {
eglMakeCurrent(egl_display, popup_egl_surface, popup_egl_surface, egl_context); eglMakeCurrent(egl_display, popup_egl_surface, popup_egl_surface, egl_context);
glViewport(0, 0, popup_width, popup_height); glViewport(0, 0, popup_width, popup_height);
glClearColor(popup_red, 0.5f, 0.5f, popup_alpha); glClearColor(popup_red * popup_alpha, 0.5f * popup_alpha,
0.5f * popup_alpha, popup_alpha);
popup_alpha += alpha_mod; popup_alpha += alpha_mod;
if (popup_alpha < 0.01 || popup_alpha >= 1.0f) { if (popup_alpha < 0.01 || popup_alpha >= 1.0f) {
alpha_mod *= -1.0; alpha_mod *= -1.0;

View file

@ -5,6 +5,7 @@ wayland_client = dependency('wayland-client')
libpng = dependency('libpng', required: false, disabler: true) libpng = dependency('libpng', required: false, disabler: true)
egl = dependency('egl', required: false, disabler: true) egl = dependency('egl', required: false, disabler: true)
glesv2 = dependency('glesv2', required: false, disabler: true) glesv2 = dependency('glesv2', required: false, disabler: true)
gbm = dependency('gbm', required: false, disabler: true)
# These versions correspond to ffmpeg 4.0 # These versions correspond to ffmpeg 4.0
libavutil = dependency('libavutil', version: '>=56.14.100', required: false, disabler: true) libavutil = dependency('libavutil', version: '>=56.14.100', required: false, disabler: true)
libavcodec = dependency('libavcodec', version: '>=58.18.100', required: false, disabler: true) libavcodec = dependency('libavcodec', version: '>=58.18.100', required: false, disabler: true)

View file

@ -64,7 +64,7 @@ struct sample_output {
struct sample_keyboard { struct sample_keyboard {
struct sample_state *sample; struct sample_state *sample;
struct wlr_input_device *device; struct wlr_keyboard *wlr_keyboard;
struct wl_listener key; struct wl_listener key;
struct wl_listener destroy; struct wl_listener destroy;
}; };
@ -109,8 +109,8 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
static void handle_cursor_motion(struct wl_listener *listener, void *data) { static void handle_cursor_motion(struct wl_listener *listener, void *data) {
struct sample_cursor *cursor = struct sample_cursor *cursor =
wl_container_of(listener, cursor, cursor_motion); wl_container_of(listener, cursor, cursor_motion);
struct wlr_event_pointer_motion *event = data; struct wlr_pointer_motion_event *event = data;
wlr_cursor_move(cursor->cursor, event->device, event->delta_x, wlr_cursor_move(cursor->cursor, &event->pointer->base, event->delta_x,
event->delta_y); event->delta_y);
} }
@ -118,8 +118,9 @@ static void handle_cursor_motion_absolute(struct wl_listener *listener,
void *data) { void *data) {
struct sample_cursor *cursor = struct sample_cursor *cursor =
wl_container_of(listener, cursor, cursor_motion_absolute); wl_container_of(listener, cursor, cursor_motion_absolute);
struct wlr_event_pointer_motion_absolute *event = data; struct wlr_pointer_motion_absolute_event *event = data;
wlr_cursor_warp_absolute(cursor->cursor, event->device, event->x, event->y); wlr_cursor_warp_absolute(cursor->cursor, &event->pointer->base, event->x,
event->y);
} }
static void cursor_destroy(struct sample_cursor *cursor) { static void cursor_destroy(struct sample_cursor *cursor) {
@ -184,10 +185,10 @@ static void new_output_notify(struct wl_listener *listener, void *data) {
static void keyboard_key_notify(struct wl_listener *listener, void *data) { static void keyboard_key_notify(struct wl_listener *listener, void *data) {
struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, key); struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, key);
struct sample_state *sample = keyboard->sample; struct sample_state *sample = keyboard->sample;
struct wlr_event_keyboard_key *event = data; struct wlr_keyboard_key_event *event = data;
uint32_t keycode = event->keycode + 8; uint32_t keycode = event->keycode + 8;
const xkb_keysym_t *syms; const xkb_keysym_t *syms;
int nsyms = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, int nsyms = xkb_state_key_get_syms(keyboard->wlr_keyboard->xkb_state,
keycode, &syms); keycode, &syms);
for (int i = 0; i < nsyms; i++) { for (int i = 0; i < nsyms; i++) {
xkb_keysym_t sym = syms[i]; xkb_keysym_t sym = syms[i];
@ -210,11 +211,11 @@ static void new_input_notify(struct wl_listener *listener, void *data) {
switch (device->type) { switch (device->type) {
case WLR_INPUT_DEVICE_KEYBOARD:; case WLR_INPUT_DEVICE_KEYBOARD:;
struct sample_keyboard *keyboard = calloc(1, sizeof(struct sample_keyboard)); struct sample_keyboard *keyboard = calloc(1, sizeof(struct sample_keyboard));
keyboard->device = device; keyboard->wlr_keyboard = wlr_keyboard_from_input_device(device);
keyboard->sample = sample; keyboard->sample = sample;
wl_signal_add(&device->events.destroy, &keyboard->destroy); wl_signal_add(&device->events.destroy, &keyboard->destroy);
keyboard->destroy.notify = keyboard_destroy_notify; keyboard->destroy.notify = keyboard_destroy_notify;
wl_signal_add(&device->keyboard->events.key, &keyboard->key); wl_signal_add(&keyboard->wlr_keyboard->events.key, &keyboard->key);
keyboard->key.notify = keyboard_key_notify; keyboard->key.notify = keyboard_key_notify;
struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if (!context) { if (!context) {
@ -227,7 +228,7 @@ static void new_input_notify(struct wl_listener *listener, void *data) {
wlr_log(WLR_ERROR, "Failed to create XKB keymap"); wlr_log(WLR_ERROR, "Failed to create XKB keymap");
exit(1); exit(1);
} }
wlr_keyboard_set_keymap(device->keyboard, keymap); wlr_keyboard_set_keymap(keyboard->wlr_keyboard, keymap);
xkb_keymap_unref(keymap); xkb_keymap_unref(keymap);
xkb_context_unref(context); xkb_context_unref(context);
break; break;

View file

@ -45,7 +45,7 @@ struct sample_output {
struct sample_keyboard { struct sample_keyboard {
struct sample_state *sample; struct sample_state *sample;
struct wlr_input_device *device; struct wlr_keyboard *wlr_keyboard;
struct wl_listener key; struct wl_listener key;
struct wl_listener destroy; struct wl_listener destroy;
}; };
@ -183,10 +183,10 @@ static void new_output_notify(struct wl_listener *listener, void *data) {
static void keyboard_key_notify(struct wl_listener *listener, void *data) { static void keyboard_key_notify(struct wl_listener *listener, void *data) {
struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, key); struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, key);
struct sample_state *sample = keyboard->sample; struct sample_state *sample = keyboard->sample;
struct wlr_event_keyboard_key *event = data; struct wlr_keyboard_key_event *event = data;
uint32_t keycode = event->keycode + 8; uint32_t keycode = event->keycode + 8;
const xkb_keysym_t *syms; const xkb_keysym_t *syms;
int nsyms = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, int nsyms = xkb_state_key_get_syms(keyboard->wlr_keyboard->xkb_state,
keycode, &syms); keycode, &syms);
for (int i = 0; i < nsyms; i++) { for (int i = 0; i < nsyms; i++) {
xkb_keysym_t sym = syms[i]; xkb_keysym_t sym = syms[i];
@ -229,11 +229,11 @@ static void new_input_notify(struct wl_listener *listener, void *data) {
switch (device->type) { switch (device->type) {
case WLR_INPUT_DEVICE_KEYBOARD:; case WLR_INPUT_DEVICE_KEYBOARD:;
struct sample_keyboard *keyboard = calloc(1, sizeof(struct sample_keyboard)); struct sample_keyboard *keyboard = calloc(1, sizeof(struct sample_keyboard));
keyboard->device = device; keyboard->wlr_keyboard = wlr_keyboard_from_input_device(device);
keyboard->sample = sample; keyboard->sample = sample;
wl_signal_add(&device->events.destroy, &keyboard->destroy); wl_signal_add(&device->events.destroy, &keyboard->destroy);
keyboard->destroy.notify = keyboard_destroy_notify; keyboard->destroy.notify = keyboard_destroy_notify;
wl_signal_add(&device->keyboard->events.key, &keyboard->key); wl_signal_add(&keyboard->wlr_keyboard->events.key, &keyboard->key);
keyboard->key.notify = keyboard_key_notify; keyboard->key.notify = keyboard_key_notify;
struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if (!context) { if (!context) {
@ -246,7 +246,7 @@ static void new_input_notify(struct wl_listener *listener, void *data) {
wlr_log(WLR_ERROR, "Failed to create XKB keymap"); wlr_log(WLR_ERROR, "Failed to create XKB keymap");
exit(1); exit(1);
} }
wlr_keyboard_set_keymap(device->keyboard, keymap); wlr_keyboard_set_keymap(keyboard->wlr_keyboard, keymap);
xkb_keymap_unref(keymap); xkb_keymap_unref(keymap);
xkb_context_unref(context); xkb_context_unref(context);
break; break;

View file

@ -70,7 +70,7 @@ struct sample_output {
struct sample_keyboard { struct sample_keyboard {
struct sample_state *state; struct sample_state *state;
struct wlr_input_device *device; struct wlr_keyboard *wlr_keyboard;
struct wl_listener key; struct wl_listener key;
struct wl_listener destroy; struct wl_listener destroy;
}; };
@ -112,8 +112,8 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
static void handle_cursor_motion(struct wl_listener *listener, void *data) { static void handle_cursor_motion(struct wl_listener *listener, void *data) {
struct sample_state *sample = struct sample_state *sample =
wl_container_of(listener, sample, cursor_motion); wl_container_of(listener, sample, cursor_motion);
struct wlr_event_pointer_motion *event = data; struct wlr_pointer_motion_event *event = data;
wlr_cursor_move(sample->cursor, event->device, event->delta_x, wlr_cursor_move(sample->cursor, &event->pointer->base, event->delta_x,
event->delta_y); event->delta_y);
} }
@ -121,19 +121,19 @@ static void handle_cursor_motion_absolute(struct wl_listener *listener,
void *data) { void *data) {
struct sample_state *sample = struct sample_state *sample =
wl_container_of(listener, sample, cursor_motion_absolute); wl_container_of(listener, sample, cursor_motion_absolute);
struct wlr_event_pointer_motion_absolute *event = data; struct wlr_pointer_motion_absolute_event *event = data;
sample->cur_x = event->x; sample->cur_x = event->x;
sample->cur_y = event->y; sample->cur_y = event->y;
wlr_cursor_warp_absolute(sample->cursor, event->device, sample->cur_x, wlr_cursor_warp_absolute(sample->cursor, &event->pointer->base,
sample->cur_y); sample->cur_x, sample->cur_y);
} }
static void handle_cursor_button(struct wl_listener *listener, void *data) { static void handle_cursor_button(struct wl_listener *listener, void *data) {
struct sample_state *sample = struct sample_state *sample =
wl_container_of(listener, sample, cursor_button); wl_container_of(listener, sample, cursor_button);
struct wlr_event_pointer_button *event = data; struct wlr_pointer_button_event *event = data;
float (*color)[4]; float (*color)[4];
if (event->state == WLR_BUTTON_RELEASED) { if (event->state == WLR_BUTTON_RELEASED) {
@ -150,7 +150,7 @@ static void handle_cursor_button(struct wl_listener *listener, void *data) {
static void handle_cursor_axis(struct wl_listener *listener, void *data) { static void handle_cursor_axis(struct wl_listener *listener, void *data) {
struct sample_state *sample = struct sample_state *sample =
wl_container_of(listener, sample, cursor_axis); wl_container_of(listener, sample, cursor_axis);
struct wlr_event_pointer_axis *event = data; struct wlr_pointer_axis_event *event = data;
for (size_t i = 0; i < 3; ++i) { for (size_t i = 0; i < 3; ++i) {
sample->default_color[i] += event->delta > 0 ? -0.05f : 0.05f; sample->default_color[i] += event->delta > 0 ? -0.05f : 0.05f;
@ -168,7 +168,7 @@ static void handle_cursor_axis(struct wl_listener *listener, void *data) {
static void handle_touch_up(struct wl_listener *listener, void *data) { static void handle_touch_up(struct wl_listener *listener, void *data) {
struct sample_state *sample = wl_container_of(listener, sample, touch_up); struct sample_state *sample = wl_container_of(listener, sample, touch_up);
struct wlr_event_touch_up *event = data; struct wlr_touch_up_event *event = data;
struct touch_point *point, *tmp; struct touch_point *point, *tmp;
wl_list_for_each_safe(point, tmp, &sample->touch_points, link) { wl_list_for_each_safe(point, tmp, &sample->touch_points, link) {
@ -178,25 +178,25 @@ static void handle_touch_up(struct wl_listener *listener, void *data) {
} }
} }
warp_to_touch(sample, event->device); warp_to_touch(sample, &event->touch->base);
} }
static void handle_touch_down(struct wl_listener *listener, void *data) { static void handle_touch_down(struct wl_listener *listener, void *data) {
struct sample_state *sample = wl_container_of(listener, sample, touch_down); struct sample_state *sample = wl_container_of(listener, sample, touch_down);
struct wlr_event_touch_down *event = data; struct wlr_touch_down_event *event = data;
struct touch_point *point = calloc(1, sizeof(struct touch_point)); struct touch_point *point = calloc(1, sizeof(struct touch_point));
point->touch_id = event->touch_id; point->touch_id = event->touch_id;
point->x = event->x; point->x = event->x;
point->y = event->y; point->y = event->y;
wl_list_insert(&sample->touch_points, &point->link); wl_list_insert(&sample->touch_points, &point->link);
warp_to_touch(sample, event->device); warp_to_touch(sample, &event->touch->base);
} }
static void handle_touch_motion(struct wl_listener *listener, void *data) { static void handle_touch_motion(struct wl_listener *listener, void *data) {
struct sample_state *sample = struct sample_state *sample =
wl_container_of(listener, sample, touch_motion); wl_container_of(listener, sample, touch_motion);
struct wlr_event_touch_motion *event = data; struct wlr_touch_motion_event *event = data;
struct touch_point *point; struct touch_point *point;
wl_list_for_each(point, &sample->touch_points, link) { wl_list_for_each(point, &sample->touch_points, link) {
@ -207,7 +207,7 @@ static void handle_touch_motion(struct wl_listener *listener, void *data) {
} }
} }
warp_to_touch(sample, event->device); warp_to_touch(sample, &event->touch->base);
} }
static void handle_touch_cancel(struct wl_listener *listener, void *data) { static void handle_touch_cancel(struct wl_listener *listener, void *data) {
@ -217,21 +217,21 @@ static void handle_touch_cancel(struct wl_listener *listener, void *data) {
static void handle_tablet_tool_axis(struct wl_listener *listener, void *data) { static void handle_tablet_tool_axis(struct wl_listener *listener, void *data) {
struct sample_state *sample = struct sample_state *sample =
wl_container_of(listener, sample, tablet_tool_axis); wl_container_of(listener, sample, tablet_tool_axis);
struct wlr_event_tablet_tool_axis *event = data; struct wlr_tablet_tool_axis_event *event = data;
if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_X) && if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_X) &&
(event->updated_axes & WLR_TABLET_TOOL_AXIS_Y)) { (event->updated_axes & WLR_TABLET_TOOL_AXIS_Y)) {
wlr_cursor_warp_absolute(sample->cursor, wlr_cursor_warp_absolute(sample->cursor, &event->tablet->base,
event->device, event->x, event->y); event->x, event->y);
} }
} }
static void keyboard_key_notify(struct wl_listener *listener, void *data) { static void keyboard_key_notify(struct wl_listener *listener, void *data) {
struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, key); struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, key);
struct sample_state *sample = keyboard->state; struct sample_state *sample = keyboard->state;
struct wlr_event_keyboard_key *event = data; struct wlr_keyboard_key_event *event = data;
uint32_t keycode = event->keycode + 8; uint32_t keycode = event->keycode + 8;
const xkb_keysym_t *syms; const xkb_keysym_t *syms;
int nsyms = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, int nsyms = xkb_state_key_get_syms(keyboard->wlr_keyboard->xkb_state,
keycode, &syms); keycode, &syms);
for (int i = 0; i < nsyms; i++) { for (int i = 0; i < nsyms; i++) {
xkb_keysym_t sym = syms[i]; xkb_keysym_t sym = syms[i];
@ -297,11 +297,11 @@ static void new_input_notify(struct wl_listener *listener, void *data) {
case WLR_INPUT_DEVICE_KEYBOARD:; case WLR_INPUT_DEVICE_KEYBOARD:;
struct sample_keyboard *keyboard = calloc(1, sizeof(struct sample_keyboard)); struct sample_keyboard *keyboard = calloc(1, sizeof(struct sample_keyboard));
keyboard->device = device; keyboard->wlr_keyboard = wlr_keyboard_from_input_device(device);
keyboard->state = state; keyboard->state = state;
wl_signal_add(&device->events.destroy, &keyboard->destroy); wl_signal_add(&device->events.destroy, &keyboard->destroy);
keyboard->destroy.notify = keyboard_destroy_notify; keyboard->destroy.notify = keyboard_destroy_notify;
wl_signal_add(&device->keyboard->events.key, &keyboard->key); wl_signal_add(&keyboard->wlr_keyboard->events.key, &keyboard->key);
keyboard->key.notify = keyboard_key_notify; keyboard->key.notify = keyboard_key_notify;
struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if (!context) { if (!context) {
@ -314,7 +314,7 @@ static void new_input_notify(struct wl_listener *listener, void *data) {
wlr_log(WLR_ERROR, "Failed to create XKB keymap"); wlr_log(WLR_ERROR, "Failed to create XKB keymap");
exit(1); exit(1);
} }
wlr_keyboard_set_keymap(device->keyboard, keymap); wlr_keyboard_set_keymap(keyboard->wlr_keyboard, keymap);
xkb_keymap_unref(keymap); xkb_keymap_unref(keymap);
xkb_context_unref(context); xkb_context_unref(context);
break; break;

View file

@ -39,7 +39,7 @@ struct sample_output {
struct sample_keyboard { struct sample_keyboard {
struct sample_state *sample; struct sample_state *sample;
struct wlr_input_device *device; struct wlr_keyboard *wlr_keyboard;
struct wl_listener key; struct wl_listener key;
struct wl_listener destroy; struct wl_listener destroy;
}; };
@ -129,10 +129,10 @@ static void new_output_notify(struct wl_listener *listener, void *data) {
static void keyboard_key_notify(struct wl_listener *listener, void *data) { static void keyboard_key_notify(struct wl_listener *listener, void *data) {
struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, key); struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, key);
struct sample_state *sample = keyboard->sample; struct sample_state *sample = keyboard->sample;
struct wlr_event_keyboard_key *event = data; struct wlr_keyboard_key_event *event = data;
uint32_t keycode = event->keycode + 8; uint32_t keycode = event->keycode + 8;
const xkb_keysym_t *syms; const xkb_keysym_t *syms;
int nsyms = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, int nsyms = xkb_state_key_get_syms(keyboard->wlr_keyboard->xkb_state,
keycode, &syms); keycode, &syms);
for (int i = 0; i < nsyms; i++) { for (int i = 0; i < nsyms; i++) {
xkb_keysym_t sym = syms[i]; xkb_keysym_t sym = syms[i];
@ -155,11 +155,11 @@ static void new_input_notify(struct wl_listener *listener, void *data) {
switch (device->type) { switch (device->type) {
case WLR_INPUT_DEVICE_KEYBOARD:; case WLR_INPUT_DEVICE_KEYBOARD:;
struct sample_keyboard *keyboard = calloc(1, sizeof(struct sample_keyboard)); struct sample_keyboard *keyboard = calloc(1, sizeof(struct sample_keyboard));
keyboard->device = device; keyboard->wlr_keyboard = wlr_keyboard_from_input_device(device);
keyboard->sample = sample; keyboard->sample = sample;
wl_signal_add(&device->events.destroy, &keyboard->destroy); wl_signal_add(&device->events.destroy, &keyboard->destroy);
keyboard->destroy.notify = keyboard_destroy_notify; keyboard->destroy.notify = keyboard_destroy_notify;
wl_signal_add(&device->keyboard->events.key, &keyboard->key); wl_signal_add(&keyboard->wlr_keyboard->events.key, &keyboard->key);
keyboard->key.notify = keyboard_key_notify; keyboard->key.notify = keyboard_key_notify;
struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if (!context) { if (!context) {
@ -172,7 +172,7 @@ static void new_input_notify(struct wl_listener *listener, void *data) {
wlr_log(WLR_ERROR, "Failed to create XKB keymap"); wlr_log(WLR_ERROR, "Failed to create XKB keymap");
exit(1); exit(1);
} }
wlr_keyboard_set_keymap(device->keyboard, keymap); wlr_keyboard_set_keymap(keyboard->wlr_keyboard, keymap);
xkb_keymap_unref(keymap); xkb_keymap_unref(keymap);
xkb_context_unref(context); xkb_context_unref(context);
break; break;

View file

@ -44,7 +44,7 @@ struct sample_output {
struct sample_keyboard { struct sample_keyboard {
struct sample_state *sample; struct sample_state *sample;
struct wlr_input_device *device; struct wlr_keyboard *wlr_keyboard;
struct wl_listener key; struct wl_listener key;
struct wl_listener destroy; struct wl_listener destroy;
}; };
@ -134,10 +134,10 @@ static void new_output_notify(struct wl_listener *listener, void *data) {
static void keyboard_key_notify(struct wl_listener *listener, void *data) { static void keyboard_key_notify(struct wl_listener *listener, void *data) {
struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, key); struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, key);
struct sample_state *sample = keyboard->sample; struct sample_state *sample = keyboard->sample;
struct wlr_event_keyboard_key *event = data; struct wlr_keyboard_key_event *event = data;
uint32_t keycode = event->keycode + 8; uint32_t keycode = event->keycode + 8;
const xkb_keysym_t *syms; const xkb_keysym_t *syms;
int nsyms = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, int nsyms = xkb_state_key_get_syms(keyboard->wlr_keyboard->xkb_state,
keycode, &syms); keycode, &syms);
for (int i = 0; i < nsyms; i++) { for (int i = 0; i < nsyms; i++) {
xkb_keysym_t sym = syms[i]; xkb_keysym_t sym = syms[i];
@ -176,11 +176,11 @@ static void new_input_notify(struct wl_listener *listener, void *data) {
switch (device->type) { switch (device->type) {
case WLR_INPUT_DEVICE_KEYBOARD:; case WLR_INPUT_DEVICE_KEYBOARD:;
struct sample_keyboard *keyboard = calloc(1, sizeof(struct sample_keyboard)); struct sample_keyboard *keyboard = calloc(1, sizeof(struct sample_keyboard));
keyboard->device = device; keyboard->wlr_keyboard = wlr_keyboard_from_input_device(device);
keyboard->sample = sample; keyboard->sample = sample;
wl_signal_add(&device->events.destroy, &keyboard->destroy); wl_signal_add(&device->events.destroy, &keyboard->destroy);
keyboard->destroy.notify = keyboard_destroy_notify; keyboard->destroy.notify = keyboard_destroy_notify;
wl_signal_add(&device->keyboard->events.key, &keyboard->key); wl_signal_add(&keyboard->wlr_keyboard->events.key, &keyboard->key);
keyboard->key.notify = keyboard_key_notify; keyboard->key.notify = keyboard_key_notify;
struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if (!context) { if (!context) {
@ -193,7 +193,7 @@ static void new_input_notify(struct wl_listener *listener, void *data) {
wlr_log(WLR_ERROR, "Failed to create XKB keymap"); wlr_log(WLR_ERROR, "Failed to create XKB keymap");
exit(1); exit(1);
} }
wlr_keyboard_set_keymap(device->keyboard, keymap); wlr_keyboard_set_keymap(keyboard->wlr_keyboard, keymap);
xkb_keymap_unref(keymap); xkb_keymap_unref(keymap);
xkb_context_unref(context); xkb_context_unref(context);
break; break;

View file

@ -99,7 +99,7 @@ static void surface_handle_commit(struct wl_listener *listener, void *data) {
static void surface_handle_destroy(struct wl_listener *listener, void *data) { static void surface_handle_destroy(struct wl_listener *listener, void *data) {
struct surface *surface = wl_container_of(listener, surface, destroy); struct surface *surface = wl_container_of(listener, surface, destroy);
wlr_scene_node_destroy(&surface->scene_surface->node); wlr_scene_node_destroy(&surface->scene_surface->buffer->node);
wlr_scene_node_destroy(&surface->border->node); wlr_scene_node_destroy(&surface->border->node);
wl_list_remove(&surface->destroy.link); wl_list_remove(&surface->destroy.link);
wl_list_remove(&surface->link); wl_list_remove(&surface->link);
@ -122,14 +122,14 @@ static void server_handle_new_surface(struct wl_listener *listener,
wl_signal_add(&wlr_surface->events.destroy, &surface->destroy); wl_signal_add(&wlr_surface->events.destroy, &surface->destroy);
/* Border dimensions will be set in surface.commit handler */ /* Border dimensions will be set in surface.commit handler */
surface->border = wlr_scene_rect_create(&server->scene->node, surface->border = wlr_scene_rect_create(&server->scene->tree,
0, 0, (float[4]){ 0.5f, 0.5f, 0.5f, 1 }); 0, 0, (float[4]){ 0.5f, 0.5f, 0.5f, 1 });
wlr_scene_node_set_position(&surface->border->node, pos, pos); wlr_scene_node_set_position(&surface->border->node, pos, pos);
surface->scene_surface = surface->scene_surface =
wlr_scene_surface_create(&server->scene->node, wlr_surface); wlr_scene_surface_create(&server->scene->tree, wlr_surface);
wlr_scene_node_set_position(&surface->scene_surface->node, wlr_scene_node_set_position(&surface->scene_surface->buffer->node,
pos + border_width, pos + border_width); pos + border_width, pos + border_width);
} }
@ -169,7 +169,7 @@ int main(int argc, char *argv[]) {
struct wlr_compositor *compositor = struct wlr_compositor *compositor =
wlr_compositor_create(server.display, server.renderer); wlr_compositor_create(server.display, server.renderer);
wlr_xdg_shell_create(server.display); wlr_xdg_shell_create(server.display, 2);
server.new_output.notify = server_handle_new_output; server.new_output.notify = server_handle_new_output;
wl_signal_add(&server.backend->events.new_output, &server.new_output); wl_signal_add(&server.backend->events.new_output, &server.new_output);

View file

@ -76,7 +76,7 @@ static const struct format formats[] = {
{DRM_FORMAT_ABGR8888, false}, {DRM_FORMAT_ABGR8888, false},
}; };
static bool find_render_node(char *node, size_t maxlen) { static bool find_render_node(char *node, size_t node_size) {
bool r = false; bool r = false;
drmDevice *devices[64]; drmDevice *devices[64];
@ -87,8 +87,7 @@ static bool find_render_node(char *node, size_t maxlen) {
continue; continue;
} }
strncpy(node, dev->nodes[DRM_NODE_RENDER], maxlen - 1); snprintf(node, node_size, "%s", dev->nodes[DRM_NODE_RENDER]);
node[maxlen - 1] = '\0';
r = true; r = true;
break; break;
} }

View file

@ -35,7 +35,7 @@ struct sample_output {
struct sample_keyboard { struct sample_keyboard {
struct sample_state *sample; struct sample_state *sample;
struct wlr_input_device *device; struct wlr_keyboard *wlr_keyboard;
struct wl_listener key; struct wl_listener key;
struct wl_listener destroy; struct wl_listener destroy;
}; };
@ -109,10 +109,10 @@ static void new_output_notify(struct wl_listener *listener, void *data) {
static void keyboard_key_notify(struct wl_listener *listener, void *data) { static void keyboard_key_notify(struct wl_listener *listener, void *data) {
struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, key); struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, key);
struct sample_state *sample = keyboard->sample; struct sample_state *sample = keyboard->sample;
struct wlr_event_keyboard_key *event = data; struct wlr_keyboard_key_event *event = data;
uint32_t keycode = event->keycode + 8; uint32_t keycode = event->keycode + 8;
const xkb_keysym_t *syms; const xkb_keysym_t *syms;
int nsyms = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, int nsyms = xkb_state_key_get_syms(keyboard->wlr_keyboard->xkb_state,
keycode, &syms); keycode, &syms);
for (int i = 0; i < nsyms; i++) { for (int i = 0; i < nsyms; i++) {
xkb_keysym_t sym = syms[i]; xkb_keysym_t sym = syms[i];
@ -137,11 +137,11 @@ static void new_input_notify(struct wl_listener *listener, void *data) {
case WLR_INPUT_DEVICE_KEYBOARD:; case WLR_INPUT_DEVICE_KEYBOARD:;
struct sample_keyboard *keyboard = struct sample_keyboard *keyboard =
calloc(1, sizeof(struct sample_keyboard)); calloc(1, sizeof(struct sample_keyboard));
keyboard->device = device; keyboard->wlr_keyboard = wlr_keyboard_from_input_device(device);
keyboard->sample = sample; keyboard->sample = sample;
wl_signal_add(&device->events.destroy, &keyboard->destroy); wl_signal_add(&device->events.destroy, &keyboard->destroy);
keyboard->destroy.notify = keyboard_destroy_notify; keyboard->destroy.notify = keyboard_destroy_notify;
wl_signal_add(&device->keyboard->events.key, &keyboard->key); wl_signal_add(&keyboard->wlr_keyboard->events.key, &keyboard->key);
keyboard->key.notify = keyboard_key_notify; keyboard->key.notify = keyboard_key_notify;
struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if (!context) { if (!context) {
@ -154,7 +154,7 @@ static void new_input_notify(struct wl_listener *listener, void *data) {
wlr_log(WLR_ERROR, "Failed to create XKB keymap"); wlr_log(WLR_ERROR, "Failed to create XKB keymap");
exit(1); exit(1);
} }
wlr_keyboard_set_keymap(device->keyboard, keymap); wlr_keyboard_set_keymap(keyboard->wlr_keyboard, keymap);
xkb_keymap_unref(keymap); xkb_keymap_unref(keymap);
xkb_context_unref(context); xkb_context_unref(context);
break; break;

View file

@ -43,7 +43,7 @@ struct sample_state {
struct tablet_tool_state { struct tablet_tool_state {
struct sample_state *sample; struct sample_state *sample;
struct wlr_input_device *device; struct wlr_tablet *wlr_tablet;
struct wl_listener destroy; struct wl_listener destroy;
struct wl_listener axis; struct wl_listener axis;
struct wl_listener proximity; struct wl_listener proximity;
@ -55,7 +55,7 @@ struct tablet_tool_state {
struct tablet_pad_state { struct tablet_pad_state {
struct sample_state *sample; struct sample_state *sample;
struct wlr_input_device *device; struct wlr_tablet_pad *wlr_tablet_pad;
struct wl_listener destroy; struct wl_listener destroy;
struct wl_listener button; struct wl_listener button;
struct wl_listener ring; struct wl_listener ring;
@ -72,7 +72,7 @@ struct sample_output {
struct sample_keyboard { struct sample_keyboard {
struct sample_state *sample; struct sample_state *sample;
struct wlr_input_device *device; struct wlr_keyboard *wlr_keyboard;
struct wl_listener key; struct wl_listener key;
struct wl_listener destroy; struct wl_listener destroy;
}; };
@ -136,7 +136,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
static void tablet_tool_axis_notify(struct wl_listener *listener, void *data) { static void tablet_tool_axis_notify(struct wl_listener *listener, void *data) {
struct tablet_tool_state *tstate = wl_container_of(listener, tstate, axis); struct tablet_tool_state *tstate = wl_container_of(listener, tstate, axis);
struct wlr_event_tablet_tool_axis *event = data; struct wlr_tablet_tool_axis_event *event = data;
struct sample_state *sample = tstate->sample; struct sample_state *sample = tstate->sample;
if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_X)) { if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_X)) {
sample->x = event->x; sample->x = event->x;
@ -160,14 +160,14 @@ static void tablet_tool_axis_notify(struct wl_listener *listener, void *data) {
static void tablet_tool_proximity_notify(struct wl_listener *listener, void *data) { static void tablet_tool_proximity_notify(struct wl_listener *listener, void *data) {
struct tablet_tool_state *tstate = wl_container_of(listener, tstate, proximity); struct tablet_tool_state *tstate = wl_container_of(listener, tstate, proximity);
struct wlr_event_tablet_tool_proximity *event = data; struct wlr_tablet_tool_proximity_event *event = data;
struct sample_state *sample = tstate->sample; struct sample_state *sample = tstate->sample;
sample->proximity = event->state == WLR_TABLET_TOOL_PROXIMITY_IN; sample->proximity = event->state == WLR_TABLET_TOOL_PROXIMITY_IN;
} }
static void tablet_tool_button_notify(struct wl_listener *listener, void *data) { static void tablet_tool_button_notify(struct wl_listener *listener, void *data) {
struct tablet_tool_state *tstate = wl_container_of(listener, tstate, button); struct tablet_tool_state *tstate = wl_container_of(listener, tstate, button);
struct wlr_event_tablet_tool_button *event = data; struct wlr_tablet_tool_button_event *event = data;
struct sample_state *sample = tstate->sample; struct sample_state *sample = tstate->sample;
if (event->state == WLR_BUTTON_RELEASED) { if (event->state == WLR_BUTTON_RELEASED) {
sample->button = false; sample->button = false;
@ -185,7 +185,7 @@ static void tablet_tool_button_notify(struct wl_listener *listener, void *data)
static void tablet_pad_button_notify(struct wl_listener *listener, void *data) { static void tablet_pad_button_notify(struct wl_listener *listener, void *data) {
struct tablet_pad_state *pstate = wl_container_of(listener, pstate, button); struct tablet_pad_state *pstate = wl_container_of(listener, pstate, button);
struct wlr_event_tablet_pad_button *event = data; struct wlr_tablet_pad_button_event *event = data;
struct sample_state *sample = pstate->sample; struct sample_state *sample = pstate->sample;
float default_color[4] = { 0.5, 0.5, 0.5, 1.0 }; float default_color[4] = { 0.5, 0.5, 0.5, 1.0 };
if (event->state == WLR_BUTTON_RELEASED) { if (event->state == WLR_BUTTON_RELEASED) {
@ -203,7 +203,7 @@ static void tablet_pad_button_notify(struct wl_listener *listener, void *data) {
static void tablet_pad_ring_notify(struct wl_listener *listener, void *data) { static void tablet_pad_ring_notify(struct wl_listener *listener, void *data) {
struct tablet_pad_state *pstate = wl_container_of(listener, pstate, ring); struct tablet_pad_state *pstate = wl_container_of(listener, pstate, ring);
struct wlr_event_tablet_pad_ring *event = data; struct wlr_tablet_pad_ring_event *event = data;
struct sample_state *sample = pstate->sample; struct sample_state *sample = pstate->sample;
if (event->position != -1) { if (event->position != -1) {
sample->ring = -(event->position * (M_PI / 180.0)); sample->ring = -(event->position * (M_PI / 180.0));
@ -261,10 +261,10 @@ static void new_output_notify(struct wl_listener *listener, void *data) {
static void keyboard_key_notify(struct wl_listener *listener, void *data) { static void keyboard_key_notify(struct wl_listener *listener, void *data) {
struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, key); struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, key);
struct sample_state *sample = keyboard->sample; struct sample_state *sample = keyboard->sample;
struct wlr_event_keyboard_key *event = data; struct wlr_keyboard_key_event *event = data;
uint32_t keycode = event->keycode + 8; uint32_t keycode = event->keycode + 8;
const xkb_keysym_t *syms; const xkb_keysym_t *syms;
int nsyms = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, int nsyms = xkb_state_key_get_syms(keyboard->wlr_keyboard->xkb_state,
keycode, &syms); keycode, &syms);
for (int i = 0; i < nsyms; i++) { for (int i = 0; i < nsyms; i++) {
xkb_keysym_t sym = syms[i]; xkb_keysym_t sym = syms[i];
@ -287,11 +287,11 @@ static void new_input_notify(struct wl_listener *listener, void *data) {
switch (device->type) { switch (device->type) {
case WLR_INPUT_DEVICE_KEYBOARD:; case WLR_INPUT_DEVICE_KEYBOARD:;
struct sample_keyboard *keyboard = calloc(1, sizeof(struct sample_keyboard)); struct sample_keyboard *keyboard = calloc(1, sizeof(struct sample_keyboard));
keyboard->device = device; keyboard->wlr_keyboard = wlr_keyboard_from_input_device(device);
keyboard->sample = sample; keyboard->sample = sample;
wl_signal_add(&device->events.destroy, &keyboard->destroy); wl_signal_add(&device->events.destroy, &keyboard->destroy);
keyboard->destroy.notify = keyboard_destroy_notify; keyboard->destroy.notify = keyboard_destroy_notify;
wl_signal_add(&device->keyboard->events.key, &keyboard->key); wl_signal_add(&keyboard->wlr_keyboard->events.key, &keyboard->key);
keyboard->key.notify = keyboard_key_notify; keyboard->key.notify = keyboard_key_notify;
struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if (!context) { if (!context) {
@ -304,39 +304,40 @@ static void new_input_notify(struct wl_listener *listener, void *data) {
wlr_log(WLR_ERROR, "Failed to create XKB keymap"); wlr_log(WLR_ERROR, "Failed to create XKB keymap");
exit(1); exit(1);
} }
wlr_keyboard_set_keymap(device->keyboard, keymap); wlr_keyboard_set_keymap(keyboard->wlr_keyboard, keymap);
xkb_keymap_unref(keymap); xkb_keymap_unref(keymap);
xkb_context_unref(context); xkb_context_unref(context);
break; break;
case WLR_INPUT_DEVICE_TABLET_PAD:; case WLR_INPUT_DEVICE_TABLET_PAD:;
struct tablet_pad_state *pstate = calloc(sizeof(struct tablet_pad_state), 1); struct tablet_pad_state *pstate = calloc(sizeof(struct tablet_pad_state), 1);
pstate->device = device; pstate->wlr_tablet_pad = wlr_tablet_pad_from_input_device(device);
pstate->sample = sample; pstate->sample = sample;
pstate->destroy.notify = tablet_pad_destroy_notify; pstate->destroy.notify = tablet_pad_destroy_notify;
wl_signal_add(&device->events.destroy, &pstate->destroy); wl_signal_add(&device->events.destroy, &pstate->destroy);
pstate->button.notify = tablet_pad_button_notify; pstate->button.notify = tablet_pad_button_notify;
wl_signal_add(&device->tablet_pad->events.button, &pstate->button); wl_signal_add(&pstate->wlr_tablet_pad->events.button, &pstate->button);
pstate->ring.notify = tablet_pad_ring_notify; pstate->ring.notify = tablet_pad_ring_notify;
wl_signal_add(&device->tablet_pad->events.ring, &pstate->ring); wl_signal_add(&pstate->wlr_tablet_pad->events.ring, &pstate->ring);
wl_list_insert(&sample->tablet_pads, &pstate->link); wl_list_insert(&sample->tablet_pads, &pstate->link);
break; break;
case WLR_INPUT_DEVICE_TABLET_TOOL: case WLR_INPUT_DEVICE_TABLET_TOOL:;
sample->width_mm = device->width_mm == 0 ? struct wlr_tablet *tablet = wlr_tablet_from_input_device(device);
20 : device->width_mm; sample->width_mm = tablet->width_mm == 0 ?
sample->height_mm = device->height_mm == 0 ? 20 : tablet->width_mm;
10 : device->height_mm; sample->height_mm = tablet->height_mm == 0 ?
10 : tablet->height_mm;
struct tablet_tool_state *tstate = calloc(sizeof(struct tablet_tool_state), 1); struct tablet_tool_state *tstate = calloc(sizeof(struct tablet_tool_state), 1);
tstate->device = device; tstate->wlr_tablet = tablet;
tstate->sample = sample; tstate->sample = sample;
tstate->destroy.notify = tablet_tool_destroy_notify; tstate->destroy.notify = tablet_tool_destroy_notify;
wl_signal_add(&device->events.destroy, &tstate->destroy); wl_signal_add(&device->events.destroy, &tstate->destroy);
tstate->axis.notify = tablet_tool_axis_notify; tstate->axis.notify = tablet_tool_axis_notify;
wl_signal_add(&device->tablet->events.axis, &tstate->axis); wl_signal_add(&tablet->events.axis, &tstate->axis);
tstate->proximity.notify = tablet_tool_proximity_notify; tstate->proximity.notify = tablet_tool_proximity_notify;
wl_signal_add(&device->tablet->events.proximity, &tstate->proximity); wl_signal_add(&tablet->events.proximity, &tstate->proximity);
tstate->button.notify = tablet_tool_button_notify; tstate->button.notify = tablet_tool_button_notify;
wl_signal_add(&device->tablet->events.button, &tstate->button); wl_signal_add(&tablet->events.button, &tstate->button);
wl_list_insert(&sample->tablet_tools, &tstate->link); wl_list_insert(&sample->tablet_tools, &tstate->link);
break; break;
default: default:
@ -344,7 +345,6 @@ static void new_input_notify(struct wl_listener *listener, void *data) {
} }
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
wlr_log_init(WLR_DEBUG, NULL); wlr_log_init(WLR_DEBUG, NULL);
struct wl_display *display = wl_display_create(); struct wl_display *display = wl_display_create();

View file

@ -244,15 +244,15 @@ static void text_input_handle_done(void *data,
buffer[strlen(buffer) - delete_before] = '\0'; buffer[strlen(buffer) - delete_before] = '\0';
} }
char *commit_string = current.commit; const char *commit_string = current.commit;
if (!commit_string) { if (!commit_string) {
commit_string = ""; commit_string = "";
} }
char *old_buffer = buffer; size_t new_size = strlen(buffer) + strlen(commit_string) + 1;
buffer = calloc(strlen(buffer) + strlen(commit_string) + 1, sizeof(char)); // realloc may fail anyway char *new_buffer = calloc(new_size, sizeof(char)); // realloc may fail anyway
strcpy(buffer, old_buffer); snprintf(new_buffer, new_size, "%s%s", buffer, commit_string);
free(old_buffer); free(buffer);
strcat(buffer, commit_string); buffer = new_buffer;
send_status_update(zwp_text_input_v3); send_status_update(zwp_text_input_v3);
show_status(); show_status();

View file

@ -41,7 +41,7 @@ struct touch_point {
struct touch_state { struct touch_state {
struct sample_state *sample; struct sample_state *sample;
struct wlr_input_device *device; struct wlr_touch *wlr_touch;
struct wl_listener destroy; struct wl_listener destroy;
struct wl_listener down; struct wl_listener down;
struct wl_listener up; struct wl_listener up;
@ -59,7 +59,7 @@ struct sample_output {
struct sample_keyboard { struct sample_keyboard {
struct sample_state *sample; struct sample_state *sample;
struct wlr_input_device *device; struct wlr_keyboard *wlr_keyboard;
struct wl_listener key; struct wl_listener key;
struct wl_listener destroy; struct wl_listener destroy;
}; };
@ -93,7 +93,7 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
} }
static void touch_down_notify(struct wl_listener *listener, void *data) { static void touch_down_notify(struct wl_listener *listener, void *data) {
struct wlr_event_touch_motion *event = data; struct wlr_touch_motion_event *event = data;
struct touch_state *tstate = wl_container_of(listener, tstate, down); struct touch_state *tstate = wl_container_of(listener, tstate, down);
struct sample_state *sample = tstate->sample; struct sample_state *sample = tstate->sample;
struct touch_point *point = calloc(1, sizeof(struct touch_point)); struct touch_point *point = calloc(1, sizeof(struct touch_point));
@ -104,7 +104,7 @@ static void touch_down_notify(struct wl_listener *listener, void *data) {
} }
static void touch_up_notify(struct wl_listener *listener, void *data ) { static void touch_up_notify(struct wl_listener *listener, void *data ) {
struct wlr_event_touch_up *event = data; struct wlr_touch_up_event *event = data;
struct touch_state *tstate = wl_container_of(listener, tstate, up); struct touch_state *tstate = wl_container_of(listener, tstate, up);
struct sample_state *sample = tstate->sample; struct sample_state *sample = tstate->sample;
struct touch_point *point, *tmp; struct touch_point *point, *tmp;
@ -117,7 +117,7 @@ static void touch_up_notify(struct wl_listener *listener, void *data ) {
} }
static void touch_motion_notify(struct wl_listener *listener, void *data) { static void touch_motion_notify(struct wl_listener *listener, void *data) {
struct wlr_event_touch_motion *event = data; struct wlr_touch_motion_event *event = data;
struct touch_state *tstate = wl_container_of(listener, tstate, motion); struct touch_state *tstate = wl_container_of(listener, tstate, motion);
struct sample_state *sample = tstate->sample; struct sample_state *sample = tstate->sample;
struct touch_point *point; struct touch_point *point;
@ -172,10 +172,10 @@ static void new_output_notify(struct wl_listener *listener, void *data) {
static void keyboard_key_notify(struct wl_listener *listener, void *data) { static void keyboard_key_notify(struct wl_listener *listener, void *data) {
struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, key); struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, key);
struct sample_state *sample = keyboard->sample; struct sample_state *sample = keyboard->sample;
struct wlr_event_keyboard_key *event = data; struct wlr_keyboard_key_event *event = data;
uint32_t keycode = event->keycode + 8; uint32_t keycode = event->keycode + 8;
const xkb_keysym_t *syms; const xkb_keysym_t *syms;
int nsyms = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, int nsyms = xkb_state_key_get_syms(keyboard->wlr_keyboard->xkb_state,
keycode, &syms); keycode, &syms);
for (int i = 0; i < nsyms; i++) { for (int i = 0; i < nsyms; i++) {
xkb_keysym_t sym = syms[i]; xkb_keysym_t sym = syms[i];
@ -198,11 +198,11 @@ static void new_input_notify(struct wl_listener *listener, void *data) {
switch (device->type) { switch (device->type) {
case WLR_INPUT_DEVICE_KEYBOARD:; case WLR_INPUT_DEVICE_KEYBOARD:;
struct sample_keyboard *keyboard = calloc(1, sizeof(struct sample_keyboard)); struct sample_keyboard *keyboard = calloc(1, sizeof(struct sample_keyboard));
keyboard->device = device; keyboard->wlr_keyboard = wlr_keyboard_from_input_device(device);
keyboard->sample = sample; keyboard->sample = sample;
wl_signal_add(&device->events.destroy, &keyboard->destroy); wl_signal_add(&device->events.destroy, &keyboard->destroy);
keyboard->destroy.notify = keyboard_destroy_notify; keyboard->destroy.notify = keyboard_destroy_notify;
wl_signal_add(&device->keyboard->events.key, &keyboard->key); wl_signal_add(&keyboard->wlr_keyboard->events.key, &keyboard->key);
keyboard->key.notify = keyboard_key_notify; keyboard->key.notify = keyboard_key_notify;
struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if (!context) { if (!context) {
@ -215,22 +215,22 @@ static void new_input_notify(struct wl_listener *listener, void *data) {
wlr_log(WLR_ERROR, "Failed to create XKB keymap"); wlr_log(WLR_ERROR, "Failed to create XKB keymap");
exit(1); exit(1);
} }
wlr_keyboard_set_keymap(device->keyboard, keymap); wlr_keyboard_set_keymap(keyboard->wlr_keyboard, keymap);
xkb_keymap_unref(keymap); xkb_keymap_unref(keymap);
xkb_context_unref(context); xkb_context_unref(context);
break; break;
case WLR_INPUT_DEVICE_TOUCH:; case WLR_INPUT_DEVICE_TOUCH:;
struct touch_state *tstate = calloc(sizeof(struct touch_state), 1); struct touch_state *tstate = calloc(sizeof(struct touch_state), 1);
tstate->device = device; tstate->wlr_touch = wlr_touch_from_input_device(device);
tstate->sample = sample; tstate->sample = sample;
tstate->destroy.notify = touch_destroy_notify; tstate->destroy.notify = touch_destroy_notify;
wl_signal_add(&device->events.destroy, &tstate->destroy); wl_signal_add(&device->events.destroy, &tstate->destroy);
tstate->down.notify = touch_down_notify; tstate->down.notify = touch_down_notify;
wl_signal_add(&device->touch->events.down, &tstate->down); wl_signal_add(&tstate->wlr_touch->events.down, &tstate->down);
tstate->motion.notify = touch_motion_notify; tstate->motion.notify = touch_motion_notify;
wl_signal_add(&device->touch->events.motion, &tstate->motion); wl_signal_add(&tstate->wlr_touch->events.motion, &tstate->motion);
tstate->up.notify = touch_up_notify; tstate->up.notify = touch_up_notify;
wl_signal_add(&device->touch->events.up, &tstate->up); wl_signal_add(&tstate->wlr_touch->events.up, &tstate->up);
wl_list_insert(&sample->touch, &tstate->link); wl_list_insert(&sample->touch, &tstate->link);
break; break;
default: default:

View file

@ -58,6 +58,7 @@ struct wlr_drm_backend {
const struct wlr_drm_interface *iface; const struct wlr_drm_interface *iface;
clockid_t clock; clockid_t clock;
bool addfb2_modifiers; bool addfb2_modifiers;
struct udev_hwdb *hwdb;
int fd; int fd;
char *name; char *name;
@ -89,15 +90,6 @@ struct wlr_drm_backend {
struct wlr_drm_format_set mgpu_formats; struct wlr_drm_format_set mgpu_formats;
}; };
enum wlr_drm_connector_status {
// Connector is available but no output is plugged in
WLR_DRM_CONN_DISCONNECTED,
// An output just has been plugged in and is waiting for a modeset
WLR_DRM_CONN_NEEDS_MODESET,
WLR_DRM_CONN_CLEANUP,
WLR_DRM_CONN_CONNECTED,
};
struct wlr_drm_mode { struct wlr_drm_mode {
struct wlr_output_mode wlr_mode; struct wlr_output_mode wlr_mode;
drmModeModeInfo drm_mode; drmModeModeInfo drm_mode;
@ -115,9 +107,10 @@ struct wlr_drm_connector {
struct wlr_drm_backend *backend; struct wlr_drm_backend *backend;
char name[24]; char name[24];
enum wlr_drm_connector_status status; drmModeConnection status;
bool desired_enabled; bool desired_enabled;
uint32_t id; uint32_t id;
uint64_t max_bpc;
struct wlr_drm_lease *lease; struct wlr_drm_lease *lease;
struct wlr_drm_crtc *crtc; struct wlr_drm_crtc *crtc;

View file

@ -21,6 +21,8 @@ union wlr_drm_connector_props {
uint32_t non_desktop; uint32_t non_desktop;
uint32_t panel_orientation; // not guaranteed to exist uint32_t panel_orientation; // not guaranteed to exist
uint32_t tile; uint32_t tile;
uint32_t content_type; // not guaranteed to exist
uint32_t max_bpc; // not guaranteed to exist
// atomic-modesetting only // atomic-modesetting only
@ -76,4 +78,7 @@ bool get_drm_prop(int fd, uint32_t obj, uint32_t prop, uint64_t *ret);
void *get_drm_prop_blob(int fd, uint32_t obj, uint32_t prop, size_t *ret_len); void *get_drm_prop_blob(int fd, uint32_t obj, uint32_t prop, size_t *ret_len);
char *get_drm_prop_enum(int fd, uint32_t obj, uint32_t prop); char *get_drm_prop_enum(int fd, uint32_t obj, uint32_t prop);
bool introspect_drm_prop_range(int fd, uint32_t prop_id,
uint64_t *min, uint64_t *max);
#endif #endif

View file

@ -19,10 +19,6 @@ struct wlr_drm_renderer {
struct wlr_drm_surface { struct wlr_drm_surface {
struct wlr_drm_renderer *renderer; struct wlr_drm_renderer *renderer;
uint32_t width;
uint32_t height;
struct wlr_swapchain *swapchain; struct wlr_swapchain *swapchain;
}; };
@ -40,7 +36,7 @@ bool init_drm_renderer(struct wlr_drm_backend *drm,
void finish_drm_renderer(struct wlr_drm_renderer *renderer); void finish_drm_renderer(struct wlr_drm_renderer *renderer);
bool init_drm_surface(struct wlr_drm_surface *surf, bool init_drm_surface(struct wlr_drm_surface *surf,
struct wlr_drm_renderer *renderer, uint32_t width, uint32_t height, struct wlr_drm_renderer *renderer, int width, int height,
const struct wlr_drm_format *drm_format); const struct wlr_drm_format *drm_format);
bool drm_fb_import(struct wlr_drm_fb **fb, struct wlr_drm_backend *drm, bool drm_fb_import(struct wlr_drm_fb **fb, struct wlr_drm_backend *drm,

View file

@ -2,20 +2,17 @@
#define BACKEND_DRM_UTIL_H #define BACKEND_DRM_UTIL_H
#include <stdint.h> #include <stdint.h>
#include <wlr/types/wlr_output.h>
#include <xf86drm.h> #include <xf86drm.h>
#include <xf86drmMode.h> #include <xf86drmMode.h>
struct wlr_drm_connector;
// Calculates a more accurate refresh rate (mHz) than what mode itself provides // Calculates a more accurate refresh rate (mHz) than what mode itself provides
int32_t calculate_refresh_rate(const drmModeModeInfo *mode); int32_t calculate_refresh_rate(const drmModeModeInfo *mode);
// Populates the make/model/phys_{width,height} of output from the edid data // Populates the make/model/phys_{width,height} of output from the edid data
void parse_edid(struct wlr_output *restrict output, size_t len, void parse_edid(struct wlr_drm_connector *conn, size_t len, const uint8_t *data);
const uint8_t *data);
// Parses the TILE property // Parses the TILE property
void parse_tile(struct wlr_output *restrict output, size_t len, void parse_tile(struct wlr_drm_connector *conn, size_t len, const uint8_t *data);
const uint8_t *data);
// Returns the string representation of a DRM output type
const char *conn_get_name(uint32_t type_id);
// Part of match_obj // Part of match_obj
enum { enum {

View file

@ -5,13 +5,12 @@
#include <wayland-server-core.h> #include <wayland-server-core.h>
#include <wlr/backend/interface.h> #include <wlr/backend/interface.h>
#include <wlr/backend/libinput.h> #include <wlr/backend/libinput.h>
#include <wlr/interfaces/wlr_keyboard.h> #include <wlr/types/wlr_keyboard.h>
#include <wlr/interfaces/wlr_pointer.h> #include <wlr/types/wlr_pointer.h>
#include <wlr/interfaces/wlr_switch.h> #include <wlr/types/wlr_switch.h>
#include <wlr/interfaces/wlr_tablet_pad.h> #include <wlr/types/wlr_tablet_pad.h>
#include <wlr/interfaces/wlr_tablet_tool.h> #include <wlr/types/wlr_tablet_tool.h>
#include <wlr/interfaces/wlr_touch.h> #include <wlr/types/wlr_touch.h>
#include <wlr/types/wlr_input_device.h>
struct wlr_libinput_backend { struct wlr_libinput_backend {
struct wlr_backend backend; struct wlr_backend backend;
@ -26,13 +25,21 @@ struct wlr_libinput_backend {
struct wl_listener session_destroy; struct wl_listener session_destroy;
struct wl_listener session_signal; struct wl_listener session_signal;
struct wl_array wlr_device_lists; // struct wl_list * struct wl_list devices; // wlr_libinput_device::link
}; };
struct wlr_libinput_input_device { struct wlr_libinput_input_device {
struct wlr_input_device wlr_input_device;
struct wl_list link;
struct libinput_device *handle; struct libinput_device *handle;
struct wlr_keyboard keyboard;
struct wlr_pointer pointer;
struct wlr_switch switch_device;
struct wlr_touch touch;
struct wlr_tablet tablet;
struct wl_list tablet_tools; // see backend/libinput/tablet_tool.c
struct wlr_tablet_pad tablet_pad;
struct wl_list link;
}; };
uint32_t usec_to_msec(uint64_t usec); uint32_t usec_to_msec(uint64_t usec);
@ -40,10 +47,6 @@ uint32_t usec_to_msec(uint64_t usec);
void handle_libinput_event(struct wlr_libinput_backend *state, void handle_libinput_event(struct wlr_libinput_backend *state,
struct libinput_event *event); struct libinput_event *event);
struct wlr_input_device *get_appropriate_device(
enum wlr_input_device_type desired_type,
struct libinput_device *device);
void destroy_libinput_input_device(struct wlr_libinput_input_device *dev); void destroy_libinput_input_device(struct wlr_libinput_input_device *dev);
extern const struct wlr_keyboard_impl libinput_keyboard_impl; extern const struct wlr_keyboard_impl libinput_keyboard_impl;
@ -53,74 +56,83 @@ extern const struct wlr_tablet_impl libinput_tablet_impl;
extern const struct wlr_tablet_pad_impl libinput_tablet_pad_impl; extern const struct wlr_tablet_pad_impl libinput_tablet_pad_impl;
extern const struct wlr_touch_impl libinput_touch_impl; extern const struct wlr_touch_impl libinput_touch_impl;
struct wlr_keyboard *create_libinput_keyboard( void init_device_keyboard(struct wlr_libinput_input_device *dev);
struct libinput_device *device); struct wlr_libinput_input_device *device_from_keyboard(struct wlr_keyboard *kb);
void handle_keyboard_key(struct libinput_event *event, void handle_keyboard_key(struct libinput_event *event, struct wlr_keyboard *kb);
struct libinput_device *device);
struct wlr_pointer *create_libinput_pointer( void init_device_pointer(struct wlr_libinput_input_device *dev);
struct libinput_device *device); struct wlr_libinput_input_device *device_from_pointer(struct wlr_pointer *kb);
void handle_pointer_motion(struct libinput_event *event, void handle_pointer_motion(struct libinput_event *event,
struct libinput_device *device); struct wlr_pointer *pointer);
void handle_pointer_motion_abs(struct libinput_event *event, void handle_pointer_motion_abs(struct libinput_event *event,
struct libinput_device *device); struct wlr_pointer *pointer);
void handle_pointer_button(struct libinput_event *event, void handle_pointer_button(struct libinput_event *event,
struct libinput_device *device); struct wlr_pointer *pointer);
void handle_pointer_axis(struct libinput_event *event, void handle_pointer_axis(struct libinput_event *event,
struct libinput_device *device); struct wlr_pointer *pointer);
#if LIBINPUT_HAS_SCROLL_VALUE120
void handle_pointer_axis_value120(struct libinput_event *event,
struct wlr_pointer *pointer, enum wlr_axis_source source);
#endif
void handle_pointer_swipe_begin(struct libinput_event *event, void handle_pointer_swipe_begin(struct libinput_event *event,
struct libinput_device *device); struct wlr_pointer *pointer);
void handle_pointer_swipe_update(struct libinput_event *event, void handle_pointer_swipe_update(struct libinput_event *event,
struct libinput_device *device); struct wlr_pointer *pointer);
void handle_pointer_swipe_end(struct libinput_event *event, void handle_pointer_swipe_end(struct libinput_event *event,
struct libinput_device *device); struct wlr_pointer *pointer);
void handle_pointer_pinch_begin(struct libinput_event *event, void handle_pointer_pinch_begin(struct libinput_event *event,
struct libinput_device *device); struct wlr_pointer *pointer);
void handle_pointer_pinch_update(struct libinput_event *event, void handle_pointer_pinch_update(struct libinput_event *event,
struct libinput_device *device); struct wlr_pointer *pointer);
void handle_pointer_pinch_end(struct libinput_event *event, void handle_pointer_pinch_end(struct libinput_event *event,
struct libinput_device *device); struct wlr_pointer *pointer);
void handle_pointer_hold_begin(struct libinput_event *event, void handle_pointer_hold_begin(struct libinput_event *event,
struct libinput_device *device); struct wlr_pointer *pointer);
void handle_pointer_hold_end(struct libinput_event *event, void handle_pointer_hold_end(struct libinput_event *event,
struct libinput_device *device); struct wlr_pointer *pointer);
struct wlr_switch *create_libinput_switch( void init_device_switch(struct wlr_libinput_input_device *dev);
struct libinput_device *device); struct wlr_libinput_input_device *device_from_switch(
struct wlr_switch *switch_device);
void handle_switch_toggle(struct libinput_event *event, void handle_switch_toggle(struct libinput_event *event,
struct libinput_device *device); struct wlr_switch *switch_device);
struct wlr_touch *create_libinput_touch( void init_device_touch(struct wlr_libinput_input_device *dev);
struct libinput_device *device); struct wlr_libinput_input_device *device_from_touch(
struct wlr_touch *touch);
void handle_touch_down(struct libinput_event *event, void handle_touch_down(struct libinput_event *event,
struct libinput_device *device); struct wlr_touch *touch);
void handle_touch_up(struct libinput_event *event, void handle_touch_up(struct libinput_event *event,
struct libinput_device *device); struct wlr_touch *touch);
void handle_touch_motion(struct libinput_event *event, void handle_touch_motion(struct libinput_event *event,
struct libinput_device *device); struct wlr_touch *touch);
void handle_touch_cancel(struct libinput_event *event, void handle_touch_cancel(struct libinput_event *event,
struct libinput_device *device); struct wlr_touch *touch);
void handle_touch_frame(struct libinput_event *event, void handle_touch_frame(struct libinput_event *event,
struct libinput_device *device); struct wlr_touch *touch);
struct wlr_tablet *create_libinput_tablet( void init_device_tablet(struct wlr_libinput_input_device *dev);
struct libinput_device *device); void finish_device_tablet(struct wlr_libinput_input_device *dev);
struct wlr_libinput_input_device *device_from_tablet(
struct wlr_tablet *tablet);
void handle_tablet_tool_axis(struct libinput_event *event, void handle_tablet_tool_axis(struct libinput_event *event,
struct libinput_device *device); struct wlr_tablet *tablet);
void handle_tablet_tool_proximity(struct libinput_event *event, void handle_tablet_tool_proximity(struct libinput_event *event,
struct libinput_device *device); struct wlr_tablet *tablet);
void handle_tablet_tool_tip(struct libinput_event *event, void handle_tablet_tool_tip(struct libinput_event *event,
struct libinput_device *device); struct wlr_tablet *tablet);
void handle_tablet_tool_button(struct libinput_event *event, void handle_tablet_tool_button(struct libinput_event *event,
struct libinput_device *device); struct wlr_tablet *tablet);
struct wlr_tablet_pad *create_libinput_tablet_pad( void init_device_tablet_pad(struct wlr_libinput_input_device *dev);
struct libinput_device *device); void finish_device_tablet_pad(struct wlr_libinput_input_device *dev);
struct wlr_libinput_input_device *device_from_tablet_pad(
struct wlr_tablet_pad *tablet_pad);
void handle_tablet_pad_button(struct libinput_event *event, void handle_tablet_pad_button(struct libinput_event *event,
struct libinput_device *device); struct wlr_tablet_pad *tablet_pad);
void handle_tablet_pad_ring(struct libinput_event *event, void handle_tablet_pad_ring(struct libinput_event *event,
struct libinput_device *device); struct wlr_tablet_pad *tablet_pad);
void handle_tablet_pad_strip(struct libinput_event *event, void handle_tablet_pad_strip(struct libinput_event *event,
struct libinput_device *device); struct wlr_tablet_pad *tablet_pad);
#endif #endif

View file

@ -8,7 +8,11 @@
#include <wlr/backend/wayland.h> #include <wlr/backend/wayland.h>
#include <wlr/render/wlr_renderer.h> #include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_keyboard.h>
#include <wlr/types/wlr_pointer.h> #include <wlr/types/wlr_pointer.h>
#include <wlr/types/wlr_tablet_pad.h>
#include <wlr/types/wlr_tablet_tool.h>
#include <wlr/types/wlr_touch.h>
#include <wlr/render/drm_format_set.h> #include <wlr/render/drm_format_set.h>
struct wlr_wl_backend { struct wlr_wl_backend {
@ -17,7 +21,6 @@ struct wlr_wl_backend {
/* local state */ /* local state */
bool started; bool started;
struct wl_display *local_display; struct wl_display *local_display;
struct wl_list devices;
struct wl_list outputs; struct wl_list outputs;
int drm_fd; int drm_fd;
struct wl_list buffers; // wlr_wl_buffer.link struct wl_list buffers; // wlr_wl_buffer.link
@ -85,64 +88,73 @@ struct wlr_wl_output {
} cursor; } cursor;
}; };
struct wlr_wl_input_device {
struct wlr_input_device wlr_input_device;
struct wl_list link;
uint32_t fingers;
struct wlr_wl_backend *backend;
struct wlr_wl_seat *seat;
void *resource;
};
struct wlr_wl_pointer { struct wlr_wl_pointer {
struct wlr_pointer wlr_pointer; struct wlr_pointer wlr_pointer;
struct wlr_wl_input_device *input_device; struct wlr_wl_seat *seat;
struct wlr_wl_output *output;
enum wlr_axis_source axis_source;
int32_t axis_discrete;
uint32_t fingers; // trackpad gesture
struct wl_listener output_destroy;
struct wl_list link;
};
struct wlr_wl_seat {
char *name;
struct wl_seat *wl_seat;
struct wlr_wl_backend *backend;
struct wl_keyboard *wl_keyboard;
struct wlr_keyboard wlr_keyboard;
struct wl_pointer *wl_pointer; struct wl_pointer *wl_pointer;
struct wlr_wl_pointer *active_pointer;
struct wl_list pointers; // wlr_wl_pointer::link
struct zwp_pointer_gesture_swipe_v1 *gesture_swipe; struct zwp_pointer_gesture_swipe_v1 *gesture_swipe;
struct zwp_pointer_gesture_pinch_v1 *gesture_pinch; struct zwp_pointer_gesture_pinch_v1 *gesture_pinch;
struct zwp_pointer_gesture_hold_v1 *gesture_hold; struct zwp_pointer_gesture_hold_v1 *gesture_hold;
struct zwp_relative_pointer_v1 *relative_pointer; struct zwp_relative_pointer_v1 *relative_pointer;
enum wlr_axis_source axis_source;
int32_t axis_discrete;
struct wlr_wl_output *output;
struct wl_listener output_destroy; struct wl_touch *wl_touch;
}; struct wlr_touch wlr_touch;
struct wlr_wl_seat { struct zwp_tablet_seat_v2 *zwp_tablet_seat_v2;
struct wl_seat *wl_seat; struct zwp_tablet_v2 *zwp_tablet_v2;
struct wlr_tablet wlr_tablet;
struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2;
struct wlr_tablet_tool wlr_tablet_tool;
struct zwp_tablet_pad_v2 *zwp_tablet_pad_v2;
struct wlr_tablet_pad wlr_tablet_pad;
struct wl_list link; // wlr_wl_backend.seats struct wl_list link; // wlr_wl_backend.seats
char *name;
struct wl_touch *touch;
struct wl_pointer *pointer;
struct wl_keyboard *keyboard;
struct wlr_wl_backend *backend;
struct wlr_wl_pointer *active_pointer;
}; };
struct wlr_wl_backend *get_wl_backend_from_backend(struct wlr_backend *backend); struct wlr_wl_backend *get_wl_backend_from_backend(struct wlr_backend *backend);
void update_wl_output_cursor(struct wlr_wl_output *output); void update_wl_output_cursor(struct wlr_wl_output *output);
struct wlr_wl_pointer *pointer_get_wl(struct wlr_pointer *wlr_pointer);
void create_wl_pointer(struct wlr_wl_seat *seat, struct wlr_wl_output *output); void init_seat_keyboard(struct wlr_wl_seat *seat);
void create_wl_keyboard(struct wlr_wl_seat *seat);
void create_wl_touch(struct wlr_wl_seat *seat); void init_seat_pointer(struct wlr_wl_seat *seat);
struct wlr_wl_input_device *create_wl_input_device( void finish_seat_pointer(struct wlr_wl_seat *seat);
struct wlr_wl_seat *seat, enum wlr_input_device_type type); void create_pointer(struct wlr_wl_seat *seat, struct wlr_wl_output *output);
void init_seat_touch(struct wlr_wl_seat *seat);
void init_seat_tablet(struct wlr_wl_seat *seat);
void finish_seat_tablet(struct wlr_wl_seat *seat);
bool create_wl_seat(struct wl_seat *wl_seat, struct wlr_wl_backend *wl); bool create_wl_seat(struct wl_seat *wl_seat, struct wlr_wl_backend *wl);
void destroy_wl_seats(struct wlr_wl_backend *wl); void destroy_wl_seats(struct wlr_wl_backend *wl);
void destroy_wl_input_device(struct wlr_wl_input_device *dev);
void destroy_wl_buffer(struct wlr_wl_buffer *buffer); void destroy_wl_buffer(struct wlr_wl_buffer *buffer);
extern const struct wl_seat_listener seat_listener; extern const struct wlr_pointer_impl wl_pointer_impl;
extern const struct wlr_tablet_pad_impl tablet_pad_impl; extern const struct wlr_tablet_pad_impl wl_tablet_pad_impl;
extern const struct wlr_tablet_impl tablet_impl; extern const struct wlr_tablet_impl wl_tablet_impl;
struct wlr_wl_tablet_seat *wl_add_tablet_seat(
struct zwp_tablet_manager_v2 *manager,
struct wlr_wl_seat *seat);
#endif #endif

View file

@ -0,0 +1,20 @@
#ifndef INTERFACES_INPUT_DEVICE_H
#define INTERFACES_INPUT_DEVICE_H
#include <wlr/types/wlr_input_device.h>
/**
* Initializes a given wlr_input_device. Allocates memory for the name and sets
* its vendor and product id to 0.
* wlr_device must be non-NULL.
*/
void wlr_input_device_init(struct wlr_input_device *wlr_device,
enum wlr_input_device_type type, const char *name);
/**
* Cleans up all the memory owned by a given wlr_input_device and signals
* the destroy event.
*/
void wlr_input_device_finish(struct wlr_input_device *wlr_device);
#endif

View file

@ -3,6 +3,47 @@
#include <wlr/render/egl.h> #include <wlr/render/egl.h>
struct wlr_egl {
EGLDisplay display;
EGLContext context;
EGLDeviceEXT device; // may be EGL_NO_DEVICE_EXT
struct gbm_device *gbm_device;
struct {
// Display extensions
bool KHR_image_base;
bool EXT_image_dma_buf_import;
bool EXT_image_dma_buf_import_modifiers;
bool IMG_context_priority;
// Device extensions
bool EXT_device_drm;
bool EXT_device_drm_render_node;
// Client extensions
bool EXT_device_query;
bool KHR_platform_gbm;
bool EXT_platform_device;
} exts;
struct {
PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT;
PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR;
PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR;
PFNEGLQUERYWAYLANDBUFFERWL eglQueryWaylandBufferWL;
PFNEGLQUERYDMABUFFORMATSEXTPROC eglQueryDmaBufFormatsEXT;
PFNEGLQUERYDMABUFMODIFIERSEXTPROC eglQueryDmaBufModifiersEXT;
PFNEGLDEBUGMESSAGECONTROLKHRPROC eglDebugMessageControlKHR;
PFNEGLQUERYDISPLAYATTRIBEXTPROC eglQueryDisplayAttribEXT;
PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT;
PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT;
} procs;
bool has_modifiers;
struct wlr_drm_format_set dmabuf_texture_formats;
struct wlr_drm_format_set dmabuf_render_formats;
};
struct wlr_egl_context { struct wlr_egl_context {
EGLDisplay display; EGLDisplay display;
EGLContext context; EGLContext context;
@ -60,4 +101,16 @@ void wlr_egl_save_context(struct wlr_egl_context *context);
*/ */
bool wlr_egl_restore_context(struct wlr_egl_context *context); bool wlr_egl_restore_context(struct wlr_egl_context *context);
/**
* Make the EGL context current.
*
* Callers are expected to clear the current context when they are done by
* calling wlr_egl_unset_current().
*/
bool wlr_egl_make_current(struct wlr_egl *egl);
bool wlr_egl_unset_current(struct wlr_egl *egl);
bool wlr_egl_is_current(struct wlr_egl *egl);
#endif #endif

View file

@ -17,6 +17,8 @@
struct wlr_gles2_pixel_format { struct wlr_gles2_pixel_format {
uint32_t drm_format; uint32_t drm_format;
// optional field, if empty then internalformat = format
GLint gl_internalformat;
GLint gl_format, gl_type; GLint gl_format, gl_type;
bool has_alpha; bool has_alpha;
}; };
@ -45,6 +47,7 @@ struct wlr_gles2_renderer {
bool OES_egl_image; bool OES_egl_image;
bool EXT_texture_type_2_10_10_10_REV; bool EXT_texture_type_2_10_10_10_REV;
bool OES_texture_half_float_linear; bool OES_texture_half_float_linear;
bool EXT_texture_norm16;
} exts; } exts;
struct { struct {

View file

@ -69,4 +69,13 @@ struct wlr_dmabuf_buffer *dmabuf_buffer_create(
*/ */
bool dmabuf_buffer_drop(struct wlr_dmabuf_buffer *buffer); bool dmabuf_buffer_drop(struct wlr_dmabuf_buffer *buffer);
/**
* Check whether a buffer is fully opaque.
*
* When true is returned, the buffer is guaranteed to be fully opaque, but the
* reverse is not true: false may be returned in cases where the buffer is fully
* opaque.
*/
bool buffer_is_opaque(struct wlr_buffer *buffer);
#endif #endif

View file

@ -1,7 +1,7 @@
#include <wlr/types/wlr_keyboard.h> #include <wlr/types/wlr_keyboard.h>
void keyboard_key_update(struct wlr_keyboard *keyboard, void keyboard_key_update(struct wlr_keyboard *keyboard,
struct wlr_event_keyboard_key *event); struct wlr_keyboard_key_event *event);
bool keyboard_modifier_update(struct wlr_keyboard *keyboard); bool keyboard_modifier_update(struct wlr_keyboard *keyboard);

View file

@ -0,0 +1,15 @@
#ifndef TYPES_WLR_MATRIX_H
#define TYPES_WLR_MATRIX_H
#include <wlr/types/wlr_matrix.h>
/**
* Writes a 2D orthographic projection matrix to mat of (width, height) with a
* specified wl_output_transform.
*
* Equivalent to glOrtho(0, width, 0, height, 1, -1) with the transform applied.
*/
void matrix_projection(float mat[static 9], int width, int height,
enum wl_output_transform transform);
#endif

View file

@ -4,12 +4,15 @@
#include <wlr/render/drm_format_set.h> #include <wlr/render/drm_format_set.h>
#include <wlr/types/wlr_output.h> #include <wlr/types/wlr_output.h>
void output_pending_resolution(struct wlr_output *output, int *width, void output_pending_resolution(struct wlr_output *output,
int *height); const struct wlr_output_state *state, int *width, int *height);
void output_state_attach_buffer(struct wlr_output_state *state,
struct wlr_buffer *buffer);
struct wlr_drm_format *output_pick_format(struct wlr_output *output, struct wlr_drm_format *output_pick_format(struct wlr_output *output,
const struct wlr_drm_format_set *display_formats, uint32_t format); const struct wlr_drm_format_set *display_formats, uint32_t format);
void output_clear_back_buffer(struct wlr_output *output); void output_clear_back_buffer(struct wlr_output *output);
bool output_ensure_buffer(struct wlr_output *output); bool output_ensure_buffer(struct wlr_output *output,
const struct wlr_output_state *state, bool *new_back_buffer);
#endif #endif

View file

@ -0,0 +1,8 @@
#ifndef TYPES_WLR_SCENE_H
#define TYPES_WLR_SCENE_H
#include <wlr/types/wlr_scene.h>
struct wlr_scene *scene_node_get_root(struct wlr_scene_node *node);
#endif

View file

@ -26,6 +26,10 @@ void create_xdg_popup(struct wlr_xdg_surface *surface,
void unmap_xdg_popup(struct wlr_xdg_popup *popup); void unmap_xdg_popup(struct wlr_xdg_popup *popup);
void destroy_xdg_popup(struct wlr_xdg_popup *popup); void destroy_xdg_popup(struct wlr_xdg_popup *popup);
void handle_xdg_popup_committed(struct wlr_xdg_popup *popup); void handle_xdg_popup_committed(struct wlr_xdg_popup *popup);
struct wlr_xdg_popup_configure *send_xdg_popup_configure(
struct wlr_xdg_popup *popup);
void handle_xdg_popup_ack_configure(struct wlr_xdg_popup *popup,
struct wlr_xdg_popup_configure *configure);
void create_xdg_toplevel(struct wlr_xdg_surface *surface, void create_xdg_toplevel(struct wlr_xdg_surface *surface,
uint32_t id); uint32_t id);

View file

@ -1,30 +1,18 @@
#ifndef UTIL_ARRAY_H #ifndef UTIL_ARRAY_H
#define UTIL_ARRAY_H #define UTIL_ARRAY_H
#include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
#include <wayland-util.h> #include <wayland-util.h>
size_t push_zeroes_to_end(uint32_t arr[], size_t n);
/**
* Add `target` to `values` if it doesn't exist
* "set"s should only be modified with set_* functions
* Values MUST be greater than 0
*/
bool set_add(uint32_t values[], size_t *len, size_t cap, uint32_t target);
/**
* Remove `target` from `values` if it exists
* "set"s should only be modified with set_* functions
* Values MUST be greater than 0
*/
bool set_remove(uint32_t values[], size_t *len, size_t cap, uint32_t target);
/** /**
* Remove a chunk of memory of the specified size at the specified offset. * Remove a chunk of memory of the specified size at the specified offset.
*/ */
void array_remove_at(struct wl_array *arr, size_t offset, size_t size); void array_remove_at(struct wl_array *arr, size_t offset, size_t size);
/**
* Grow or shrink the array to fit the specifized size.
*/
bool array_realloc(struct wl_array *arr, size_t size);
#endif #endif

11
include/util/env.h Normal file
View file

@ -0,0 +1,11 @@
#ifndef UTIL_ENV_H
#define UTIL_ENV_H
#include <stdbool.h>
#include <unistd.h>
bool env_parse_bool(const char *option);
ssize_t env_parse_switch(const char *option, const char **switches);
#endif

29
include/util/set.h Normal file
View file

@ -0,0 +1,29 @@
#ifndef UTIL_SET_H
#define UTIL_SET_H
#include <stdint.h>
#include <stdbool.h>
#include <sys/types.h>
/**
* Add target to values.
*
* Target is added to the end of the set.
*
* Returns the index of target, or -1 if the set is full or target already
* exists.
*/
ssize_t set_add(uint32_t values[], size_t *len, size_t cap, uint32_t target);
/**
* Remove target from values.
*
* When target is removed, the last element of the set is moved to where
* target was.
*
* Returns the previous index of target, or -1 if target wasn't in values.
*/
ssize_t set_remove(uint32_t values[], size_t *len, size_t cap, uint32_t target);
#endif

View file

@ -1,8 +0,0 @@
#ifndef UTIL_SIGNAL_H
#define UTIL_SIGNAL_H
#include <wayland-server-core.h>
void wlr_signal_emit_safe(struct wl_signal *signal, void *data);
#endif

View file

@ -14,22 +14,25 @@
struct wlr_backend_impl; struct wlr_backend_impl;
/**
* A backend provides a set of input and output devices.
*/
struct wlr_backend { struct wlr_backend {
const struct wlr_backend_impl *impl; const struct wlr_backend_impl *impl;
struct { struct {
/** Raised when destroyed, passed the wlr_backend reference */ /** Raised when destroyed */
struct wl_signal destroy; struct wl_signal destroy;
/** Raised when new inputs are added, passed the wlr_input_device */ /** Raised when new inputs are added, passed the struct wlr_input_device */
struct wl_signal new_input; struct wl_signal new_input;
/** Raised when new outputs are added, passed the wlr_output */ /** Raised when new outputs are added, passed the struct wlr_output */
struct wl_signal new_output; struct wl_signal new_output;
} events; } events;
}; };
/** /**
* Automatically initializes the most suitable backend given the environment. * Automatically initializes the most suitable backend given the environment.
* Will always return a multibackend. The backend is created but not started. * Will always return a multi-backend. The backend is created but not started.
* Returns NULL on failure. * Returns NULL on failure.
*/ */
struct wlr_backend *wlr_backend_autocreate(struct wl_display *display); struct wlr_backend *wlr_backend_autocreate(struct wl_display *display);
@ -41,11 +44,11 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display);
bool wlr_backend_start(struct wlr_backend *backend); bool wlr_backend_start(struct wlr_backend *backend);
/** /**
* Destroy the backend and clean up all of its resources. Normally called * Destroy the backend and clean up all of its resources. Normally called
* automatically when the wl_display is destroyed. * automatically when the struct wl_display is destroyed.
*/ */
void wlr_backend_destroy(struct wlr_backend *backend); void wlr_backend_destroy(struct wlr_backend *backend);
/** /**
* Obtains the wlr_session reference from this backend if there is any. * Obtains the struct wlr_session reference from this backend if there is any.
* Might return NULL for backends that don't use a session. * Might return NULL for backends that don't use a session.
*/ */
struct wlr_session *wlr_backend_get_session(struct wlr_backend *backend); struct wlr_session *wlr_backend_get_session(struct wlr_backend *backend);

View file

@ -48,8 +48,9 @@ bool wlr_output_is_drm(struct wlr_output *output);
uint32_t wlr_drm_connector_get_id(struct wlr_output *output); uint32_t wlr_drm_connector_get_id(struct wlr_output *output);
/** /**
* Tries to open non-master DRM FD. The compositor must not call `drmSetMaster` * Tries to open non-master DRM FD. The compositor must not call drmSetMaster()
* on the returned FD. * on the returned FD.
*
* Returns a valid opened DRM FD, or -1 on error. * Returns a valid opened DRM FD, or -1 on error.
*/ */
int wlr_drm_backend_get_non_master_fd(struct wlr_backend *backend); int wlr_drm_backend_get_non_master_fd(struct wlr_backend *backend);
@ -71,7 +72,7 @@ struct wlr_drm_lease *wlr_drm_create_lease(struct wlr_output **outputs,
void wlr_drm_lease_terminate(struct wlr_drm_lease *lease); void wlr_drm_lease_terminate(struct wlr_drm_lease *lease);
/** /**
* Add mode to the list of available modes * Add mode to the list of available modes.
*/ */
typedef struct _drmModeModeInfo drmModeModeInfo; typedef struct _drmModeModeInfo drmModeModeInfo;
struct wlr_output_mode *wlr_drm_connector_add_mode(struct wlr_output *output, struct wlr_output_mode *wlr_drm_connector_add_mode(struct wlr_output *output,

View file

@ -10,7 +10,6 @@
#define WLR_BACKEND_HEADLESS_H #define WLR_BACKEND_HEADLESS_H
#include <wlr/backend.h> #include <wlr/backend.h>
#include <wlr/types/wlr_input_device.h>
#include <wlr/types/wlr_output.h> #include <wlr/types/wlr_output.h>
/** /**
@ -19,9 +18,9 @@
*/ */
struct wlr_backend *wlr_headless_backend_create(struct wl_display *display); struct wlr_backend *wlr_headless_backend_create(struct wl_display *display);
/** /**
* Create a new headless output backed by an in-memory EGL framebuffer. You can * Create a new headless output.
* read pixels from this framebuffer via wlr_renderer_read_pixels but it is *
* otherwise not displayed. * The buffers presented on the output won't be displayed to the user.
*/ */
struct wlr_output *wlr_headless_add_output(struct wlr_backend *backend, struct wlr_output *wlr_headless_add_output(struct wlr_backend *backend,
unsigned int width, unsigned int height); unsigned int width, unsigned int height);

View file

@ -23,8 +23,8 @@ struct wlr_backend_impl {
}; };
/** /**
* Initializes common state on a wlr_backend and sets the implementation to the * Initializes common state on a struct wlr_backend and sets the implementation
* provided wlr_backend_impl reference. * to the provided struct wlr_backend_impl reference.
*/ */
void wlr_backend_init(struct wlr_backend *backend, void wlr_backend_init(struct wlr_backend *backend,
const struct wlr_backend_impl *impl); const struct wlr_backend_impl *impl);

View file

@ -13,11 +13,14 @@
#include <wayland-server-core.h> #include <wayland-server-core.h>
#include <wlr/backend.h> #include <wlr/backend.h>
#include <wlr/backend/session.h> #include <wlr/backend/session.h>
#include <wlr/types/wlr_input_device.h>
struct wlr_input_device;
struct wlr_backend *wlr_libinput_backend_create(struct wl_display *display, struct wlr_backend *wlr_libinput_backend_create(struct wl_display *display,
struct wlr_session *session); struct wlr_session *session);
/** Gets the underlying libinput_device handle for the given wlr_input_device */ /**
* Gets the underlying struct libinput_device handle for the given input device.
*/
struct libinput_device *wlr_libinput_get_device_handle( struct libinput_device *wlr_libinput_get_device_handle(
struct wlr_input_device *dev); struct wlr_input_device *dev);

View file

@ -79,36 +79,33 @@ struct wlr_device_change_event {
* This should not be called if another program is already in control * This should not be called if another program is already in control
* of the terminal (Xorg, another Wayland compositor, etc.). * of the terminal (Xorg, another Wayland compositor, etc.).
* *
* If libseat support is not enabled, or if a standalone backend is to be used,
* then you must have CAP_SYS_ADMIN or be root. It is safe to drop privileges
* after this is called.
*
* Returns NULL on error. * Returns NULL on error.
*/ */
struct wlr_session *wlr_session_create(struct wl_display *disp); struct wlr_session *wlr_session_create(struct wl_display *disp);
/* /*
* Closes a previously opened session and restores the virtual terminal. * Closes a previously opened session and restores the virtual terminal.
* You should call wlr_session_close_file on each files you opened * You should call wlr_session_close_file() on each files you opened
* with wlr_session_open_file before you call this. * with wlr_session_open_file() before you call this.
*/ */
void wlr_session_destroy(struct wlr_session *session); void wlr_session_destroy(struct wlr_session *session);
/* /*
* Opens the file at path. * Opens the file at path.
* This can only be used to open DRM or evdev (input) devices. *
* This can only be used to open DRM or evdev (input) devices. Files opened via
* this function must be closed by calling wlr_session_close_file().
* *
* When the session becomes inactive: * When the session becomes inactive:
*
* - DRM files lose their DRM master status * - DRM files lose their DRM master status
* - evdev files become invalid and should be closed * - evdev files become invalid and should be closed
*
* Returns -errno on error.
*/ */
struct wlr_device *wlr_session_open_file(struct wlr_session *session, struct wlr_device *wlr_session_open_file(struct wlr_session *session,
const char *path); const char *path);
/* /*
* Closes a file previously opened with wlr_session_open_file. * Closes a file previously opened with wlr_session_open_file().
*/ */
void wlr_session_close_file(struct wlr_session *session, void wlr_session_close_file(struct wlr_session *session,
struct wlr_device *device); struct wlr_device *device);

View file

@ -4,22 +4,23 @@
#include <wayland-client.h> #include <wayland-client.h>
#include <wayland-server-core.h> #include <wayland-server-core.h>
#include <wlr/backend.h> #include <wlr/backend.h>
#include <wlr/types/wlr_input_device.h>
#include <wlr/types/wlr_output.h> #include <wlr/types/wlr_output.h>
struct wlr_input_device;
/** /**
* Creates a new wlr_wl_backend. This backend will be created with no outputs; * Creates a new Wayland backend. This backend will be created with no outputs;
* you must use wlr_wl_output_create to add them. * you must use wlr_wl_output_create() to add them.
* *
* The `remote` argument is the name of the host compositor wayland socket. Set * The `remote` argument is the name of the host compositor wayland socket. Set
* to NULL for the default behaviour (WAYLAND_DISPLAY env variable or wayland-0 * to NULL for the default behaviour (WAYLAND_DISPLAY env variable or wayland-0
* default) * default).
*/ */
struct wlr_backend *wlr_wl_backend_create(struct wl_display *display, struct wlr_backend *wlr_wl_backend_create(struct wl_display *display,
const char *remote); const char *remote);
/** /**
* Returns the remote wl_display used by the Wayland backend. * Returns the remote struct wl_display used by the Wayland backend.
*/ */
struct wl_display *wlr_wl_backend_get_remote_display(struct wlr_backend *backend); struct wl_display *wlr_wl_backend_get_remote_display(struct wlr_backend *backend);
@ -27,37 +28,37 @@ struct wl_display *wlr_wl_backend_get_remote_display(struct wlr_backend *backend
* Adds a new output to this backend. You may remove outputs by destroying them. * Adds a new output to this backend. You may remove outputs by destroying them.
* Note that if called before initializing the backend, this will return NULL * Note that if called before initializing the backend, this will return NULL
* and your outputs will be created during initialization (and given to you via * and your outputs will be created during initialization (and given to you via
* the output_add signal). * the new_output signal).
*/ */
struct wlr_output *wlr_wl_output_create(struct wlr_backend *backend); struct wlr_output *wlr_wl_output_create(struct wlr_backend *backend);
/** /**
* True if the given backend is a wlr_wl_backend. * Check whether the provided backend is a Wayland backend.
*/ */
bool wlr_backend_is_wl(struct wlr_backend *backend); bool wlr_backend_is_wl(struct wlr_backend *backend);
/** /**
* True if the given input device is a wlr_wl_input_device. * Check whether the provided input device is a Wayland input device.
*/ */
bool wlr_input_device_is_wl(struct wlr_input_device *device); bool wlr_input_device_is_wl(struct wlr_input_device *device);
/** /**
* True if the given output is a wlr_wl_output. * Check whether the provided output device is a Wayland output device.
*/ */
bool wlr_output_is_wl(struct wlr_output *output); bool wlr_output_is_wl(struct wlr_output *output);
/** /**
* Sets the title of a wlr_output which is a Wayland window. * Sets the title of a struct wlr_output which is a Wayland toplevel.
*/ */
void wlr_wl_output_set_title(struct wlr_output *output, const char *title); void wlr_wl_output_set_title(struct wlr_output *output, const char *title);
/** /**
* Returns the remote wl_surface used by the Wayland output. * Returns the remote struct wl_surface used by the Wayland output.
*/ */
struct wl_surface *wlr_wl_output_get_surface(struct wlr_output *output); struct wl_surface *wlr_wl_output_get_surface(struct wlr_output *output);
/** /**
* Returns the remote wl_seat for a Wayland input device. * Returns the remote struct wl_seat for a Wayland input device.
*/ */
struct wl_seat *wlr_wl_input_device_get_seat(struct wlr_input_device *dev); struct wl_seat *wlr_wl_input_device_get_seat(struct wlr_input_device *dev);

View file

@ -6,15 +6,16 @@
#include <wayland-server-core.h> #include <wayland-server-core.h>
#include <wlr/backend.h> #include <wlr/backend.h>
#include <wlr/types/wlr_input_device.h>
#include <wlr/types/wlr_output.h> #include <wlr/types/wlr_output.h>
struct wlr_input_device;
/** /**
* Creates a new wlr_x11_backend. This backend will be created with no outputs; * Creates a new X11 backend. This backend will be created with no outputs;
* you must use wlr_x11_output_create to add them. * you must use wlr_x11_output_create() to add them.
* *
* The `x11_display` argument is the name of the X Display socket. Set * The `x11_display` argument is the name of the X Display socket. Set
* to NULL for the default behaviour of XOpenDisplay. * to NULL for the default behaviour of XOpenDisplay().
*/ */
struct wlr_backend *wlr_x11_backend_create(struct wl_display *display, struct wlr_backend *wlr_x11_backend_create(struct wl_display *display,
const char *x11_display); const char *x11_display);
@ -23,27 +24,27 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_display *display,
* Adds a new output to this backend. You may remove outputs by destroying them. * Adds a new output to this backend. You may remove outputs by destroying them.
* Note that if called before initializing the backend, this will return NULL * Note that if called before initializing the backend, this will return NULL
* and your outputs will be created during initialization (and given to you via * and your outputs will be created during initialization (and given to you via
* the output_add signal). * the new_output signal).
*/ */
struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend); struct wlr_output *wlr_x11_output_create(struct wlr_backend *backend);
/** /**
* True if the given backend is a wlr_x11_backend. * Check whether this backend is an X11 backend.
*/ */
bool wlr_backend_is_x11(struct wlr_backend *backend); bool wlr_backend_is_x11(struct wlr_backend *backend);
/** /**
* True if the given input device is a wlr_x11_input_device. * Check whether this input device is an X11 input device.
*/ */
bool wlr_input_device_is_x11(struct wlr_input_device *device); bool wlr_input_device_is_x11(struct wlr_input_device *device);
/** /**
* True if the given output is a wlr_x11_output. * Check whether this output device is an X11 output device.
*/ */
bool wlr_output_is_x11(struct wlr_output *output); bool wlr_output_is_x11(struct wlr_output *output);
/** /**
* Sets the title of a wlr_output which is an X11 window. * Sets the title of a struct wlr_output which is an X11 window.
*/ */
void wlr_x11_output_set_title(struct wlr_output *output, const char *title); void wlr_x11_output_set_title(struct wlr_output *output, const char *title);

View file

@ -6,9 +6,10 @@
#mesondefine WLR_HAS_X11_BACKEND #mesondefine WLR_HAS_X11_BACKEND
#mesondefine WLR_HAS_GLES2_RENDERER #mesondefine WLR_HAS_GLES2_RENDERER
#mesondefine WLR_HAS_VULKAN_RENDERER #mesondefine WLR_HAS_VULKAN_RENDERER
#mesondefine WLR_HAS_GBM_ALLOCATOR
#mesondefine WLR_HAS_XWAYLAND #mesondefine WLR_HAS_XWAYLAND
#endif #endif

View file

@ -0,0 +1,48 @@
/*
* This an unstable interface of wlroots. No guarantees are made regarding the
* future consistency of this API.
*/
#ifndef WLR_USE_UNSTABLE
#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
#endif
#ifndef WLR_INTERFACES_WLR_BUFFER_H
#define WLR_INTERFACES_WLR_BUFFER_H
#include <wlr/types/wlr_buffer.h>
struct wlr_buffer_impl {
void (*destroy)(struct wlr_buffer *buffer);
bool (*get_dmabuf)(struct wlr_buffer *buffer,
struct wlr_dmabuf_attributes *attribs);
bool (*get_shm)(struct wlr_buffer *buffer,
struct wlr_shm_attributes *attribs);
bool (*begin_data_ptr_access)(struct wlr_buffer *buffer, uint32_t flags,
void **data, uint32_t *format, size_t *stride);
void (*end_data_ptr_access)(struct wlr_buffer *buffer);
};
struct wlr_buffer_resource_interface {
const char *name;
bool (*is_instance)(struct wl_resource *resource);
struct wlr_buffer *(*from_resource)(struct wl_resource *resource);
};
/**
* Initialize a buffer. This function should be called by producers. The
* initialized buffer is referenced: once the producer is done with the buffer
* they should call wlr_buffer_drop().
*/
void wlr_buffer_init(struct wlr_buffer *buffer,
const struct wlr_buffer_impl *impl, int width, int height);
/**
* Allows the registration of a struct wl_resource implementation.
*
* The matching function will be called for the struct wl_resource when creating
* a struct wlr_buffer from a struct wl_resource.
*/
void wlr_buffer_register_resource_interface(
const struct wlr_buffer_resource_interface *iface);
#endif

View file

@ -13,15 +13,20 @@
#include <wlr/types/wlr_keyboard.h> #include <wlr/types/wlr_keyboard.h>
struct wlr_keyboard_impl { struct wlr_keyboard_impl {
void (*destroy)(struct wlr_keyboard *keyboard); const char *name;
void (*led_update)(struct wlr_keyboard *keyboard, uint32_t leds); void (*led_update)(struct wlr_keyboard *keyboard, uint32_t leds);
}; };
void wlr_keyboard_init(struct wlr_keyboard *keyboard, void wlr_keyboard_init(struct wlr_keyboard *keyboard,
const struct wlr_keyboard_impl *impl, const char *name); const struct wlr_keyboard_impl *impl, const char *name);
void wlr_keyboard_destroy(struct wlr_keyboard *keyboard);
/**
* Cleans up all of the resources owned by the struct wlr_keyboard.
*/
void wlr_keyboard_finish(struct wlr_keyboard *keyboard);
void wlr_keyboard_notify_key(struct wlr_keyboard *keyboard, void wlr_keyboard_notify_key(struct wlr_keyboard *keyboard,
struct wlr_event_keyboard_key *event); struct wlr_keyboard_key_event *event);
void wlr_keyboard_notify_modifiers(struct wlr_keyboard *keyboard, void wlr_keyboard_notify_modifiers(struct wlr_keyboard *keyboard,
uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked,
uint32_t group); uint32_t group);

View file

@ -22,10 +22,10 @@
WLR_OUTPUT_STATE_SCALE | \ WLR_OUTPUT_STATE_SCALE | \
WLR_OUTPUT_STATE_TRANSFORM | \ WLR_OUTPUT_STATE_TRANSFORM | \
WLR_OUTPUT_STATE_RENDER_FORMAT | \ WLR_OUTPUT_STATE_RENDER_FORMAT | \
WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) WLR_OUTPUT_STATE_SUBPIXEL)
/** /**
* A backend implementation of wlr_output. * A backend implementation of struct wlr_output.
* *
* The commit function is mandatory. Other functions are optional. * The commit function is mandatory. Other functions are optional.
*/ */
@ -38,7 +38,7 @@ struct wlr_output_impl {
* The hotspot indicates the offset that needs to be applied to the * The hotspot indicates the offset that needs to be applied to the
* top-left corner of the image to match the cursor position. In other * top-left corner of the image to match the cursor position. In other
* words, the image should be displayed at (x - hotspot_x, y - hotspot_y). * words, the image should be displayed at (x - hotspot_x, y - hotspot_y).
* The hotspot is given in the texture's coordinate space. * The hotspot is given in the buffer's coordinate space.
*/ */
bool (*set_cursor)(struct wlr_output *output, struct wlr_buffer *buffer, bool (*set_cursor)(struct wlr_output *output, struct wlr_buffer *buffer,
int hotspot_x, int hotspot_y); int hotspot_x, int hotspot_y);
@ -53,18 +53,18 @@ struct wlr_output_impl {
*/ */
void (*destroy)(struct wlr_output *output); void (*destroy)(struct wlr_output *output);
/** /**
* Check that the pending output state is a valid configuration. * Check that the supplied output state is a valid configuration.
* *
* If this function returns true, commit can only fail due to a runtime * If this function returns true, commit can only fail due to a runtime
* error. * error.
*/ */
bool (*test)(struct wlr_output *output); bool (*test)(struct wlr_output *output, const struct wlr_output_state *state);
/** /**
* Commit the pending output state. * Commit the supplied output state.
* *
* If a buffer has been attached, a frame event is scheduled. * If a buffer has been attached, a frame event is scheduled.
*/ */
bool (*commit)(struct wlr_output *output); bool (*commit)(struct wlr_output *output, const struct wlr_output_state *state);
/** /**
* Get the maximum number of gamma LUT elements for each channel. * Get the maximum number of gamma LUT elements for each channel.
* *

View file

@ -12,11 +12,11 @@
#include <wlr/types/wlr_pointer.h> #include <wlr/types/wlr_pointer.h>
struct wlr_pointer_impl { struct wlr_pointer_impl {
void (*destroy)(struct wlr_pointer *pointer); const char *name;
}; };
void wlr_pointer_init(struct wlr_pointer *pointer, void wlr_pointer_init(struct wlr_pointer *pointer,
const struct wlr_pointer_impl *impl, const char *name); const struct wlr_pointer_impl *impl, const char *name);
void wlr_pointer_destroy(struct wlr_pointer *pointer); void wlr_pointer_finish(struct wlr_pointer *pointer);
#endif #endif

View file

@ -12,11 +12,11 @@
#include <wlr/types/wlr_switch.h> #include <wlr/types/wlr_switch.h>
struct wlr_switch_impl { struct wlr_switch_impl {
void (*destroy)(struct wlr_switch *switch_device); const char *name;
}; };
void wlr_switch_init(struct wlr_switch *switch_device, void wlr_switch_init(struct wlr_switch *switch_device,
const struct wlr_switch_impl *impl, const char *name); const struct wlr_switch_impl *impl, const char *name);
void wlr_switch_destroy(struct wlr_switch *switch_device); void wlr_switch_finish(struct wlr_switch *switch_device);
#endif #endif

View file

@ -12,11 +12,19 @@
#include <wlr/types/wlr_tablet_pad.h> #include <wlr/types/wlr_tablet_pad.h>
struct wlr_tablet_pad_impl { struct wlr_tablet_pad_impl {
void (*destroy)(struct wlr_tablet_pad *pad); const char *name;
}; };
void wlr_tablet_pad_init(struct wlr_tablet_pad *pad, void wlr_tablet_pad_init(struct wlr_tablet_pad *pad,
const struct wlr_tablet_pad_impl *impl, const char *name); const struct wlr_tablet_pad_impl *impl, const char *name);
void wlr_tablet_pad_destroy(struct wlr_tablet_pad *pad);
/**
* Cleans up the resources owned by a struct wlr_tablet_pad.
*
* This function will not clean the memory allocated by
* struct wlr_tablet_pad_group, it's the responsibility of the caller to clean
* it.
*/
void wlr_tablet_pad_finish(struct wlr_tablet_pad *pad);
#endif #endif

View file

@ -12,11 +12,11 @@
#include <wlr/types/wlr_tablet_tool.h> #include <wlr/types/wlr_tablet_tool.h>
struct wlr_tablet_impl { struct wlr_tablet_impl {
void (*destroy)(struct wlr_tablet *tablet); const char *name;
}; };
void wlr_tablet_init(struct wlr_tablet *tablet, void wlr_tablet_init(struct wlr_tablet *tablet,
const struct wlr_tablet_impl *impl, const char *name); const struct wlr_tablet_impl *impl, const char *name);
void wlr_tablet_destroy(struct wlr_tablet *tablet); void wlr_tablet_finish(struct wlr_tablet *tablet);
#endif #endif

View file

@ -12,11 +12,11 @@
#include <wlr/types/wlr_touch.h> #include <wlr/types/wlr_touch.h>
struct wlr_touch_impl { struct wlr_touch_impl {
void (*destroy)(struct wlr_touch *touch); const char *name;
}; };
void wlr_touch_init(struct wlr_touch *touch, void wlr_touch_init(struct wlr_touch *touch,
const struct wlr_touch_impl *impl, const char *name); const struct wlr_touch_impl *impl, const char *name);
void wlr_touch_destroy(struct wlr_touch *touch); void wlr_touch_finish(struct wlr_touch *touch);
#endif #endif

View file

@ -1,4 +1,5 @@
version_array = meson.project_version().split('.') version_base = meson.project_version().split('-')[0]
version_array = version_base.split('.')
version_data = configuration_data() version_data = configuration_data()
version_data.set_quoted('WLR_VERSION_STR', meson.project_version()) version_data.set_quoted('WLR_VERSION_STR', meson.project_version())
version_data.set('WLR_VERSION_MAJOR', version_array[0]) version_data.set('WLR_VERSION_MAJOR', version_array[0])

View file

@ -37,7 +37,7 @@ struct wlr_allocator {
}; };
/** /**
* Creates the adequate wlr_allocator given a backend and a renderer * Creates the adequate struct wlr_allocator given a backend and a renderer.
*/ */
struct wlr_allocator *wlr_allocator_autocreate(struct wlr_backend *backend, struct wlr_allocator *wlr_allocator_autocreate(struct wlr_backend *backend,
struct wlr_renderer *renderer); struct wlr_renderer *renderer);
@ -50,7 +50,7 @@ void wlr_allocator_destroy(struct wlr_allocator *alloc);
* Allocate a new buffer. * Allocate a new buffer.
* *
* When the caller is done with it, they must unreference it by calling * When the caller is done with it, they must unreference it by calling
* wlr_buffer_drop. * wlr_buffer_drop().
* *
* The `format` passed in indicates the format to use and the list of * The `format` passed in indicates the format to use and the list of
* acceptable modifiers. The order in which modifiers are listed is not * acceptable modifiers. The order in which modifiers are listed is not

View file

@ -51,7 +51,7 @@ struct wlr_drm_format_set {
void wlr_drm_format_set_finish(struct wlr_drm_format_set *set); void wlr_drm_format_set_finish(struct wlr_drm_format_set *set);
/** /**
* Return a pointer to a member of this `wlr_drm_format_set` of format * Return a pointer to a member of this struct wlr_drm_format_set of format
* `format`, or NULL if none exists. * `format`, or NULL if none exists.
*/ */
const struct wlr_drm_format *wlr_drm_format_set_get( const struct wlr_drm_format *wlr_drm_format_set_get(

View file

@ -9,9 +9,6 @@
#ifndef WLR_RENDER_EGL_H #ifndef WLR_RENDER_EGL_H
#define WLR_RENDER_EGL_H #define WLR_RENDER_EGL_H
#ifndef MESA_EGL_NO_X11_HEADERS
#define MESA_EGL_NO_X11_HEADERS
#endif
#ifndef EGL_NO_X11 #ifndef EGL_NO_X11
#define EGL_NO_X11 #define EGL_NO_X11
#endif #endif
@ -29,60 +26,31 @@
#include <wlr/render/dmabuf.h> #include <wlr/render/dmabuf.h>
#include <wlr/render/drm_format_set.h> #include <wlr/render/drm_format_set.h>
struct wlr_egl { struct wlr_egl;
EGLDisplay display;
EGLContext context;
EGLDeviceEXT device; // may be EGL_NO_DEVICE_EXT
struct gbm_device *gbm_device;
struct {
// Display extensions
bool KHR_image_base;
bool EXT_image_dma_buf_import;
bool EXT_image_dma_buf_import_modifiers;
bool IMG_context_priority;
// Device extensions
bool EXT_device_drm;
bool EXT_device_drm_render_node;
// Client extensions
bool EXT_device_query;
bool KHR_platform_gbm;
bool EXT_platform_device;
} exts;
struct {
PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT;
PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR;
PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR;
PFNEGLQUERYWAYLANDBUFFERWL eglQueryWaylandBufferWL;
PFNEGLQUERYDMABUFFORMATSEXTPROC eglQueryDmaBufFormatsEXT;
PFNEGLQUERYDMABUFMODIFIERSEXTPROC eglQueryDmaBufModifiersEXT;
PFNEGLDEBUGMESSAGECONTROLKHRPROC eglDebugMessageControlKHR;
PFNEGLQUERYDISPLAYATTRIBEXTPROC eglQueryDisplayAttribEXT;
PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT;
PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT;
} procs;
bool has_modifiers;
struct wlr_drm_format_set dmabuf_texture_formats;
struct wlr_drm_format_set dmabuf_render_formats;
};
/**
* Create a struct wlr_egl with an existing EGL display and context.
*
* This is typically used by compositors which want to customize EGL
* initialization.
*/
struct wlr_egl *wlr_egl_create_with_context(EGLDisplay display, struct wlr_egl *wlr_egl_create_with_context(EGLDisplay display,
EGLContext context); EGLContext context);
/** /**
* Make the EGL context current. * Get the EGL display used by the struct wlr_egl.
* *
* Callers are expected to clear the current context when they are done by * This is typically used by compositors which need to perform custom OpenGL
* calling wlr_egl_unset_current. * operations.
*/ */
bool wlr_egl_make_current(struct wlr_egl *egl); EGLDisplay wlr_egl_get_display(struct wlr_egl *egl);
bool wlr_egl_unset_current(struct wlr_egl *egl); /**
* Get the EGL context used by the struct wlr_egl.
bool wlr_egl_is_current(struct wlr_egl *egl); *
* This is typically used by compositors which need to perform custom OpenGL
* operations.
*/
EGLContext wlr_egl_get_context(struct wlr_egl *egl);
#endif #endif

View file

@ -54,11 +54,8 @@ void wlr_renderer_init(struct wlr_renderer *renderer,
const struct wlr_renderer_impl *impl); const struct wlr_renderer_impl *impl);
struct wlr_texture_impl { struct wlr_texture_impl {
bool (*is_opaque)(struct wlr_texture *texture); bool (*update_from_buffer)(struct wlr_texture *texture,
bool (*write_pixels)(struct wlr_texture *texture, struct wlr_buffer *buffer, pixman_region32_t *damage);
uint32_t stride, uint32_t width, uint32_t height,
uint32_t src_x, uint32_t src_y, uint32_t dst_x, uint32_t dst_y,
const void *data);
void (*destroy)(struct wlr_texture *texture); void (*destroy)(struct wlr_texture *texture);
}; };

View file

@ -77,13 +77,13 @@ void wlr_render_quad_with_matrix(struct wlr_renderer *r,
const float color[static 4], const float matrix[static 9]); const float color[static 4], const float matrix[static 9]);
/** /**
* Get the shared-memory formats supporting import usage. Buffers allocated * Get the shared-memory formats supporting import usage. Buffers allocated
* with a format from this list may be imported via wlr_texture_from_pixels. * with a format from this list may be imported via wlr_texture_from_pixels().
*/ */
const uint32_t *wlr_renderer_get_shm_texture_formats( const uint32_t *wlr_renderer_get_shm_texture_formats(
struct wlr_renderer *r, size_t *len); struct wlr_renderer *r, size_t *len);
/** /**
* Get the DMA-BUF formats supporting sampling usage. Buffers allocated with * Get the DMA-BUF formats supporting sampling usage. Buffers allocated with
* a format from this list may be imported via wlr_texture_from_dmabuf. * a format from this list may be imported via wlr_texture_from_dmabuf().
*/ */
const struct wlr_drm_format_set *wlr_renderer_get_dmabuf_texture_formats( const struct wlr_drm_format_set *wlr_renderer_get_dmabuf_texture_formats(
struct wlr_renderer *renderer); struct wlr_renderer *renderer);
@ -92,7 +92,7 @@ const struct wlr_drm_format_set *wlr_renderer_get_dmabuf_texture_formats(
* bytes. * bytes.
* *
* If `flags` is not NULl, the caller indicates that it accepts frame flags * If `flags` is not NULl, the caller indicates that it accepts frame flags
* defined in `enum wlr_renderer_read_pixels_flags`. * defined in enum wlr_renderer_read_pixels_flags.
*/ */
bool wlr_renderer_read_pixels(struct wlr_renderer *r, uint32_t fmt, bool wlr_renderer_read_pixels(struct wlr_renderer *r, uint32_t fmt,
uint32_t *flags, uint32_t stride, uint32_t width, uint32_t height, uint32_t *flags, uint32_t stride, uint32_t width, uint32_t height,
@ -107,7 +107,7 @@ bool wlr_renderer_init_wl_display(struct wlr_renderer *r,
struct wl_display *wl_display); struct wl_display *wl_display);
/** /**
* Initializes wl_shm on the provided wl_display. * Initializes wl_shm on the provided struct wl_display.
*/ */
bool wlr_renderer_init_wl_shm(struct wlr_renderer *r, bool wlr_renderer_init_wl_shm(struct wlr_renderer *r,
struct wl_display *wl_display); struct wl_display *wl_display);
@ -120,7 +120,9 @@ bool wlr_renderer_init_wl_shm(struct wlr_renderer *r,
int wlr_renderer_get_drm_fd(struct wlr_renderer *r); int wlr_renderer_get_drm_fd(struct wlr_renderer *r);
/** /**
* Destroys this wlr_renderer. Textures must be destroyed separately. * Destroys the renderer.
*
* Textures must be destroyed separately.
*/ */
void wlr_renderer_destroy(struct wlr_renderer *renderer); void wlr_renderer_destroy(struct wlr_renderer *renderer);

View file

@ -9,6 +9,7 @@
#ifndef WLR_RENDER_WLR_TEXTURE_H #ifndef WLR_RENDER_WLR_TEXTURE_H
#define WLR_RENDER_WLR_TEXTURE_H #define WLR_RENDER_WLR_TEXTURE_H
#include <pixman.h>
#include <stdint.h> #include <stdint.h>
#include <wayland-server-core.h> #include <wayland-server-core.h>
#include <wlr/render/dmabuf.h> #include <wlr/render/dmabuf.h>
@ -25,9 +26,6 @@ struct wlr_texture {
/** /**
* Create a new texture from raw pixel data. `stride` is in bytes. The returned * Create a new texture from raw pixel data. `stride` is in bytes. The returned
* texture is mutable. * texture is mutable.
*
* Should not be called in a rendering block like renderer_begin()/end() or
* between attaching a renderer to an output and committing it.
*/ */
struct wlr_texture *wlr_texture_from_pixels(struct wlr_renderer *renderer, struct wlr_texture *wlr_texture_from_pixels(struct wlr_renderer *renderer,
uint32_t fmt, uint32_t stride, uint32_t width, uint32_t height, uint32_t fmt, uint32_t stride, uint32_t width, uint32_t height,
@ -35,40 +33,30 @@ struct wlr_texture *wlr_texture_from_pixels(struct wlr_renderer *renderer,
/** /**
* Create a new texture from a DMA-BUF. The returned texture is immutable. * Create a new texture from a DMA-BUF. The returned texture is immutable.
*
* Should not be called in a rendering block like renderer_begin()/end() or
* between attaching a renderer to an output and committing it.
*/ */
struct wlr_texture *wlr_texture_from_dmabuf(struct wlr_renderer *renderer, struct wlr_texture *wlr_texture_from_dmabuf(struct wlr_renderer *renderer,
struct wlr_dmabuf_attributes *attribs); struct wlr_dmabuf_attributes *attribs);
/** /**
* Returns true if this texture is using a fully opaque format. * Update a texture with a struct wlr_buffer's contents.
*/
bool wlr_texture_is_opaque(struct wlr_texture *texture);
/**
* Update a texture with raw pixels. The texture must be mutable, and the input
* data must have the same pixel format that the texture was created with.
* *
* Should not be called in a rendering block like renderer_begin()/end() or * The update might be rejected (in case the texture is immutable, the buffer
* between attaching a renderer to an output and committing it. * has an unsupported type/format, etc), so callers must be prepared to fall
* back to re-creating the texture from scratch via wlr_texture_from_buffer().
*
* The damage can be used by the renderer as an optimization: only the supplied
* region needs to be updated.
*/ */
bool wlr_texture_write_pixels(struct wlr_texture *texture, bool wlr_texture_update_from_buffer(struct wlr_texture *texture,
uint32_t stride, uint32_t width, uint32_t height, struct wlr_buffer *buffer, pixman_region32_t *damage);
uint32_t src_x, uint32_t src_y, uint32_t dst_x, uint32_t dst_y,
const void *data);
/** /**
* Destroys this wlr_texture. * Destroys the texture.
*/ */
void wlr_texture_destroy(struct wlr_texture *texture); void wlr_texture_destroy(struct wlr_texture *texture);
/** /**
* Create a new texture from a buffer. * Create a new texture from a buffer.
*
* Should not be called in a rendering block like renderer_begin()/end() or
* between attaching a renderer to an output and committing it.
*/ */
struct wlr_texture *wlr_texture_from_buffer(struct wlr_renderer *renderer, struct wlr_texture *wlr_texture_from_buffer(struct wlr_renderer *renderer,
struct wlr_buffer *buffer); struct wlr_buffer *buffer);

View file

@ -24,22 +24,11 @@ struct wlr_shm_attributes {
off_t offset; off_t offset;
}; };
struct wlr_buffer_impl {
void (*destroy)(struct wlr_buffer *buffer);
bool (*get_dmabuf)(struct wlr_buffer *buffer,
struct wlr_dmabuf_attributes *attribs);
bool (*get_shm)(struct wlr_buffer *buffer,
struct wlr_shm_attributes *attribs);
bool (*begin_data_ptr_access)(struct wlr_buffer *buffer, uint32_t flags,
void **data, uint32_t *format, size_t *stride);
void (*end_data_ptr_access)(struct wlr_buffer *buffer);
};
/** /**
* Buffer capabilities. * Buffer capabilities.
* *
* These bits indicate the features supported by a wlr_buffer. There is one bit * These bits indicate the features supported by a struct wlr_buffer. There is
* per function in wlr_buffer_impl. * one bit per function in struct wlr_buffer_impl.
*/ */
enum wlr_buffer_cap { enum wlr_buffer_cap {
WLR_BUFFER_CAP_DATA_PTR = 1 << 0, WLR_BUFFER_CAP_DATA_PTR = 1 << 0,
@ -72,19 +61,6 @@ struct wlr_buffer {
struct wlr_addon_set addons; struct wlr_addon_set addons;
}; };
struct wlr_buffer_resource_interface {
const char *name;
bool (*is_instance)(struct wl_resource *resource);
struct wlr_buffer *(*from_resource)(struct wl_resource *resource);
};
/**
* Initialize a buffer. This function should be called by producers. The
* initialized buffer is referenced: once the producer is done with the buffer
* they should call wlr_buffer_drop.
*/
void wlr_buffer_init(struct wlr_buffer *buffer,
const struct wlr_buffer_impl *impl, int width, int height);
/** /**
* Unreference the buffer. This function should be called by producers when * Unreference the buffer. This function should be called by producers when
* they are done with the buffer. * they are done with the buffer.
@ -93,7 +69,7 @@ void wlr_buffer_drop(struct wlr_buffer *buffer);
/** /**
* Lock the buffer. This function should be called by consumers to make * Lock the buffer. This function should be called by consumers to make
* sure the buffer can be safely read from. Once the consumer is done with the * sure the buffer can be safely read from. Once the consumer is done with the
* buffer, they should call wlr_buffer_unlock. * buffer, they should call wlr_buffer_unlock().
*/ */
struct wlr_buffer *wlr_buffer_lock(struct wlr_buffer *buffer); struct wlr_buffer *wlr_buffer_lock(struct wlr_buffer *buffer);
/** /**
@ -106,7 +82,7 @@ void wlr_buffer_unlock(struct wlr_buffer *buffer);
* returns false. * returns false.
* *
* The returned DMA-BUF attributes are valid for the lifetime of the * The returned DMA-BUF attributes are valid for the lifetime of the
* wlr_buffer. The caller isn't responsible for cleaning up the DMA-BUF * struct wlr_buffer. The caller isn't responsible for cleaning up the DMA-BUF
* attributes. * attributes.
*/ */
bool wlr_buffer_get_dmabuf(struct wlr_buffer *buffer, bool wlr_buffer_get_dmabuf(struct wlr_buffer *buffer,
@ -116,24 +92,16 @@ bool wlr_buffer_get_dmabuf(struct wlr_buffer *buffer,
* memory, returns false. * memory, returns false.
* *
* The returned shared memory attributes are valid for the lifetime of the * The returned shared memory attributes are valid for the lifetime of the
* wlr_buffer. The caller isn't responsible for cleaning up the shared memory * struct wlr_buffer. The caller isn't responsible for cleaning up the shared
* attributes. * memory attributes.
*/ */
bool wlr_buffer_get_shm(struct wlr_buffer *buffer, bool wlr_buffer_get_shm(struct wlr_buffer *buffer,
struct wlr_shm_attributes *attribs); struct wlr_shm_attributes *attribs);
/** /**
* Allows the registration of a wl_resource implementation. * Transforms a struct wl_resource into a struct wlr_buffer and locks it. Once
* the caller is done with the buffer, they must call wlr_buffer_unlock().
* *
* The matching function will be called for the wl_resource when creating a * The provided struct wl_resource must be a wl_buffer.
* wlr_buffer from a wl_resource.
*/
void wlr_buffer_register_resource_interface(
const struct wlr_buffer_resource_interface *iface);
/**
* Transforms a wl_resource into a wlr_buffer and locks it. Once the caller is
* done with the buffer, they must call wlr_buffer_unlock.
*
* The provided wl_resource must be a wl_buffer.
*/ */
struct wlr_buffer *wlr_buffer_from_resource(struct wl_resource *resource); struct wlr_buffer *wlr_buffer_from_resource(struct wl_resource *resource);
@ -158,7 +126,7 @@ enum wlr_buffer_data_ptr_access_flag {
* *
* The returned pointer should be pointing to a valid memory region for the * The returned pointer should be pointing to a valid memory region for the
* operations specified in the flags. The returned pointer is only valid up to * operations specified in the flags. The returned pointer is only valid up to
* the next buffer_end_data_ptr_access call. * the next wlr_buffer_end_data_ptr_access() call.
*/ */
bool wlr_buffer_begin_data_ptr_access(struct wlr_buffer *buffer, uint32_t flags, bool wlr_buffer_begin_data_ptr_access(struct wlr_buffer *buffer, uint32_t flags,
void **data, uint32_t *format, size_t *stride); void **data, uint32_t *format, size_t *stride);
@ -183,14 +151,11 @@ struct wlr_client_buffer {
// private state // private state
struct wl_listener source_destroy; struct wl_listener source_destroy;
// If the client buffer has been created from a wl_shm buffer
uint32_t shm_source_format;
}; };
/** /**
* Creates a wlr_client_buffer from a given wlr_buffer by creating a texture * Creates a struct wlr_client_buffer from a given struct wlr_buffer by creating
* from it, and copying its wl_resource. * a texture from it, and copying its struct wl_resource.
*/ */
struct wlr_client_buffer *wlr_client_buffer_create(struct wlr_buffer *buffer, struct wlr_client_buffer *wlr_client_buffer_create(struct wlr_buffer *buffer,
struct wlr_renderer *renderer); struct wlr_renderer *renderer);

View file

@ -28,6 +28,7 @@ enum wlr_surface_state_field {
WLR_SURFACE_STATE_SCALE = 1 << 6, WLR_SURFACE_STATE_SCALE = 1 << 6,
WLR_SURFACE_STATE_FRAME_CALLBACK_LIST = 1 << 7, WLR_SURFACE_STATE_FRAME_CALLBACK_LIST = 1 << 7,
WLR_SURFACE_STATE_VIEWPORT = 1 << 8, WLR_SURFACE_STATE_VIEWPORT = 1 << 8,
WLR_SURFACE_STATE_OFFSET = 1 << 9,
}; };
struct wlr_surface_state { struct wlr_surface_state {
@ -147,7 +148,7 @@ struct wlr_surface {
struct wl_signal destroy; struct wl_signal destroy;
} events; } events;
struct wl_list current_outputs; // wlr_surface_output::link struct wl_list current_outputs; // wlr_surface_output.link
struct wlr_addon_set addons; struct wlr_addon_set addons;
void *data; void *data;
@ -162,6 +163,8 @@ struct wlr_surface {
int width, height; int width, height;
int buffer_width, buffer_height; int buffer_width, buffer_height;
} previous; } previous;
bool opaque;
}; };
struct wlr_renderer; struct wlr_renderer;
@ -243,9 +246,10 @@ void wlr_surface_send_frame_done(struct wlr_surface *surface,
void wlr_surface_get_extends(struct wlr_surface *surface, struct wlr_box *box); void wlr_surface_get_extends(struct wlr_surface *surface, struct wlr_box *box);
/** /**
* Get the wlr_surface corresponding to a wl_surface resource. This asserts * Get the struct wlr_surface corresponding to a wl_surface resource.
* that the resource is a valid wl_surface resource created by wlroots and *
* will never return NULL. * This asserts that the resource is a valid wl_surface resource created by
* wlroots and will never return NULL.
*/ */
struct wlr_surface *wlr_surface_from_resource(struct wl_resource *resource); struct wlr_surface *wlr_surface_from_resource(struct wl_resource *resource);
@ -281,7 +285,7 @@ void wlr_surface_get_buffer_source_box(struct wlr_surface *surface,
* Acquire a lock for the pending surface state. * Acquire a lock for the pending surface state.
* *
* The state won't be committed before the caller releases the lock. Instead, * The state won't be committed before the caller releases the lock. Instead,
* the state becomes cached. The caller needs to use wlr_surface_unlock_cached * the state becomes cached. The caller needs to use wlr_surface_unlock_cached()
* to release the lock. * to release the lock.
* *
* Returns a surface commit sequence number for the cached state. * Returns a surface commit sequence number for the cached state.

View file

@ -10,19 +10,20 @@
#define WLR_TYPES_WLR_CURSOR_H #define WLR_TYPES_WLR_CURSOR_H
#include <wayland-server-core.h> #include <wayland-server-core.h>
#include <wlr/types/wlr_input_device.h>
#include <wlr/types/wlr_output_layout.h> #include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_output.h> #include <wlr/types/wlr_output.h>
struct wlr_input_device;
/** /**
* wlr_cursor implements the behavior of the "cursor", that is, the image on the * wlr_cursor implements the behavior of the "cursor", that is, the image on the
* screen typically moved about with a mouse or so. It provides tracking for * screen typically moved about with a mouse or so. It provides tracking for
* this in global coordinates, and integrates with wlr_output, * this in global coordinates, and integrates with struct wlr_output,
* wlr_output_layout, and wlr_input_device. You can use it to abstract multiple * struct wlr_output_layout, and struct wlr_input_device. You can use it to
* input devices over a single cursor, constrain cursor movement to the usable * abstract multiple input devices over a single cursor, constrain cursor
* area of a wlr_output_layout and communicate position updates to the hardware * movement to the usable area of a struct wlr_output_layout and communicate
* cursor, constrain specific input devices to specific outputs or regions of * position updates to the hardware cursor, constrain specific input devices to
* the screen, and so on. * specific outputs or regions of the screen, and so on.
*/ */
struct wlr_box; struct wlr_box;
@ -36,15 +37,15 @@ struct wlr_cursor {
* The interpretation of these signals is the responsibility of the * The interpretation of these signals is the responsibility of the
* compositor, but some helpers are provided for your benefit. If you * compositor, but some helpers are provided for your benefit. If you
* receive a relative motion event, for example, you may want to call * receive a relative motion event, for example, you may want to call
* wlr_cursor_move. If you receive an absolute event, call * wlr_cursor_move(). If you receive an absolute event, call
* wlr_cursor_warp_absolute. If you pass an input device into these * wlr_cursor_warp_absolute(). If you pass an input device into these
* functions, it will apply the region/output constraints associated with * functions, it will apply the region/output constraints associated with
* that device to the resulting cursor motion. If an output layout is * that device to the resulting cursor motion. If an output layout is
* attached, these functions will constrain the resulting cursor motion to * attached, these functions will constrain the resulting cursor motion to
* within the usable space of the output layout. * within the usable space of the output layout.
* *
* Re-broadcasting these signals to, for example, a wlr_seat, is also your * Re-broadcasting these signals to, for example, a struct wlr_seat, is also
* responsibility. * your responsibility.
*/ */
struct { struct {
struct wl_signal motion; struct wl_signal motion;
@ -190,13 +191,14 @@ void wlr_cursor_map_input_to_output(struct wlr_cursor *cur,
struct wlr_input_device *dev, struct wlr_output *output); struct wlr_input_device *dev, struct wlr_output *output);
/** /**
* Maps this cursor to an arbitrary region on the associated wlr_output_layout. * Maps this cursor to an arbitrary region on the associated
* struct wlr_output_layout.
*/ */
void wlr_cursor_map_to_region(struct wlr_cursor *cur, const struct wlr_box *box); void wlr_cursor_map_to_region(struct wlr_cursor *cur, const struct wlr_box *box);
/** /**
* Maps inputs from this input device to an arbitrary region on the associated * Maps inputs from this input device to an arbitrary region on the associated
* wlr_output_layout. * struct wlr_output_layout.
*/ */
void wlr_cursor_map_input_to_region(struct wlr_cursor *cur, void wlr_cursor_map_input_to_region(struct wlr_cursor *cur,
struct wlr_input_device *dev, const struct wlr_box *box); struct wlr_input_device *dev, const struct wlr_box *box);

View file

@ -0,0 +1,81 @@
/*
* This an unstable interface of wlroots. No guarantees are made regarding the
* future consistency of this API.
*/
#ifndef WLR_USE_UNSTABLE
#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
#endif
#ifndef WLR_TYPES_WLR_DAMAGE_RING_H
#define WLR_TYPES_WLR_DAMAGE_RING_H
#include <stdbool.h>
/* For triple buffering, a history of two frames is required. */
#define WLR_DAMAGE_RING_PREVIOUS_LEN 2
struct wlr_box;
struct wlr_damage_ring {
int32_t width, height;
// Difference between the current buffer and the previous one
pixman_region32_t current;
// private state
pixman_region32_t previous[WLR_DAMAGE_RING_PREVIOUS_LEN];
size_t previous_idx;
};
void wlr_damage_ring_init(struct wlr_damage_ring *ring);
void wlr_damage_ring_finish(struct wlr_damage_ring *ring);
/**
* Set ring bounds and damage the ring fully.
*
* Next time damage will be added, it will be cropped to the ring bounds.
* If at least one of the dimensions is 0, bounds are removed.
*
* By default, a damage ring doesn't have bounds.
*/
void wlr_damage_ring_set_bounds(struct wlr_damage_ring *ring,
int32_t width, int32_t height);
/**
* Add a region to the current damage.
*
* Returns true if the region intersects the ring bounds, false otherwise.
*/
bool wlr_damage_ring_add(struct wlr_damage_ring *ring,
pixman_region32_t *damage);
/**
* Add a box to the current damage.
*
* Returns true if the box intersects the ring bounds, false otherwise.
*/
bool wlr_damage_ring_add_box(struct wlr_damage_ring *ring,
const struct wlr_box *box);
/**
* Damage the ring fully.
*/
void wlr_damage_ring_add_whole(struct wlr_damage_ring *ring);
/**
* Rotate the damage ring. This needs to be called after using the accumulated
* damage, e.g. after rendering to an output's back buffer.
*/
void wlr_damage_ring_rotate(struct wlr_damage_ring *ring);
/**
* Get accumulated damage, which is the difference between the current buffer
* and the buffer with age of buffer_age; in context of rendering, this is
* the region that needs to be redrawn.
*/
void wlr_damage_ring_get_buffer_damage(struct wlr_damage_ring *ring,
int buffer_age, pixman_region32_t *damage);
#endif

View file

@ -14,7 +14,7 @@
struct wlr_data_control_manager_v1 { struct wlr_data_control_manager_v1 {
struct wl_global *global; struct wl_global *global;
struct wl_list devices; // wlr_data_control_device_v1::link struct wl_list devices; // wlr_data_control_device_v1.link
struct { struct {
struct wl_signal destroy; struct wl_signal destroy;
@ -27,7 +27,7 @@ struct wlr_data_control_manager_v1 {
struct wlr_data_control_device_v1 { struct wlr_data_control_device_v1 {
struct wl_resource *resource; struct wl_resource *resource;
struct wlr_data_control_manager_v1 *manager; struct wlr_data_control_manager_v1 *manager;
struct wl_list link; // wlr_data_control_manager_v1::devices struct wl_list link; // wlr_data_control_manager_v1.devices
struct wlr_seat *seat; struct wlr_seat *seat;
struct wl_resource *selection_offer_resource; // current selection offer struct wl_resource *selection_offer_resource; // current selection offer

View file

@ -43,7 +43,7 @@ struct wlr_data_offer {
struct wl_resource *resource; struct wl_resource *resource;
struct wlr_data_source *source; struct wlr_data_source *source;
enum wlr_data_offer_type type; enum wlr_data_offer_type type;
struct wl_list link; // wlr_seat::{selection_offers,drag_offers} struct wl_list link; // wlr_seat.{selection_offers,drag_offers}
uint32_t actions; uint32_t actions;
enum wl_data_device_manager_dnd_action preferred_action; enum wl_data_device_manager_dnd_action preferred_action;
@ -54,7 +54,7 @@ struct wlr_data_offer {
/** /**
* A data source implementation. Only the `send` function is mandatory. Refer to * A data source implementation. Only the `send` function is mandatory. Refer to
* the matching wl_data_source_* functions documentation to know what they do. * the matching `wlr_data_source_*` functions documentation to know what they do.
*/ */
struct wlr_data_source_impl { struct wlr_data_source_impl {
void (*send)(struct wlr_data_source *source, const char *mime_type, void (*send)(struct wlr_data_source *source, const char *mime_type,
@ -131,8 +131,8 @@ struct wlr_drag {
struct { struct {
struct wl_signal focus; struct wl_signal focus;
struct wl_signal motion; // wlr_drag_motion_event struct wl_signal motion; // struct wlr_drag_motion_event
struct wl_signal drop; // wlr_drag_drop_event struct wl_signal drop; // struct wlr_drag_drop_event
struct wl_signal destroy; struct wl_signal destroy;
} events; } events;
@ -155,7 +155,7 @@ struct wlr_drag_drop_event {
}; };
/** /**
* Create a wl data device manager global for this display. * Create a wl_data_device_manager global for this display.
*/ */
struct wlr_data_device_manager *wlr_data_device_manager_create( struct wlr_data_device_manager *wlr_data_device_manager_create(
struct wl_display *display); struct wl_display *display);
@ -181,7 +181,7 @@ void wlr_seat_set_selection(struct wlr_seat *seat,
/** /**
* Creates a new drag. To request to start the drag, call * Creates a new drag. To request to start the drag, call
* `wlr_seat_request_start_drag`. * wlr_seat_request_start_drag().
*/ */
struct wlr_drag *wlr_drag_create(struct wlr_seat_client *seat_client, struct wlr_drag *wlr_drag_create(struct wlr_seat_client *seat_client,
struct wlr_data_source *source, struct wlr_surface *icon_surface); struct wlr_data_source *source, struct wlr_surface *icon_surface);
@ -258,7 +258,7 @@ void wlr_data_source_dnd_finish(struct wlr_data_source *source);
* Notifies the data source that a target accepts the drag with the specified * Notifies the data source that a target accepts the drag with the specified
* action. * action.
* *
* This shouldn't be called after `wlr_data_source_dnd_drop` unless the * This shouldn't be called after wlr_data_source_dnd_drop() unless the
* drag-and-drop operation ended in an "ask" action. * drag-and-drop operation ended in an "ask" action.
*/ */
void wlr_data_source_dnd_action(struct wlr_data_source *source, void wlr_data_source_dnd_action(struct wlr_data_source *source,

View file

@ -15,7 +15,7 @@ struct wlr_backend;
struct wlr_output; struct wlr_output;
struct wlr_drm_lease_v1_manager { struct wlr_drm_lease_v1_manager {
struct wl_list devices; // wlr_drm_lease_device_v1::link; struct wl_list devices; // wlr_drm_lease_device_v1.link
struct wl_display *display; struct wl_display *display;
struct wl_listener display_destroy; struct wl_listener display_destroy;
@ -23,9 +23,9 @@ struct wlr_drm_lease_v1_manager {
struct { struct {
/** /**
* Upon receiving this signal, call * Upon receiving this signal, call
* wlr_drm_lease_device_v1_grant_lease_request to grant a lease of the * wlr_drm_lease_device_v1_grant_lease_request() to grant a lease of the
* requested DRM resources, or * requested DRM resources, or
* wlr_drm_lease_device_v1_reject_lease_request to reject the request. * wlr_drm_lease_device_v1_reject_lease_request() to reject the request.
*/ */
struct wl_signal request; struct wl_signal request;
} events; } events;
@ -38,10 +38,10 @@ struct wlr_drm_lease_device_v1 {
struct wlr_drm_lease_v1_manager *manager; struct wlr_drm_lease_v1_manager *manager;
struct wlr_backend *backend; struct wlr_backend *backend;
struct wl_list connectors; // wlr_drm_lease_connector_v1::link struct wl_list connectors; // wlr_drm_lease_connector_v1.link
struct wl_list leases; // wlr_drm_lease_v1::link struct wl_list leases; // wlr_drm_lease_v1.link
struct wl_list requests; // wlr_drm_lease_request_v1::link struct wl_list requests; // wlr_drm_lease_request_v1.link
struct wl_list link; // wlr_drm_lease_v1_manager::devices struct wl_list link; // wlr_drm_lease_v1_manager.devices
struct wl_listener backend_destroy; struct wl_listener backend_destroy;
@ -51,7 +51,7 @@ struct wlr_drm_lease_device_v1 {
struct wlr_drm_lease_v1; struct wlr_drm_lease_v1;
struct wlr_drm_lease_connector_v1 { struct wlr_drm_lease_connector_v1 {
struct wl_list resources; // wl_resource_get_link struct wl_list resources; // wl_resource_get_link()
struct wlr_output *output; struct wlr_output *output;
struct wlr_drm_lease_device_v1 *device; struct wlr_drm_lease_device_v1 *device;
@ -60,7 +60,7 @@ struct wlr_drm_lease_connector_v1 {
struct wl_listener destroy; struct wl_listener destroy;
struct wl_list link; // wlr_drm_lease_device_v1::connectors struct wl_list link; // wlr_drm_lease_device_v1.connectors
}; };
struct wlr_drm_lease_request_v1 { struct wlr_drm_lease_request_v1 {
@ -76,7 +76,7 @@ struct wlr_drm_lease_request_v1 {
bool invalid; bool invalid;
struct wl_list link; // wlr_drm_lease_device_v1::requests struct wl_list link; // wlr_drm_lease_device_v1.requests
}; };
struct wlr_drm_lease_v1 { struct wlr_drm_lease_v1 {
@ -97,7 +97,8 @@ struct wlr_drm_lease_v1 {
/** /**
* Creates a DRM lease manager. A DRM lease device will be created for each * Creates a DRM lease manager. A DRM lease device will be created for each
* DRM backend supplied in case of a wlr_multi_backend. * DRM backend supplied in case of a struct wlr_multi_backend.
*
* Returns NULL if no DRM backend is supplied. * Returns NULL if no DRM backend is supplied.
*/ */
struct wlr_drm_lease_v1_manager *wlr_drm_lease_v1_manager_create( struct wlr_drm_lease_v1_manager *wlr_drm_lease_v1_manager_create(
@ -105,6 +106,7 @@ struct wlr_drm_lease_v1_manager *wlr_drm_lease_v1_manager_create(
/** /**
* Offers a wlr_output for lease. * Offers a wlr_output for lease.
*
* Returns false if the output can't be offered to lease. * Returns false if the output can't be offered to lease.
*/ */
bool wlr_drm_lease_v1_manager_offer_output( bool wlr_drm_lease_v1_manager_offer_output(
@ -120,7 +122,7 @@ void wlr_drm_lease_v1_manager_withdraw_output(
/** /**
* Grants a client's lease request. The lease device will then provision the * Grants a client's lease request. The lease device will then provision the
* DRM lease and transfer the file descriptor to the client. After calling this, * DRM lease and transfer the file descriptor to the client. After calling this,
* each wlr_output leased is destroyed, and will be re-issued through * each struct wlr_output leased is destroyed, and will be re-issued through
* wlr_backend.events.new_outputs when the lease is revoked. * wlr_backend.events.new_outputs when the lease is revoked.
* *
* This will return NULL without leasing any resources if the lease is invalid; * This will return NULL without leasing any resources if the lease is invalid;

View file

@ -15,7 +15,7 @@
struct wlr_export_dmabuf_manager_v1 { struct wlr_export_dmabuf_manager_v1 {
struct wl_global *global; struct wl_global *global;
struct wl_list frames; // wlr_export_dmabuf_frame_v1::link struct wl_list frames; // wlr_export_dmabuf_frame_v1.link
struct wl_listener display_destroy; struct wl_listener display_destroy;
@ -27,7 +27,7 @@ struct wlr_export_dmabuf_manager_v1 {
struct wlr_export_dmabuf_frame_v1 { struct wlr_export_dmabuf_frame_v1 {
struct wl_resource *resource; struct wl_resource *resource;
struct wlr_export_dmabuf_manager_v1 *manager; struct wlr_export_dmabuf_manager_v1 *manager;
struct wl_list link; // wlr_export_dmabuf_manager_v1::frames struct wl_list link; // wlr_export_dmabuf_manager_v1.frames
struct wlr_output *output; struct wlr_output *output;

Some files were not shown because too many files have changed in this diff Show more