This patch is just the beginning of ds_input_device.
Currently, a ds_input_device is created only on the wayland backend, and
it only supports a ds_pointer.
Other devices like keyboard and touch, and other backends like libinput
will be supported in future patches.
Change-Id: I9efce1bea5fd362d5bcee86d92a81076b0be48bc
ds_backend_add_new_output_listener(struct ds_backend *backend,
struct wl_listener *listener);
+void
+ds_backend_add_new_input_listener(struct ds_backend *backend,
+ struct wl_listener *listener);
+
#ifdef __cplusplus
}
#endif
--- /dev/null
+#ifndef LIBDS_INPUT_DEVICE_H
+#define LIBDS_INPUT_DEVICE_H
+
+struct ds_input_device;
+
+struct ds_pointer;
+
+enum ds_button_state
+{
+ DS_BUTTON_RELEASED,
+ DS_BUTTON_PRESSED,
+};
+
+enum ds_input_device_type
+{
+ DS_INPUT_DEVICE_POINTER,
+ DS_INPUT_DEVICE_KEYBOARD,
+ DS_INPUT_DEVICE_TOUCH,
+};
+
+enum ds_input_device_type
+ds_input_device_get_type(struct ds_input_device *dev);
+
+struct ds_pointer *
+ds_input_device_get_pointer(struct ds_input_device *dev);
+
+void
+ds_input_device_add_destroy_listener(struct ds_input_device *dev,
+ struct wl_listener *listener);
+
+#endif
{
struct wl_signal destroy;
struct wl_signal new_output;
+ struct wl_signal new_input;
} events;
bool started;
--- /dev/null
+#ifndef LIBDS_INTERFACES_INPUT_DEVICE_H
+#define LIBDS_INTERFACES_INPUT_DEVICE_H
+
+#include <wayland-server.h>
+#include <libds/input_device.h>
+#include <libds/pointer.h>
+
+struct ds_input_device_interface
+{
+ void (*destroy)(struct ds_input_device *dev);
+};
+
+struct ds_input_device
+{
+ const struct ds_input_device_interface *iface;
+
+ char *name;
+ double width_mm, height_mm;
+ char *output_name;
+
+ enum ds_input_device_type type;
+ union {
+ void *_device;
+ struct ds_pointer *pointer;
+ };
+
+ struct {
+ struct wl_signal destroy;
+ } events;
+
+ struct wl_list link;
+};
+
+void ds_input_device_init(struct ds_input_device *dev,
+ enum ds_input_device_type type,
+ const struct ds_input_device_interface *iface,
+ const char *name, int vendor, int product);
+void ds_input_device_destroy(struct ds_input_device *dev);
+
+#endif
--- /dev/null
+#ifndef LIBDS_INTERFACES_POINTER_H
+#define LIBDS_INTERFACES_POINTER_H
+
+#include <wayland-server.h>
+
+struct ds_pointer;
+
+struct ds_pointer_interface
+{
+ void (*destroy)(struct ds_pointer *pointer);
+};
+
+struct ds_pointer
+{
+ const struct ds_pointer_interface *iface;
+
+ struct {
+ struct wl_signal motion;
+ struct wl_signal motion_absolute;
+ struct wl_signal button;
+ struct wl_signal frame;
+ } events;
+};
+
+void ds_pointer_init(struct ds_pointer *pointer,
+ const struct ds_pointer_interface *iface);
+
+void ds_pointer_destroy(struct ds_pointer *pointer);
+
+#endif
--- /dev/null
+#ifndef LIBDS_POINTER_H
+#define LIBDS_POINTER_H
+
+#include <stdint.h>
+#include <wayland-server.h>
+#include <libds/input_device.h>
+
+struct ds_pointer;
+
+struct ds_event_pointer_motion_absolute
+{
+ struct ds_input_device *device;
+ uint32_t time_msec;
+ // From 0..1
+ double x, y;
+};
+
+struct ds_event_pointer_button
+{
+ struct ds_input_device *device;
+ uint32_t time_msec;
+ uint32_t button;
+ enum ds_button_state state;
+};
+
+void ds_pointer_add_motion_listener(struct ds_pointer *pointer,
+ struct wl_listener *listener);
+
+void ds_pointer_add_motion_absolute_listener(struct ds_pointer *pointer,
+ struct wl_listener *listener);
+
+void ds_pointer_add_button_listener(struct ds_pointer *pointer,
+ struct wl_listener *listener);
+
+void ds_pointer_add_frame_listener(struct ds_pointer *pointer,
+ struct wl_listener *listener);
+
+#endif
install : true
)
+executable('pointer-test',
+ [
+ 'pointer-test.c',
+ 'pixman-helper.c',
+ ],
+ dependencies: common_deps,
+ install_dir: libds_bindir,
+ install : true)
+
if get_option('tizen')
common_deps += dep_libds_tizen
--- /dev/null
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <drm_fourcc.h>
+#include <libds/log.h>
+#include <libds/backend/wayland.h>
+#include <libds/input_device.h>
+#include <libds/pointer.h>
+#include <libds/allocator/shm.h>
+#include <libds/swapchain.h>
+
+#include "pixman-helper.h"
+
+#define WIDTH 700
+#define HEIGHT 400
+
+struct pointer_device {
+ struct ds_pointer *ds_pointer;
+
+ struct wl_listener destroy;
+ struct wl_listener motion_absolute;
+ struct wl_listener button;
+ struct wl_listener frame;
+};
+
+struct output
+{
+ struct server *server;
+
+ struct ds_output *ds_output;
+ struct ds_allocator *allocator;
+ struct ds_swapchain *swapchain;
+
+ struct ds_buffer *front_buffer;
+
+ struct wl_listener destroy;
+};
+
+struct server
+{
+ struct wl_display *display;
+
+ struct output output;
+
+ struct ds_backend *backend;
+
+ struct wl_listener backend_destroy;
+ struct wl_listener new_input;
+};
+
+struct server _server;
+
+static struct ds_backend *create_backend_auto(struct wl_display *display);
+static void handle_backend_destroy(struct wl_listener *listener, void *data);
+static void handle_new_input(struct wl_listener *listener, void *data);
+static void output_init(struct output *output, struct server *sever);
+static void output_draw(struct output *output);
+
+int
+main(void)
+{
+ struct server *server = &_server;
+
+ ds_log_init(DS_DBG, NULL);
+
+ server->display = wl_display_create();
+ assert(server->display);
+
+ server->backend = create_backend_auto(server->display);
+ assert(server->backend);
+
+ server->backend_destroy.notify = handle_backend_destroy;
+ ds_backend_add_destroy_listener(server->backend, &server->backend_destroy);
+
+ server->new_input.notify = handle_new_input;
+ ds_backend_add_new_input_listener(server->backend, &server->new_input);
+
+ output_init(&server->output, server);
+
+ ds_backend_start(server->backend);
+
+ output_draw(&server->output);
+
+ wl_display_run(server->display);
+
+ wl_display_destroy(server->display);
+
+ return 0;
+}
+
+static struct ds_backend *
+create_backend_auto(struct wl_display *display)
+{
+ struct ds_backend *backend = NULL;
+ char name[512];
+ int i;
+
+ for (i = 0; i < 5; i++) {
+ snprintf(name, sizeof name, "wayland-%d", i);
+ backend = ds_wl_backend_create(display, name);
+ if (backend)
+ break;
+ }
+
+ return backend;
+}
+
+static void
+handle_backend_destroy(struct wl_listener *listener, void *data)
+{
+ struct server *server;
+
+ server = wl_container_of(listener, server, backend_destroy);
+
+ wl_list_remove(&server->backend_destroy.link);
+ wl_list_remove(&server->new_input.link);
+}
+
+static char *
+device_type_to_string(enum ds_input_device_type type)
+{
+ switch (type) {
+ case DS_INPUT_DEVICE_POINTER:
+ return "pointer";
+ break;
+ case DS_INPUT_DEVICE_KEYBOARD:
+ return "keyboard";
+ break;
+ case DS_INPUT_DEVICE_TOUCH:
+ return "touch";
+ break;
+ default:
+ return "Unknown";
+ }
+}
+
+static void
+pointer_handle_device_destroy(struct wl_listener *listener, void *data)
+{
+ struct pointer_device *pointer;
+
+ pointer = wl_container_of(listener, pointer, destroy);
+
+ wl_list_remove(&pointer->destroy.link);
+ wl_list_remove(&pointer->motion_absolute.link);
+ wl_list_remove(&pointer->button.link);
+ wl_list_remove(&pointer->frame.link);
+
+ free(pointer);
+}
+
+static void
+pointer_handle_motion_absolute(struct wl_listener *listener, void *data)
+{
+ struct ds_event_pointer_motion_absolute *event = data;
+
+ ds_inf("Pointer device(%p): motion absolute (%f, %f) time(%d ms)",
+ event->device, event->x, event->y, event->time_msec);
+}
+
+static void
+pointer_handle_button(struct wl_listener *listener, void *data)
+{
+ struct ds_event_pointer_button *event = data;
+
+ ds_inf("Pointer Device(%p): button(%d) state(%d) time(%d ms)",
+ event->device, event->button, event->state, event->time_msec);
+}
+
+static void
+pointer_handle_frame(struct wl_listener *listener, void *data)
+{
+ ds_inf("Pointer device(%p): frame", data);
+}
+
+static void
+add_pointer(struct ds_input_device *dev)
+{
+ struct pointer_device *pointer;
+
+ pointer = calloc(1, sizeof *pointer);
+ if (!pointer)
+ return;
+
+ pointer->ds_pointer = ds_input_device_get_pointer(dev);
+
+ pointer->destroy.notify = pointer_handle_device_destroy;
+ ds_input_device_add_destroy_listener(dev, &pointer->destroy);
+
+ pointer->motion_absolute.notify = pointer_handle_motion_absolute;
+ ds_pointer_add_motion_absolute_listener(pointer->ds_pointer,
+ &pointer->motion_absolute);
+
+ pointer->button.notify = pointer_handle_button;
+ ds_pointer_add_button_listener(pointer->ds_pointer,
+ &pointer->button);
+
+ pointer->frame.notify = pointer_handle_frame;
+ ds_pointer_add_frame_listener(pointer->ds_pointer,
+ &pointer->frame);
+}
+
+static void
+handle_new_input(struct wl_listener *listener, void *data)
+{
+ struct ds_input_device *dev = data;
+ enum ds_input_device_type type;
+
+ type = ds_input_device_get_type(dev);
+
+ if (type != DS_INPUT_DEVICE_POINTER)
+ return;
+
+ ds_inf("New pointer device(%p) type(%s)", dev,
+ device_type_to_string(type));
+
+ add_pointer(dev);
+}
+
+static void
+output_handle_destroy(struct wl_listener *listener, void *data)
+{
+ struct output *output;
+
+ output = wl_container_of(listener, output, destroy);
+
+ wl_list_remove(&output->destroy.link);
+
+ ds_swapchain_destroy(output->swapchain);
+ ds_allocator_destroy(output->allocator);
+}
+
+static void
+output_init(struct output *output, struct server *server)
+{
+ output->server = server;
+
+ output->ds_output = ds_wl_backend_create_output(server->backend);
+ assert(output->ds_output);
+
+ output->destroy.notify = output_handle_destroy;
+ ds_output_add_destroy_listener(output->ds_output, &output->destroy);
+
+ output->allocator = ds_shm_allocator_create();
+ assert(output->allocator);
+
+ output->swapchain = ds_swapchain_create(output->allocator,
+ WIDTH, HEIGHT, DRM_FORMAT_XRGB8888);
+ assert(output->swapchain);
+}
+
+static void
+output_draw(struct output *output)
+{
+ struct ds_buffer *buffer;
+ pixman_image_t *img;
+
+ ds_dbg("Redraw output");
+
+ buffer = ds_swapchain_acquire(output->swapchain, NULL);
+ assert(buffer);
+
+ img = pixman_image_from_buffer(buffer, DS_BUFFER_DATA_PTR_ACCESS_WRITE);
+ assert(img);
+
+ pixman_image_fill_color(img, 80, 80, 80);
+
+ pixman_image_unref(img);
+
+ ds_output_attach_buffer(output->ds_output, buffer);
+ ds_output_commit(output->ds_output);
+
+ if (output->front_buffer)
+ ds_buffer_unlock(output->front_buffer);
+
+ output->front_buffer = buffer;
+}
wl_signal_add(&backend->events.new_output, listener);
}
+WL_EXPORT void
+ds_backend_add_new_input_listener(struct ds_backend *backend,
+ struct wl_listener *listener)
+{
+ wl_signal_add(&backend->events.new_input, listener);
+}
+
void
ds_backend_init(struct ds_backend *backend,
const struct ds_backend_interface *iface)
backend->iface = iface;
wl_signal_init(&backend->events.destroy);
wl_signal_init(&backend->events.new_output);
+ wl_signal_init(&backend->events.new_input);
}
void
static const struct ds_backend_interface wl_backend_interface;
static void wl_backend_handle_display_destroy(struct wl_listener *listener,
void *data);
-static bool wl_backend_server_init(struct ds_wl_backend_server *server,
- const char *name);
+static bool wl_backend_server_init(struct ds_wl_backend *wl_backend,
+ struct ds_wl_backend_server *server, const char *name);
static void wl_backend_server_finish(struct ds_wl_backend_server *server);
static int wl_backend_handle_dispatch_events(int fd, uint32_t mask,
void *data);
wl_backend->display = display;
wl_list_init(&wl_backend->buffers);
wl_list_init(&wl_backend->outputs);
+ wl_list_init(&wl_backend->seats);
- if (!wl_backend_server_init(&wl_backend->server, server_name)) {
+ if (!wl_backend_server_init(wl_backend, &wl_backend->server, server_name)) {
ds_err("Failed to initialize Wayland Server");
goto err_server;
}
fd = wl_display_get_fd(wl_backend->server.display);
wl_backend->server_event_source =
- wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
+ wl_event_loop_add_fd(loop, fd, WL_EVENT_WRITABLE | WL_EVENT_READABLE,
wl_backend_handle_dispatch_events, wl_backend);
if (!wl_backend->server_event_source) {
ds_err("Failed to create event source");
{
struct ds_wl_output *output, *tmp_output;
struct ds_wl_buffer *buffer, *tmp_buffer;
+ struct ds_wl_seat *seat, *tmp_seat;
ds_dbg("Destroy wayland backend(%p)", backend);
wl_list_for_each_safe(buffer, tmp_buffer, &backend->buffers, link)
destroy_wl_buffer(buffer);
+ wl_list_for_each_safe(seat, tmp_seat, &backend->seats, link)
+ destroy_wl_seat(seat);
+
ds_backend_finish(&backend->base);
wl_list_remove(&backend->display_destroy.link);
uint32_t name, const char *iface, uint32_t version)
{
struct ds_wl_backend_server *server = data;
+ struct ds_wl_seat *seat;
ds_log(DS_DBG, "Wayland global: %s v%d", iface, version);
server->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
wl_shm_add_listener(server->shm, &shm_listener, server);
}
+ else if (strcmp(iface, wl_seat_interface.name) == 0) {
+ seat = create_wl_seat(server->backend, name, version);
+ if (!seat) {
+ ds_err("Could not create ds_wl_seat");
+ return;
+ }
+
+ wl_list_insert(&server->backend->seats, &seat->link);
+ }
}
static void
};
static bool
-wl_backend_server_init(struct ds_wl_backend_server *server, const char *name)
+wl_backend_server_init(struct ds_wl_backend *wl_backend, struct ds_wl_backend_server *server, const char *name)
{
+ server->backend = wl_backend;
+
server->display = wl_display_connect(name);
if (!server->display) {
ds_log_errno(DS_ERR, "Could not connect to display: name \"%s\"", name);
#include "libds/interfaces/backend.h"
#include "libds/interfaces/output.h"
+#include "libds/interfaces/input_device.h"
+#include "libds/interfaces/pointer.h"
struct ds_wl_backend_server
{
+ struct ds_wl_backend *backend;
struct wl_display *display;
struct wl_registry *registry;
struct wl_compositor *compositor;
struct wl_list outputs; // ds_wl_output.link
struct wl_list buffers; // ds_wl_buffer.link
+ struct wl_list seats; // ds_wl_seat.link
struct wl_event_source *server_event_source;
struct ds_wl_backend_server server;
struct wl_callback *frame_callback;
struct wl_list link;
+
+ struct {
+ struct ds_wl_pointer *pointer;
+ struct wl_surface *surface;
+ int32_t hotspot_x, hotspot_y;
+ uint32_t enter_serial;
+ } cursor;
+};
+
+struct ds_wl_seat
+{
+ struct ds_wl_backend *backend;
+ struct ds_wl_output *output;
+
+ struct wl_seat *wl_seat;
+ char *name;
+
+ struct ds_input_device *pointer_dev;
+ struct ds_input_device *keyboard_dev;
+ struct ds_input_device *touch_dev;
+
+ struct wl_callback *initial_info_cb;
+
+ struct wl_list link; // ds_wl_backend.seats
+
+ enum wl_seat_capability caps;
+
+ int version;
+ uint32_t enter_serial;
+
+ bool initialized;
+};
+
+struct ds_wl_input_device
+{
+ struct ds_input_device base;
+
+ struct ds_wl_backend *backend;
+ struct ds_wl_seat *seat;
+};
+
+struct ds_wl_pointer
+{
+ struct ds_pointer base;
+
+ struct ds_wl_input_device *input_device;
+ struct wl_pointer *wl_pointer;
};
struct ds_wl_backend *
void
destroy_wl_buffer(struct ds_wl_buffer *buffer);
+struct ds_wl_seat *create_wl_seat(struct ds_wl_backend *backend, uint32_t id,
+ uint32_t available_version);
+
+void destroy_wl_seat(struct ds_wl_seat *seat);
+
+void output_enter_pointer(struct ds_wl_output *output,
+ struct ds_wl_pointer *pointer, uint32_t serial);
+
+void output_leave_pointer(struct ds_wl_output *output);
+
#endif
libds_files += files(
'backend.c',
'output.c',
+ 'seat.c',
)
protocols = {
static const struct xdg_surface_listener wl_output_xdg_surface_listener;
static const struct xdg_toplevel_listener wl_output_xdg_toplevel_listener;
+static void output_update_cursor(struct ds_wl_output *output);
+
struct ds_output *
ds_wl_backend_create_output(struct ds_backend *ds_backend)
{
free(buffer);
}
+void
+output_enter_pointer(struct ds_wl_output *output,
+ struct ds_wl_pointer *pointer, uint32_t serial)
+{
+ output->cursor.pointer = pointer;
+ output->cursor.enter_serial = serial;
+
+ output_update_cursor(output);
+}
+
+void
+output_leave_pointer(struct ds_wl_output *output)
+{
+ output->cursor.pointer = NULL;
+ output->cursor.enter_serial = 0;
+}
+
+static void output_update_cursor(struct ds_wl_output *output)
+{
+ struct ds_wl_pointer *pointer = output->cursor.pointer;
+
+ wl_pointer_set_cursor(pointer->wl_pointer, output->cursor.enter_serial,
+ output->cursor.surface, output->cursor.hotspot_x,
+ output->cursor.hotspot_y);
+}
+
static struct ds_wl_output *
wl_output_from_output(struct ds_output *ds_output)
{
--- /dev/null
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wayland-client.h>
+
+#include "libds/log.h"
+#include "libds/pointer.h"
+
+#include "backend.h"
+
+#ifdef MIN
+# undef MIN
+#endif
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+static const struct wl_seat_listener seat_listener;
+static const struct wl_callback_listener seat_callback_listener;
+
+static void seat_update_capabilities(struct ds_wl_seat *seat,
+ enum wl_seat_capability caps);
+static struct ds_input_device *
+create_wl_input_device(struct ds_wl_seat *seat,
+ enum ds_input_device_type type);
+static struct ds_pointer *create_wl_pointer(struct ds_wl_seat *seat);
+
+struct ds_wl_seat *
+create_wl_seat(struct ds_wl_backend *backend, uint32_t id,
+ uint32_t available_version)
+{
+ struct ds_wl_seat *seat;
+
+ seat = calloc(1, sizeof *seat);
+ if (!seat)
+ return NULL;
+
+ seat->backend = backend;
+ seat->version = MIN(available_version, 5);
+ seat->wl_seat = wl_registry_bind(backend->server.registry, id,
+ &wl_seat_interface, seat->version);
+
+ wl_seat_add_listener(seat->wl_seat, &seat_listener, seat);
+
+ seat->initial_info_cb = wl_display_sync(backend->server.display);
+ wl_callback_add_listener(seat->initial_info_cb, &seat_callback_listener,
+ seat);
+
+ ds_dbg("wl_backend: Seat(%p) created", seat);
+
+ return seat;
+}
+
+void
+destroy_wl_seat(struct ds_wl_seat *seat)
+{
+ ds_dbg("wl_backend: Seat(%p) destroy", seat);
+
+ if (seat->pointer_dev)
+ ds_input_device_destroy(seat->pointer_dev);
+
+ if (seat->keyboard_dev)
+ ds_input_device_destroy(seat->keyboard_dev);
+
+ if (seat->touch_dev)
+ ds_input_device_destroy(seat->touch_dev);
+
+ if (seat->version >= WL_SEAT_RELEASE_SINCE_VERSION)
+ wl_seat_release(seat->wl_seat);
+ else
+ wl_seat_destroy(seat->wl_seat);
+
+ wl_list_remove(&seat->link);
+
+ free(seat->name);
+ free(seat);
+}
+
+static void
+seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
+ enum wl_seat_capability caps)
+{
+ struct ds_wl_seat *seat = data;
+
+ if (seat->initialized)
+ seat_update_capabilities(seat, caps);
+ else
+ seat->caps = caps;
+
+ ds_dbg("wl_backend: Seat(%p) capabilities(%d)", seat, caps);
+}
+
+static void
+seat_handle_name(void *data, struct wl_seat *wl_seat, const char *name)
+{
+ struct ds_wl_seat *seat = data;
+
+ if (seat->name)
+ free(seat->name);
+
+ ds_dbg("wl_backend: Seat(%p) name(%s)", seat, name);
+
+ seat->name = strdup(name);
+}
+
+static const struct wl_seat_listener seat_listener = {
+ .capabilities = seat_handle_capabilities,
+ .name = seat_handle_name,
+};
+
+static void
+seat_add_callback_handle_done(void *data, struct wl_callback *callback,
+ uint32_t callback_data)
+{
+ struct ds_wl_seat *seat = data;
+
+ wl_callback_destroy(seat->initial_info_cb);
+ seat->initial_info_cb = NULL;
+ seat->initialized = true;
+
+ seat_update_capabilities(seat, seat->caps);
+}
+
+static const struct wl_callback_listener seat_callback_listener = {
+ .done = seat_add_callback_handle_done,
+};
+
+static void
+seat_update_capabilities(struct ds_wl_seat *seat, enum wl_seat_capability caps)
+{
+ if ((caps & WL_SEAT_CAPABILITY_POINTER) && seat->pointer_dev == NULL) {
+ ds_dbg("wl_backend: Seat(%p) offered pointer", seat);
+
+ seat->pointer_dev = create_wl_input_device(seat,
+ DS_INPUT_DEVICE_POINTER);
+ seat->pointer_dev->pointer = create_wl_pointer(seat);
+
+ wl_signal_emit(&seat->backend->base.events.new_input,
+ seat->pointer_dev);
+ }
+ else if (!(caps & WL_SEAT_CAPABILITY_POINTER) &&
+ seat->pointer_dev != NULL) {
+ ds_dbg("wl_backend: Seat(%p) dropped pointer", seat);
+ ds_input_device_destroy(seat->pointer_dev);
+ seat->pointer_dev = NULL;
+ }
+
+ if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && seat->keyboard_dev == NULL) {
+ ds_dbg("wl_backend: Seat(%p) offered keyboard", seat);
+
+ seat->keyboard_dev = create_wl_input_device(seat,
+ DS_INPUT_DEVICE_KEYBOARD);
+ }
+ else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) &&
+ seat->keyboard_dev != NULL) {
+ ds_dbg("wl_backend: Seat(%p) dropped keyboard", seat);
+ ds_input_device_destroy(seat->keyboard_dev);
+ seat->keyboard_dev = NULL;
+ }
+
+ if ((caps & WL_SEAT_CAPABILITY_TOUCH) && seat->touch_dev == NULL) {
+ ds_dbg("wl_backend: Seat(%p) offered touch", seat);
+ seat->touch_dev = create_wl_input_device(seat,
+ DS_INPUT_DEVICE_TOUCH);
+ }
+ else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) &&
+ seat->touch_dev != NULL) {
+ ds_dbg("wl_backend: Seat(%p) dropped touch", seat);
+ ds_input_device_destroy(seat->touch_dev);
+ seat->touch_dev = NULL;
+ }
+}
+
+static const struct ds_input_device_interface input_device_iface;
+
+static bool
+ds_input_device_is_wl(struct ds_input_device *ds_dev)
+{
+ return ds_dev->iface == &input_device_iface;
+}
+
+static struct ds_wl_input_device *
+get_wl_input_device_from_input_device(struct ds_input_device *ds_dev)
+{
+ assert(ds_input_device_is_wl(ds_dev));
+ return (struct ds_wl_input_device *)ds_dev;
+}
+
+static void
+input_device_iface_destroy(struct ds_input_device *ds_dev)
+{
+ struct ds_wl_input_device *dev;
+
+ dev = get_wl_input_device_from_input_device(ds_dev);
+
+ free(dev);
+}
+
+static const struct ds_input_device_interface input_device_iface =
+{
+ .destroy = input_device_iface_destroy,
+};
+
+static struct ds_input_device *
+create_wl_input_device(struct ds_wl_seat *seat,
+ enum ds_input_device_type type)
+{
+ struct ds_wl_input_device *dev;
+ unsigned int vendor = 0, product = 0;
+ size_t name_size;
+ char *name;
+
+ dev = calloc(1, sizeof *dev);
+ if (!dev)
+ return NULL;
+
+ dev->backend = seat->backend;
+ dev->seat = seat;
+
+ name_size = 8 + strlen(seat->name) + 1;
+ name = alloca(name_size);
+ (void) snprintf(name, name_size, "wayland-%s", seat->name);
+
+ ds_input_device_init(&dev->base, type, &input_device_iface, name, vendor,
+ product);
+
+ return &dev->base;
+}
+
+static const struct ds_pointer_interface pointer_iface;
+
+static struct ds_wl_pointer *
+get_wl_pointer_from_pointer(struct ds_pointer *ds_pointer)
+{
+ assert(ds_pointer->iface == &pointer_iface);
+ return (struct ds_wl_pointer *)ds_pointer;
+}
+
+static void
+pointer_iface_destroy(struct ds_pointer *ds_pointer)
+{
+ struct ds_wl_pointer *pointer;
+
+ pointer = get_wl_pointer_from_pointer(ds_pointer);
+
+ wl_pointer_release(pointer->wl_pointer);
+
+ free(pointer);
+}
+
+static const struct ds_pointer_interface pointer_iface = {
+ .destroy = pointer_iface_destroy,
+};
+
+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 ds_wl_seat *seat = data;
+ struct ds_wl_pointer *pointer;
+
+ if (!surface)
+ return;
+
+ ds_dbg("Enter pointer");
+
+ seat->output = wl_surface_get_user_data(surface);
+ seat->enter_serial = serial;
+
+ pointer = get_wl_pointer_from_pointer(seat->pointer_dev->pointer);
+ output_enter_pointer(seat->output, pointer, seat->enter_serial);
+}
+
+static void
+pointer_handle_leave(void *data, struct wl_pointer *wl_pointer,
+ uint32_t serial, struct wl_surface *surface)
+{
+ struct ds_wl_seat *seat = data;
+ struct ds_wl_output *output;
+
+ if (!seat->output)
+ return;
+
+ output = wl_surface_get_user_data(surface);
+ if (seat->output != output)
+ return;
+
+ ds_dbg("Leave pointer");
+
+ output_leave_pointer(seat->output);
+
+ seat->output = NULL;
+ seat->enter_serial = 0;
+}
+
+static void
+pointer_handle_motion(void *data, struct wl_pointer *wl_pointer,
+ uint32_t time, wl_fixed_t sx, wl_fixed_t sy)
+{
+ struct ds_wl_seat *seat = data;
+
+ if (!seat->output)
+ return;
+
+ // FIXME take size size of a output into account
+ struct ds_event_pointer_motion_absolute event = {
+ .device = seat->pointer_dev,
+ .time_msec = time,
+ .x = wl_fixed_to_double(sx) / 700,
+ .y = wl_fixed_to_double(sy) / 400,
+ };
+
+ wl_signal_emit(&seat->pointer_dev->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 ds_wl_seat *seat = data;
+
+ if (!seat->output)
+ return;
+
+ struct ds_event_pointer_button event = {
+ .device = seat->pointer_dev,
+ .button = button,
+ .state = state,
+ .time_msec = time,
+ };
+
+ wl_signal_emit(&seat->pointer_dev->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)
+{
+ // TODO
+}
+
+static void
+pointer_handle_frame(void *data, struct wl_pointer *wl_pointer)
+{
+ struct ds_wl_seat *seat = data;
+
+ if (!seat->output)
+ return;
+
+ wl_signal_emit(&seat->pointer_dev->pointer->events.frame,
+ seat->pointer_dev);
+}
+
+static void
+pointer_handle_axis_source(void *data, struct wl_pointer *wl_pointer,
+ uint32_t axis_source)
+{
+ // TODO
+}
+
+static void
+pointer_handle_axis_stop(void *data, struct wl_pointer *wl_pointer,
+ uint32_t time, uint32_t axis)
+{
+ // TODO
+}
+
+static void
+pointer_handle_axis_discrete(void *data, struct wl_pointer *wl_pointer,
+ uint32_t axis, int32_t discrete)
+{
+ // TODO
+}
+
+static const struct wl_pointer_listener wl_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,
+};
+
+static struct ds_pointer *
+create_wl_pointer(struct ds_wl_seat *seat)
+{
+ struct ds_wl_pointer *pointer;
+
+ pointer = calloc(1, sizeof *pointer);
+ if (!pointer) {
+ ds_err("Could not allocate memory");
+ return NULL;
+ }
+
+ ds_pointer_init(&pointer->base, &pointer_iface);
+
+ pointer->wl_pointer = wl_seat_get_pointer(seat->wl_seat);
+ wl_pointer_add_listener(pointer->wl_pointer, &wl_pointer_listener, seat);
+
+ return &pointer->base;
+}
--- /dev/null
+#define _POSIX_C_SOURCE 200809L
+#include <stdlib.h>
+#include <string.h>
+#include <wayland-server.h>
+
+#include "libds/log.h"
+#include "libds/interfaces/input_device.h"
+#include "libds/interfaces/pointer.h"
+
+WL_EXPORT enum ds_input_device_type
+ds_input_device_get_type(struct ds_input_device *dev)
+{
+ return dev->type;
+}
+
+WL_EXPORT struct ds_pointer *
+ds_input_device_get_pointer(struct ds_input_device *dev)
+{
+ if (dev->type != DS_INPUT_DEVICE_POINTER) {
+ ds_err("Given ds_input_device is not a pointer device");
+ return NULL;
+ }
+
+ return dev->pointer;
+}
+
+WL_EXPORT void
+ds_input_device_add_destroy_listener(struct ds_input_device *dev,
+ struct wl_listener *listener)
+{
+ wl_signal_add(&dev->events.destroy, listener);
+}
+
+void
+ds_input_device_init(struct ds_input_device *dev,
+ enum ds_input_device_type type,
+ const struct ds_input_device_interface *iface,
+ const char *name, int vendor, int product)
+{
+ dev->type = type;
+ dev->iface = iface;
+ dev->name = strdup(name);
+
+ wl_signal_init(&dev->events.destroy);
+}
+
+void
+ds_input_device_destroy(struct ds_input_device *dev)
+{
+ wl_signal_emit(&dev->events.destroy, dev);
+
+ if (dev->_device) {
+ switch (dev->type) {
+ case DS_INPUT_DEVICE_POINTER:
+ ds_pointer_destroy(dev->pointer);
+ break;
+ default:
+ ds_err("Warning: leaking memory %p %p %d",
+ dev->_device, dev, dev->type);
+ break;
+ }
+ }
+
+ free(dev->name);
+ if (dev->iface && dev->iface->destroy)
+ dev->iface->destroy(dev);
+ else
+ free(dev);
+}
'xdg_shell/xdg_toplevel.c',
'pixel_format.c',
'backend.c',
+ 'input_device.c',
+ 'pointer.c',
]
protocols = {
--- /dev/null
+#include <stdlib.h>
+#include <wayland-server.h>
+#include "libds/interfaces/pointer.h"
+
+void
+ds_pointer_init(struct ds_pointer *pointer,
+ const struct ds_pointer_interface *iface)
+{
+ pointer->iface = iface;
+
+ wl_signal_init(&pointer->events.motion);
+ wl_signal_init(&pointer->events.motion_absolute);
+ wl_signal_init(&pointer->events.button);
+ wl_signal_init(&pointer->events.frame);
+}
+
+void
+ds_pointer_destroy(struct ds_pointer *pointer)
+{
+ if (!pointer)
+ return;
+
+ if (pointer->iface && pointer->iface->destroy)
+ pointer->iface->destroy(pointer);
+ else
+ free(pointer);
+}
+
+WL_EXPORT void
+ds_pointer_add_motion_listener(struct ds_pointer *pointer,
+ struct wl_listener *listener)
+{
+ wl_signal_add(&pointer->events.motion, listener);
+}
+
+WL_EXPORT void
+ds_pointer_add_motion_absolute_listener(struct ds_pointer *pointer,
+ struct wl_listener *listener)
+{
+ wl_signal_add(&pointer->events.motion_absolute, listener);
+}
+
+WL_EXPORT void
+ds_pointer_add_button_listener(struct ds_pointer *pointer,
+ struct wl_listener *listener)
+{
+ wl_signal_add(&pointer->events.button, listener);
+}
+
+WL_EXPORT void
+ds_pointer_add_frame_listener(struct ds_pointer *pointer,
+ struct wl_listener *listener)
+{
+ wl_signal_add(&pointer->events.frame, listener);
+}