initial commit
This commit is contained in:
commit
1c606d0274
36 changed files with 9908 additions and 0 deletions
247
wayland/driver.c
Normal file
247
wayland/driver.c
Normal file
|
|
@ -0,0 +1,247 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* Wayland driver.
|
||||
*
|
||||
* Copyright (c) 2024, Richard Acayan. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wayland-client.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
#include "input.h"
|
||||
#include "ufkbd.h"
|
||||
#include "wayland.h"
|
||||
|
||||
static void on_global_object(void *data,
|
||||
struct wl_registry *reg,
|
||||
uint32_t name,
|
||||
const char *iface,
|
||||
uint32_t version);
|
||||
|
||||
static const struct wl_registry_listener reg_listener = {
|
||||
.global = on_global_object,
|
||||
.global_remove = NULL,
|
||||
};
|
||||
|
||||
static void on_global_object(void *data,
|
||||
struct wl_registry *reg,
|
||||
uint32_t name,
|
||||
const char *iface,
|
||||
uint32_t version)
|
||||
{
|
||||
struct ufkbd_input_wayland *ctx = data;
|
||||
struct ufkbd_wl_global_listener *listener;
|
||||
size_t i;
|
||||
|
||||
// This is assumed to be a small list.
|
||||
for (i = 0; i < ctx->n_global_listeners; i++) {
|
||||
listener = ctx->global_listeners[i];
|
||||
|
||||
if (!strcmp(iface, listener->iface->name))
|
||||
listener->cb(listener->data, reg, name, version);
|
||||
}
|
||||
}
|
||||
|
||||
int ufkbd_wl_global_listener_add(struct ufkbd_input_wayland *ctx,
|
||||
struct ufkbd_wl_global_listener *listener)
|
||||
{
|
||||
size_t idx = ctx->n_global_listeners;
|
||||
|
||||
if (idx >= MAX_GLOBAL_LISTENERS) {
|
||||
fprintf(stderr, "wl: no space for internal callback\n");
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
ctx->global_listeners[idx] = listener;
|
||||
ctx->n_global_listeners++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ufkbd_wayland_listen_one(void *data, bool block)
|
||||
{
|
||||
struct ufkbd_input_wayland *ctx = data;
|
||||
struct pollfd pollfd;
|
||||
int timeout = 0;
|
||||
int ret;
|
||||
|
||||
if (block)
|
||||
timeout = -1;
|
||||
|
||||
// Some listen events may be queued, so send them.
|
||||
ret = wl_display_flush(ctx->display);
|
||||
if (ret < 0)
|
||||
fprintf(stderr, "warn: failed to flush outgoing events: %d\n", -errno);
|
||||
|
||||
pollfd.fd = ctx->fd;
|
||||
pollfd.events = POLLIN;
|
||||
pollfd.revents = 0;
|
||||
|
||||
ret = poll(&pollfd, 1, timeout);
|
||||
if (ret == -1)
|
||||
return;
|
||||
|
||||
if (pollfd.revents) {
|
||||
ret = wl_display_dispatch(ctx->display);
|
||||
if (ret == -1)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void ufkbd_wayland_listen_step(void *data, int timeout)
|
||||
{
|
||||
struct ufkbd_input_wayland *ctx = data;
|
||||
struct pollfd pollfd;
|
||||
int ret;
|
||||
|
||||
// Some listen events may be queued, so send them.
|
||||
ret = wl_display_flush(ctx->display);
|
||||
if (ret < 0)
|
||||
fprintf(stderr, "warn: failed to flush outgoing events: %d\n", -errno);
|
||||
|
||||
pollfd.fd = ctx->fd;
|
||||
pollfd.events = POLLIN;
|
||||
pollfd.revents = 0;
|
||||
|
||||
ret = poll(&pollfd, 1, timeout);
|
||||
if (ret == -1)
|
||||
return;
|
||||
|
||||
if (pollfd.revents) {
|
||||
ret = wl_display_dispatch(ctx->display);
|
||||
if (ret == -1)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static int ufkbd_wayland_send_key(void *data, int code, bool repeat)
|
||||
{
|
||||
struct ufkbd_input_wayland *ctx = data;
|
||||
|
||||
ufkbd_wl_input_send_key(ctx->input, code - 8, repeat);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ufkbd_wayland_send_mod(void *data, enum ufkbd_modifier mod, bool pressed)
|
||||
{
|
||||
struct ufkbd_input_wayland *ctx = data;
|
||||
|
||||
ufkbd_wl_input_send_mod(ctx->input, mod, pressed);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ufkbd_wayland_draw_begin(void *data, size_t *stride, void **ptr)
|
||||
{
|
||||
struct ufkbd_input_wayland *ctx = data;
|
||||
struct wl_buffer *buf;
|
||||
int ret;
|
||||
|
||||
ret = ufkbd_wl_surface_consume_buffer(ctx->surface, &buf, ptr);
|
||||
if (ret) {
|
||||
fprintf(stderr, "wl: warn: could not consume buffer: %s\n",
|
||||
strerror(-ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
wl_surface_attach(ctx->surface->wl, buf, 0, 0);
|
||||
|
||||
// NOPUSH
|
||||
*stride = (size_t) ctx->surface->bufs[0].width * 4;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ufkbd_wayland_draw_touch(void *data, int x, int y, int width, int height)
|
||||
{
|
||||
struct ufkbd_input_wayland *ctx = data;
|
||||
|
||||
wl_surface_damage_buffer(ctx->surface->wl, x, y, width, height);
|
||||
}
|
||||
|
||||
static void ufkbd_wayland_draw_end(void *data)
|
||||
{
|
||||
struct ufkbd_input_wayland *ctx = data;
|
||||
|
||||
wl_surface_commit(ctx->surface->wl);
|
||||
}
|
||||
|
||||
static void *ufkbd_wayland_init(struct ufkbd_ctx *ufkbd)
|
||||
{
|
||||
struct ufkbd_input_wayland *ctx;
|
||||
int ret;
|
||||
|
||||
if (ufkbd == NULL)
|
||||
return NULL;
|
||||
|
||||
ctx = calloc(1, sizeof(*ctx));
|
||||
if (ctx == NULL)
|
||||
return NULL;
|
||||
|
||||
ctx->ufkbd = ufkbd;
|
||||
|
||||
ctx->display = wl_display_connect(NULL);
|
||||
if (ctx->display == NULL)
|
||||
goto err_free_ctx;
|
||||
|
||||
ctx->registry = wl_display_get_registry(ctx->display);
|
||||
if (ctx->registry == NULL)
|
||||
goto err_disconnect;
|
||||
|
||||
ret = wl_registry_add_listener(ctx->registry, ®_listener, ctx);
|
||||
if (ret)
|
||||
goto err_destroy_reg;
|
||||
|
||||
ret = ufkbd_wl_surface_init(ctx, &ctx->surface);
|
||||
if (ret)
|
||||
goto err_destroy_reg;
|
||||
|
||||
ret = ufkbd_wl_input_init(ctx, &ctx->input);
|
||||
if (ret)
|
||||
goto err_uninit_surface;
|
||||
|
||||
ctx->fd = wl_display_get_fd(ctx->display);
|
||||
|
||||
return ctx;
|
||||
|
||||
err_uninit_surface:
|
||||
ufkbd_wl_surface_uninit(ctx->surface);
|
||||
err_destroy_reg:
|
||||
wl_registry_destroy(ctx->registry);
|
||||
err_disconnect:
|
||||
wl_display_disconnect(ctx->display);
|
||||
err_free_ctx:
|
||||
free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ufkbd_wayland_uninit(void *data)
|
||||
{
|
||||
struct ufkbd_input_wayland *ctx = data;
|
||||
|
||||
ufkbd_wl_input_uninit(ctx->input);
|
||||
ufkbd_wl_surface_uninit(ctx->surface);
|
||||
|
||||
wl_registry_destroy(ctx->registry);
|
||||
wl_display_disconnect(ctx->display);
|
||||
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
struct ufkbd_driver ufkbd_wayland = {
|
||||
.init = ufkbd_wayland_init,
|
||||
.uninit = ufkbd_wayland_uninit,
|
||||
.listen_one = ufkbd_wayland_listen_one,
|
||||
.listen_step = ufkbd_wayland_listen_step,
|
||||
.send_key = ufkbd_wayland_send_key,
|
||||
.send_mod = ufkbd_wayland_send_mod,
|
||||
.draw_begin = ufkbd_wayland_draw_begin,
|
||||
.draw_touch = ufkbd_wayland_draw_touch,
|
||||
.draw_end = ufkbd_wayland_draw_end,
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue