ds_seat abstracts wl_seat protocol of server implementation.
Change-Id: Ic3dcf2c9c374af762c2fbeccbe0f2174b9b1be3d
void (*destroy)(struct ds_keyboard *keyboard);
};
-struct ds_keyboard_modifiers
-{
- xkb_mod_mask_t depressed;
- xkb_mod_mask_t latched;
- xkb_mod_mask_t locked;
- xkb_mod_mask_t group;
-};
-
struct ds_keyboard
{
const struct ds_keyboard_interface *iface;
DS_MODIFIER_MOD5 = 1 << 7,
};
+struct ds_keyboard_modifiers
+{
+ xkb_mod_mask_t depressed;
+ xkb_mod_mask_t latched;
+ xkb_mod_mask_t locked;
+ xkb_mod_mask_t group;
+};
+
struct ds_event_keyboard_key
{
uint32_t time_msec;
--- /dev/null
+#ifndef LIBDS_SEAT_H
+#define LIBDS_SEAT_H
+
+#include <stdint.h>
+#include <wayland-server.h>
+
+#include <libds/input_device.h>
+#include <libds/keyboard.h>
+#include <libds/surface.h>
+
+struct ds_seat;
+
+enum ds_axis_orientation
+{
+ DS_AXIS_ORIENTATION_VERTICAL,
+ DS_AXIS_ORIENTATION_HORIZONTAL,
+};
+
+enum ds_axis_source
+{
+ DS_AXIS_SOURCE_WHEEL,
+ DS_AXIS_SOURCE_FINGER,
+ DS_AXIS_SOURCE_CONTINUOUS,
+ DS_AXIS_SOURCE_WHEEL_TILT,
+};
+
+struct ds_event_seat_pointer_focus_change
+{
+ struct ds_seat *seat;
+ struct ds_surface *old_surface, *new_surface;
+ double sx, sy;
+};
+
+struct ds_event_seat_keyboard_focus_change
+{
+ struct ds_seat *seat;
+ struct ds_surface *old_surface, *new_surface;
+};
+
+struct ds_seat *ds_seat_create(struct wl_display *display, const char *name);
+
+void ds_seat_destroy(struct ds_seat *seat);
+
+void ds_seat_set_capabilities(struct ds_seat *seat,
+ enum wl_seat_capability capabilities);
+
+void ds_seat_set_name(struct ds_seat *seat, const char *name);
+
+void ds_seat_add_destroy_listener(struct ds_seat *seat,
+ struct wl_listener *listener);
+
+void ds_seat_pointer_notify_enter(struct ds_seat *seat,
+ struct ds_surface *surface, double sx, double sy);
+
+void ds_seat_pointer_notify_clear_focus(struct ds_seat *seat);
+
+void ds_seat_pointer_notify_motion(struct ds_seat *seat, uint32_t time_msec,
+ double sx, double sy);
+
+uint32_t ds_seat_pointer_notify_button(struct ds_seat *seat,
+ uint32_t time_msec, uint32_t button, enum ds_button_state state);
+
+void ds_seat_pointer_notify_axis(struct ds_seat *seat, uint32_t time_msec,
+ enum ds_axis_orientation orientation, double value,
+ int32_t value_discrete, enum ds_axis_source source);
+
+void ds_seat_pointer_notify_frame(struct ds_seat *seat);
+
+void ds_seat_pointer_add_grab_begin_listener(struct ds_seat *seat,
+ struct wl_listener *listener);
+
+void ds_seat_pointer_add_grab_end_listener(struct ds_seat *seat,
+ struct wl_listener *listener);
+
+void ds_seat_pointer_add_focus_change_listener(struct ds_seat *seat,
+ struct wl_listener *listener);
+
+void ds_seat_keyboard_notify_enter(struct ds_seat *seat,
+ struct ds_surface *surface, uint32_t keycodes[], size_t num_keycodes,
+ struct ds_keyboard_modifiers *modifiers);
+
+void ds_seat_keyboard_notify_clear_focus(struct ds_seat *seat);
+
+void ds_seat_keyboard_notify_modifiers(struct ds_seat *seat,
+ struct ds_keyboard_modifiers *modifiers);
+
+void ds_seat_keyboard_notify_key(struct ds_seat *seat, uint32_t time_msec,
+ uint32_t key, uint32_t state);
+
+void ds_seat_keyboard_add_grab_begin_listener(struct ds_seat *seat,
+ struct wl_listener *listener);
+
+void ds_seat_keyboard_add_grab_end_listener(struct ds_seat *seat,
+ struct wl_listener *listener);
+
+void ds_seat_keyboard_add_focus_change_listener(struct ds_seat *seat,
+ struct wl_listener *listener);
+
+void ds_seat_touch_end_grab_start_listener(struct ds_seat *seat,
+ struct wl_listener *listener);
+
+uint32_t ds_seat_touch_notify_down(struct ds_seat *seat,
+ struct ds_surface *surface, uint32_t time_msec, int32_t touch_id,
+ double sx, double sy);
+
+void ds_seat_touch_notify_up(struct ds_seat *seat, uint32_t time_msec,
+ int32_t touch_id);
+
+void ds_seat_touch_notify_motion(struct ds_seat *seat, uint32_t time_msec,
+ int32_t touch_id, double sx, double sy);
+
+void ds_seat_touch_notify_frame(struct ds_seat *seat);
+
+void ds_seat_touch_add_grab_start_listener(struct ds_seat *seat,
+ struct wl_listener *listener);
+
+#endif
'pointer.c',
'keyboard.c',
'touch.c',
+ 'seat/seat.c',
+ 'seat/seat_pointer.c',
+ 'seat/seat_keyboard.c',
+ 'seat/seat_touch.c',
]
protocols = {
xkbcommon = dependency('xkbcommon', required: true)
rt = meson.get_compiler('c').find_library('rt')
+if wayland_server.version().version_compare('>= 1.19')
+ cdata.set('HAVE_WL_SEAT_ERROR_MISSING_CAPABILITY', '1')
+endif
+
libds_deps = [
math,
wayland_server,
--- /dev/null
+#ifndef DS_SEAT_H
+#define DS_SEAT_H
+
+#include "libds/keyboard.h"
+#include "libds/seat.h"
+
+struct ds_seat_pointer_grab;
+
+struct ds_pointer_grab_interface
+{
+ void (*enter)(struct ds_seat_pointer_grab *grab,
+ struct ds_surface *surface, double sx, double sy);
+ void (*clear_focus)(struct ds_seat_pointer_grab *grab);
+ void (*motion)(struct ds_seat_pointer_grab *grab, uint32_t time_msec,
+ double sx, double sy);
+ uint32_t (*button)(struct ds_seat_pointer_grab *grab, uint32_t time_msec,
+ uint32_t button, enum ds_button_state state);
+ void (*axis)(struct ds_seat_pointer_grab *grab, uint32_t time_msec,
+ enum ds_axis_orientation orientation, double value,
+ int32_t value_discrete, enum ds_axis_source source);
+ void (*frame)(struct ds_seat_pointer_grab *grab);
+ void (*cancel)(struct ds_seat_pointer_grab *grab);
+};
+
+struct ds_seat_keyboard_grab;
+
+struct ds_keyboard_grab_interface
+{
+ void (*enter)(struct ds_seat_keyboard_grab *grab,
+ struct ds_surface *surface, uint32_t keycodes[],
+ size_t num_keycodes, struct ds_keyboard_modifiers *modifiers);
+ void (*clear_focus)(struct ds_seat_keyboard_grab *grab);
+ void (*key)(struct ds_seat_keyboard_grab *grab, uint32_t time_msec,
+ uint32_t key, uint32_t state);
+ void (*modifiers)(struct ds_seat_keyboard_grab *grab,
+ struct ds_keyboard_modifiers *modifiers);
+ void (*cancel)(struct ds_seat_keyboard_grab *grab);
+};
+
+struct ds_touch_point;
+
+struct ds_seat_touch_grab;
+
+struct ds_touch_grab_interface
+{
+ uint32_t (*down)(struct ds_seat_touch_grab *grab, uint32_t time_msec,
+ struct ds_touch_point *point);
+ void (*up)(struct ds_seat_touch_grab *grab, uint32_t time_msec,
+ struct ds_touch_point *point);
+ void (*motion)(struct ds_seat_touch_grab *grab, uint32_t time_msec,
+ struct ds_touch_point *point);
+ void (*enter)(struct ds_seat_touch_grab *grab, uint32_t time_msec,
+ struct ds_touch_point *point);
+ void (*frame)(struct ds_seat_touch_grab *grab);
+ void (*cancel)(struct ds_seat_touch_grab *grab);
+};
+
+struct ds_seat_pointer_grab
+{
+ const struct ds_pointer_grab_interface *iface;
+ struct ds_seat *seat;
+ void *data;
+};
+
+struct ds_seat_keyboard_grab
+{
+ const struct ds_keyboard_grab_interface *iface;
+ struct ds_seat *seat;
+ void *data;
+};
+
+struct ds_seat_touch_grab
+{
+ const struct ds_touch_grab_interface *iface;
+ struct ds_seat *seat;
+ void *data;
+};
+
+void ds_seat_pointer_start_grab(struct ds_seat *seat,
+ struct ds_seat_pointer_grab *grab);
+
+void ds_seat_pointer_end_grab(struct ds_seat *seat);
+
+void ds_seat_pointer_enter(struct ds_seat *seat, struct ds_surface *surface,
+ double sx, double sy);
+
+void ds_seat_pointer_clear_focus(struct ds_seat *seat);
+
+void ds_seat_pointer_send_motion(struct ds_seat *seat, uint32_t time_msec,
+ double sx, double sy);
+
+uint32_t ds_seat_pointer_send_button(struct ds_seat *seat, uint32_t time_msec,
+ uint32_t button, enum ds_button_state state);
+
+void ds_seat_pointer_send_axis(struct ds_seat *seat, uint32_t time_msec,
+ enum ds_axis_orientation orientation, double value,
+ int32_t value_discrete, enum ds_axis_source source);
+
+void ds_seat_pointer_send_frame(struct ds_seat *seat);
+
+void ds_seat_keyboard_start_grab(struct ds_seat *seat,
+ struct ds_seat_keyboard_grab *grab);
+
+void ds_seat_keyboard_end_grab(struct ds_seat *seat);
+
+void ds_seat_keyboard_enter(struct ds_seat *seat, struct ds_surface *surface,
+ uint32_t keycodes[], size_t num_keycodes,
+ struct ds_keyboard_modifiers *modifiers);
+
+void ds_seat_keyboard_clear_focus(struct ds_seat *seat);
+
+void ds_seat_keyboard_send_key(struct ds_seat *seat, uint32_t time_msec,
+ uint32_t key, uint32_t state);
+
+void ds_seat_keyboard_send_modifiers(struct ds_seat *seat,
+ struct ds_keyboard_modifiers *modifiers);
+
+void ds_seat_touch_start_grab(struct ds_seat *seat,
+ struct ds_seat_touch_grab *grab);
+
+void ds_seat_touch_end_grab(struct ds_seat *seat);
+
+uint32_t ds_seat_touch_send_down(struct ds_seat *seat,
+ struct ds_surface *surface, uint32_t time_msec, int32_t touch_id,
+ double sx, double sy);
+
+void ds_seat_touch_send_up(struct ds_seat *seat, uint32_t time_msec,
+ int32_t touch_id);
+
+void ds_seat_touch_send_motion(struct ds_seat *seat, uint32_t time_msec,
+ int32_t touch_id, double sx, double sy);
+
+void ds_seat_touch_send_frame(struct ds_seat *seat);
+
+#endif
--- /dev/null
+#include "config.h"
+
+#define _POSIX_C_SOURCE 200809L
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libds/log.h"
+#include "seat_private.h"
+
+#define SEAT_VERSION 7
+
+static void seat_handle_bind(struct wl_client *wl_client, void *data,
+ uint32_t version, uint32_t id);
+static void seat_handle_display_destroy(struct wl_listener *listener,
+ void *data);
+static void seat_destroy(struct ds_seat *seat);
+static struct ds_seat_client *seat_client_create(struct ds_seat *seat,
+ struct wl_client *wl_client);
+static void seat_client_destroy(struct ds_seat_client *seat_client);
+static void
+seat_client_send_capabilities(struct ds_seat_client *seat_client);
+static void seat_client_send_name(struct ds_seat_client *seat_client);
+
+WL_EXPORT struct ds_seat *
+ds_seat_create(struct wl_display *display, const char *name)
+{
+ struct ds_seat *seat;
+
+ seat = calloc(1, sizeof *seat);
+ if (!seat)
+ return NULL;
+
+ if (!seat_pointer_init(seat)) {
+ ds_err("Failed to initialize pointer for seat(%s)", name);
+ goto err_ptr;
+ }
+
+ if (!seat_keyboard_init(seat)) {
+ ds_err("Failed to initialize keyboard for seat(%s)", name);
+ goto err_kbd;
+ }
+
+ if (!seat_touch_init(seat)) {
+ ds_err("Failed to initialize touch for seat(%s)", name);
+ goto err_touch;
+ }
+
+ seat->global = wl_global_create(display, &wl_seat_interface,
+ SEAT_VERSION, seat, seat_handle_bind);
+ if (!seat->global) {
+ ds_err("Failed to create wl_global for seat(%s)", name);
+ goto err_global;
+ }
+
+ seat->display = display;
+ seat->name = strdup(name);
+
+ wl_list_init(&seat->clients);
+
+ wl_signal_init(&seat->events.destroy);
+ wl_signal_init(&seat->events.pointer_grab_begin);
+ wl_signal_init(&seat->events.pointer_grab_end);
+ wl_signal_init(&seat->events.keyboard_grab_begin);
+ wl_signal_init(&seat->events.keyboard_grab_end);
+ wl_signal_init(&seat->events.touch_grab_begin);
+ wl_signal_init(&seat->events.touch_grab_end);
+
+ seat->display_destroy.notify = seat_handle_display_destroy;
+ wl_display_add_destroy_listener(display, &seat->display_destroy);
+
+ return seat;
+
+err_global:
+ seat_touch_finish(seat);
+err_touch:
+ seat_keyboard_finish(seat);
+err_kbd:
+ seat_pointer_finish(seat);
+err_ptr:
+ free(seat);
+
+ return NULL;
+}
+
+WL_EXPORT void
+ds_seat_destroy(struct ds_seat *seat)
+{
+ seat_destroy(seat);
+}
+
+WL_EXPORT void
+ds_seat_set_capabilities(struct ds_seat *seat,
+ enum wl_seat_capability capabilities)
+{
+ struct ds_seat_client *seat_client;
+
+ if (capabilities == seat->capabilities)
+ return;
+
+ seat->capabilities = capabilities;
+ seat->accumulated_capabilities |= capabilities;
+
+ wl_list_for_each(seat_client, &seat->clients, link) {
+ if (!(capabilities & WL_SEAT_CAPABILITY_POINTER)) {
+ seat_client_remove_all_pointer_resources(seat_client);
+ }
+ if (!(capabilities & WL_SEAT_CAPABILITY_KEYBOARD)) {
+ seat_client_remove_all_keyboard_resources(seat_client);
+ }
+ if (!(capabilities & WL_SEAT_CAPABILITY_TOUCH)) {
+ seat_client_remove_all_touch_resources(seat_client);
+ }
+
+ seat_client_send_capabilities(seat_client);
+ }
+}
+
+WL_EXPORT void
+ds_seat_set_name(struct ds_seat *seat, const char *name)
+{
+ struct ds_seat_client *seat_client;
+
+ free(seat->name);
+ seat->name = strdup(name);
+
+ wl_list_for_each(seat_client, &seat->clients, link) {
+ seat_client_send_name(seat_client);
+ }
+}
+
+WL_EXPORT void
+ds_seat_add_destroy_listener(struct ds_seat *seat,
+ struct wl_listener *listener)
+{
+ wl_signal_add(&seat->events.destroy, listener);
+}
+
+struct ds_seat_client *
+seat_client_for_wl_client(struct ds_seat *seat, struct wl_client *wl_client)
+{
+ struct ds_seat_client *seat_client;
+
+ wl_list_for_each(seat_client, &seat->clients, link) {
+ if (seat_client->wl_client == wl_client)
+ return seat_client;
+ }
+
+ return NULL;
+}
+
+static struct ds_seat_client *
+ds_seat_client_get_or_create(struct ds_seat *seat, struct wl_client *wl_client)
+{
+ struct ds_seat_client *seat_client;
+
+ seat_client = seat_client_for_wl_client(seat, wl_client);
+ if (!seat_client) {
+ seat_client = seat_client_create(seat, wl_client);
+ if (!seat_client)
+ return NULL;
+
+ wl_list_insert(&seat->clients, &seat_client->link);
+ }
+
+ return seat_client;
+}
+
+static void
+seat_handle_get_pointer(struct wl_client *wl_client,
+ struct wl_resource *resource, uint32_t id)
+{
+ struct ds_seat_client *seat_client;
+
+ seat_client = wl_resource_get_user_data(resource);
+ if (!seat_client)
+ return;
+
+ if (!(seat_client->seat->accumulated_capabilities &
+ WL_SEAT_CAPABILITY_POINTER)) {
+#ifdef HAVE_WL_SEAT_ERROR_MISSING_CAPABILITY
+ wl_resource_post_error(resource, WL_SEAT_ERROR_MISSING_CAPABILITY,
+ "wl_seat.get_pointer called when no "
+ "pointer capability has existed");
+#endif
+ return;
+ }
+
+ seat_client_add_pointer_resource(seat_client,
+ wl_resource_get_version(resource), id);
+}
+
+static void
+seat_handle_get_keyboard(struct wl_client *wl_client,
+ struct wl_resource *resource, uint32_t id)
+{
+ struct ds_seat_client *seat_client;
+
+ seat_client = wl_resource_get_user_data(resource);
+ if (!seat_client)
+ return;
+
+ if (!(seat_client->seat->accumulated_capabilities &
+ WL_SEAT_CAPABILITY_POINTER)) {
+#ifdef HAVE_WL_SEAT_ERROR_MISSING_CAPABILITY
+ wl_resource_post_error(resource, WL_SEAT_ERROR_MISSING_CAPABILITY,
+ "wl_seat.get_pointer called when no "
+ "keyboard capability has existed");
+#endif
+ return;
+ }
+
+ seat_client_add_keyboard_resource(seat_client,
+ wl_resource_get_version(resource), id);
+}
+
+static void
+seat_handle_get_touch(struct wl_client *wl_client,
+ struct wl_resource *resource, uint32_t id)
+{
+ struct ds_seat_client *seat_client;
+
+ seat_client = wl_resource_get_user_data(resource);
+ if (!seat_client)
+ return;
+
+ if (!(seat_client->seat->accumulated_capabilities &
+ WL_SEAT_CAPABILITY_POINTER)) {
+#ifdef HAVE_WL_SEAT_ERROR_MISSING_CAPABILITY
+ wl_resource_post_error(resource, WL_SEAT_ERROR_MISSING_CAPABILITY,
+ "wl_seat.get_pointer called when no "
+ "touch capability has existed");
+#endif
+ return;
+ }
+
+ seat_client_add_touch_resource(seat_client,
+ wl_resource_get_version(resource), id);
+}
+
+static void
+seat_handle_release(struct wl_client *wl_client, struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static const struct wl_seat_interface seat_impl =
+{
+ .get_pointer = seat_handle_get_pointer,
+ .get_keyboard = seat_handle_get_keyboard,
+ .get_touch = seat_handle_get_touch,
+ .release = seat_handle_release,
+};
+
+static void
+seat_client_handle_resource_destroy(struct wl_resource *resource)
+{
+ struct ds_seat_client *seat_client;
+
+ seat_client = wl_resource_get_user_data(resource);
+ if (!seat_client)
+ return;
+
+ wl_list_remove(wl_resource_get_link(resource));
+ if (!wl_list_empty(&seat_client->resources))
+ return;
+
+ seat_client_destroy(seat_client);
+}
+
+static void
+seat_handle_bind(struct wl_client *wl_client, void *data, uint32_t version,
+ uint32_t id)
+{
+ struct ds_seat *seat = data;
+ struct ds_seat_client *seat_client;
+ struct wl_resource *resource;
+
+ resource = wl_resource_create(wl_client, &wl_seat_interface, version, id);
+ if (!resource) {
+ wl_client_post_no_memory(wl_client);
+ return;
+ }
+
+ seat_client = ds_seat_client_get_or_create(seat, wl_client);
+ if (!seat_client) {
+ wl_resource_destroy(resource);
+ wl_client_post_no_memory(wl_client);
+ return;
+ }
+
+ wl_resource_set_implementation(resource, &seat_impl,
+ seat_client, seat_client_handle_resource_destroy);
+
+ wl_list_insert(&seat_client->resources, wl_resource_get_link(resource));
+
+ wl_seat_send_capabilities(resource, seat->capabilities);
+
+ if (version >= WL_SEAT_NAME_SINCE_VERSION)
+ wl_seat_send_name(resource, seat->name);
+}
+
+static void
+seat_handle_display_destroy(struct wl_listener *listener, void *data)
+{
+ struct ds_seat *seat;
+
+ seat = wl_container_of(listener, seat, display_destroy);
+ seat_destroy(seat);
+}
+
+static void
+seat_destroy(struct ds_seat *seat)
+{
+ struct ds_seat_client *seat_client, *tmp;
+ struct wl_resource *resource, *next;
+
+ wl_signal_emit(&seat->events.destroy, seat);
+
+ wl_list_remove(&seat->display_destroy.link);
+
+ wl_list_for_each_safe(seat_client, tmp, &seat->clients, link) {
+ wl_resource_for_each_safe(resource, next, &seat_client->resources) {
+ wl_list_remove(wl_resource_get_link(resource));
+ wl_resource_set_user_data(resource, NULL);
+ }
+ seat_client_destroy(seat_client);
+ }
+
+ seat_pointer_finish(seat);
+ seat_keyboard_finish(seat);
+ seat_touch_finish(seat);
+
+ wl_global_destroy(seat->global);
+ free(seat->name);
+ free(seat);
+}
+
+static struct ds_seat_client *
+seat_client_create(struct ds_seat *seat, struct wl_client *wl_client)
+{
+ struct ds_seat_client *seat_client;
+
+ seat_client = calloc(1, sizeof *seat_client);
+ seat_client->seat = seat;
+ seat_client->wl_client = wl_client;
+
+ wl_list_init(&seat_client->resources);
+ wl_list_init(&seat_client->pointers);
+ wl_list_init(&seat_client->keyboards);
+ wl_list_init(&seat_client->touches);
+
+ wl_signal_init(&seat_client->events.destroy);
+
+ return seat_client;
+}
+
+static void
+seat_client_destroy(struct ds_seat_client *seat_client)
+{
+ wl_signal_emit(&seat_client->events.destroy, seat_client);
+
+ seat_client_remove_all_pointer_resources(seat_client);
+ seat_client_remove_all_keyboard_resources(seat_client);
+ seat_client_remove_all_touch_resources(seat_client);
+
+ wl_list_remove(&seat_client->link);
+
+ free(seat_client);
+}
+
+static void
+seat_client_send_capabilities(struct ds_seat_client *seat_client)
+{
+ struct wl_resource *resource;
+
+ wl_resource_for_each(resource, &seat_client->resources) {
+ wl_seat_send_capabilities(resource, seat_client->seat->capabilities);
+ }
+}
+
+static void
+seat_client_send_name(struct ds_seat_client *seat_client)
+{
+ struct wl_resource *resource;
+
+ wl_resource_for_each(resource, &seat_client->resources) {
+ wl_seat_send_name(resource, seat_client->seat->name);
+ }
+}
--- /dev/null
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "libds/log.h"
+#include "seat_private.h"
+
+static const struct ds_keyboard_grab_interface default_keyboard_grab_iface;
+static const struct wl_keyboard_interface keyboard_impl;
+
+static void
+seat_client_send_keyboard_leave_raw(struct ds_seat_client *seat_client,
+ struct ds_surface *surface);
+static void
+seat_keyboard_handle_surface_destroy(struct wl_listener *listener,
+ void *data);
+static void keyboard_handle_resource_destroy(struct wl_resource *resource);
+
+WL_EXPORT void
+ds_seat_keyboard_notify_enter(struct ds_seat *seat,
+ struct ds_surface *surface, uint32_t keycodes[], size_t num_keycodes,
+ struct ds_keyboard_modifiers *modifiers)
+{
+ struct ds_seat_keyboard_grab *grab = seat->keyboard.grab;
+
+ grab->iface->enter(grab, surface, keycodes, num_keycodes, modifiers);
+}
+
+WL_EXPORT void
+ds_seat_keyboard_notify_clear_focus(struct ds_seat *seat)
+{
+ struct ds_seat_keyboard_grab *grab = seat->keyboard.grab;
+
+ grab->iface->clear_focus(grab);
+}
+
+WL_EXPORT void
+ds_seat_keyboard_notify_modifiers(struct ds_seat *seat,
+ struct ds_keyboard_modifiers *modifiers)
+{
+ struct ds_seat_keyboard_grab *grab = seat->keyboard.grab;
+
+ clock_gettime(CLOCK_MONOTONIC, &seat->last_event);
+ grab->iface->modifiers(grab, modifiers);
+}
+
+WL_EXPORT void
+ds_seat_keyboard_notify_key(struct ds_seat *seat, uint32_t time_msec,
+ uint32_t key, uint32_t state)
+{
+ struct ds_seat_keyboard_grab *grab = seat->keyboard.grab;
+
+ clock_gettime(CLOCK_MONOTONIC, &seat->last_event);
+ grab->iface->key(grab, time_msec, key, state);
+}
+
+WL_EXPORT void
+ds_seat_keyboard_add_grab_begin_listener(struct ds_seat *seat,
+ struct wl_listener *listener)
+{
+ wl_signal_add(&seat->events.keyboard_grab_begin, listener);
+}
+
+WL_EXPORT void
+ds_seat_keyboard_add_grab_end_listener(struct ds_seat *seat,
+ struct wl_listener *listener)
+{
+ wl_signal_add(&seat->events.keyboard_grab_end, listener);
+}
+
+WL_EXPORT void
+ds_seat_keyboard_add_focus_change_listener(struct ds_seat *seat,
+ struct wl_listener *listener)
+{
+ wl_signal_add(&seat->keyboard.events.focus_change, listener);
+}
+
+void
+ds_seat_keyboard_start_grab(struct ds_seat *seat,
+ struct ds_seat_keyboard_grab *grab)
+{
+ grab->seat = seat;
+ seat->keyboard.grab = grab;
+
+ wl_signal_emit(&seat->events.keyboard_grab_begin, grab);
+}
+
+void
+ds_seat_keyboard_end_grab(struct ds_seat *seat)
+{
+ struct ds_seat_keyboard *keyboard = &seat->keyboard;
+ struct ds_seat_keyboard_grab *grab = keyboard->grab;
+
+ if (grab != keyboard->default_grab) {
+ keyboard->grab = keyboard->default_grab;
+ wl_signal_emit(&seat->events.keyboard_grab_end, grab);
+ if (grab->iface->cancel)
+ grab->iface->cancel(grab);
+ }
+}
+
+void
+ds_seat_keyboard_enter(struct ds_seat *seat, struct ds_surface *surface,
+ uint32_t keycodes[], size_t num_keycodes,
+ struct ds_keyboard_modifiers *modifiers)
+{
+ struct ds_seat_keyboard *keyboard = &seat->keyboard;
+ struct ds_seat_client *seat_client = NULL, *focused_client;
+ struct ds_surface *focused_surface;
+ struct wl_client *wl_client;
+ struct wl_array keys;
+ struct wl_resource *resource;
+ uint32_t *p;
+ uint32_t serial;
+
+ if (keyboard->focused_surface == surface)
+ return;
+
+ if (surface) {
+ wl_client =
+ wl_resource_get_client(ds_surface_get_wl_resource(surface));
+ seat_client = seat_client_for_wl_client(seat, wl_client);
+ }
+
+ focused_client = keyboard->focused_client;
+ focused_surface = keyboard->focused_surface;
+
+ if (focused_client != NULL && focused_surface != NULL)
+ seat_client_send_keyboard_leave_raw(focused_client, focused_surface);
+
+ if (seat_client) {
+ wl_array_init(&keys);
+
+ for (size_t i = 0; i < num_keycodes; i++) {
+ p = wl_array_add(&keys, sizeof(uint32_t));
+ if (!p) {
+ ds_err("Cannot allocate memory, skipping keycode: %" PRIu32
+ "\n", keycodes[i]);
+ continue;
+ }
+ *p = keycodes[i];
+ }
+
+ serial = wl_display_next_serial(seat->display);
+
+ wl_resource_for_each(resource, &seat_client->keyboards) {
+ wl_keyboard_send_enter(resource, serial,
+ ds_surface_get_wl_resource(surface), &keys);
+ }
+ wl_array_release(&keys);
+ }
+
+ wl_list_remove(&keyboard->surface_destroy.link);
+ wl_list_init(&keyboard->surface_destroy.link);
+
+ if (surface) {
+ keyboard->surface_destroy.notify =
+ seat_keyboard_handle_surface_destroy;
+ ds_surface_add_destroy_listener(surface, &keyboard->surface_destroy);
+ }
+
+ keyboard->focused_client = seat_client;
+ keyboard->focused_surface = surface;
+
+ if (seat_client) {
+ ds_seat_keyboard_send_modifiers(seat, modifiers);
+
+ // TODO handle selection
+ }
+
+ struct ds_event_seat_keyboard_focus_change event = {
+ .seat = seat,
+ .old_surface = focused_surface,
+ .new_surface = surface,
+ };
+ wl_signal_emit(&keyboard->events.focus_change, &event);
+}
+
+void
+ds_seat_keyboard_clear_focus(struct ds_seat *seat)
+{
+ ds_seat_keyboard_enter(seat, NULL, NULL, 0, NULL);
+}
+
+void
+ds_seat_keyboard_send_key(struct ds_seat *seat, uint32_t time_msec,
+ uint32_t key, uint32_t state)
+{
+ struct ds_seat_client *seat_client;
+ struct wl_resource *resource;
+ uint32_t serial;
+
+ seat_client = seat->keyboard.focused_client;
+ if (!seat_client)
+ return;
+
+ serial = wl_display_next_serial(seat->display);
+ wl_resource_for_each(resource, &seat_client->keyboards)
+ wl_keyboard_send_key(resource, serial, time_msec, key, state);
+}
+
+void
+ds_seat_keyboard_send_modifiers(struct ds_seat *seat,
+ struct ds_keyboard_modifiers *modifiers)
+{
+ struct ds_seat_keyboard *keyboard = &seat->keyboard;
+ struct ds_seat_client *seat_client = keyboard->focused_client;
+ struct wl_resource *resource;
+ uint32_t serial;
+
+ if (!seat_client)
+ return;
+
+ serial = wl_display_next_serial(seat->display);
+ wl_resource_for_each(resource, &seat_client->keyboards) {
+ if (!modifiers) {
+ wl_keyboard_send_modifiers(resource, serial, 0, 0, 0, 0);
+ }
+ else {
+ wl_keyboard_send_modifiers(resource, serial,
+ modifiers->depressed, modifiers->latched,
+ modifiers->locked, modifiers->group);
+ }
+ }
+}
+
+bool
+seat_keyboard_init(struct ds_seat *seat)
+{
+ struct ds_seat_keyboard *keyboard = &seat->keyboard;
+ struct ds_seat_keyboard_grab *grab;
+
+ grab = calloc(1, sizeof *grab);
+ if (!grab)
+ return false;
+
+ grab->iface = &default_keyboard_grab_iface;
+ grab->seat = seat;
+
+ keyboard->default_grab = grab;
+ keyboard->grab = grab;
+ keyboard->seat = seat;
+
+ wl_list_init(&keyboard->surface_destroy.link);
+
+ wl_signal_init(&keyboard->events.focus_change);
+
+ return true;
+}
+
+void seat_keyboard_finish(struct ds_seat *seat)
+{
+ struct ds_seat_keyboard *keyboard = &seat->keyboard;
+
+ wl_list_remove(&keyboard->surface_destroy.link);
+ free(keyboard->default_grab);
+}
+
+void
+seat_client_add_keyboard_resource(struct ds_seat_client *seat_client,
+ uint32_t version, uint32_t id)
+{
+ struct wl_resource *resource;
+
+ resource = wl_resource_create(seat_client->wl_client,
+ &wl_keyboard_interface, version, id);
+ if (!resource) {
+ wl_client_post_no_memory(seat_client->wl_client);
+ return;
+ }
+
+ wl_resource_set_implementation(resource, &keyboard_impl, seat_client,
+ keyboard_handle_resource_destroy);
+
+ wl_list_insert(&seat_client->keyboards, wl_resource_get_link(resource));
+
+ if (!(seat_client->seat->capabilities & WL_SEAT_CAPABILITY_KEYBOARD)) {
+ wl_resource_set_user_data(resource, NULL);
+ return;
+ }
+}
+
+void
+seat_client_remove_all_keyboard_resources(struct ds_seat_client *seat_client)
+{
+ struct wl_resource *resource, *tmp;
+
+ wl_resource_for_each_safe(resource, tmp, &seat_client->keyboards) {
+ wl_list_remove(wl_resource_get_link(resource));
+ wl_resource_set_user_data(resource, NULL);
+ }
+}
+
+static void
+keyboard_handle_release(struct wl_client *client, struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static const struct wl_keyboard_interface keyboard_impl =
+{
+ .release = keyboard_handle_release,
+};
+
+static void
+keyboard_handle_resource_destroy(struct wl_resource *resource)
+{
+ if (!wl_resource_get_user_data(resource))
+ return;
+
+ wl_list_remove(wl_resource_get_link(resource));
+}
+
+static void
+default_keyboard_grab_iface_enter(struct ds_seat_keyboard_grab *grab,
+ struct ds_surface *surface, uint32_t keycodes[],
+ size_t num_keycodes, struct ds_keyboard_modifiers *modifiers)
+{
+ ds_seat_keyboard_enter(grab->seat, surface, keycodes, num_keycodes,
+ modifiers);
+}
+
+static void
+default_keyboard_grab_iface_clear_focus(struct ds_seat_keyboard_grab *grab)
+{
+ ds_seat_keyboard_clear_focus(grab->seat);
+}
+
+static void
+default_keyboard_grab_iface_key(struct ds_seat_keyboard_grab *grab,
+ uint32_t time_msec, uint32_t key, uint32_t state)
+{
+ ds_seat_keyboard_send_key(grab->seat, time_msec, key, state);
+}
+
+static void
+default_modifiers_grab_iface_key(struct ds_seat_keyboard_grab *grab,
+ struct ds_keyboard_modifiers *modifiers)
+{
+ ds_seat_keyboard_send_modifiers(grab->seat, modifiers);
+}
+
+static void
+default_cancel_grab_iface_key(struct ds_seat_keyboard_grab *grab)
+{
+ // cannot be cancelled
+}
+
+static const struct ds_keyboard_grab_interface default_keyboard_grab_iface = {
+ .enter = default_keyboard_grab_iface_enter,
+ .clear_focus = default_keyboard_grab_iface_clear_focus,
+ .key = default_keyboard_grab_iface_key,
+ .modifiers = default_modifiers_grab_iface_key,
+ .cancel = default_cancel_grab_iface_key,
+};
+
+static void
+seat_client_send_keyboard_leave_raw(struct ds_seat_client *seat_client,
+ struct ds_surface *surface)
+{
+ struct wl_resource *resource;
+ uint32_t serial;
+
+ serial = wl_display_next_serial(seat_client->seat->display);
+ wl_resource_for_each(resource, &seat_client->keyboards) {
+ wl_keyboard_send_leave(resource, serial,
+ ds_surface_get_wl_resource(surface));
+ }
+}
+
+static void
+seat_keyboard_handle_surface_destroy(struct wl_listener *listener,
+ void *data)
+{
+ struct ds_seat_keyboard *keyboard;
+
+ keyboard = wl_container_of(listener, keyboard, surface_destroy);
+
+ wl_list_remove(&keyboard->surface_destroy.link);
+ wl_list_init(&keyboard->surface_destroy.link);
+ ds_seat_keyboard_clear_focus(keyboard->seat);
+}
--- /dev/null
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "seat_private.h"
+
+static const struct ds_pointer_grab_interface default_pointer_grab_iface;
+static const struct wl_pointer_interface pointer_impl;
+
+static void seat_pointer_warp(struct ds_seat *seat, double sx, double sy);
+static void
+seat_client_send_pointer_leave_raw(struct ds_seat_client *seat_client,
+ struct ds_surface *surface);
+static void
+seat_pointer_handle_surface_destroy(struct wl_listener *listener,
+ void *data);
+static void pointer_handle_resource_destroy(struct wl_resource *resource);
+static void pointer_send_frame(struct wl_resource *resource);
+
+WL_EXPORT void
+ds_seat_pointer_notify_enter(struct ds_seat *seat, struct ds_surface *surface,
+ double sx, double sy)
+{
+ struct ds_seat_pointer_grab *grab = seat->pointer.grab;
+
+ assert(surface);
+ grab->iface->enter(grab, surface, sx, sy);
+}
+
+WL_EXPORT void
+ds_seat_pointer_notify_clear_focus(struct ds_seat *seat)
+{
+ struct ds_seat_pointer_grab *grab = seat->pointer.grab;
+
+ grab->iface->clear_focus(grab);
+}
+
+WL_EXPORT void
+ds_seat_pointer_notify_motion(struct ds_seat *seat, uint32_t time_msec,
+ double sx, double sy)
+{
+ struct ds_seat_pointer_grab *grab = seat->pointer.grab;
+
+ grab->iface->motion(grab, time_msec, sx, sy);
+}
+
+WL_EXPORT uint32_t
+ds_seat_pointer_notify_button(struct ds_seat *seat, uint32_t time_msec,
+ uint32_t button, enum ds_button_state state)
+{
+ struct ds_seat_pointer *pointer = &seat->pointer;
+ struct ds_seat_pointer_grab *grab = pointer->grab;
+ uint32_t serial;
+
+ if (state == DS_BUTTON_PRESSED) {
+ if (pointer->button_count == 0) {
+ pointer->grab_button = button;
+ pointer->grab_time = time_msec;
+ }
+ // TODO need a set struct for assigning pointer->buttons
+ }
+ else {
+ // TODO
+ }
+
+ serial = grab->iface->button(grab, time_msec, button, state);
+ if (serial && pointer->button_count == 1 &&
+ state == DS_BUTTON_PRESSED)
+ pointer->grab_serial = serial;
+
+ return serial;
+}
+
+WL_EXPORT void
+ds_seat_pointer_notify_axis(struct ds_seat *seat, uint32_t time_msec,
+ enum ds_axis_orientation orientation, double value,
+ int32_t value_discrete, enum ds_axis_source source)
+{
+ struct ds_seat_pointer_grab *grab = seat->pointer.grab;
+
+ clock_gettime(CLOCK_MONOTONIC, &seat->last_event);
+ grab->iface->axis(grab, time_msec, orientation, value, value_discrete, source);
+}
+
+WL_EXPORT void
+ds_seat_pointer_notify_frame(struct ds_seat *seat)
+{
+ struct ds_seat_pointer_grab *grab = seat->pointer.grab;
+
+ clock_gettime(CLOCK_MONOTONIC, &seat->last_event);
+ if (grab->iface->frame)
+ grab->iface->frame(grab);
+}
+
+WL_EXPORT void
+ds_seat_pointer_add_grab_begin_listener(struct ds_seat *seat,
+ struct wl_listener *listener)
+{
+ wl_signal_add(&seat->events.pointer_grab_begin, listener);
+}
+
+WL_EXPORT void
+ds_seat_pointer_add_grab_end_listener(struct ds_seat *seat,
+ struct wl_listener *listener)
+{
+ wl_signal_add(&seat->events.pointer_grab_end, listener);
+}
+
+WL_EXPORT void
+ds_seat_pointer_add_focus_change_listener(struct ds_seat *seat,
+ struct wl_listener *listener)
+{
+ wl_signal_add(&seat->pointer.events.focus_change, listener);
+}
+
+void
+ds_seat_pointer_start_grab(struct ds_seat *seat,
+ struct ds_seat_pointer_grab *grab)
+{
+ grab->seat = seat;
+ seat->pointer.grab = grab;
+ wl_signal_emit(&seat->events.pointer_grab_begin, grab);
+}
+
+void
+ds_seat_pointer_end_grab(struct ds_seat *seat)
+{
+ struct ds_seat_pointer *pointer = &seat->pointer;
+ struct ds_seat_pointer_grab *grab = pointer->grab;
+
+ if (grab != pointer->default_grab) {
+ pointer->grab = pointer->default_grab;
+ wl_signal_emit(&seat->events.pointer_grab_end, grab);
+ if (grab->iface->cancel)
+ grab->iface->cancel(grab);
+ }
+}
+
+void
+ds_seat_pointer_enter(struct ds_seat *seat, struct ds_surface *surface,
+ double sx, double sy)
+{
+ struct ds_seat_pointer *pointer = &seat->pointer;
+ struct ds_seat_client *seat_client = NULL, *focused_client;
+ struct ds_surface *focused_surface;
+ struct wl_client *wl_client;
+ struct wl_resource *resource;
+ uint32_t serial;
+
+ if (pointer->focused_surface == surface) {
+ // this surface already got an enter notify
+ return;
+ }
+
+ focused_client = pointer->focused_client;
+ focused_surface = pointer->focused_surface;
+
+ if (focused_client != NULL && focused_surface != NULL)
+ seat_client_send_pointer_leave_raw(focused_client, focused_surface);
+
+ if (surface) {
+ wl_client =
+ wl_resource_get_client(ds_surface_get_wl_resource(surface));
+ seat_client = seat_client_for_wl_client(seat, wl_client);
+ }
+
+ if (seat_client) {
+ serial = wl_display_next_serial(seat->display);
+ wl_resource_for_each(resource, &seat_client->pointers) {
+ wl_pointer_send_enter(resource, serial,
+ ds_surface_get_wl_resource(surface),
+ wl_fixed_from_double(sx), wl_fixed_from_double(sy));
+ pointer_send_frame(resource);
+ }
+ }
+
+ wl_list_remove(&pointer->surface_destroy.link);
+ wl_list_init(&pointer->surface_destroy.link);
+
+ if (surface) {
+ pointer->surface_destroy.notify =
+ seat_pointer_handle_surface_destroy;
+ ds_surface_add_destroy_listener(surface, &pointer->surface_destroy);
+ }
+
+ pointer->focused_client = seat_client;
+ pointer->focused_surface = surface;
+ if (surface)
+ seat_pointer_warp(seat, sx, sy);
+ else
+ seat_pointer_warp(seat, NAN, NAN);
+
+ struct ds_event_seat_pointer_focus_change event = {
+ .seat = seat,
+ .new_surface = surface,
+ .old_surface = focused_surface,
+ .sx = sx,
+ .sy = sy,
+ };
+ wl_signal_emit(&pointer->events.focus_change, &event);
+}
+
+void
+ds_seat_pointer_clear_focus(struct ds_seat *seat)
+{
+ ds_seat_pointer_enter(seat, NULL, 0, 0);
+}
+
+void
+ds_seat_pointer_send_motion(struct ds_seat *seat, uint32_t time_msec,
+ double sx, double sy)
+{
+ struct ds_seat_pointer *pointer = &seat->pointer;
+ struct ds_seat_client *seat_client = pointer->focused_client;
+ struct wl_resource *resource;
+ wl_fixed_t sx_fixed, sy_fixed;
+
+ if (!seat_client)
+ return;
+
+ sx_fixed = wl_fixed_from_double(sx);
+ sy_fixed = wl_fixed_from_double(sy);
+ if (wl_fixed_from_double(pointer->sx) != sx_fixed ||
+ wl_fixed_from_double(pointer->sy) != sy_fixed) {
+ wl_resource_for_each(resource, &seat_client->pointers)
+ wl_pointer_send_motion(resource, time_msec, sx_fixed, sy_fixed);
+ }
+
+ seat_pointer_warp(seat, sx, sy);
+}
+
+uint32_t
+ds_seat_pointer_send_button(struct ds_seat *seat, uint32_t time_msec,
+ uint32_t button, enum ds_button_state state)
+{
+ struct ds_seat_client *seat_client = seat->pointer.focused_client;
+ struct wl_resource *resource;
+ uint32_t serial;
+
+ if (!seat_client)
+ return 0;
+
+ serial = wl_display_next_serial(seat->display);
+ wl_resource_for_each(resource, &seat_client->pointers)
+ wl_pointer_send_button(resource, serial, time_msec, button, state);
+
+ return serial;
+}
+
+void
+ds_seat_pointer_send_axis(struct ds_seat *seat, uint32_t time_msec,
+ enum ds_axis_orientation orientation, double value,
+ int32_t value_discrete, enum ds_axis_source source)
+{
+ struct ds_seat_pointer *pointer = &seat->pointer;
+ struct ds_seat_client *seat_client = pointer->focused_client;
+ struct wl_resource *resource;
+ uint32_t version;
+ bool send_source = false;
+
+ if (!seat_client)
+ return;
+
+ if (pointer->sent_axis_source) {
+ assert(pointer->cached_axis_source == source);
+ }
+ else {
+ pointer->sent_axis_source = true;
+ pointer->cached_axis_source = source;
+ send_source = true;
+ }
+
+ wl_resource_for_each(resource, &seat_client->pointers) {
+ version = wl_resource_get_version(resource);
+
+ if (send_source && version >= WL_POINTER_AXIS_SOURCE_SINCE_VERSION)
+ wl_pointer_send_axis_source(resource, source);
+
+ if (value) {
+ if (value_discrete &&
+ version >= WL_POINTER_AXIS_DISCRETE_SINCE_VERSION) {
+ wl_pointer_send_axis_discrete(resource, orientation,
+ value_discrete);
+ }
+
+ wl_pointer_send_axis(resource, time_msec, orientation,
+ wl_fixed_from_double(value));
+ }
+ else if (version >= WL_POINTER_AXIS_STOP_SINCE_VERSION) {
+ wl_pointer_send_axis_stop(resource, time_msec, orientation);
+ }
+ }
+}
+
+void
+ds_seat_pointer_send_frame(struct ds_seat *seat)
+{
+ struct ds_seat_pointer *pointer = &seat->pointer;
+ struct ds_seat_client *seat_client = pointer->focused_client;
+ struct wl_resource *resource;
+
+ if (!seat_client)
+ return;
+
+ pointer->sent_axis_source = false;
+
+ wl_resource_for_each(resource, &seat_client->pointers)
+ pointer_send_frame(resource);
+}
+
+bool
+seat_pointer_init(struct ds_seat *seat)
+{
+ struct ds_seat_pointer *pointer = &seat->pointer;
+ struct ds_seat_pointer_grab *grab;
+
+ grab = calloc(1, sizeof *grab);
+ if (!grab)
+ return false;
+
+ grab->iface = &default_pointer_grab_iface;
+ grab->seat = seat;
+
+ pointer->default_grab = grab;
+ pointer->grab = grab;
+ pointer->seat = seat;
+
+ wl_list_init(&pointer->surface_destroy.link);
+
+ wl_signal_init(&pointer->events.focus_change);
+
+ return true;
+}
+
+void
+seat_pointer_finish(struct ds_seat *seat)
+{
+ struct ds_seat_pointer *pointer = &seat->pointer;
+
+ wl_list_remove(&pointer->surface_destroy.link);
+ free(pointer->default_grab);
+}
+
+void
+seat_client_add_pointer_resource(struct ds_seat_client *seat_client,
+ uint32_t version, uint32_t id)
+{
+ struct wl_resource *resource;
+
+ resource = wl_resource_create(seat_client->wl_client,
+ &wl_pointer_interface, version, id);
+ if (!resource) {
+ wl_client_post_no_memory(seat_client->wl_client);
+ return;
+ }
+
+ wl_resource_set_implementation(resource, &pointer_impl, seat_client,
+ &pointer_handle_resource_destroy);
+
+ if (!(seat_client->seat->capabilities & WL_SEAT_CAPABILITY_POINTER)) {
+ wl_resource_set_user_data(resource, NULL);
+ return;
+ }
+
+ wl_list_insert(&seat_client->pointers, wl_resource_get_link(resource));
+}
+
+void
+seat_client_remove_all_pointer_resources(struct ds_seat_client *seat_client)
+{
+ struct wl_resource *resource, *tmp;
+
+ wl_resource_for_each_safe(resource, tmp, &seat_client->pointers) {
+ wl_list_remove(wl_resource_get_link(resource));
+ wl_resource_set_user_data(resource, NULL);
+ }
+}
+
+static void
+seat_pointer_warp(struct ds_seat *seat, double sx, double sy)
+{
+ seat->pointer.sx = sx;
+ seat->pointer.sy = sy;
+}
+
+static void
+seat_client_send_pointer_leave_raw(struct ds_seat_client *seat_client,
+ struct ds_surface *surface)
+{
+ struct wl_resource *resource;
+ uint32_t serial;
+
+ serial = wl_display_next_serial(seat_client->seat->display);
+ wl_resource_for_each(resource, &seat_client->pointers) {
+ wl_pointer_send_leave(resource, serial,
+ ds_surface_get_wl_resource(surface));
+ pointer_send_frame(resource);
+ }
+}
+
+static void
+seat_pointer_handle_surface_destroy(struct wl_listener *listener, void *data)
+{
+ struct ds_seat_pointer *pointer;
+
+ pointer = wl_container_of(listener, pointer, surface_destroy);
+ wl_list_remove(&pointer->surface_destroy.link);
+ wl_list_init(&pointer->surface_destroy.link);
+ ds_seat_pointer_clear_focus(pointer->seat);
+}
+
+static void
+default_pointer_grab_iface_enter(struct ds_seat_pointer_grab *grab,
+ struct ds_surface *surface, double sx, double sy)
+{
+ ds_seat_pointer_enter(grab->seat, surface, sx, sy);
+}
+
+static void
+default_pointer_grab_iface_clear_focus(struct ds_seat_pointer_grab *grab)
+{
+ ds_seat_pointer_clear_focus(grab->seat);
+}
+
+static void
+default_pointer_grab_iface_motion(struct ds_seat_pointer_grab *grab,
+ uint32_t time_msec, double sx, double sy)
+{
+ ds_seat_pointer_send_motion(grab->seat, time_msec, sx, sy);
+}
+
+static uint32_t
+default_pointer_grab_iface_button(struct ds_seat_pointer_grab *grab,
+ uint32_t time_msec, uint32_t button, enum ds_button_state state)
+{
+ return ds_seat_pointer_send_button(grab->seat, time_msec, button, state);
+}
+
+static void
+default_pointer_grab_iface_axis(struct ds_seat_pointer_grab *grab,
+ uint32_t time_msec, enum ds_axis_orientation orientation, double value,
+ int32_t value_discrete, enum ds_axis_source source)
+{
+ ds_seat_pointer_send_axis(grab->seat, time_msec, orientation, value,
+ value_discrete, source);
+}
+
+static void
+default_pointer_grab_iface_frame(struct ds_seat_pointer_grab *grab)
+{
+ ds_seat_pointer_send_frame(grab->seat);
+}
+
+static void
+default_pointer_grab_iface_cancel(struct ds_seat_pointer_grab *grab)
+{
+ // cannot be cancelled
+}
+
+static const struct ds_pointer_grab_interface default_pointer_grab_iface = {
+ .enter = default_pointer_grab_iface_enter,
+ .clear_focus = default_pointer_grab_iface_clear_focus,
+ .motion = default_pointer_grab_iface_motion,
+ .button = default_pointer_grab_iface_button,
+ .axis = default_pointer_grab_iface_axis,
+ .frame = default_pointer_grab_iface_frame,
+ .cancel = default_pointer_grab_iface_cancel,
+};
+
+static void
+pointer_handle_set_cursor(struct wl_client *client,
+ struct wl_resource *pointer_resource, uint32_t serial,
+ struct wl_resource *surface_resource,
+ int32_t hotspot_x, int32_t hotspot_y)
+{
+ struct ds_seat_client *seat_client;
+
+ seat_client = wl_resource_get_user_data(pointer_resource);
+ if (!seat_client)
+ return;
+
+ // TODO
+}
+
+static void
+pointer_handle_release(struct wl_client *client, struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static const struct wl_pointer_interface pointer_impl =
+{
+ .set_cursor = pointer_handle_set_cursor,
+ .release = pointer_handle_release,
+};
+
+static void pointer_handle_resource_destroy(struct wl_resource *resource)
+{
+ if (!wl_resource_get_user_data(resource))
+ return;
+
+ wl_list_remove(wl_resource_get_link(resource));
+}
+
+static void
+pointer_send_frame(struct wl_resource *resource)
+{
+ if (wl_resource_get_version(resource) >=
+ WL_POINTER_FRAME_SINCE_VERSION)
+ wl_pointer_send_frame(resource);
+}
--- /dev/null
+#ifndef DS_SEAT_PRIVATE_H
+#define DS_SEAT_PRIVATE_H
+
+#include <time.h>
+#include <wayland-server.h>
+
+#include "libds/seat.h"
+#include "seat.h"
+#include "surface.h"
+
+struct ds_seat_client
+{
+ struct ds_seat *seat;
+ struct wl_client *wl_client;
+ struct wl_list link;
+
+ struct wl_list resources; // wl_seat
+ struct wl_list pointers; // wl_pointer
+ struct wl_list keyboards; // wl_keyboard
+ struct wl_list touches; // wl_touch
+
+ struct {
+ struct wl_signal destroy;
+ } events;
+
+ bool needs_touch_frame;
+};
+
+#define DS_POINTER_BUTTONS_CAP 16
+
+struct ds_seat_pointer
+{
+ struct ds_seat *seat;
+ struct ds_seat_client *focused_client;
+ struct ds_surface *focused_surface;
+ double sx, sy;
+
+ struct ds_seat_pointer_grab *grab;
+ struct ds_seat_pointer_grab *default_grab;
+
+ bool sent_axis_source;
+ enum ds_axis_source cached_axis_source;
+
+ uint32_t buttons[DS_POINTER_BUTTONS_CAP];
+ size_t button_count;
+ uint32_t grab_button;
+ uint32_t grab_serial;
+ uint32_t grab_time;
+
+ struct wl_listener surface_destroy;
+
+ struct {
+ struct wl_signal focus_change;
+ } events;
+};
+
+struct ds_seat_keyboard
+{
+ struct ds_seat *seat;
+
+ struct ds_seat_client *focused_client;
+ struct ds_surface *focused_surface;
+
+ struct wl_listener surface_destroy;
+
+ struct ds_seat_keyboard_grab *grab;
+ struct ds_seat_keyboard_grab *default_grab;
+
+ struct {
+ struct wl_signal focus_change;
+ } events;
+};
+
+struct ds_touch_point
+{
+ int32_t touch_id;
+ struct ds_surface *surface;
+ struct ds_seat_client *seat_client;
+
+ struct ds_seat_client *focused_client;
+ struct ds_surface *focused_surface;
+ double sx, sy;
+
+ struct wl_listener surface_destroy;
+ struct wl_listener focused_surface_destroy;
+ struct wl_listener client_destroy;
+
+ struct {
+ struct wl_signal destroy;
+ } events;
+
+ struct wl_list link;
+};
+
+struct ds_seat_touch
+{
+ struct ds_seat *seat;
+ struct wl_list touch_points; // ds_touch_point::link
+
+ uint32_t grab_serial;
+ uint32_t grab_id;
+
+ struct ds_seat_touch_grab *grab;
+ struct ds_seat_touch_grab *default_grab;
+};
+
+struct ds_seat
+{
+ char *name;
+ enum wl_seat_capability capabilities;
+ enum wl_seat_capability accumulated_capabilities;
+ struct timespec last_event;
+
+ struct wl_display *display;
+ struct wl_global *global;
+
+ struct wl_list clients; // ds_seat_client::link
+
+ struct ds_seat_pointer pointer;
+ struct ds_seat_keyboard keyboard;
+ struct ds_seat_touch touch;
+
+ struct wl_listener display_destroy;
+
+ struct {
+ struct wl_signal destroy;
+
+ struct wl_signal pointer_grab_begin;
+ struct wl_signal pointer_grab_end;
+
+ struct wl_signal keyboard_grab_begin;
+ struct wl_signal keyboard_grab_end;
+
+ struct wl_signal touch_grab_begin;
+ struct wl_signal touch_grab_end;
+ } events;
+};
+
+struct ds_seat_client *
+seat_client_for_wl_client(struct ds_seat *seat, struct wl_client *wl_client);
+
+bool seat_pointer_init(struct ds_seat *seat);
+
+void seat_pointer_finish(struct ds_seat *seat);
+
+void seat_client_add_pointer_resource(struct ds_seat_client *seat_client,
+ uint32_t version, uint32_t id);
+
+void
+seat_client_remove_all_pointer_resources(struct ds_seat_client *seat_client);
+
+bool seat_keyboard_init(struct ds_seat *seat);
+
+void seat_keyboard_finish(struct ds_seat *seat);
+
+void seat_client_add_keyboard_resource(struct ds_seat_client *seat_client,
+ uint32_t version, uint32_t id);
+
+void
+seat_client_remove_all_keyboard_resources(struct ds_seat_client *seat_client);
+
+bool seat_touch_init(struct ds_seat *seat);
+
+void seat_touch_finish(struct ds_seat *seat);
+
+void seat_client_add_touch_resource(struct ds_seat_client *seat_client,
+ uint32_t version, uint32_t id);
+
+void
+seat_client_remove_all_touch_resources(struct ds_seat_client *seat_client);
+
+#endif
--- /dev/null
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "libds/log.h"
+#include "seat_private.h"
+
+static const struct ds_touch_grab_interface default_touch_grab_iface;
+static const struct wl_touch_interface touch_impl;
+
+static void touch_handle_resource_destroy(struct wl_resource *resource);
+static struct ds_touch_point *touch_point_create(struct ds_seat *seat,
+ int32_t touch_id, struct ds_surface *surface, double sx, double sy);
+static void touch_point_destroy(struct ds_touch_point *point);
+static void touch_point_clear_focus(struct ds_touch_point *point);
+static struct ds_touch_point *seat_find_touch_point(struct ds_seat *seat,
+ int32_t touch_id);
+static int seat_touch_num_points(struct ds_seat *seat);
+
+WL_EXPORT uint32_t
+ds_seat_touch_notify_down(struct ds_seat *seat, struct ds_surface *surface,
+ uint32_t time_msec, int32_t touch_id, double sx, double sy)
+{
+ struct ds_seat_touch_grab *grab = seat->touch.grab;
+ struct ds_touch_point *point;
+ uint32_t serial;
+
+ // FIXME
+ // What if ds_touch_point is already exist associated with given touch_id?
+ point = touch_point_create(seat, touch_id, surface, sx, sy);
+ if (!point) {
+ ds_err("Could not create touch point");
+ return 0;
+ }
+
+ serial = grab->iface->down(grab, time_msec, point);
+ if (!serial) {
+ touch_point_destroy(point);
+ return 0;
+ }
+
+ if (serial && seat_touch_num_points(seat) == 1) {
+ seat->touch.grab_serial = serial;
+ seat->touch.grab_id = touch_id;
+ }
+
+ return serial;
+}
+
+WL_EXPORT void
+ds_seat_touch_notify_up(struct ds_seat *seat, uint32_t time_msec,
+ int32_t touch_id)
+{
+ struct ds_seat_touch_grab *grab = seat->touch.grab;
+ struct ds_touch_point *point;
+
+ clock_gettime(CLOCK_MONOTONIC, &seat->last_event);
+
+ point = seat_find_touch_point(seat, touch_id);
+ if (!point)
+ return;
+
+ grab->iface->up(grab, time_msec, point);
+
+ touch_point_destroy(point);
+}
+
+WL_EXPORT void
+ds_seat_touch_notify_motion(struct ds_seat *seat, uint32_t time_msec,
+ int32_t touch_id, double sx, double sy)
+{
+ struct ds_seat_touch_grab *grab = seat->touch.grab;
+ struct ds_touch_point *point;
+
+ clock_gettime(CLOCK_MONOTONIC, &seat->last_event);
+
+ point = seat_find_touch_point(seat, touch_id);
+ if (!point)
+ return;
+
+ point->sx = sx;
+ point->sy = sy;
+
+ grab->iface->motion(grab, time_msec, point);
+}
+
+WL_EXPORT void
+ds_seat_touch_notify_frame(struct ds_seat *seat)
+{
+ struct ds_seat_touch_grab *grab = seat->touch.grab;
+
+ if (grab->iface->frame)
+ grab->iface->frame(grab);
+}
+
+WL_EXPORT void
+ds_seat_touch_add_grab_start_listener(struct ds_seat *seat,
+ struct wl_listener *listener)
+{
+ wl_signal_add(&seat->events.touch_grab_begin, listener);
+}
+
+WL_EXPORT void
+ds_seat_touch_end_grab_start_listener(struct ds_seat *seat,
+ struct wl_listener *listener)
+{
+ wl_signal_add(&seat->events.touch_grab_end, listener);
+}
+
+uint32_t
+ds_seat_touch_send_down(struct ds_seat *seat, struct ds_surface *surface,
+ uint32_t time_msec, int32_t touch_id, double sx, double sy)
+{
+ struct ds_touch_point *point;
+ struct wl_resource *resource;
+ uint32_t serial;
+
+ point = seat_find_touch_point(seat, touch_id);
+ if (!point) {
+ ds_err("Got touch down for unknown touch point");
+ return 0;
+ }
+
+ serial = wl_display_next_serial(seat->display);
+ wl_resource_for_each(resource, &point->seat_client->touches) {
+ wl_touch_send_down(resource, serial, time_msec,
+ ds_surface_get_wl_resource(surface), touch_id,
+ wl_fixed_from_double(sx), wl_fixed_from_double(sy));
+ }
+
+ point->seat_client->needs_touch_frame = true;
+
+ return serial;
+}
+
+void
+ds_seat_touch_send_up(struct ds_seat *seat, uint32_t time_msec,
+ int32_t touch_id)
+{
+ struct ds_touch_point *point;
+ struct wl_resource *resource;
+ uint32_t serial;
+
+ point = seat_find_touch_point(seat, touch_id);
+ if (!point) {
+ ds_err("Got touch up for unknown touch point");
+ return;
+ }
+
+ serial = wl_display_next_serial(seat->display);
+ wl_resource_for_each(resource, &point->seat_client->touches)
+ wl_touch_send_up(resource, serial, time_msec, touch_id);
+
+ point->seat_client->needs_touch_frame = true;
+}
+
+void
+ds_seat_touch_send_motion(struct ds_seat *seat, uint32_t time_msec,
+ int32_t touch_id, double sx, double sy)
+{
+ struct ds_touch_point *point;
+ struct wl_resource *resource;
+
+ point = seat_find_touch_point(seat, touch_id);
+ if (!point) {
+ ds_err("Got touch motion for unknown touch point");
+ return;
+ }
+
+ wl_resource_for_each(resource, &point->seat_client->touches) {
+ wl_touch_send_motion(resource, time_msec, touch_id,
+ wl_fixed_from_double(sx), wl_fixed_from_double(sy));
+ }
+
+ point->seat_client->needs_touch_frame = true;
+}
+
+void
+ds_seat_touch_send_frame(struct ds_seat *seat)
+{
+ struct ds_seat_client *seat_client;
+ struct wl_resource *resource;
+
+ wl_list_for_each(seat_client, &seat->clients, link) {
+ if (!seat_client->needs_touch_frame)
+ continue;
+
+ wl_resource_for_each(resource, &seat_client->touches)
+ wl_touch_send_frame(resource);
+
+ seat_client->needs_touch_frame = false;
+ }
+}
+
+bool
+seat_touch_init(struct ds_seat *seat)
+{
+ struct ds_seat_touch *touch = &seat->touch;
+ struct ds_seat_touch_grab *grab;
+
+ grab = calloc(1, sizeof *grab);
+ if (!grab)
+ return false;
+
+ grab->iface = &default_touch_grab_iface;
+ grab->seat = seat;
+
+ touch->default_grab = grab;
+ touch->grab = grab;
+ touch->seat = seat;
+
+ wl_list_init(&touch->touch_points);
+
+ return true;
+}
+
+void
+seat_touch_finish(struct ds_seat *seat)
+{
+ struct ds_seat_touch *touch = &seat->touch;
+ struct ds_touch_point *point;
+
+ wl_list_for_each(point, &touch->touch_points, link)
+ touch_point_clear_focus(point);
+
+ free(touch->default_grab);
+}
+
+void
+seat_client_add_touch_resource(struct ds_seat_client *seat_client,
+ uint32_t version, uint32_t id)
+{
+ struct wl_resource *resource;
+
+ resource = wl_resource_create(seat_client->wl_client,
+ &wl_keyboard_interface, version, id);
+ if (!resource) {
+ wl_client_post_no_memory(seat_client->wl_client);
+ return;
+ }
+
+ wl_resource_set_implementation(resource, &touch_impl, seat_client,
+ touch_handle_resource_destroy);
+
+ wl_list_insert(&seat_client->touches, wl_resource_get_link(resource));
+
+ if (!(seat_client->seat->capabilities & WL_SEAT_CAPABILITY_TOUCH))
+ wl_resource_set_user_data(resource, NULL);
+}
+
+void
+seat_client_remove_all_touch_resources(struct ds_seat_client *seat_client)
+{
+ struct wl_resource *resource, *tmp;
+
+ wl_resource_for_each_safe(resource, tmp, &seat_client->touches) {
+ wl_list_remove(wl_resource_get_link(resource));
+ wl_resource_set_user_data(resource, NULL);
+ }
+}
+
+static uint32_t
+default_touch_grab_iface_down(struct ds_seat_touch_grab *grab,
+ uint32_t time_msec, struct ds_touch_point *point)
+{
+ return ds_seat_touch_send_down(grab->seat, point->surface, time_msec,
+ point->touch_id, point->sx, point->sy);
+}
+
+static void
+default_touch_grab_iface_up(struct ds_seat_touch_grab *grab,
+ uint32_t time_msec, struct ds_touch_point *point)
+{
+ ds_seat_touch_send_up(grab->seat, time_msec, point->touch_id);
+}
+
+static void
+default_touch_grab_iface_motion(struct ds_seat_touch_grab *grab,
+ uint32_t time_msec, struct ds_touch_point *point)
+{
+ if (!point->focused_surface || point->focused_surface == point->surface) {
+ ds_seat_touch_send_motion(grab->seat, time_msec, point->touch_id,
+ point->sx, point->sy);
+ }
+}
+
+static void
+default_touch_grab_iface_enter(struct ds_seat_touch_grab *grab,
+ uint32_t time_msec, struct ds_touch_point *point)
+{
+ // not handled by default
+}
+
+static void
+default_touch_grab_iface_frame(struct ds_seat_touch_grab *grab)
+{
+ ds_seat_touch_send_frame(grab->seat);
+}
+
+static void
+default_touch_grab_iface_cancel(struct ds_seat_touch_grab *grab)
+{
+ // cannot be cancelled
+}
+
+static const struct ds_touch_grab_interface default_touch_grab_iface = {
+ .down = default_touch_grab_iface_down,
+ .up = default_touch_grab_iface_up,
+ .motion = default_touch_grab_iface_motion,
+ .enter = default_touch_grab_iface_enter,
+ .frame = default_touch_grab_iface_frame,
+ .cancel = default_touch_grab_iface_cancel,
+};
+
+static void
+touch_handle_release(struct wl_client *client, struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static const struct wl_touch_interface touch_impl =
+{
+ .release = touch_handle_release,
+};
+
+static void
+touch_handle_resource_destroy(struct wl_resource *resource)
+{
+ if (!wl_resource_get_user_data(resource))
+ return;
+
+ wl_list_remove(wl_resource_get_link(resource));
+}
+
+static void
+touch_point_handle_surface_destroy(struct wl_listener *listener, void *data)
+{
+ struct ds_touch_point *point;
+
+ point = wl_container_of(listener, point, surface_destroy);
+ point->surface = NULL;
+ wl_list_remove(&point->surface_destroy.link);
+ wl_list_init(&point->surface_destroy.link);
+}
+
+static void
+touch_point_handle_client_destroy(struct wl_listener *listener, void *data)
+{
+ struct ds_touch_point *point;
+
+ point = wl_container_of(listener, point, surface_destroy);
+ touch_point_destroy(point);
+}
+
+static struct ds_touch_point *
+touch_point_create(struct ds_seat *seat, int32_t touch_id,
+ struct ds_surface *surface, double sx, double sy)
+{
+ struct ds_touch_point *point;
+ struct ds_seat_client *seat_client;
+ struct wl_client *wl_client;
+
+ wl_client = wl_resource_get_client(ds_surface_get_wl_resource(surface));
+ seat_client = seat_client_for_wl_client(seat, wl_client);
+ if (!seat_client || wl_list_empty(&seat_client->touches))
+ return NULL;
+
+ point = calloc(1, sizeof *point);
+ if (!point)
+ return NULL;
+
+ point->touch_id = touch_id;
+ point->surface = surface;
+ point->seat_client = seat_client;
+ point->sx = sx;
+ point->sy = sy;
+
+ wl_signal_init(&point->events.destroy);
+
+ point->surface_destroy.notify = touch_point_handle_surface_destroy;
+ ds_surface_add_destroy_listener(surface, &point->surface_destroy);
+
+ point->client_destroy.notify = touch_point_handle_client_destroy;
+ wl_signal_add(&seat_client->events.destroy, &point->client_destroy);
+
+ wl_list_insert(&seat->touch.touch_points, &point->link);
+
+ return point;
+}
+
+static void
+touch_point_destroy(struct ds_touch_point *point)
+{
+ wl_signal_emit(&point->events.destroy, point);
+
+ touch_point_clear_focus(point);
+
+ wl_list_remove(&point->surface_destroy.link);
+ wl_list_remove(&point->client_destroy.link);
+ wl_list_remove(&point->link);
+ free(point);
+}
+
+static void
+touch_point_clear_focus(struct ds_touch_point *point)
+{
+ if (!point->focused_surface)
+ return;
+
+ wl_list_remove(&point->focused_surface_destroy.link);
+ point->focused_client = NULL;
+ point->focused_surface = NULL;
+}
+
+static struct ds_touch_point *seat_find_touch_point(struct ds_seat *seat,
+ int32_t touch_id)
+{
+ struct ds_touch_point *point;
+
+ wl_list_for_each(point, &seat->touch.touch_points, link) {
+ if (point->touch_id == touch_id)
+ return point;
+ }
+
+ return NULL;
+}
+
+static int
+seat_touch_num_points(struct ds_seat *seat)
+{
+ return wl_list_length(&seat->touch.touch_points);
+}
struct ds_surface *surface, struct ds_surface *parent,
uint32_t version, uint32_t id);
+struct wl_resource *
+ds_surface_get_wl_resource(struct ds_surface *surface);
+
#endif
return !!surface->buffer;
}
+struct wl_resource *
+ds_surface_get_wl_resource(struct ds_surface *surface)
+{
+ return surface->resource;
+}
+
static void
surface_handle_destroy(struct wl_client *client, struct wl_resource *resource)
{