aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/types/wlr_data_device.h32
-rw-r--r--include/types/wlr_seat.h20
-rw-r--r--include/wlr/types/wlr_seat.h3
-rw-r--r--rootston/output.c2
-rw-r--r--types/data_device/wlr_data_device.c248
-rw-r--r--types/data_device/wlr_data_offer.c217
-rw-r--r--types/data_device/wlr_data_source.c288
-rw-r--r--types/data_device/wlr_drag.c481
-rw-r--r--types/meson.build13
-rw-r--r--types/seat/wlr_seat.c305
-rw-r--r--types/seat/wlr_seat_keyboard.c355
-rw-r--r--types/seat/wlr_seat_pointer.c314
-rw-r--r--types/seat/wlr_seat_touch.c335
-rw-r--r--types/wlr_data_device.c1203
-rw-r--r--types/wlr_seat.c1271
15 files changed, 2606 insertions, 2481 deletions
diff --git a/include/types/wlr_data_device.h b/include/types/wlr_data_device.h
new file mode 100644
index 00000000..4aa53dc0
--- /dev/null
+++ b/include/types/wlr_data_device.h
@@ -0,0 +1,32 @@
+#ifndef TYPES_WLR_DATA_DEVICE_H
+#define TYPES_WLR_DATA_DEVICE_H
+
+#include <wayland-server.h>
+
+#define DATA_DEVICE_ALL_ACTIONS (WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY | \
+ WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | \
+ WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK)
+
+struct wlr_client_data_source {
+ struct wlr_data_source source;
+ struct wlr_data_source_impl impl;
+ struct wl_resource *resource;
+};
+
+struct wlr_data_offer *data_offer_create(struct wl_client *client,
+ struct wlr_data_source *source, uint32_t version);
+void data_offer_update_action(struct wlr_data_offer *offer);
+
+struct wlr_client_data_source *client_data_source_create(
+ struct wl_client *client, uint32_t version, uint32_t id);
+struct wlr_client_data_source *client_data_source_from_resource(
+ struct wl_resource *resource);
+struct wlr_data_offer *data_source_send_offer(struct wlr_data_source *source,
+ struct wlr_seat_client *target);
+void data_source_notify_finish(struct wlr_data_source *source);
+
+bool seat_client_start_drag(struct wlr_seat_client *client,
+ struct wlr_data_source *source, struct wlr_surface *icon_surface,
+ struct wlr_surface *origin, uint32_t serial);
+
+#endif
diff --git a/include/types/wlr_seat.h b/include/types/wlr_seat.h
new file mode 100644
index 00000000..b76525ec
--- /dev/null
+++ b/include/types/wlr_seat.h
@@ -0,0 +1,20 @@
+#ifndef TYPES_WLR_SEAT_H
+#define TYPES_WLR_SEAT_H
+
+#include <wayland-server.h>
+#include <wlr/types/wlr_seat.h>
+
+const struct wlr_pointer_grab_interface default_pointer_grab_impl;
+const struct wlr_keyboard_grab_interface default_keyboard_grab_impl;
+const struct wlr_touch_grab_interface default_touch_grab_impl;
+
+void seat_client_create_pointer(struct wlr_seat_client *seat_client,
+ uint32_t version, uint32_t id);
+
+void seat_client_create_keyboard(struct wlr_seat_client *seat_client,
+ uint32_t version, uint32_t id);
+
+void seat_client_create_touch(struct wlr_seat_client *seat_client,
+ uint32_t version, uint32_t id);
+
+#endif
diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h
index ff907f97..e1fa27bb 100644
--- a/include/wlr/types/wlr_seat.h
+++ b/include/wlr/types/wlr_seat.h
@@ -42,7 +42,6 @@ struct wlr_touch_point {
struct wl_listener surface_destroy;
struct wl_listener focus_surface_destroy;
- struct wl_listener resource_destroy;
struct {
struct wl_signal destroy;
@@ -138,7 +137,6 @@ struct wlr_seat_pointer_state {
uint32_t grab_time;
struct wl_listener surface_destroy;
- struct wl_listener resource_destroy;
};
// TODO: May be useful to be able to simulate keyboard input events
@@ -154,7 +152,6 @@ struct wlr_seat_keyboard_state {
struct wl_listener keyboard_repeat_info;
struct wl_listener surface_destroy;
- struct wl_listener resource_destroy;
struct wlr_seat_keyboard_grab *grab;
struct wlr_seat_keyboard_grab *default_grab;
diff --git a/rootston/output.c b/rootston/output.c
index 225b7213..d4c6d5a2 100644
--- a/rootston/output.c
+++ b/rootston/output.c
@@ -756,6 +756,8 @@ static void output_destroy(struct roots_output *output) {
wl_list_remove(&output->link);
wl_list_remove(&output->destroy.link);
+ wl_list_remove(&output->mode.link);
+ wl_list_remove(&output->transform.link);
wl_list_remove(&output->damage_frame.link);
wl_list_remove(&output->damage_destroy.link);
free(output);
diff --git a/types/data_device/wlr_data_device.c b/types/data_device/wlr_data_device.c
new file mode 100644
index 00000000..fffb2f1b
--- /dev/null
+++ b/types/data_device/wlr_data_device.c
@@ -0,0 +1,248 @@
+#define _XOPEN_SOURCE 700
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <wayland-server.h>
+#include <wlr/types/wlr_data_device.h>
+#include <wlr/types/wlr_seat.h>
+#include <wlr/util/log.h>
+#include "types/wlr_data_device.h"
+#include "util/signal.h"
+
+static const struct wl_data_device_interface data_device_impl;
+
+static struct wlr_seat_client *seat_client_from_data_device_resource(
+ struct wl_resource *resource) {
+ assert(wl_resource_instance_of(resource, &wl_data_device_interface,
+ &data_device_impl));
+ return wl_resource_get_user_data(resource);
+}
+
+static void data_device_set_selection(struct wl_client *client,
+ struct wl_resource *device_resource,
+ struct wl_resource *source_resource, uint32_t serial) {
+ struct wlr_client_data_source *source = NULL;
+ if (source_resource != NULL) {
+ source = client_data_source_from_resource(source_resource);
+ }
+
+ struct wlr_seat_client *seat_client =
+ seat_client_from_data_device_resource(device_resource);
+
+ struct wlr_data_source *wlr_source = (struct wlr_data_source *)source;
+ wlr_seat_set_selection(seat_client->seat, wlr_source, serial);
+}
+
+static void data_device_start_drag(struct wl_client *client,
+ struct wl_resource *device_resource,
+ struct wl_resource *source_resource,
+ struct wl_resource *origin_resource, struct wl_resource *icon_resource,
+ uint32_t serial) {
+ struct wlr_seat_client *seat_client =
+ seat_client_from_data_device_resource(device_resource);
+ struct wlr_surface *origin = wlr_surface_from_resource(origin_resource);
+ struct wlr_data_source *source = NULL;
+ struct wlr_surface *icon = NULL;
+
+ if (source_resource) {
+ struct wlr_client_data_source *client_source =
+ client_data_source_from_resource(source_resource);
+ source = (struct wlr_data_source *)client_source;
+ }
+
+ if (icon_resource) {
+ icon = wlr_surface_from_resource(icon_resource);
+ }
+ if (icon) {
+ if (wlr_surface_set_role(icon, "wl_data_device-icon",
+ icon_resource, WL_DATA_DEVICE_ERROR_ROLE) < 0) {
+ return;
+ }
+ }
+
+ if (!seat_client_start_drag(seat_client, source, icon, origin, serial)) {
+ wl_resource_post_no_memory(device_resource);
+ return;
+ }
+
+ if (source) {
+ source->seat_client = seat_client;
+ }
+}
+
+static void data_device_release(struct wl_client *client,
+ struct wl_resource *resource) {
+ wl_resource_destroy(resource);
+}
+
+static const struct wl_data_device_interface data_device_impl = {
+ .start_drag = data_device_start_drag,
+ .set_selection = data_device_set_selection,
+ .release = data_device_release,
+};
+
+static void data_device_destroy(struct wl_resource *resource) {
+ wl_list_remove(wl_resource_get_link(resource));
+}
+
+
+void wlr_seat_client_send_selection(struct wlr_seat_client *seat_client) {
+ if (wl_list_empty(&seat_client->data_devices)) {
+ return;
+ }
+
+ if (seat_client->seat->selection_source) {
+ struct wlr_data_offer *offer = data_source_send_offer(
+ seat_client->seat->selection_source, seat_client);
+ if (offer == NULL) {
+ return;
+ }
+
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &seat_client->data_devices) {
+ wl_data_device_send_selection(resource, offer->resource);
+ }
+ } else {
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &seat_client->data_devices) {
+ wl_data_device_send_selection(resource, NULL);
+ }
+ }
+}
+
+static void seat_client_selection_source_destroy(
+ struct wl_listener *listener, void *data) {
+ struct wlr_seat *seat =
+ wl_container_of(listener, seat, selection_source_destroy);
+ struct wlr_seat_client *seat_client = seat->keyboard_state.focused_client;
+
+ if (seat_client && seat->keyboard_state.focused_surface) {
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &seat_client->data_devices) {
+ wl_data_device_send_selection(resource, NULL);
+ }
+ }
+
+ seat->selection_source = NULL;
+
+ wlr_signal_emit_safe(&seat->events.selection, seat);
+}
+
+void wlr_seat_set_selection(struct wlr_seat *seat,
+ struct wlr_data_source *source, uint32_t serial) {
+ if (seat->selection_source &&
+ seat->selection_serial - serial < UINT32_MAX / 2) {
+ return;
+ }
+
+ if (seat->selection_source) {
+ wl_list_remove(&seat->selection_source_destroy.link);
+ wlr_data_source_cancel(seat->selection_source);
+ seat->selection_source = NULL;
+ }
+
+ seat->selection_source = source;
+ seat->selection_serial = serial;
+
+ struct wlr_seat_client *focused_client =
+ seat->keyboard_state.focused_client;
+
+ if (focused_client) {
+ wlr_seat_client_send_selection(focused_client);
+ }
+
+ wlr_signal_emit_safe(&seat->events.selection, seat);
+
+ if (source) {
+ seat->selection_source_destroy.notify =
+ seat_client_selection_source_destroy;
+ wl_signal_add(&source->events.destroy,
+ &seat->selection_source_destroy);
+ }
+}
+
+
+static void data_device_manager_get_data_device(struct wl_client *client,
+ struct wl_resource *manager_resource, uint32_t id,
+ struct wl_resource *seat_resource) {
+ struct wlr_seat_client *seat_client =
+ wlr_seat_client_from_resource(seat_resource);
+
+ struct wl_resource *resource = wl_resource_create(client,
+ &wl_data_device_interface, wl_resource_get_version(manager_resource),
+ id);
+ if (resource == NULL) {
+ wl_resource_post_no_memory(manager_resource);
+ return;
+ }
+ wl_resource_set_implementation(resource, &data_device_impl, seat_client,
+ &data_device_destroy);
+ wl_list_insert(&seat_client->data_devices, wl_resource_get_link(resource));
+}
+
+static void data_device_manager_create_data_source(struct wl_client *client,
+ struct wl_resource *resource, uint32_t id) {
+ client_data_source_create(client, wl_resource_get_version(resource), id);
+}
+
+static const struct wl_data_device_manager_interface
+ data_device_manager_impl = {
+ .create_data_source = data_device_manager_create_data_source,
+ .get_data_device = data_device_manager_get_data_device,
+};
+
+static void data_device_manager_bind(struct wl_client *client,
+ void *data, uint32_t version, uint32_t id) {
+ struct wl_resource *resource = wl_resource_create(client,
+ &wl_data_device_manager_interface,
+ version, id);
+ if (resource == NULL) {
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ wl_resource_set_implementation(resource, &data_device_manager_impl,
+ NULL, NULL);
+}
+
+void wlr_data_device_manager_destroy(struct wlr_data_device_manager *manager) {
+ if (!manager) {
+ return;
+ }
+ wl_list_remove(&manager->display_destroy.link);
+ // TODO: free wl_resources
+ wl_global_destroy(manager->global);
+ free(manager);
+}
+
+static void handle_display_destroy(struct wl_listener *listener, void *data) {
+ struct wlr_data_device_manager *manager =
+ wl_container_of(listener, manager, display_destroy);
+ wlr_data_device_manager_destroy(manager);
+}
+
+struct wlr_data_device_manager *wlr_data_device_manager_create(
+ struct wl_display *display) {
+ struct wlr_data_device_manager *manager =
+ calloc(1, sizeof(struct wlr_data_device_manager));
+ if (manager == NULL) {
+ wlr_log(L_ERROR, "could not create data device manager");
+ return NULL;
+ }
+
+ manager->global =
+ wl_global_create(display, &wl_data_device_manager_interface,
+ 3, NULL, data_device_manager_bind);
+ if (!manager->global) {
+ wlr_log(L_ERROR, "could not create data device manager wl global");
+ free(manager);
+ return NULL;
+ }
+
+ manager->display_destroy.notify = handle_display_destroy;
+ wl_display_add_destroy_listener(display, &manager->display_destroy);
+
+ return manager;
+}
diff --git a/types/data_device/wlr_data_offer.c b/types/data_device/wlr_data_offer.c
new file mode 100644
index 00000000..dfaf054c
--- /dev/null
+++ b/types/data_device/wlr_data_offer.c
@@ -0,0 +1,217 @@
+#define _XOPEN_SOURCE 700
+#include <assert.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#include <wayland-server.h>
+#include <wlr/types/wlr_data_device.h>
+#include <wlr/types/wlr_seat.h>
+#include <wlr/util/log.h>
+#include "types/wlr_data_device.h"
+#include "util/signal.h"
+
+static const struct wl_data_offer_interface data_offer_impl;
+
+static struct wlr_data_offer *data_offer_from_resource(
+ struct wl_resource *resource) {
+ assert(wl_resource_instance_of(resource, &wl_data_offer_interface,
+ &data_offer_impl));
+ return wl_resource_get_user_data(resource);
+}
+
+static uint32_t data_offer_choose_action(struct wlr_data_offer *offer) {
+ uint32_t offer_actions, preferred_action = 0;
+ if (wl_resource_get_version(offer->resource) >=
+ WL_DATA_OFFER_ACTION_SINCE_VERSION) {
+ offer_actions = offer->actions;
+ preferred_action = offer->preferred_action;
+ } else {
+ offer_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
+ }
+
+ uint32_t source_actions;
+ if (offer->source->actions >= 0) {
+ source_actions = offer->source->actions;
+ } else {
+ source_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
+ }
+
+ uint32_t available_actions = offer_actions & source_actions;
+ if (!available_actions) {
+ return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
+ }
+
+ if (offer->source->seat_client &&
+ offer->source->compositor_action & available_actions) {
+ return offer->source->compositor_action;
+ }
+
+ // If the dest side has a preferred DnD action, use it
+ if ((preferred_action & available_actions) != 0) {
+ return preferred_action;
+ }
+
+ // Use the first found action, in bit order
+ return 1 << (ffs(available_actions) - 1);
+}
+
+void data_offer_update_action(struct wlr_data_offer *offer) {
+ if (!offer->source) {
+ return;
+ }
+
+ uint32_t action = data_offer_choose_action(offer);
+ if (offer->source->current_dnd_action == action) {
+ return;
+ }
+
+ offer->source->current_dnd_action = action;
+
+ if (offer->in_ask) {
+ return;
+ }
+
+ wlr_data_source_dnd_action(offer->source, action);
+
+ if (wl_resource_get_version(offer->resource) >=
+ WL_DATA_OFFER_ACTION_SINCE_VERSION) {
+ wl_data_offer_send_action(offer->resource, action);
+ }
+}
+
+static void data_offer_accept(struct wl_client *client,
+ struct wl_resource *resource, uint32_t serial, const char *mime_type) {
+ struct wlr_data_offer *offer = data_offer_from_resource(resource);
+
+ if (!offer->source || offer != offer->source->offer) {
+ return;
+ }
+
+ // TODO check that client is currently focused by the input device
+
+ wlr_data_source_accept(offer->source, serial, mime_type);
+}
+
+static void data_offer_receive(struct wl_client *client,
+ struct wl_resource *resource, const char *mime_type, int32_t fd) {
+ struct wlr_data_offer *offer = data_offer_from_resource(resource);
+
+ if (offer->source && offer == offer->source->offer) {
+ wlr_data_source_send(offer->source, mime_type, fd);
+ } else {
+ close(fd);
+ }
+}
+
+static void data_offer_destroy(struct wl_client *client,
+ struct wl_resource *resource) {
+ wl_resource_destroy(resource);
+}
+
+static void data_offer_finish(struct wl_client *client,
+ struct wl_resource *resource) {
+ struct wlr_data_offer *offer = data_offer_from_resource(resource);
+
+ if (!offer->source || offer->source->offer != offer) {
+ return;
+ }
+
+ data_source_notify_finish(offer->source);
+}
+
+static void data_offer_set_actions(struct wl_client *client,
+ struct wl_resource *resource, uint32_t actions,
+ uint32_t preferred_action) {
+ struct wlr_data_offer *offer = data_offer_from_resource(resource);
+
+ if (actions & ~DATA_DEVICE_ALL_ACTIONS) {
+ wl_resource_post_error(offer->resource,
+ WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK,
+ "invalid action mask %x", actions);
+ return;
+ }
+
+ if (preferred_action && (!(preferred_action & actions) ||
+ __builtin_popcount(preferred_action) > 1)) {
+ wl_resource_post_error(offer->resource,
+ WL_DATA_OFFER_ERROR_INVALID_ACTION,
+ "invalid action %x", preferred_action);
+ return;
+ }
+
+ offer->actions = actions;
+ offer->preferred_action = preferred_action;
+
+ data_offer_update_action(offer);
+}
+
+static void data_offer_resource_destroy(struct wl_resource *resource) {
+ struct wlr_data_offer *offer = data_offer_from_resource(resource);
+
+ if (!offer->source) {
+ goto out;
+ }
+
+ wl_list_remove(&offer->source_destroy.link);
+
+ if (offer->source->offer != offer) {
+ goto out;
+ }
+
+ // If the drag destination has version < 3, wl_data_offer.finish
+ // won't be called, so do this here as a safety net, because
+ // we still want the version >= 3 drag source to be happy.
+ if (wl_resource_get_version(offer->resource) <
+ WL_DATA_OFFER_ACTION_SINCE_VERSION) {
+ data_source_notify_finish(offer->source);
+ offer->source->offer = NULL;
+ } else if (offer->source->impl->dnd_finish) {
+ // source->cancel can free the source
+ offer->source->offer = NULL;
+ wlr_data_source_cancel(offer->source);
+ } else {
+ offer->source->offer = NULL;
+ }
+
+out:
+ free(offer);
+}
+
+static const struct wl_data_offer_interface data_offer_impl = {
+ .accept = data_offer_accept,
+ .receive = data_offer_receive,
+ .destroy = data_offer_destroy,
+ .finish = data_offer_finish,
+ .set_actions = data_offer_set_actions,
+};
+
+static void handle_offer_source_destroyed(struct wl_listener *listener,
+ void *data) {
+ struct wlr_data_offer *offer =
+ wl_container_of(listener, offer, source_destroy);
+
+ offer->source = NULL;
+}
+
+struct wlr_data_offer *data_offer_create(struct wl_client *client,
+ struct wlr_data_source *source, uint32_t version) {
+ struct wlr_data_offer *offer = calloc(1, sizeof(struct wlr_data_offer));
+ if (offer == NULL) {
+ return NULL;
+ }
+ offer->source = source;
+
+ offer->resource = wl_resource_create(client,
+ &wl_data_offer_interface, version, 0);
+ if (offer->resource == NULL) {
+ free(offer);
+ return NULL;
+ }
+ wl_resource_set_implementation(offer->resource, &data_offer_impl, offer,
+ data_offer_resource_destroy);
+
+ offer->source_destroy.notify = handle_offer_source_destroyed;
+ wl_signal_add(&source->events.destroy, &offer->source_destroy);
+
+ return offer;
+}
diff --git a/types/data_device/wlr_data_source.c b/types/data_device/wlr_data_source.c
new file mode 100644
index 00000000..7c554d35
--- /dev/null
+++ b/types/data_device/wlr_data_source.c
@@ -0,0 +1,288 @@
+#define _XOPEN_SOURCE 700
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <wayland-server.h>
+#include <wlr/types/wlr_data_device.h>
+#include <wlr/types/wlr_seat.h>
+#include <wlr/util/log.h>
+#include "types/wlr_data_device.h"
+#include "util/signal.h"
+
+void data_source_notify_finish(struct wlr_data_source *source) {
+ assert(source->offer);
+ if (source->actions < 0) {
+ return;
+ }
+
+ if (source->offer->in_ask) {
+ wlr_data_source_dnd_action(source, source->current_dnd_action);
+ }
+
+ source->offer = NULL;
+ wlr_data_source_dnd_finish(source);
+}
+
+struct wlr_data_offer *data_source_send_offer(struct wlr_data_source *source,
+ struct wlr_seat_client *target) {
+ if (wl_list_empty(&target->data_devices)) {
+ return NULL;
+ }
+
+ uint32_t version = wl_resource_get_version(
+ wl_resource_from_link(target->data_devices.next));
+
+ struct wlr_data_offer *offer =
+ data_offer_create(target->client, source, version);
+ if (offer == NULL) {
+ return NULL;
+ }
+
+ struct wl_resource *target_resource;
+ wl_resource_for_each(target_resource, &target->data_devices) {
+ wl_data_device_send_data_offer(target_resource, offer->resource);
+ }
+
+ char **p;
+ wl_array_for_each(p, &source->mime_types) {
+ wl_data_offer_send_offer(offer->resource, *p);
+ }
+
+ source->offer = offer;
+ source->accepted = false;
+ return offer;
+}
+
+void wlr_data_source_init(struct wlr_data_source *source,
+ const struct wlr_data_source_impl *impl) {
+ assert(impl->send);
+
+ source->impl = impl;
+ wl_array_init(&source->mime_types);
+ wl_signal_init(&source->events.destroy);
+ source->actions = -1;
+}
+
+void wlr_data_source_finish(struct wlr_data_source *source) {
+ if (source == NULL) {
+ return;
+ }
+
+ wlr_signal_emit_safe(&source->events.destroy, source);
+
+ char **p;
+ wl_array_for_each(p, &source->mime_types) {
+ free(*p);
+ }
+ wl_array_release(&source->mime_types);
+}
+
+void wlr_data_source_send(struct wlr_data_source *source, const char *mime_type,
+ int32_t fd) {
+ source->impl->send(source, mime_type, fd);
+}
+
+void wlr_data_source_accept(struct wlr_data_source *source, uint32_t serial,
+ const char *mime_type) {
+ source->accepted = (mime_type != NULL);
+ if (source->impl->accept) {
+ source->impl->accept(source, serial, mime_type);
+ }
+}
+
+void wlr_data_source_cancel(struct wlr_data_source *source) {
+ if (source->impl->cancel) {
+ source->impl->cancel(source);
+ }
+}
+
+void wlr_data_source_dnd_drop(struct wlr_data_source *source) {
+ if (source->impl->dnd_drop) {
+ source->impl->dnd_drop(source);
+ }
+}
+
+void wlr_data_source_dnd_finish(struct wlr_data_source *source) {
+ if (source->impl->dnd_finish) {
+ source->impl->dnd_finish(source);
+ }
+}
+
+void wlr_data_source_dnd_action(struct wlr_data_source *source,
+ enum wl_data_device_manager_dnd_action action) {
+ source->current_dnd_action = action;
+ if (source->impl->dnd_action) {
+ source->impl->dnd_action(source, action);
+ }
+}
+
+
+static const struct wl_data_source_interface data_source_impl;
+
+struct wlr_client_data_source *client_data_source_from_resource(
+ struct wl_resource *resource) {
+ assert(wl_resource_instance_of(resource, &wl_data_source_interface,
+ &data_source_impl));
+ return wl_resource_get_user_data(resource);
+}
+
+static void client_data_source_accept(struct wlr_data_source *wlr_source,
+ uint32_t serial, const char *mime_type);
+
+static struct wlr_client_data_source *client_data_source_from_wlr_data_source(
+ struct wlr_data_source *wlr_source) {
+ assert(wlr_source->impl->accept == client_data_source_accept);
+ return (struct wlr_client_data_source *)wlr_source;
+}
+
+static void client_data_source_accept(struct wlr_data_source *wlr_source,
+ uint32_t serial, const char *mime_type) {
+ struct wlr_client_data_source *source =
+ client_data_source_from_wlr_data_source(wlr_source);
+ wl_data_source_send_target(source->resource, mime_type);
+}
+
+static void client_data_source_send(struct wlr_data_source *wlr_source,
+ const char *mime_type, int32_t fd) {
+ struct wlr_client_data_source *source =
+ client_data_source_from_wlr_data_source(wlr_source);
+ wl_data_source_send_send(source->resource, mime_type, fd);
+ close(fd);
+}
+
+static void client_data_source_cancel(struct wlr_data_source *wlr_source) {
+ struct wlr_client_data_source *source =
+ client_data_source_from_wlr_data_source(wlr_source);
+ wl_data_source_send_cancelled(source->resource);
+}
+
+static void client_data_source_dnd_drop(struct wlr_data_source *wlr_source) {
+ struct wlr_client_data_source *source =
+ client_data_source_from_wlr_data_source(wlr_source);
+ assert(wl_resource_get_version(source->resource) >=
+ WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION);
+ wl_data_source_send_dnd_drop_performed(source->resource);
+}
+
+static void client_data_source_dnd_finish(struct wlr_data_source *wlr_source) {
+ struct wlr_client_data_source *source =
+ client_data_source_from_wlr_data_source(wlr_source);
+ assert(wl_resource_get_version(source->resource) >=
+ WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION);
+ wl_data_source_send_dnd_finished(source->resource);
+}
+
+static void client_data_source_dnd_action(struct wlr_data_source *wlr_source,
+ enum wl_data_device_manager_dnd_action action) {
+ struct wlr_client_data_source *source =
+ client_data_source_from_wlr_data_source(wlr_source);
+ assert(wl_resource_get_version(source->resource) >=
+ WL_DATA_SOURCE_ACTION_SINCE_VERSION);
+ wl_data_source_send_action(source->resource, action);
+}
+
+static void data_source_destroy(struct wl_client *client,
+ struct wl_resource *resource) {
+ wl_resource_destroy(resource);
+}
+
+static void data_source_set_actions(struct wl_client *client,
+ struct wl_resource *resource, uint32_t dnd_actions) {
+ struct wlr_client_data_source *source =
+ client_data_source_from_resource(resource);
+
+ if (source->source.actions >= 0) {
+ wl_resource_post_error(source->resource,
+ WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
+ "cannot set actions more than once");
+ return;
+ }
+
+ if (dnd_actions & ~DATA_DEVICE_ALL_ACTIONS) {
+ wl_resource_post_error(source->resource,
+ WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
+ "invalid action mask %x", dnd_actions);
+ return;
+ }
+
+ if (source->source.seat_client) {
+ wl_resource_post_error(source->resource,
+ WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
+ "invalid action change after "
+ "wl_data_device.start_drag");
+ return;
+ }
+
+ source->source.actions = dnd_actions;
+}
+
+static void data_source_offer(struct wl_client *client,
+ struct wl_resource *resource, const char *mime_type) {
+ struct wlr_client_data_source *source =
+ client_data_source_from_resource(resource);
+
+ char **p = wl_array_add(&source->source.mime_types, sizeof(*p));
+ if (p) {
+ *p = strdup(mime_type);
+ }
+ if (!p || !*p) {
+ if (p) {
+ source->source.mime_types.size -= sizeof(*p);
+ }
+ wl_resource_post_no_memory(resource);
+ }
+}
+
+static const struct wl_data_source_interface data_source_impl = {
+ .offer = data_source_offer,
+ .destroy = data_source_destroy,
+ .set_actions = data_source_set_actions,
+};
+
+static void data_source_handle_resource_destroy(struct wl_resource *resource) {
+ struct wlr_client_data_source *source =
+ client_data_source_from_resource(resource);
+ wlr_data_source_finish(&source->source);
+ free(source);
+}
+
+struct wlr_client_data_source *client_data_source_create(
+ struct wl_client *client, uint32_t version, uint32_t id) {
+ struct wlr_client_data_source *source =
+ calloc(1, sizeof(struct wlr_client_data_source));
+ if (source == NULL) {
+ return NULL;
+ }
+
+ source->resource = wl_resource_create(client, &wl_data_source_interface,
+ version, id);
+ if (source->resource == NULL) {
+ wl_resource_post_no_memory(source->resource);
+ free(source);
+ return NULL;
+ }
+ wl_resource_set_implementation(source->resource, &data_source_impl,
+ source, data_source_handle_resource_destroy);
+
+ source->impl.accept = client_data_source_accept;
+ source->impl.send = client_data_source_send;
+ source->impl.cancel = client_data_source_cancel;
+
+ if (wl_resource_get_version(source->resource) >=
+ WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION) {
+ source->impl.dnd_drop = client_data_source_dnd_drop;
+ }
+ if (wl_resource_get_version(source->resource) >=
+ WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) {
+ source->impl.dnd_finish = client_data_source_dnd_finish;
+ }
+ if (wl_resource_get_version(source->resource) >=
+ WL_DATA_SOURCE_ACTION_SINCE_VERSION) {
+ source->impl.dnd_action = client_data_source_dnd_action;
+ }
+
+ wlr_data_source_init(&source->source, &source->impl);
+ return source;
+}
diff --git a/types/data_device/wlr_drag.c b/types/data_device/wlr_drag.c
new file mode 100644
index 00000000..72a5bc41
--- /dev/null
+++ b/types/data_device/wlr_drag.c
@@ -0,0 +1,481 @@
+#define _XOPEN_SOURCE 700
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <wayland-server.h>
+#include <wlr/types/wlr_data_device.h>
+#include <wlr/types/wlr_seat.h>
+#include <wlr/util/log.h>
+#include "types/wlr_data_device.h"
+#include "util/signal.h"
+
+static void drag_handle_seat_client_destroy(struct wl_listener *listener,
+ void *data) {
+ struct wlr_drag *drag =
+ wl_container_of(listener, drag, seat_client_destroy);
+
+ drag->focus_client = NULL;
+ wl_list_remove(&drag->seat_client_destroy.link);
+}
+
+static void drag_set_focus(struct wlr_drag *drag,
+ struct wlr_surface *surface, double sx, double sy) {
+ if (drag->focus == surface) {
+ return;
+ }
+
+ if (drag->focus_client) {
+ wl_list_remove(&drag->seat_client_destroy.link);
+
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &drag->focus_client->data_devices) {
+ wl_data_device_send_leave(resource);
+ }
+
+ drag->focus_client = NULL;
+ drag->focus = NULL;
+ }
+
+ if (!surface || !surface->resource) {
+ return;
+ }
+
+ if (!drag->source &&
+ wl_resource_get_client(surface->resource) !=
+ wl_resource_get_client(drag->seat_client->wl_resource)) {
+ return;
+ }
+
+ if (drag->source && drag->source->offer) {
+ // unlink the offer from the source
+ wl_list_remove(&drag->source->offer->source_destroy.link);
+ drag->source->offer->source = NULL;
+ drag->source->offer = NULL;
+ }
+
+ struct wlr_seat_client *focus_client = wlr_seat_client_for_wl_client(
+ drag->seat_client->seat, wl_resource_get_client(surface->resource));
+ if (!focus_client) {
+ return;
+ }
+
+ struct wl_resource *offer_resource = NULL;
+ if (drag->source) {
+ drag->source->accepted = false;
+ struct wlr_data_offer *offer = data_source_send_offer(drag->source,
+ focus_client);
+ if (offer != NULL) {
+ data_offer_update_action(offer);
+
+ if (wl_resource_get_version(offer->resource) >=
+ WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION) {
+ wl_data_offer_send_source_actions(offer->resource,
+ drag->source->actions);
+ }
+
+ offer_resource = offer->resource;
+ }
+ }
+
+ if (!wl_list_empty(&focus_client->data_devices)) {
+ uint32_t serial =
+ wl_display_next_serial(drag->seat_client->seat->display);
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &focus_client->data_devices) {
+ wl_data_device_send_enter(resource, serial, surface->resource,
+ wl_fixed_from_double(sx), wl_fixed_from_double(sy),
+ offer_resource);
+ }
+ }
+
+ drag->focus = surface;
+ drag->focus_client = focus_client;
+ drag->seat_client_destroy.notify = drag_handle_seat_client_destroy;
+ wl_signal_add(&focus_client->events.destroy, &drag->seat_client_destroy);
+
+ wlr_signal_emit_safe(&drag->events.focus, drag);
+}
+
+static void drag_end(struct wlr_drag *drag) {
+ if (!drag->cancelling) {
+ drag->cancelling = true;
+ if (drag->is_pointer_grab) {
+ wlr_seat_pointer_end_grab(drag->seat);
+ } else {
+ wlr_seat_touch_end_grab(drag->seat);
+ }
+ wlr_seat_keyboard_end_grab(drag->seat);
+
+ if (drag->source) {
+ wl_list_remove(&drag->source_destroy.link);
+ }
+
+ drag_set_focus(drag, NULL, 0, 0);
+
+ if (drag->icon) {
+ drag->icon->mapped = false;
+ wl_list_remove(&drag->icon_destroy.link);
+ wlr_signal_emit_safe(&drag->icon->events.map, drag->icon);
+ }
+
+ wlr_signal_emit_safe(&drag->events.destroy, drag);
+ free(drag);
+ }
+}
+
+static void drag_handle_pointer_enter(struct wlr_seat_pointer_grab *grab,
+ struct wlr_surface *surface, double sx, double sy) {
+ struct wlr_drag *drag = grab->data;
+ drag_set_focus(drag, surface, sx, sy);
+}
+
+static void drag_handle_pointer_motion(struct wlr_seat_pointer_grab *grab,
+ uint32_t time, double sx, double sy) {
+ struct wlr_drag *drag = grab->data;
+ if (drag->focus != NULL && drag->focus_client != NULL) {
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &drag->focus_client->data_devices) {
+ wl_data_device_send_motion(resource, time, wl_fixed_from_double(sx),
+ wl_fixed_from_double(sy));
+ }
+
+ struct wlr_drag_motion_event event = {
+ .drag = drag,
+ .time = time,
+ .sx = sx,
+ .sy = sy,
+ };
+ wlr_signal_emit_safe(&drag->events.motion, &event);
+ }
+}
+
+static uint32_t drag_handle_pointer_button(struct wlr_seat_pointer_grab *grab,
+ uint32_t time, uint32_t button, uint32_t state) {
+ struct wlr_drag *drag = grab->data;
+
+ if (drag->source &&
+ grab->seat->pointer_state.grab_button == button &&
+ state == WL_POINTER_BUTTON_STATE_RELEASED) {
+ if (drag->focus_client && drag->source->current_dnd_action &&
+ drag->source->accepted) {
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &drag->focus_client->data_devices) {
+ wl_data_device_send_drop(resource);
+ }
+ wlr_data_source_dnd_drop(drag->source);
+
+ if (drag->source->offer != NULL) {
+ drag->source->offer->in_ask =
+ drag->source->current_dnd_action ==
+ WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
+ }
+
+ struct wlr_drag_drop_event event = {
+ .drag = drag,
+ .time = time,
+ };
+ wlr_signal_emit_safe(&drag->events.drop, &event);
+ } else if (drag->source->impl->dnd_finish) {
+ wlr_data_source_cancel(drag->source);
+ }
+ }
+
+ if (grab->seat->pointer_state.button_count == 0 &&
+ state == WL_POINTER_BUTTON_STATE_RELEASED) {
+ drag_end(drag);
+ }
+
+ return 0;
+}
+
+static void drag_handle_pointer_axis(struct wlr_seat_pointer_grab *grab,
+ uint32_t time, enum wlr_axis_orientation orientation, double value) {
+ // This space is intentionally left blank
+}
+
+static void drag_handle_pointer_cancel(struct wlr_seat_pointer_grab *grab) {
+ struct wlr_drag *drag = grab->data;
+ drag_end(drag);
+}
+
+static const struct wlr_pointer_grab_interface
+ data_device_pointer_drag_interface = {
+ .enter = drag_handle_pointer_enter,
+ .motion = drag_handle_pointer_motion,
+ .button = drag_handle_pointer_button,
+ .axis = drag_handle_pointer_axis,
+ .cancel = drag_handle_pointer_cancel,
+};
+
+uint32_t drag_handle_touch_down(struct wlr_seat_touch_grab *grab,
+ uint32_t time, struct wlr_touch_point *point) {
+ // eat the event
+ return 0;
+}
+
+static void drag_handle_touch_up(struct wlr_seat_touch_grab *grab,
+ uint32_t time, struct wlr_touch_point *point) {
+ struct wlr_drag *drag = grab->data;
+ if (drag->grab_touch_id != point->touch_id) {
+ return;
+ }
+
+ if (drag->focus_client) {
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &drag->focus_client->data_devices) {
+ wl_data_device_send_drop(resource);
+ }
+ }
+
+ drag_end(drag);
+}
+
+static void drag_handle_touch_motion(struct wlr_seat_touch_grab *grab,
+ uint32_t time, struct wlr_touch_point *point) {
+ struct wlr_drag *drag = grab->data;
+ if (drag->focus && drag->focus_client) {
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &drag->focus_client->data_devices) {
+ wl_data_device_send_motion(resource, time,
+ wl_fixed_from_double(point->sx),
+ wl_fixed_from_double(point->sy));
+ }
+ }
+}
+
+static void drag_handle_touch_enter(struct wlr_seat_touch_grab *grab,
+ uint32_t time, struct wlr_touch_point *point) {
+ struct wlr_drag *drag = grab->data;
+ drag_set_focus(drag, point->focus_surface, point->sx, point->sy);
+}
+
+static void drag_handle_touch_cancel(struct wlr_seat_touch_grab *grab) {
+ struct wlr_drag *drag = grab->data;
+ drag_end(drag);
+}
+
+static const struct wlr_touch_grab_interface
+ data_device_touch_drag_interface = {
+ .down = drag_handle_touch_down,
+ .up = drag_handle_touch_up,
+ .motion = drag_handle_touch_motion,
+ .enter = drag_handle_touch_enter,
+ .cancel = drag_handle_touch_cancel,
+};
+
+static void drag_handle_keyboard_enter(struct wlr_seat_keyboard_grab *grab,
+ struct wlr_surface *surface, uint32_t keycodes[], size_t num_keycodes,
+ struct wlr_keyboard_modifiers *modifiers) {
+ // nothing has keyboard focus during drags
+}
+
+static void drag_handle_keyboard_key(struct wlr_seat_keyboard_grab *grab,
+ uint32_t time, uint32_t key, uint32_t state) {
+ // no keyboard input during drags
+}
+
+static void drag_handle_keyboard_modifiers(struct wlr_seat_keyboard_grab *grab,
+ struct wlr_keyboard_modifiers *modifiers) {
+ //struct wlr_keyboard *keyboard = grab->seat->keyboard_state.keyboard;
+ // TODO change the dnd action based on what modifier is pressed on the
+ // keyboard
+}
+
+static void drag_handle_keyboard_cancel(struct wlr_seat_keyboard_grab *grab) {
+ struct wlr_drag *drag = grab->data;
+ drag_end(drag);
+}
+
+static const struct wlr_keyboard_grab_interface
+ data_device_keyboard_drag_interface = {
+ .enter = drag_handle_keyboard_enter,
+ .key = drag_handle_keyboard_key,
+ .modifiers = drag_handle_keyboard_modifiers,
+ .cancel = drag_handle_keyboard_cancel,
+};
+
+static void drag_handle_icon_destroy(struct wl_listener *listener, void *data) {
+ struct wlr_drag *drag = wl_container_of(listener, drag, icon_destroy);
+ drag->icon = NULL;
+}
+
+static void drag_handle_drag_source_destroy(struct wl_listener *listener,
+ void *data) {
+ struct wlr_drag *drag = wl_container_of(listener, drag, source_destroy);
+ drag_end(drag);
+}
+
+
+static void drag_icon_destroy(struct wlr_drag_icon *icon) {
+ if (!icon) {
+ return;
+ }
+ wlr_signal_emit_safe(&icon->events.destroy, icon);
+ wlr_surface_set_role_committed(icon->surface, NULL, NULL);
+ wl_list_remove(&icon->surface_destroy.link);
+ wl_list_remove(&icon->seat_client_destroy.link);
+ wl_list_remove(&icon->link);
+ free(icon);
+}
+
+static void drag_icon_handle_surface_destroy(struct wl_listener *listener,
+ void *data) {
+ struct wlr_drag_icon *icon =
+ wl_container_of(listener, icon, surface_destroy);
+ drag_icon_destroy(icon);
+}
+
+static void drag_icon_handle_surface_commit(struct wlr_surface *surface,
+ void *role_data) {
+ struct wlr_drag_icon *icon = role_data;
+ icon->sx += icon->surface->current->sx;
+ icon->sy += icon->surface->current->sy;
+}
+
+static void drag_icon_handle_seat_client_destroy(struct wl_listener *listener,
+ void *data) {
+ struct wlr_drag_icon *icon =
+ wl_container_of(listener, icon, seat_client_destroy);
+
+ drag_icon_destroy(icon);
+}
+
+static struct wlr_drag_icon *drag_icon_create(
+ struct wlr_surface *icon_surface, struct wlr_seat_client *client,
+ bool is_pointer, int32_t touch_id) {
+ struct wlr_drag_icon *icon = calloc(1, sizeof(struct wlr_drag_icon));
+ if (!icon) {
+ return NULL;
+ }
+
+ icon->surface = icon_surface;
+ icon->client = client;
+ icon->is_pointer = is_pointer;
+ icon->touch_id = touch_id;
+ icon->mapped = true;
+
+ wl_signal_init(&icon->events.map);
+ wl_signal_init(&icon->events.destroy);
+
+ wl_signal_add(&icon->surface->events.destroy, &icon->surface_destroy);
+ icon->surface_destroy.notify = drag_icon_handle_surface_destroy;
+
+ wlr_surface_set_role_committed(icon->surface,
+ drag_icon_handle_surface_commit, icon);
+
+ wl_signal_add(&client->events.destroy, &icon->seat_client_destroy);
+ icon->seat_client_destroy.notify = drag_icon_handle_seat_client_destroy;
+
+ wl_list_insert(&client->seat->drag_icons, &icon->link);
+ wlr_signal_emit_safe(&client->seat->events.new_drag_icon, icon);
+
+ return icon;
+}
+
+
+static void seat_handle_drag_source_destroy(struct wl_listener *listener,
+ void *data) {
+ struct wlr_seat *seat =
+ wl_container_of(listener, seat, drag_source_destroy);
+ wl_list_remove(&seat->drag_source_destroy.link);
+ seat->drag_source = NULL;
+}
+
+bool seat_client_start_drag(struct wlr_seat_client *client,
+ struct wlr_data_source *source, struct wlr_surface *icon_surface,
+ struct wlr_surface *origin, uint32_t serial) {
+ struct wlr_drag *drag = calloc(1, sizeof(struct wlr_drag));
+ if (drag == NULL) {
+ return false;
+ }
+
+ wl_signal_init(&drag->events.focus);
+ wl_signal_init(&drag->events.motion);
+ wl_signal_init(&drag->events.drop);
+ wl_signal_init(&drag->events.destroy);
+
+ struct wlr_seat *seat = client->seat;
+ drag->seat = seat;
+
+ drag->is_pointer_grab = !wl_list_empty(&client->pointers) &&
+ seat->pointer_state.button_count == 1 &&
+ seat->pointer_state.grab_serial == serial &&
+ seat->pointer_state.focused_surface &&
+ seat->pointer_state.focused_surface == origin;
+
+ bool is_touch_grab = !wl_list_empty(&client->touches) &&
+ wlr_seat_touch_num_points(seat) == 1 &&
+ seat->touch_state.grab_serial == serial;
+
+ // set in the iteration
+ struct wlr_touch_point *point = NULL;
+ if (is_touch_grab) {
+ wl_list_for_each(point, &seat->touch_state.touch_points, link) {
+ is_touch_grab = point->surface && point->surface == origin;
+ break;
+ }
+ }
+
+ if (!drag->is_pointer_grab && !is_touch_grab) {
+ free(drag);
+ return true;
+ }
+
+ if (icon_surface) {
+ int32_t touch_id = (point ? point->touch_id : 0);
+ struct wlr_drag_icon *icon =
+ drag_icon_create(icon_surface, client, drag->is_pointer_grab,
+ touch_id);
+ if (!icon) {
+ free(drag);
+ return false;
+ }
+
+ drag->icon = icon;
+ drag->icon_destroy.notify = drag_handle_icon_destroy;
+ wl_signal_add(&icon->events.destroy, &drag->icon_destroy);
+ }
+
+ drag->source = source;
+ if (source != NULL) {
+ drag->source_destroy.notify = drag_handle_drag_source_destroy;
+ wl_signal_add(&source->events.destroy, &drag->source_destroy);
+ }
+
+ drag->seat_client = client;
+ drag->pointer_grab.data = drag;
+ drag->pointer_grab.interface = &data_device_pointer_drag_interface;
+
+ drag->touch_grab.data = drag;
+ drag->touch_grab.interface = &data_device_touch_drag_interface;
+ drag->grab_touch_id = seat->touch_state.grab_id;
+
+ drag->keyboard_grab.data = drag;
+ drag->keyboard_grab.interface = &data_device_keyboard_drag_interface;
+
+ wlr_seat_keyboard_start_grab(seat, &drag->keyboard_grab);
+
+ if (drag->is_pointer_grab) {
+ wlr_seat_pointer_clear_focus(seat);
+ wlr_seat_pointer_start_grab(seat, &drag->pointer_grab);
+ } else {
+ assert(point);
+ wlr_seat_touch_start_grab(seat, &drag->touch_grab);
+ drag_set_focus(drag, point->surface, point->sx, point->sy);
+ }
+
+ seat->drag = drag; // TODO: unset this thing somewhere
+ seat->drag_serial = serial;
+
+ seat->drag_source = source;
+ if (source != NULL) {
+ seat->drag_source_destroy.notify = seat_handle_drag_source_destroy;
+ wl_signal_add(&source->events.destroy, &seat->drag_source_destroy);
+ }
+
+ wlr_signal_emit_safe(&seat->events.start_drag, drag);
+
+ return true;
+}
diff --git a/types/meson.build b/types/meson.build
index 7e089d03..36db897e 100644
--- a/types/meson.build
+++ b/types/meson.build
@@ -1,14 +1,20 @@
lib_wlr_types = static_library(
'wlr_types',
files(
+ 'data_device/wlr_data_device.c',
+ 'data_device/wlr_data_offer.c',
+ 'data_device/wlr_data_source.c',
+ 'data_device/wlr_drag.c',
+ 'seat/wlr_seat_keyboard.c',
+ 'seat/wlr_seat_pointer.c',
+ 'seat/wlr_seat_touch.c',
+ 'seat/wlr_seat.c',
'wlr_box.c',
'wlr_compositor.c',
'wlr_cursor.c',
- 'wlr_data_device.c',
'wlr_gamma_control.c',
'wlr_idle_inhibit_v1.c',
'wlr_idle.c',
- 'wlr_idle_inhibit_v1.c',
'wlr_input_device.c',
'wlr_input_inhibitor.c',
'wlr_keyboard.c',
@@ -23,7 +29,6 @@ lib_wlr_types = static_library(
'wlr_primary_selection.c',
'wlr_region.c',
'wlr_screenshooter.c',
- 'wlr_seat.c',
'wlr_server_decoration.c',
'wlr_surface.c',
'wlr_tablet_pad.c',
@@ -31,9 +36,9 @@ lib_wlr_types = static_library(
'wlr_touch.c',
'wlr_wl_shell.c',
'wlr_xcursor_manager.c',
+ 'wlr_xdg_output.c',
'wlr_xdg_shell_v6.c',
'wlr_xdg_shell.c',
- 'wlr_xdg_output.c',
),
include_directories: wlr_inc,
dependencies: [pixman, xkbcommon, wayland_server, wlr_protos],
diff --git a/types/seat/wlr_seat.c b/types/seat/wlr_seat.c
new file mode 100644
index 00000000..dc876f04
--- /dev/null
+++ b/types/seat/wlr_seat.c
@@ -0,0 +1,305 @@
+#define _POSIX_C_SOURCE 200809L
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <wayland-server.h>
+#include <wlr/types/wlr_data_device.h>
+#include <wlr/types/wlr_input_device.h>
+#include <wlr/types/wlr_primary_selection.h>
+#include <wlr/types/wlr_seat.h>
+#include <wlr/util/log.h>
+#include "types/wlr_seat.h"
+#include "util/signal.h"
+
+static void seat_handle_get_pointer(struct wl_client *client,
+ struct wl_resource *seat_resource, uint32_t id) {
+ struct wlr_seat_client *seat_client =
+ wlr_seat_client_from_resource(seat_resource);
+ if (!(seat_client->seat->capabilities & WL_SEAT_CAPABILITY_POINTER)) {
+ return;
+ }
+
+ uint32_t version = wl_resource_get_version(seat_resource);
+ seat_client_create_pointer(seat_client, version, id);
+}
+
+static void seat_handle_get_keyboard(struct wl_client *client,
+ struct wl_resource *seat_resource, uint32_t id) {
+ struct wlr_seat_client *seat_client =
+ wlr_seat_client_from_resource(seat_resource);
+ if (!(seat_client->seat->capabilities & WL_SEAT_CAPABILITY_KEYBOARD)) {
+ return;
+ }
+
+ uint32_t version = wl_resource_get_version(seat_resource);
+ seat_client_create_keyboard(seat_client, version, id);
+}
+
+static void seat_handle_get_touch(struct wl_client *client,
+ struct wl_resource *seat_resource, uint32_t id) {
+ struct wlr_seat_client *seat_client =
+ wlr_seat_client_from_resource(seat_resource);
+ if (!(seat_client->seat->capabilities & WL_SEAT_CAPABILITY_TOUCH)) {
+ return;
+ }
+
+ uint32_t version = wl_resource_get_version(seat_resource);
+ seat_client_create_touch(seat_client, version, id);
+}
+
+static void seat_client_resource_destroy(struct wl_resource *seat_resource) {
+ struct wlr_seat_client *client =
+ wlr_seat_client_from_resource(seat_resource);
+ wlr_signal_emit_safe(&client->events.destroy, client);
+
+ if (client == client->seat->pointer_state.focused_client) {
+ client->seat->pointer_state.focused_client = NULL;
+ }
+ if (client == client->seat->keyboard_state.focused_client) {
+ client->seat->keyboard_state.focused_client = NULL;
+ }
+
+ struct wl_resource *resource, *tmp;
+ wl_resource_for_each_safe(resource, tmp, &client->pointers) {
+ wl_resource_destroy(resource);
+ }
+ wl_resource_for_each_safe(resource, tmp, &client->keyboards) {
+ wl_resource_destroy(resource);
+ }
+ wl_resource_for_each_safe(resource, tmp, &client->touches) {
+ wl_resource_destroy(resource);
+ }
+ wl_resource_for_each_safe(resource, tmp, &client->data_devices) {
+ wl_resource_destroy(resource);
+ }
+ wl_resource_for_each_safe(resource, tmp,
+ &client->primary_selection_devices) {
+ wl_resource_destroy(resource);
+ }
+
+ wl_list_remove(&client->link);
+ free(client);
+}
+
+static void seat_handle_release(struct wl_client *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_handle_bind(struct wl_client *client, void *_wlr_seat,
+ uint32_t version, uint32_t id) {
+ struct wlr_seat *wlr_seat = _wlr_seat;
+ assert(client && wlr_seat);
+
+ struct wlr_seat_client *seat_client =
+ calloc(1, sizeof(struct wlr_seat_client));
+ if (seat_client == NULL) {
+ wl_client_post_no_memory(client);
+ return;
+ }
+ seat_client->wl_resource =
+ wl_resource_create(client, &wl_seat_interface, version, id);
+ if (seat_client->wl_resource == NULL) {
+ free(seat_client);
+ wl_client_post_no_memory(client);
+ return;
+ }
+ seat_client->client = client;
+ seat_client->seat = wlr_seat;
+ wl_list_init(&seat_client->pointers);
+ wl_list_init(&seat_client->keyboards);
+ wl_list_init(&seat_client->touches);
+ wl_list_init(&seat_client->data_devices);
+ wl_list_init(&seat_client->primary_selection_devices);
+ wl_resource_set_implementation(seat_client->wl_resource, &seat_impl,
+ seat_client, seat_client_resource_destroy);
+ wl_list_insert(&wlr_seat->clients, &seat_client->link);
+ if (version >= WL_SEAT_NAME_SINCE_VERSION) {
+ wl_seat_send_name(seat_client->wl_resource, wlr_seat->name);
+ }
+ wl_seat_send_capabilities(seat_client->wl_resource, wlr_seat->capabilities);
+ wl_signal_init(&seat_client->events.destroy);
+}
+
+void wlr_seat_destroy(struct wlr_seat *seat) {
+ if (!seat) {
+ return;
+ }
+
+ wlr_signal_emit_safe(&seat->events.destroy, seat);
+
+ wl_list_remove(&seat->display_destroy.link);
+
+ if (seat->selection_source) {
+ wl_list_remove(&seat->selection_source_destroy.link);
+ wlr_data_source_cancel(seat->selection_source);
+ seat->selection_source = NULL;
+ }
+ if (seat->primary_selection_source) {
+ seat->primary_selection_source->cancel(seat->primary_selection_source);
+ seat->primary_selection_source = NULL;
+ wl_list_remove(&seat->primary_selection_source_destroy.link);
+ }
+
+ struct wlr_seat_client *client, *tmp;
+ wl_list_for_each_safe(client, tmp, &seat->clients, link) {
+ // will destroy other resources as well
+ wl_resource_destroy(client->wl_resource);
+ }
+
+ wl_global_destroy(seat->wl_global);
+ free(seat->pointer_state.default_grab);
+ free(seat->keyboard_state.default_grab);
+ free(seat->touch_state.default_grab);
+ free(seat->name);
+ free(seat);
+}
+
+static void handle_display_destroy(struct wl_listener *listener, void *data) {
+ struct wlr_seat *seat =
+ wl_container_of(listener, seat, display_destroy);
+ wlr_seat_destroy(seat);
+}
+
+struct wlr_seat *wlr_seat_create(struct wl_display *display, const char *name) {
+ struct wlr_seat *wlr_seat = calloc(1, sizeof(struct wlr_seat));
+ if (!wlr_seat) {
+ return NULL;
+ }
+
+ // pointer state
+ wlr_seat->pointer_state.seat = wlr_seat;
+ wl_list_init(&wlr_seat->pointer_state.surface_destroy.link);
+
+ struct wlr_seat_pointer_grab *pointer_grab =
+ calloc(1, sizeof(struct wlr_seat_pointer_grab));
+ if (!pointer_grab) {
+ free(wlr_seat);
+ return NULL;
+ }
+ pointer_grab->interface = &default_pointer_grab_impl;
+ pointer_grab->seat = wlr_seat;
+ wlr_seat->pointer_state.default_grab = pointer_grab;
+ wlr_seat->pointer_state.grab = pointer_grab;
+
+ // keyboard state
+ struct wlr_seat_keyboard_grab *keyboard_grab =
+ calloc(1, sizeof(struct wlr_seat_keyboard_grab));
+ if (!keyboard_grab) {
+ free(pointer_grab);
+ free(wlr_seat);
+ return NULL;
+ }
+ keyboard_grab->interface = &default_keyboard_grab_impl;
+ keyboard_grab->seat = wlr_seat;
+ wlr_seat->keyboard_state.default_grab = keyboard_grab;
+ wlr_seat->keyboard_state.grab = keyboard_grab;
+
+ wlr_seat->keyboard_state.seat = wlr_seat;
+ wl_list_init(&wlr_seat->keyboard_state.surface_destroy.link);
+
+ // touch state
+ struct wlr_seat_touch_grab *touch_grab =
+ calloc(1, sizeof(struct wlr_seat_touch_grab));
+ if (!touch_grab) {
+ free(pointer_grab);
+ free(keyboard_grab);
+ free(wlr_seat);
+ return NULL;
+ }
+ touch_grab->interface = &default_touch_grab_impl;
+ touch_grab->seat = wlr_seat;
+ wlr_seat->touch_state.default_grab = touch_grab;
+ wlr_seat->touch_state.grab = touch_grab;
+
+ wlr_seat->touch_state.seat = wlr_seat;
+ wl_list_init(&wlr_seat->touch_state.touch_points);
+
+ struct wl_global *wl_global = wl_global_create(display,
+ &wl_seat_interface, 6, wlr_seat, seat_handle_bind);
+ if (!wl_global) {
+ free(wlr_seat);
+ return NULL;
+ }
+ wlr_seat->wl_global = wl_global;
+ wlr_seat->display = display;
+ wlr_seat->name = strdup(name);
+ wl_list_init(&wlr_seat->clients);
+ wl_list_init(&wlr_seat->drag_icons);
+
+ wl_signal_init(&wlr_seat->events.start_drag);
+ wl_signal_init(&wlr_seat->events.new_drag_icon);
+
+ wl_signal_init(&wlr_seat->events.request_set_cursor);
+
+ wl_signal_init(&wlr_seat->events.selection);
+ wl_signal_init(&wlr_seat->events.primary_selection);
+
+ wl_signal_init(&wlr_seat->events.pointer_grab_begin);
+ wl_signal_init(&wlr_seat->events.pointer_grab_end);
+
+ wl_signal_init(&wlr_seat->events.keyboard_grab_begin);
+ wl_signal_init(&wlr_seat->events.keyboard_grab_end);
+
+ wl_signal_init(&wlr_seat->events.touch_grab_begin);
+ wl_signal_init(&wlr_seat->events.touch_grab_end);
+
+ wl_signal_init(&wlr_seat->events.destroy);
+
+ wlr_seat->display_destroy.notify = handle_display_destroy;
+ wl_display_add_destroy_listener(display, &wlr_seat->display_destroy);
+
+ return wlr_seat;
+}
+
+struct wlr_seat_client *wlr_seat_client_for_wl_client(struct wlr_seat *wlr_seat,
+ struct wl_client *wl_client) {
+ assert(wlr_seat);
+ struct wlr_seat_client *seat_client;
+ wl_list_for_each(seat_client, &wlr_seat->clients, link) {
+ if (seat_client->client == wl_client) {
+ return seat_client;
+ }
+ }
+ return NULL;
+}
+
+void wlr_seat_set_capabilities(struct wlr_seat *wlr_seat,
+ uint32_t capabilities) {
+ wlr_seat->capabilities = capabilities;
+ struct wlr_seat_client *client;
+ wl_list_for_each(client, &wlr_seat->clients, link) {
+ wl_seat_send_capabilities(client->wl_resource, capabilities);
+ }
+}
+
+void wlr_seat_set_name(struct wlr_seat *wlr_seat, const char *name) {
+ free(wlr_seat->name);
+ wlr_seat->name = strdup(name);
+ struct wlr_seat_client *client;
+ wl_list_for_each(client, &wlr_seat->clients, link) {
+ wl_seat_send_name(client->wl_resource, name);
+ }
+}
+
+struct wlr_seat_client *wlr_seat_client_from_resource(
+ struct wl_resource *resource) {
+ assert(wl_resource_instance_of(resource, &wl_seat_interface,
+ &seat_impl));
+ return wl_resource_get_user_data(resource);
+}
+
+bool wlr_seat_validate_grab_serial(struct wlr_seat *seat, uint32_t serial) {
+ // TODO
+ //return serial == seat->pointer_state.grab_serial ||
+ // serial == seat->touch_state.grab_serial;
+ return true;
+}
diff --git a/types/seat/wlr_seat_keyboard.c b/types/seat/wlr_seat_keyboard.c
new file mode 100644
index 00000000..975b195c
--- /dev/null
+++ b/types/seat/wlr_seat_keyboard.c
@@ -0,0 +1,355 @@
+#define _POSIX_C_SOURCE 200809L
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <wayland-server.h>
+#include <wlr/types/wlr_data_device.h>
+#include <wlr/types/wlr_input_device.h>
+#include <wlr/types/wlr_primary_selection.h>
+#include <wlr/util/log.h>
+#include "types/wlr_seat.h"
+#include "util/signal.h"
+
+static void default_keyboard_enter(struct wlr_seat_keyboard_grab *grab,
+ struct wlr_surface *surface, uint32_t keycodes[], size_t num_keycodes,
+ struct wlr_keyboard_modifiers *modifiers) {
+ wlr_seat_keyboard_enter(grab->seat, surface, keycodes, num_keycodes, modifiers);
+}
+
+static void default_keyboard_key(struct wlr_seat_keyboard_grab *grab,
+ uint32_t time, uint32_t key, uint32_t state) {
+ wlr_seat_keyboard_send_key(grab->seat, time, key, state);
+}
+
+static void default_keyboard_modifiers(struct wlr_seat_keyboard_grab *grab,
+ struct wlr_keyboard_modifiers *modifiers) {
+ wlr_seat_keyboard_send_modifiers(grab->seat, modifiers);
+}
+
+static void default_keyboard_cancel(struct wlr_seat_keyboard_grab *grab) {
+ // cannot be cancelled
+}
+
+const struct wlr_keyboard_grab_interface default_keyboard_grab_impl = {
+ .enter = default_keyboard_enter,
+ .key = default_keyboard_key,
+ .modifiers = default_keyboard_modifiers,
+ .cancel = default_keyboard_cancel,
+};
+
+
+static void keyboard_release(struct wl_client *client,
+ struct wl_resource *resource) {
+ wl_resource_destroy(resource);
+}
+
+static const struct wl_keyboard_interface keyboard_impl = {
+ .release = keyboard_release,
+};
+
+static void keyboard_handle_resource_destroy(struct wl_resource *resource) {
+ wl_list_remove(wl_resource_get_link(resource));
+}
+
+
+void wlr_seat_keyboard_send_key(struct wlr_seat *wlr_seat, uint32_t time,
+ uint32_t key, uint32_t state) {
+ struct wlr_seat_client *client = wlr_seat->keyboard_state.focused_client;
+ if (!client) {
+ return;
+ }
+
+ uint32_t serial = wl_display_next_serial(wlr_seat->display);
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &client->keyboards) {
+ wl_keyboard_send_key(resource, serial, time, key, state);
+ }
+}
+
+static void seat_client_send_keymap(struct wlr_seat_client *client,
+ struct wlr_keyboard *keyboard);
+
+static void handle_keyboard_keymap(struct wl_listener *listener, void *data) {
+ struct wlr_seat_keyboard_state *state =
+ wl_container_of(listener, state, keyboard_keymap);
+ struct wlr_seat_client *client;
+ struct wlr_keyboard *keyboard = data;
+ if (keyboard == state->keyboard) {
+ wl_list_for_each(client, &state->seat->clients, link) {
+ seat_client_send_keymap(client, state->keyboard);
+ }
+ }
+}
+
+static void seat_client_send_repeat_info(struct wlr_seat_client *client,
+ struct wlr_keyboard *keyboard);
+
+static void handle_keyboard_repeat_info(struct wl_listener *listener,
+ void *data) {
+ struct wlr_seat_keyboard_state *state =
+ wl_container_of(listener, state, keyboard_repeat_info);
+ struct wlr_seat_client *client;
+ wl_list_for_each(client, &state->seat->clients, link) {
+ seat_client_send_repeat_info(client, state->keyboard);
+ }
+}
+
+static void handle_keyboard_destroy(struct wl_listener *listener, void *data) {
+ struct wlr_seat_keyboard_state *state =
+ wl_container_of(listener, state, keyboard_destroy);
+ state->keyboard = NULL;
+}
+
+void wlr_seat_set_keyboard(struct wlr_seat *seat,
+ struct wlr_input_device *device) {
+ // TODO call this on device key event before the event reaches the
+ // compositor and set a pending keyboard and then send the new keyboard
+ // state on the next keyboard notify event.
+ struct wlr_keyboard *keyboard = (device ? device->keyboard : NULL);
+ if (seat->keyboard_state.keyboard == keyboard) {
+ return;
+ }
+
+ if (seat->keyboard_state.keyboard) {
+ wl_list_remove(&seat->keyboard_state.keyboard_destroy.link);
+ wl_list_remove(&seat->keyboard_state.keyboard_keymap.link);
+ wl_list_remove(&seat->keyboard_state.keyboard_repeat_info.link);
+ seat->keyboard_state.keyboard = NULL;
+ }
+
+ if (keyboard) {
+ assert(device->type == WLR_INPUT_DEVICE_KEYBOARD);
+ seat->keyboard_state.keyboard = keyboard;
+
+ wl_signal_add(&device->events.destroy,
+ &seat->keyboard_state.keyboard_destroy);
+ seat->keyboard_state.keyboard_destroy.notify = handle_keyboard_destroy;
+ wl_signal_add(&device->keyboard->events.keymap,
+ &seat->keyboard_state.keyboard_keymap);
+ seat->keyboard_state.keyboard_keymap.notify = handle_keyboard_keymap;
+ wl_signal_add(&device->keyboard->events.repeat_info,
+ &seat->keyboard_state.keyboard_repeat_info);
+ seat->keyboard_state.keyboard_repeat_info.notify =
+ handle_keyboard_repeat_info;
+
+ struct wlr_seat_client *client;
+ wl_list_for_each(client, &seat->clients, link) {
+ seat_client_send_keymap(client, keyboard);
+ seat_client_send_repeat_info(client, keyboard);
+ }
+
+ wlr_seat_keyboard_send_modifiers(seat, &keyboard->modifiers);
+ } else {
+ seat->keyboard_state.keyboard = NULL;
+ }
+}
+
+struct wlr_keyboard *wlr_seat_get_keyboard(struct wlr_seat *seat) {
+ return seat->keyboard_state.keyboard;
+}
+
+void wlr_seat_keyboard_start_grab(struct wlr_seat *wlr_seat,
+ struct wlr_seat_keyboard_grab *grab) {
+ grab->seat = wlr_seat;
+ wlr_seat->keyboard_state.grab = grab;
+
+ wlr_signal_emit_safe(&wlr_seat->events.keyboard_grab_begin, grab);
+}
+
+void wlr_seat_keyboard_end_grab(struct wlr_seat *wlr_seat) {
+ struct wlr_seat_keyboard_grab *grab = wlr_seat->keyboard_state.grab;
+
+ if (grab != wlr_seat->keyboard_state.default_grab) {
+ wlr_seat->keyboard_state.grab = wlr_seat->keyboard_state.default_grab;
+ wlr_signal_emit_safe(&wlr_seat->events.keyboard_grab_end, grab);
+ if (grab->interface->cancel) {
+ grab->interface->cancel(grab);
+ }
+ }
+}
+
+static void seat_keyboard_handle_surface_destroy(struct wl_listener *listener,
+ void *data) {
+ struct wlr_seat_keyboard_state *state = wl_container_of(
+ listener, state, surface_destroy);
+ wl_list_remove(&state->surface_destroy.link);
+ wl_list_init(&state->surface_destroy.link);
+ wlr_seat_keyboard_clear_focus(state->seat);
+}
+
+void wlr_seat_keyboard_send_modifiers(struct wlr_seat *seat,
+ struct wlr_keyboard_modifiers *modifiers) {
+ struct wlr_seat_client *client = seat->keyboard_state.focused_client;
+ if (client == NULL) {
+ return;
+ }
+
+ uint32_t serial = wl_display_next_serial(seat->display);
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &client->keyboards) {
+ if (modifiers == NULL) {
+ 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);
+ }
+ }
+}
+
+void wlr_seat_keyboard_enter(struct wlr_seat *seat,
+ struct wlr_surface *surface, uint32_t keycodes[], size_t num_keycodes,
+ struct wlr_keyboard_modifiers *modifiers) {
+ if (seat->keyboard_state.focused_surface == surface) {
+ // this surface already got an enter notify
+ return;
+ }
+
+ struct wlr_seat_client *client = NULL;
+
+ if (surface) {
+ struct wl_client *wl_client = wl_resource_get_client(surface->resource);
+ client = wlr_seat_client_for_wl_client(seat, wl_client);
+ }
+
+ struct wlr_seat_client *focused_client =
+ seat->keyboard_state.focused_client;
+ struct wlr_surface *focused_surface =
+ seat->keyboard_state.focused_surface;
+
+ // leave the previously entered surface
+ if (focused_client != NULL && focused_surface != NULL) {
+ uint32_t serial = wl_display_next_serial(seat->display);
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &focused_client->keyboards) {
+ wl_keyboard_send_leave(resource, serial, focused_surface->resource);
+ }
+ }
+
+ // enter the current surface
+ if (client != NULL) {
+ struct wl_array keys;
+ wl_array_init(&keys);
+ for (size_t i = 0; i < num_keycodes; ++i) {
+ uint32_t *p = wl_array_add(&keys, sizeof(uint32_t));
+ if (!p) {
+ wlr_log(L_ERROR, "Cannot allocate memory, skipping keycode: %d\n",
+ keycodes[i]);
+ continue;
+ }
+ *p = keycodes[i];
+ }
+ uint32_t serial = wl_display_next_serial(seat->display);
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &client->keyboards) {
+ wl_keyboard_send_enter(resource, serial, surface->resource, &keys);
+ }
+ wl_array_release(&keys);
+
+ wlr_seat_client_send_selection(client);
+ wlr_seat_client_send_primary_selection(client);
+ }
+
+ // reinitialize the focus destroy events
+ wl_list_remove(&seat->keyboard_state.surface_destroy.link);
+ wl_list_init(&seat->keyboard_state.surface_destroy.link);
+ if (surface) {
+ wl_signal_add(&surface->events.destroy,
+ &seat->keyboard_state.surface_destroy);
+ seat->keyboard_state.surface_destroy.notify =
+ seat_keyboard_handle_surface_destroy;
+ }
+
+ seat->keyboard_state.focused_client = client;
+ seat->keyboard_state.focused_surface = surface;
+
+ if (client != NULL) {
+ // tell new client about any modifier change last,
+ // as it targets seat->keyboard_state.focused_client
+ wlr_seat_keyboard_send_modifiers(seat, modifiers);
+ }
+}
+
+void wlr_seat_keyboard_notify_enter(struct wlr_seat *seat,
+ struct wlr_surface *surface, uint32_t keycodes[], size_t num_keycodes,
+ struct wlr_keyboard_modifiers *modifiers) {
+ struct wlr_seat_keyboard_grab *grab = seat->keyboard_state.grab;
+ grab->interface->enter(grab, surface, keycodes, num_keycodes, modifiers);
+}
+
+void wlr_seat_keyboard_clear_focus(struct wlr_seat *seat) {
+ // TODO respect grabs here?
+ wlr_seat_keyboard_enter(seat, NULL, NULL, 0, NULL);
+}
+
+bool wlr_seat_keyboard_has_grab(struct wlr_seat *seat) {
+ return seat->keyboard_state.grab->interface != &default_keyboard_grab_impl;
+}
+
+void wlr_seat_keyboard_notify_modifiers(struct wlr_seat *seat,
+ struct wlr_keyboard_modifiers *modifiers) {
+ clock_gettime(CLOCK_MONOTONIC, &seat->last_event);
+ struct wlr_seat_keyboard_grab *grab = seat->keyboard_state.grab;
+ grab->interface->modifiers(grab, modifiers);
+}
+
+void wlr_seat_keyboard_notify_key(struct wlr_seat *seat, uint32_t time,
+ uint32_t key, uint32_t state) {
+ clock_gettime(CLOCK_MONOTONIC, &seat->last_event);
+ struct wlr_seat_keyboard_grab *grab = seat->keyboard_state.grab;
+ grab->interface->key(grab, time, key, state);
+}
+
+
+static void seat_client_send_keymap(struct wlr_seat_client *client,
+ struct wlr_keyboard *keyboard) {
+ if (!keyboard) {
+ return;
+ }
+
+ // TODO: We should probably lift all of the keys set by the other
+ // keyboard
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &client->keyboards) {
+ wl_keyboard_send_keymap(resource,
+ WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keyboard->keymap_fd,
+ keyboard->keymap_size);
+ }
+}
+
+static void seat_client_send_repeat_info(struct wlr_seat_client *client,
+ struct wlr_keyboard *keyboard) {
+ if (!keyboard) {
+ return;
+ }
+
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &client->keyboards) {
+ if (wl_resource_get_version(resource) >=
+ WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) {
+ wl_keyboard_send_repeat_info(resource,
+ keyboard->repeat_info.rate, keyboard->repeat_info.delay);
+ }
+ }
+}
+
+void seat_client_create_keyboard(struct wlr_seat_client *seat_client,
+ uint32_t version, uint32_t id) {
+ struct wl_resource *resource = wl_resource_create(seat_client->client,
+ &wl_keyboard_interface, version, id);
+ if (resource == NULL) {
+ wl_client_post_no_memory(seat_client->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));
+
+ struct wlr_keyboard *keyboard = seat_client->seat->keyboard_state.keyboard;
+ seat_client_send_keymap(seat_client, keyboard);
+ seat_client_send_repeat_info(seat_client, keyboard);
+
+ // TODO possibly handle the case where this keyboard needs an enter
+ // right away
+}
diff --git a/types/seat/wlr_seat_pointer.c b/types/seat/wlr_seat_pointer.c
new file mode 100644
index 00000000..344597b5
--- /dev/null
+++ b/types/seat/wlr_seat_pointer.c
@@ -0,0 +1,314 @@
+#define _POSIX_C_SOURCE 200809L
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <wayland-server.h>
+#include <wlr/types/wlr_input_device.h>
+#include <wlr/util/log.h>
+#include "types/wlr_seat.h"
+#include "util/signal.h"
+
+static void default_pointer_enter(struct wlr_seat_pointer_grab *grab,
+ struct wlr_surface *surface, double sx, double sy) {
+ wlr_seat_pointer_enter(grab->seat, surface, sx, sy);
+}
+
+static void default_pointer_motion(struct wlr_seat_pointer_grab *grab,
+ uint32_t time, double sx, double sy) {
+ wlr_seat_pointer_send_motion(grab->seat, time, sx, sy);
+}
+
+static uint32_t default_pointer_button(struct wlr_seat_pointer_grab *grab,
+ uint32_t time, uint32_t button, uint32_t state) {
+ return wlr_seat_pointer_send_button(grab->seat, time, button, state);
+}
+
+static void default_pointer_axis(struct wlr_seat_pointer_grab *grab,
+ uint32_t time, enum wlr_axis_orientation orientation, double value) {
+ wlr_seat_pointer_send_axis(grab->seat, time, orientation, value);
+}
+
+static void default_pointer_cancel(struct wlr_seat_pointer_grab *grab) {
+ // cannot be cancelled
+}
+
+const struct wlr_pointer_grab_interface default_pointer_grab_impl = {
+ .enter = default_pointer_enter,
+ .motion = default_pointer_motion,
+ .button = default_pointer_button,
+ .axis = default_pointer_axis,
+ .cancel = default_pointer_cancel,
+};
+
+
+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);
+ }
+}
+
+static const struct wl_pointer_interface pointer_impl;
+
+static struct wlr_seat_client *seat_client_from_pointer_resource(
+ struct wl_resource *resource) {
+ assert(wl_resource_instance_of(resource, &wl_pointer_interface,
+ &pointer_impl));
+ return wl_resource_get_user_data(resource);
+}
+
+static void pointer_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 wlr_seat_client *seat_client =
+ seat_client_from_pointer_resource(pointer_resource);
+ struct wlr_surface *surface = NULL;
+ if (surface_resource != NULL) {
+ surface = wlr_surface_from_resource(surface_resource);
+
+ if (wlr_surface_set_role(surface, "wl_pointer-cursor", surface_resource,
+ WL_POINTER_ERROR_ROLE) < 0) {
+ return;
+ }
+ }
+
+ struct wlr_seat_pointer_request_set_cursor_event *event =
+ calloc(1, sizeof(struct wlr_seat_pointer_request_set_cursor_event));
+ if (event == NULL) {
+ return;
+ }
+ event->seat_client = seat_client;
+ event->surface = surface;
+ event->serial = serial;
+ event->hotspot_x = hotspot_x;
+ event->hotspot_y = hotspot_y;
+
+ wlr_signal_emit_safe(&seat_client->seat->events.request_set_cursor, event);
+
+ free(event);
+}
+
+static void pointer_release(struct wl_client *client,
+ struct wl_resource *resource) {
+ wl_resource_destroy(resource);
+}
+
+static const struct wl_pointer_interface pointer_impl = {
+ .set_cursor = pointer_set_cursor,
+ .release = pointer_release,
+};
+
+static void pointer_handle_resource_destroy(struct wl_resource *resource) {
+ wl_list_remove(wl_resource_get_link(resource));
+}
+
+
+bool wlr_seat_pointer_surface_has_focus(struct wlr_seat *wlr_seat,
+ struct wlr_surface *surface) {
+ return surface == wlr_seat->pointer_state.focused_surface;
+}
+
+static void seat_pointer_handle_surface_destroy(struct wl_listener *listener,
+ void *data) {
+ struct wlr_seat_pointer_state *state = wl_container_of(
+ listener, state, surface_destroy);
+ wl_list_remove(&state->surface_destroy.link);
+ wl_list_init(&state->surface_destroy.link);
+ wlr_seat_pointer_clear_focus(state->seat);
+}
+
+void wlr_seat_pointer_enter(struct wlr_seat *wlr_seat,
+ struct wlr_surface *surface, double sx, double sy) {
+ assert(wlr_seat);
+
+ if (wlr_seat->pointer_state.focused_surface == surface) {
+ // this surface already got an enter notify
+ return;
+ }
+
+ struct wlr_seat_client *client = NULL;
+ if (surface) {
+ struct wl_client *wl_client = wl_resource_get_client(surface->resource);
+ client = wlr_seat_client_for_wl_client(wlr_seat, wl_client);
+ }
+
+ struct wlr_seat_client *focused_client =
+ wlr_seat->pointer_state.focused_client;
+ struct wlr_surface *focused_surface =
+ wlr_seat->pointer_state.focused_surface;
+
+ // leave the previously entered surface
+ if (focused_client != NULL && focused_surface != NULL) {
+ uint32_t serial = wl_display_next_serial(wlr_seat->display);
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &focused_client->pointers) {
+ wl_pointer_send_leave(resource, serial, focused_surface->resource);
+ pointer_send_frame(resource);
+ }
+ }
+
+ // enter the current surface
+ if (client != NULL && surface != NULL) {
+ uint32_t serial = wl_display_next_serial(wlr_seat->display);
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &client->pointers) {
+ wl_pointer_send_enter(resource, serial, surface->resource,
+ wl_fixed_from_double(sx), wl_fixed_from_double(sy));
+ pointer_send_frame(resource);
+ }
+ }
+
+ // reinitialize the focus destroy events
+ wl_list_remove(&wlr_seat->pointer_state.surface_destroy.link);
+ wl_list_init(&wlr_seat->pointer_state.surface_destroy.link);
+ if (surface != NULL) {
+ wl_signal_add(&surface->events.destroy,
+ &wlr_seat->pointer_state.surface_destroy);
+ wlr_seat->pointer_state.surface_destroy.notify =
+ seat_pointer_handle_surface_destroy;
+ }
+
+ wlr_seat->pointer_state.focused_client = client;
+ wlr_seat->pointer_state.focused_surface = surface;
+
+ // TODO: send focus change event
+}
+
+void wlr_seat_pointer_clear_focus(struct wlr_seat *wlr_seat) {
+ wlr_seat_pointer_enter(wlr_seat, NULL, 0, 0);
+}
+
+void wlr_seat_pointer_send_motion(struct wlr_seat *wlr_seat, uint32_t time,
+ double sx, double sy) {
+ struct wlr_seat_client *client = wlr_seat->pointer_state.focused_client;
+ if (client == NULL) {
+ return;
+ }
+
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &client->pointers) {
+ wl_pointer_send_motion(resource, time, wl_fixed_from_double(sx),
+ wl_fixed_from_double(sy));
+ pointer_send_frame(resource);
+ }
+}
+
+uint32_t wlr_seat_pointer_send_button(struct wlr_seat *wlr_seat, uint32_t time,
+ uint32_t button, uint32_t state) {
+ struct wlr_seat_client *client = wlr_seat->pointer_state.focused_client;
+ if (client == NULL) {
+ return 0;
+ }
+
+ uint32_t serial = wl_display_next_serial(wlr_seat->display);
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &client->pointers) {
+ wl_pointer_send_button(resource, serial, time, button, state);
+ pointer_send_frame(resource);
+ }
+ return serial;
+}
+
+void wlr_seat_pointer_send_axis(struct wlr_seat *wlr_seat, uint32_t time,
+ enum wlr_axis_orientation orientation, double value) {
+ struct wlr_seat_client *client = wlr_seat->pointer_state.focused_client;
+ if (client == NULL) {
+ return;
+ }
+
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &client->pointers) {
+ if (value) {
+ wl_pointer_send_axis(resource, time, orientation,
+ wl_fixed_from_double(value));
+ } else if (wl_resource_get_version(resource) >=
+ WL_POINTER_AXIS_STOP_SINCE_VERSION) {
+ wl_pointer_send_axis_stop(resource, time, orientation);
+ }
+ pointer_send_frame(resource);
+ }
+}
+
+void wlr_seat_pointer_start_grab(struct wlr_seat *wlr_seat,
+ struct wlr_seat_pointer_grab *grab) {
+ assert(wlr_seat);
+ grab->seat = wlr_seat;
+ assert(grab->seat);
+ wlr_seat->pointer_state.grab = grab;
+
+ wlr_signal_emit_safe(&wlr_seat->events.pointer_grab_begin, grab);
+}
+
+void wlr_seat_pointer_end_grab(struct wlr_seat *wlr_seat) {
+ struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab;
+ if (grab != wlr_seat->pointer_state.default_grab) {
+ wlr_seat->pointer_state.grab = wlr_seat->pointer_state.default_grab;
+ wlr_signal_emit_safe(&wlr_seat->events.pointer_grab_end, grab);
+ if (grab->interface->cancel) {
+ grab->interface->cancel(grab);
+ }
+ }
+}
+
+void wlr_seat_pointer_notify_enter(struct wlr_seat *wlr_seat,
+ struct wlr_surface *surface, double sx, double sy) {
+ struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab;
+ grab->interface->enter(grab, surface, sx, sy);
+}
+
+void wlr_seat_pointer_notify_motion(struct wlr_seat *wlr_seat, uint32_t time,
+ double sx, double sy) {
+ clock_gettime(CLOCK_MONOTONIC, &wlr_seat->last_event);
+ struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab;
+ grab->interface->motion(grab, time, sx, sy);
+}
+
+uint32_t wlr_seat_pointer_notify_button(struct wlr_seat *wlr_seat,
+ uint32_t time, uint32_t button, uint32_t state) {
+ clock_gettime(CLOCK_MONOTONIC, &wlr_seat->last_event);
+ if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
+ if (wlr_seat->pointer_state.button_count == 0) {
+ wlr_seat->pointer_state.grab_button = button;
+ wlr_seat->pointer_state.grab_time = time;
+ }
+ wlr_seat->pointer_state.button_count++;
+ } else {
+ wlr_seat->pointer_state.button_count--;
+ }
+
+ struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab;
+ uint32_t serial = grab->interface->button(grab, time, button, state);
+
+ if (serial && wlr_seat->pointer_state.button_count == 1) {
+ wlr_seat->pointer_state.grab_serial = serial;
+ }
+
+ return serial;
+}
+
+void wlr_seat_pointer_notify_axis(struct wlr_seat *wlr_seat, uint32_t time,
+ enum wlr_axis_orientation orientation, double value) {
+ clock_gettime(CLOCK_MONOTONIC, &wlr_seat->last_event);
+ struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab;
+ grab->interface->axis(grab, time, orientation, value);
+}
+
+bool wlr_seat_pointer_has_grab(struct wlr_seat *seat) {
+ return seat->pointer_state.grab->interface != &default_pointer_grab_impl;
+}
+
+
+void seat_client_create_pointer(struct wlr_seat_client *seat_client,
+ uint32_t version, uint32_t id) {
+ struct wl_resource *resource = wl_resource_create(seat_client->client,
+ &wl_pointer_interface, version, id);
+ if (resource == NULL) {
+ wl_client_post_no_memory(seat_client->client);
+ return;
+ }
+ wl_resource_set_implementation(resource, &pointer_impl, seat_client,
+ &pointer_handle_resource_destroy);
+ wl_list_insert(&seat_client->pointers, wl_resource_get_link(resource));
+}
diff --git a/types/seat/wlr_seat_touch.c b/types/seat/wlr_seat_touch.c
new file mode 100644
index 00000000..a81369df
--- /dev/null
+++ b/types/seat/wlr_seat_touch.c
@@ -0,0 +1,335 @@
+#define _POSIX_C_SOURCE 200809L
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <wayland-server.h>
+#include <wlr/types/wlr_input_device.h>
+#include <wlr/util/log.h>
+#include "types/wlr_seat.h"
+#include "util/signal.h"
+
+static uint32_t default_touch_down(struct wlr_seat_touch_grab *grab, uint32_t time,
+ struct wlr_touch_point *point) {
+ return wlr_seat_touch_send_down(grab->seat, point->surface, time,
+ point->touch_id, point->sx, point->sy);
+}
+
+static void default_touch_up(struct wlr_seat_touch_grab *grab, uint32_t time,
+ struct wlr_touch_point *point) {
+ wlr_seat_touch_send_up(grab->seat, time, point->touch_id);
+}
+
+static void default_touch_motion(struct wlr_seat_touch_grab *grab,
+ uint32_t time, struct wlr_touch_point *point) {
+ if (!point->focus_surface || point->focus_surface == point->surface) {
+ wlr_seat_touch_send_motion(grab->seat, time, point->touch_id, point->sx,
+ point->sy);
+ }
+}
+
+static void default_touch_enter(struct wlr_seat_touch_grab *grab,
+ uint32_t time, struct wlr_touch_point *point) {
+ // not handled by default
+}
+
+static void default_touch_cancel(struct wlr_seat_touch_grab *grab) {
+ // cannot be cancelled
+}
+
+const struct wlr_touch_grab_interface default_touch_grab_impl = {
+ .down = default_touch_down,
+ .up = default_touch_up,
+ .motion = default_touch_motion,
+ .enter = default_touch_enter,
+ .cancel = default_touch_cancel,
+};
+
+
+static void touch_release(struct wl_client *client,
+ struct wl_resource *resource) {
+ wl_resource_destroy(resource);
+}
+
+static const struct wl_touch_interface touch_impl = {
+ .release = touch_release,
+};
+
+static void touch_handle_resource_destroy(struct wl_resource *resource) {
+ wl_list_remove(wl_resource_get_link(resource));
+}
+
+
+void wlr_seat_touch_start_grab(struct wlr_seat *wlr_seat,
+ struct wlr_seat_touch_grab *grab) {
+ grab->seat = wlr_seat;
+ wlr_seat->touch_state.grab = grab;
+
+ wlr_signal_emit_safe(&wlr_seat->events.touch_grab_begin, grab);
+}
+
+void wlr_seat_touch_end_grab(struct wlr_seat *wlr_seat) {
+ struct wlr_seat_touch_grab *grab = wlr_seat->touch_state.grab;
+
+ if (grab != wlr_seat->touch_state.default_grab) {
+ wlr_seat->touch_state.grab = wlr_seat->touch_state.default_grab;
+ wlr_signal_emit_safe(&wlr_seat->events.touch_grab_end, grab);
+ if (grab->interface->cancel) {
+ grab->interface->cancel(grab);
+ }
+ }
+}
+
+static void touch_point_clear_focus(struct wlr_touch_point *point) {
+ if (point->focus_surface) {
+ wl_list_remove(&point->focus_surface_destroy.link);
+ point->focus_client = NULL;
+ point->focus_surface = NULL;
+ }
+}
+
+static void touch_point_destroy(struct wlr_touch_point *point) {
+ wlr_signal_emit_safe(&point->events.destroy, point);
+
+ touch_point_clear_focus(point);
+ wl_list_remove(&point->surface_destroy.link);
+ wl_list_remove(&point->link);
+ free(point);
+}
+
+static void touch_point_handle_surface_destroy(struct wl_listener *listener,
+ void *data) {
+ struct wlr_touch_point *point =
+ wl_container_of(listener, point, surface_destroy);
+ touch_point_destroy(point);
+}
+
+static struct wlr_touch_point *touch_point_create(
+ struct wlr_seat *seat, int32_t touch_id,
+ struct wlr_surface *surface, double sx, double sy) {
+ struct wl_client *wl_client = wl_resource_get_client(surface->resource);
+ struct wlr_seat_client *client =
+ wlr_seat_client_for_wl_client(seat, wl_client);
+
+ if (client == NULL || wl_list_empty(&client->touches)) {
+ // touch points are not valid without a connected client with touch
+ return NULL;
+ }
+
+ struct wlr_touch_point *point = calloc(1, sizeof(struct wlr_touch_point));
+ if (!point) {
+ return NULL;
+ }
+
+ point->touch_id = touch_id;
+ point->surface = surface;
+ point->client = client;
+
+ point->sx = sx;
+ point->sy = sy;
+
+ wl_signal_init(&point->events.destroy);
+
+ wl_signal_add(&surface->events.destroy, &point->surface_destroy);
+ point->surface_destroy.notify = touch_point_handle_surface_destroy;
+
+ wl_list_insert(&seat->touch_state.touch_points, &point->link);
+
+ return point;
+}
+
+struct wlr_touch_point *wlr_seat_touch_get_point(
+ struct wlr_seat *seat, int32_t touch_id) {
+ struct wlr_touch_point *point = NULL;
+ wl_list_for_each(point, &seat->touch_state.touch_points, link) {
+ if (point->touch_id == touch_id) {
+ return point;
+ }
+ }
+
+ return NULL;
+}
+
+uint32_t wlr_seat_touch_notify_down(struct wlr_seat *seat,
+ struct wlr_surface *surface, uint32_t time, int32_t touch_id, double sx,
+ double sy) {
+ clock_gettime(CLOCK_MONOTONIC, &seat->last_event);
+ struct wlr_seat_touch_grab *grab = seat->touch_state.grab;
+ struct wlr_touch_point *point =
+ touch_point_create(seat, touch_id, surface, sx, sy);
+ if (!point) {
+ wlr_log(L_ERROR, "could not create touch point");
+ return 0;
+ }
+
+ uint32_t serial = grab->interface->down(grab, time, point);
+
+ if (serial && wlr_seat_touch_num_points(seat) == 1) {
+ seat->touch_state.grab_serial = serial;
+ seat->touch_state.grab_id = touch_id;
+ }
+
+ return serial;
+}
+
+void wlr_seat_touch_notify_up(struct wlr_seat *seat, uint32_t time,
+ int32_t touch_id) {
+ clock_gettime(CLOCK_MONOTONIC, &seat->last_event);
+ struct wlr_seat_touch_grab *grab = seat->touch_state.grab;
+ struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id);
+ if (!point) {
+ return;
+ }
+
+ grab->interface->up(grab, time, point);
+
+ touch_point_destroy(point);
+}
+
+void wlr_seat_touch_notify_motion(struct wlr_seat *seat, uint32_t time,
+ int32_t touch_id, double sx, double sy) {
+ clock_gettime(CLOCK_MONOTONIC, &seat->last_event);
+ struct wlr_seat_touch_grab *grab = seat->touch_state.grab;
+ struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id);
+ if (!point) {
+ return;
+ }
+
+ point->sx = sx;
+ point->sy = sy;
+
+ grab->interface->motion(grab, time, point);
+}
+
+static void handle_point_focus_destroy(struct wl_listener *listener,
+ void *data) {
+ struct wlr_touch_point *point =
+ wl_container_of(listener, point, focus_surface_destroy);
+ touch_point_clear_focus(point);
+}
+
+static void touch_point_set_focus(struct wlr_touch_point *point,
+ struct wlr_surface *surface, double sx, double sy) {
+ if (point->focus_surface == surface) {
+ return;
+ }
+
+ touch_point_clear_focus(point);
+
+ if (surface && surface->resource) {
+ struct wlr_seat_client *client =
+ wlr_seat_client_for_wl_client(point->client->seat,
+ wl_resource_get_client(surface->resource));
+
+ if (client && !wl_list_empty(&client->touches)) {
+ wl_signal_add(&surface->events.destroy, &point->focus_surface_destroy);
+ point->focus_surface_destroy.notify = handle_point_focus_destroy;
+ point->focus_surface = surface;
+ point->focus_client = client;
+ point->sx = sx;
+ point->sy = sy;
+ }
+ }
+}
+
+void wlr_seat_touch_point_focus(struct wlr_seat *seat,
+ struct wlr_surface *surface, uint32_t time, int32_t touch_id, double sx,
+ double sy) {
+ assert(surface);
+ struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id);
+ if (!point) {
+ wlr_log(L_ERROR, "got touch point focus for unknown touch point");
+ return;
+ }
+ struct wlr_surface *focus = point->focus_surface;
+ touch_point_set_focus(point, surface, sx, sy);
+
+ if (focus != point->focus_surface) {
+ struct wlr_seat_touch_grab *grab = seat->touch_state.grab;
+ grab->interface->enter(grab, time, point);
+ }
+}
+
+void wlr_seat_touch_point_clear_focus(struct wlr_seat *seat, uint32_t time,
+ int32_t touch_id) {
+ struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id);
+ if (!point) {
+ wlr_log(L_ERROR, "got touch point focus for unknown touch point");
+ return;
+ }
+
+ touch_point_clear_focus(point);
+}
+
+uint32_t wlr_seat_touch_send_down(struct wlr_seat *seat,
+ struct wlr_surface *surface, uint32_t time, int32_t touch_id, double sx,
+ double sy) {
+ struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id);
+ if (!point) {
+ wlr_log(L_ERROR, "got touch down for unknown touch point");
+ return 0;
+ }
+
+ uint32_t serial = wl_display_next_serial(seat->display);
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &point->client->touches) {
+ wl_touch_send_down(resource, serial, time, surface->resource,
+ touch_id, wl_fixed_from_double(sx), wl_fixed_from_double(sy));
+ wl_touch_send_frame(resource);
+ }
+
+ return serial;
+}
+
+void wlr_seat_touch_send_up(struct wlr_seat *seat, uint32_t time, int32_t touch_id) {
+ struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id);
+ if (!point) {
+ wlr_log(L_ERROR, "got touch up for unknown touch point");
+ return;
+ }
+
+ uint32_t serial = wl_display_next_serial(seat->display);
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &point->client->touches) {
+ wl_touch_send_up(resource, serial, time, touch_id);
+ wl_touch_send_frame(resource);
+ }
+}
+
+void wlr_seat_touch_send_motion(struct wlr_seat *seat, uint32_t time, int32_t touch_id,
+ double sx, double sy) {
+ struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id);
+ if (!point) {
+ wlr_log(L_ERROR, "got touch motion for unknown touch point");
+ return;
+ }
+
+ struct wl_resource *resource;
+ wl_resource_for_each(resource, &point->client->touches) {
+ wl_touch_send_motion(resource, time, touch_id, wl_fixed_from_double(sx),
+ wl_fixed_from_double(sy));
+ wl_touch_send_frame(resource);
+ }
+}
+
+int wlr_seat_touch_num_points(struct wlr_seat *seat) {
+ return wl_list_length(&seat->touch_state.touch_points);
+}
+
+bool wlr_seat_touch_has_grab(struct wlr_seat *seat) {
+ return seat->touch_state.grab->interface != &default_touch_grab_impl;
+}
+
+
+void seat_client_create_touch(struct wlr_seat_client *seat_client,
+ uint32_t version, uint32_t id) {
+ struct wl_resource *resource = wl_resource_create(seat_client->client,
+ &wl_touch_interface, version, id);
+ if (resource == NULL) {
+ wl_client_post_no_memory(seat_client->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));
+}
diff --git a/types/wlr_data_device.c b/types/wlr_data_device.c
deleted file mode 100644
index 23e54809..00000000
--- a/types/wlr_data_device.c
+++ /dev/null
@@ -1,1203 +0,0 @@
-#define _XOPEN_SOURCE 700
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#include <unistd.h>
-#include <wayland-server.h>
-#include <wlr/types/wlr_data_device.h>
-#include <wlr/types/wlr_seat.h>
-#include <wlr/util/log.h>
-#include "util/signal.h"
-
-#define ALL_ACTIONS (WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY | \
- WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | \
- WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK)
-
-static const struct wl_data_offer_interface data_offer_impl;
-
-static struct wlr_data_offer *data_offer_from_resource(
- struct wl_resource *resource) {
- assert(wl_resource_instance_of(resource, &wl_data_offer_interface,
- &data_offer_impl));
- return wl_resource_get_user_data(resource);
-}
-
-static const struct wl_data_source_interface data_source_impl;
-
-static struct client_data_source *client_data_source_from_resource(
- struct wl_resource *resource) {
- assert(wl_resource_instance_of(resource, &wl_data_source_interface,
- &data_source_impl));
- return wl_resource_get_user_data(resource);
-}
-
-static uint32_t data_offer_choose_action(struct wlr_data_offer *offer) {
- uint32_t offer_actions, preferred_action = 0;
- if (wl_resource_get_version(offer->resource) >=
- WL_DATA_OFFER_ACTION_SINCE_VERSION) {
- offer_actions = offer->actions;
- preferred_action = offer->preferred_action;
- } else {
- offer_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
- }
-
- uint32_t source_actions;
- if (offer->source->actions >= 0) {
- source_actions = offer->source->actions;
- } else {
- source_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
- }
-
- uint32_t available_actions = offer_actions & source_actions;
- if (!available_actions) {
- return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
- }
-
- if (offer->source->seat_client &&
- offer->source->compositor_action & available_actions) {
- return offer->source->compositor_action;
- }
-
- // If the dest side has a preferred DnD action, use it
- if ((preferred_action & available_actions) != 0) {
- return preferred_action;
- }
-
- // Use the first found action, in bit order
- return 1 << (ffs(available_actions) - 1);
-}
-
-static void data_offer_update_action(struct wlr_data_offer *offer) {
- if (!offer->source) {
- return;
- }
-
- uint32_t action = data_offer_choose_action(offer);
- if (offer->source->current_dnd_action == action) {
- return;
- }
-
- offer->source->current_dnd_action = action;
-
- if (offer->in_ask) {
- return;
- }
-
- wlr_data_source_dnd_action(offer->source, action);
-
- if (wl_resource_get_version(offer->resource) >=
- WL_DATA_OFFER_ACTION_SINCE_VERSION) {
- wl_data_offer_send_action(offer->resource, action);
- }
-}
-
-static void data_offer_accept(struct wl_client *client,
- struct wl_resource *resource, uint32_t serial, const char *mime_type) {
- struct wlr_data_offer *offer = data_offer_from_resource(resource);
-
- if (!offer->source || offer != offer->source->offer) {
- return;
- }
-
- // TODO check that client is currently focused by the input device
-
- wlr_data_source_accept(offer->source, serial, mime_type);
-}
-
-static void data_offer_receive(struct wl_client *client,
- struct wl_resource *resource, const char *mime_type, int32_t fd) {
- struct wlr_data_offer *offer = data_offer_from_resource(resource);
-
- if (offer->source && offer == offer->source->offer) {
- wlr_data_source_send(offer->source, mime_type, fd);
- } else {
- close(fd);
- }
-}
-static void data_offer_destroy(struct wl_client *client,
- struct wl_resource *resource) {
- wl_resource_destroy(resource);
-}
-
-static void data_source_notify_finish(struct wlr_data_source *source) {
- assert(source->offer);
- if (source->actions < 0) {
- return;
- }
-
- if (source->offer->in_ask) {
- wlr_data_source_dnd_action(source, source->current_dnd_action);
- }
-
- source->offer = NULL;
- wlr_data_source_dnd_finish(source);
-}
-
-static void data_offer_finish(struct wl_client *client,
- struct wl_resource *resource) {
- struct wlr_data_offer *offer = data_offer_from_resource(resource);
-
- if (!offer->source || offer->source->offer != offer) {
- return;
- }
-
- data_source_notify_finish(offer->source);
-}
-
-static void data_offer_set_actions(struct wl_client *client,
- struct wl_resource *resource, uint32_t actions,
- uint32_t preferred_action) {
- struct wlr_data_offer *offer = data_offer_from_resource(resource);
-
- if (actions & ~ALL_ACTIONS) {
- wl_resource_post_error(offer->resource,
- WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK,
- "invalid action mask %x", actions);
- return;
- }
-
- if (preferred_action && (!(preferred_action & actions) ||
- __builtin_popcount(preferred_action) > 1)) {
- wl_resource_post_error(offer->resource,
- WL_DATA_OFFER_ERROR_INVALID_ACTION,
- "invalid action %x", preferred_action);
- return;
- }
-
- offer->actions = actions;
- offer->preferred_action = preferred_action;
-
- data_offer_update_action(offer);
-}
-
-static void data_offer_resource_destroy(struct wl_resource *resource) {
- struct wlr_data_offer *offer = data_offer_from_resource(resource);
-
- if (!offer->source) {
- goto out;
- }
-
- wl_list_remove(&offer->source_destroy.link);
-
- if (offer->source->offer != offer) {
- goto out;
- }
-
- // If the drag destination has version < 3, wl_data_offer.finish
- // won't be called, so do this here as a safety net, because
- // we still want the version >= 3 drag source to be happy.
- if (wl_resource_get_version(offer->resource) <
- WL_DATA_OFFER_ACTION_SINCE_VERSION) {
- data_source_notify_finish(offer->source);
- offer->source->offer = NULL;
- } else if (offer->source->impl->dnd_finish) {
- // source->cancel can free the source
- offer->source->offer = NULL;
- wlr_data_source_cancel(offer->source);
- } else {
- offer->source->offer = NULL;
- }
-
-out:
- free(offer);
-}
-
-static const struct wl_data_offer_interface data_offer_impl = {
- .accept = data_offer_accept,
- .receive = data_offer_receive,
- .destroy = data_offer_destroy,
- .finish = data_offer_finish,
- .set_actions = data_offer_set_actions,
-};
-
-static void handle_offer_source_destroyed(struct wl_listener *listener,
- void *data) {
- struct wlr_data_offer *offer =
- wl_container_of(listener, offer, source_destroy);
-
- offer->source = NULL;
-}
-
-static struct wlr_data_offer *data_source_send_offer(
- struct wlr_data_source *source,
- struct wlr_seat_client *target) {
- if (wl_list_empty(&target->data_devices)) {
- return NULL;
- }
-
- struct wlr_data_offer *offer = calloc(1, sizeof(struct wlr_data_offer));
- if (offer == NULL) {
- return NULL;
- }
-
- uint32_t version = wl_resource_get_version(
- wl_resource_from_link(target->data_devices.next));
- offer->resource = wl_resource_create(target->client,
- &wl_data_offer_interface, version, 0);
- if (offer->resource == NULL) {
- free(offer);
- return NULL;
- }
- wl_resource_set_implementation(offer->resource, &data_offer_impl, offer,
- data_offer_resource_destroy);
-
- offer->source_destroy.notify = handle_offer_source_destroyed;
- wl_signal_add(&source->events.destroy, &offer->source_destroy);
-
- struct wl_resource *target_resource;
- wl_resource_for_each(target_resource, &target->data_devices) {
- wl_data_device_send_data_offer(target_resource, offer->resource);
- }
-
- char **p;
- wl_array_for_each(p, &source->mime_types) {
- wl_data_offer_send_offer(offer->resource, *p);
- }
-
- offer->source = source;
- source->offer = offer;
- source->accepted = false;
-
- return offer;
-}
-
-void wlr_seat_client_send_selection(struct wlr_seat_client *seat_client) {
- if (wl_list_empty(&seat_client->data_devices)) {
- return;
- }
-
- if (seat_client->seat->selection_source) {
- struct wlr_data_offer *offer = data_source_send_offer(
- seat_client->seat->selection_source, seat_client);
- if (offer == NULL) {
- return;
- }
-
- struct wl_resource *resource;
- wl_resource_for_each(resource, &seat_client->data_devices) {
- wl_data_device_send_selection(resource, offer->resource);
- }
- } else {
- struct wl_resource *resource;
- wl_resource_for_each(resource, &seat_client->data_devices) {
- wl_data_device_send_selection(resource, NULL);
- }
- }
-}
-
-static void seat_client_selection_source_destroy(
- struct wl_listener *listener, void *data) {
- struct wlr_seat *seat =
- wl_container_of(listener, seat, selection_source_destroy);
- struct wlr_seat_client *seat_client = seat->keyboard_state.focused_client;
-
- if (seat_client && seat->keyboard_state.focused_surface) {
- struct wl_resource *resource;
- wl_resource_for_each(resource, &seat_client->data_devices) {
- wl_data_device_send_selection(resource, NULL);
- }
- }
-
- seat->selection_source = NULL;
-
- wlr_signal_emit_safe(&seat->events.selection, seat);
-}
-
-void wlr_seat_set_selection(struct wlr_seat *seat,
- struct wlr_data_source *source, uint32_t serial) {
- if (seat->selection_source &&
- seat->selection_serial - serial < UINT32_MAX / 2) {
- return;
- }
-
- if (seat->selection_source) {
- wl_list_remove(&seat->selection_source_destroy.link);
- wlr_data_source_cancel(seat->selection_source);
- seat->selection_source = NULL;
- }
-
- seat->selection_source = source;
- seat->selection_serial = serial;
-
- struct wlr_seat_client *focused_client =
- seat->keyboard_state.focused_client;
-
- if (focused_client) {
- wlr_seat_client_send_selection(focused_client);
- }
-
- wlr_signal_emit_safe(&seat->events.selection, seat);
-
- if (source) {
- seat->selection_source_destroy.notify =
- seat_client_selection_source_destroy;
- wl_signal_add(&source->events.destroy,
- &seat->selection_source_destroy);
- }
-}
-
-static const struct wl_data_device_interface data_device_impl;
-
-static struct wlr_seat_client *seat_client_from_data_device_resource(
- struct wl_resource *resource) {
- assert(wl_resource_instance_of(resource, &wl_data_device_interface,
- &data_device_impl));
- return wl_resource_get_user_data(resource);
-}
-
-static void data_device_set_selection(struct wl_client *client,
- struct wl_resource *device_resource,
- struct wl_resource *source_resource, uint32_t serial) {
- struct client_data_source *source = NULL;
- if (source_resource != NULL) {
- source = client_data_source_from_resource(source_resource);
- }
-
- struct wlr_seat_client *seat_client =
- seat_client_from_data_device_resource(device_resource);
-
- struct wlr_data_source *wlr_source = (struct wlr_data_source *)source;
- wlr_seat_set_selection(seat_client->seat, wlr_source, serial);
-}
-
-static void data_device_release(struct wl_client *client,
- struct wl_resource *resource) {
- wl_resource_destroy(resource);
-}
-
-static void handle_drag_seat_client_destroy(struct wl_listener *listener,
- void *data) {
- struct wlr_drag *drag =
- wl_container_of(listener, drag, seat_client_destroy);
-
- drag->focus_client = NULL;
- wl_list_remove(&drag->seat_client_destroy.link);
-}
-
-static void drag_set_focus(struct wlr_drag *drag,
- struct wlr_surface *surface, double sx, double sy) {
- if (drag->focus == surface) {
- return;
- }
-
- if (drag->focus_client) {
- wl_list_remove(&drag->seat_client_destroy.link);
-
- struct wl_resource *resource;
- wl_resource_for_each(resource, &drag->focus_client->data_devices) {
- wl_data_device_send_leave(resource);
- }
-
- drag->focus_client = NULL;
- drag->focus = NULL;
- }
-
- if (!surface || !surface->resource) {
- return;
- }
-
- if (!drag->source &&
- wl_resource_get_client(surface->resource) !=
- wl_resource_get_client(drag->seat_client->wl_resource)) {
- return;
- }
-
- if (drag->source && drag->source->offer) {
- // unlink the offer from the source
- wl_list_remove(&drag->source->offer->source_destroy.link);
- drag->source->offer->source = NULL;
- drag->source->offer = NULL;
- }
-
- struct wlr_seat_client *focus_client =
- wlr_seat_client_for_wl_client(drag->seat_client->seat,
- wl_resource_get_client(surface->resource));
- if (!focus_client) {
- return;
- }
-
- struct wl_resource *offer_resource = NULL;
- if (drag->source) {
- drag->source->accepted = false;
- struct wlr_data_offer *offer = data_source_send_offer(drag->source,
- focus_client);
- if (offer != NULL) {
- data_offer_update_action(offer);
-
- if (wl_resource_get_version(offer->resource) >=
- WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION) {
- wl_data_offer_send_source_actions(offer->resource,
- drag->source->actions);
- }
-
- offer_resource = offer->resource;
- }
- }
-
- if (!wl_list_empty(&focus_client->data_devices)) {
- uint32_t serial =
- wl_display_next_serial(drag->seat_client->seat->display);
- struct wl_resource *resource;
- wl_resource_for_each(resource, &focus_client->data_devices) {
- wl_data_device_send_enter(resource, serial, surface->resource,
- wl_fixed_from_double(sx), wl_fixed_from_double(sy),
- offer_resource);
- }
- }
-
- drag->focus = surface;
- drag->focus_client = focus_client;
- drag->seat_client_destroy.notify = handle_drag_seat_client_destroy;
- wl_signal_add(&focus_client->events.destroy, &drag->seat_client_destroy);
-
- wlr_signal_emit_safe(&drag->events.focus, drag);
-}
-
-static void drag_end(struct wlr_drag *drag) {
- if (!drag->cancelling) {
- drag->cancelling = true;
- if (drag->is_pointer_grab) {
- wlr_seat_pointer_end_grab(drag->seat);
- } else {
- wlr_seat_touch_end_grab(drag->seat);
- }
- wlr_seat_keyboard_end_grab(drag->seat);
-
- if (drag->source) {
- wl_list_remove(&drag->source_destroy.link);
- }
-
- drag_set_focus(drag, NULL, 0, 0);
-
- if (drag->icon) {
- drag->icon->mapped = false;
- wl_list_remove(&drag->icon_destroy.link);
- wlr_signal_emit_safe(&drag->icon->events.map, drag->icon);
- }
-
- wlr_signal_emit_safe(&drag->events.destroy, drag);
- free(drag);
- }
-}
-
-static void pointer_drag_enter(struct wlr_seat_pointer_grab *grab,
- struct wlr_surface *surface, double sx, double sy) {
- struct wlr_drag *drag = grab->data;
- drag_set_focus(drag, surface, sx, sy);
-}
-
-static void pointer_drag_motion(struct wlr_seat_pointer_grab *grab,
- uint32_t time, double sx, double sy) {
- struct wlr_drag *drag = grab->data;
- if (drag->focus != NULL && drag->focus_client != NULL) {
- struct wl_resource *resource;
- wl_resource_for_each(resource, &drag->focus_client->data_devices) {
- wl_data_device_send_motion(resource, time, wl_fixed_from_double(sx),
- wl_fixed_from_double(sy));
- }
-
- struct wlr_drag_motion_event event = {
- .drag = drag,
- .time = time,
- .sx = sx,
- .sy = sy,
- };
- wlr_signal_emit_safe(&drag->events.motion, &event);
- }
-}
-
-static uint32_t pointer_drag_button(struct wlr_seat_pointer_grab *grab,
- uint32_t time, uint32_t button, uint32_t state) {
- struct wlr_drag *drag = grab->data;
-
- if (drag->source &&
- grab->seat->pointer_state.grab_button == button &&
- state == WL_POINTER_BUTTON_STATE_RELEASED) {
- if (drag->focus_client && drag->source->current_dnd_action &&
- drag->source->accepted) {
- struct wl_resource *resource;
- wl_resource_for_each(resource, &drag->focus_client->data_devices) {
- wl_data_device_send_drop(resource);
- }
- wlr_data_source_dnd_drop(drag->source);
-
- if (drag->source->offer != NULL) {
- drag->source->offer->in_ask =
- drag->source->current_dnd_action ==
- WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
- }
-
- struct wlr_drag_drop_event event = {
- .drag = drag,
- .time = time,
- };
- wlr_signal_emit_safe(&drag->events.drop, &event);
- } else if (drag->source->impl->dnd_finish) {
- wlr_data_source_cancel(drag->source);
- }
- }
-
- if (grab->seat->pointer_state.button_count == 0 &&
- state == WL_POINTER_BUTTON_STATE_RELEASED) {
- drag_end(drag);
- }
-
- return 0;
-}
-
-static void pointer_drag_axis(struct wlr_seat_pointer_grab *grab, uint32_t time,
- enum wlr_axis_orientation orientation, double value) {
- // This space is intentionally left blank
-}
-
-static void pointer_drag_cancel(struct wlr_seat_pointer_grab *grab) {
- struct wlr_drag *drag = grab->data;
- drag_end(drag);
-}
-
-static const struct wlr_pointer_grab_interface
- data_device_pointer_drag_interface = {
- .enter = pointer_drag_enter,
- .motion = pointer_drag_motion,
- .button = pointer_drag_button,
- .axis = pointer_drag_axis,
- .cancel = pointer_drag_cancel,
-};
-
-uint32_t touch_drag_down(struct wlr_seat_touch_grab *grab,
- uint32_t time, struct wlr_touch_point *point) {
- // eat the event
- return 0;
-}
-
-static void touch_drag_up(struct wlr_seat_touch_grab *grab, uint32_t time,
- struct wlr_touch_point *point) {
- struct wlr_drag *drag = grab->data;
- if (drag->grab_touch_id != point->touch_id) {
- return;
- }
-
- if (drag->focus_client) {
- struct wl_resource *resource;
- wl_resource_for_each(resource, &drag->focus_client->data_devices) {
- wl_data_device_send_drop(resource);
- }
- }
-
- drag_end(drag);
-}
-
-static void touch_drag_motion(struct wlr_seat_touch_grab *grab, uint32_t time,
- struct wlr_touch_point *point) {
- struct wlr_drag *drag = grab->data;
- if (drag->focus && drag->focus_client) {
- struct wl_resource *resource;
- wl_resource_for_each(resource, &drag->focus_client->data_devices) {
- wl_data_device_send_motion(resource, time,
- wl_fixed_from_double(point->sx),
- wl_fixed_from_double(point->sy));
- }
- }
-}
-
-static void touch_drag_enter(struct wlr_seat_touch_grab *grab, uint32_t time,
- struct wlr_touch_point *point) {
- struct wlr_drag *drag = grab->data;
- drag_set_focus(drag, point->focus_surface, point->sx, point->sy);
-}
-
-static void touch_drag_cancel(struct wlr_seat_touch_grab *grab) {
- struct wlr_drag *drag = grab->data;
- drag_end(drag);
-}
-
-static const struct wlr_touch_grab_interface
- data_device_touch_drag_interface = {
- .down = touch_drag_down,
- .up = touch_drag_up,
- .motion = touch_drag_motion,
- .enter = touch_drag_enter,
- .cancel = touch_drag_cancel,
-};
-
-static void keyboard_drag_enter(struct wlr_seat_keyboard_grab *grab,
- struct wlr_surface *surface, uint32_t keycodes[], size_t num_keycodes,
- struct wlr_keyboard_modifiers *modifiers) {
- // nothing has keyboard focus during drags
-}
-
-static void keyboard_drag_key(struct wlr_seat_keyboard_grab *grab,
- uint32_t time, uint32_t key, uint32_t state) {
- // no keyboard input during drags
-}
-
-static void keyboard_drag_modifiers(struct wlr_seat_keyboard_grab *grab,
- struct wlr_keyboard_modifiers *modifiers) {
- //struct wlr_keyboard *keyboard = grab->seat->keyboard_state.keyboard;
- // TODO change the dnd action based on what modifier is pressed on the
- // keyboard
-}
-
-static void keyboard_drag_cancel(struct wlr_seat_keyboard_grab *grab) {
- struct wlr_drag *drag = grab->data;
- drag_end(drag);
-}
-
-static const struct wlr_keyboard_grab_interface
- data_device_keyboard_drag_interface = {
- .enter = keyboard_drag_enter,
- .key = keyboard_drag_key,
- .modifiers = keyboard_drag_modifiers,
- .cancel = keyboard_drag_cancel,
-};
-
-static void drag_handle_icon_destroy(struct wl_listener *listener, void *data) {
- struct wlr_drag *drag = wl_container_of(listener, drag, icon_destroy);
- drag->icon = NULL;
-}
-
-static void drag_handle_drag_source_destroy(struct wl_listener *listener,
- void *data) {
- struct wlr_drag *drag = wl_container_of(listener, drag, source_destroy);
- drag_end(drag);
-}
-
-static void drag_icon_destroy(struct wlr_drag_icon *icon) {
- if (!icon) {
- return;
- }
- wlr_signal_emit_safe(&icon->events.destroy, icon);
- wlr_surface_set_role_committed(icon->surface, NULL, NULL);
- wl_list_remove(&icon->surface_destroy.link);
- wl_list_remove(&icon->seat_client_destroy.link);
- wl_list_remove(&icon->link);
- free(icon);
-}
-
-static void handle_drag_icon_surface_destroy(struct wl_listener *listener,
- void *data) {
- struct wlr_drag_icon *icon =
- wl_container_of(listener, icon, surface_destroy);
- drag_icon_destroy(icon);
-}
-
-static void handle_drag_icon_surface_commit(struct wlr_surface *surface,
- void *role_data) {
- struct wlr_drag_icon *icon = role_data;
- icon->sx += icon->surface->current->sx;
- icon->sy += icon->surface->current->sy;
-}
-
-static void handle_drag_icon_seat_client_destroy(struct wl_listener *listener,
- void *data) {
- struct wlr_drag_icon *icon =
- wl_container_of(listener, icon, seat_client_destroy);
-
- drag_icon_destroy(icon);
-}
-
-static struct wlr_drag_icon *drag_icon_create(
- struct wlr_surface *icon_surface, struct wlr_seat_client *client,
- bool is_pointer, int32_t touch_id) {
- struct wlr_drag_icon *icon = calloc(1, sizeof(struct wlr_drag_icon));
- if (!icon) {
- return NULL;
- }
-
- icon->surface = icon_surface;
- icon->client = client;
- icon->is_pointer = is_pointer;
- icon->touch_id = touch_id;
- icon->mapped = true;
-
- wl_signal_init(&icon->events.map);
- wl_signal_init(&icon->events.destroy);
-
- wl_signal_add(&icon->surface->events.destroy, &icon->surface_destroy);
- icon->surface_destroy.notify = handle_drag_icon_surface_destroy;
-
- wlr_surface_set_role_committed(icon->surface,
- handle_drag_icon_surface_commit, icon);
-
- wl_signal_add(&client->events.destroy, &icon->seat_client_destroy);
- icon->seat_client_destroy.notify = handle_drag_icon_seat_client_destroy;
-
- wl_list_insert(&client->seat->drag_icons, &icon->link);
- wlr_signal_emit_safe(&client->seat->events.new_drag_icon, icon);
-
- return icon;
-}
-
-static void seat_handle_drag_source_destroy(struct wl_listener *listener,
- void *data) {
- struct wlr_seat *seat =
- wl_container_of(listener, seat, drag_source_destroy);
- wl_list_remove(&seat->drag_source_destroy.link);
- seat->drag_source = NULL;
-}
-
-static bool seat_client_start_drag(struct wlr_seat_client *client,
- struct wlr_data_source *source, struct wlr_surface *icon_surface,
- struct wlr_surface *origin, uint32_t serial) {
- struct wlr_drag *drag = calloc(1, sizeof(struct wlr_drag));
- if (drag == NULL) {
- return false;
- }
-
- wl_signal_init(&drag->events.focus);
- wl_signal_init(&drag->events.motion);
- wl_signal_init(&drag->events.drop);
- wl_signal_init(&drag->events.destroy);
-
- struct wlr_seat *seat = client->seat;
- drag->seat = seat;
-
- drag->is_pointer_grab = !wl_list_empty(&client->pointers) &&
- seat->pointer_state.button_count == 1 &&
- seat->pointer_state.grab_serial == serial &&
- seat->pointer_state.focused_surface &&
- seat->pointer_state.focused_surface == origin;
-
- bool is_touch_grab = !wl_list_empty(&client->touches) &&
- wlr_seat_touch_num_points(seat) == 1 &&
- seat->touch_state.grab_serial == serial;
-
- // set in the iteration
- struct wlr_touch_point *point = NULL;
- if (is_touch_grab) {
- wl_list_for_each(point, &seat->touch_state.touch_points, link) {
- is_touch_grab = point->surface && point->surface == origin;
- break;
- }
- }
-
- if (!drag->is_pointer_grab && !is_touch_grab) {
- free(drag);
- return true;
- }
-
- if (icon_surface) {
- int32_t touch_id = (point ? point->touch_id : 0);
- struct wlr_drag_icon *icon =
- drag_icon_create(icon_surface, client, drag->is_pointer_grab,
- touch_id);
- if (!icon) {
- free(drag);
- return false;
- }
-
- drag->icon = icon;
- drag->icon_destroy.notify = drag_handle_icon_destroy;
- wl_signal_add(&icon->events.destroy, &drag->icon_destroy);
- }
-
- drag->source = source;
- if (source != NULL) {
- drag->source_destroy.notify = drag_handle_drag_source_destroy;
- wl_signal_add(&source->events.destroy, &drag->source_destroy);
- }
-
- drag->seat_client = client;
- drag->pointer_grab.data = drag;
- drag->pointer_grab.interface = &data_device_pointer_drag_interface;
-
- drag->touch_grab.data = drag;
- drag->touch_grab.interface = &data_device_touch_drag_interface;
- drag->grab_touch_id = seat->touch_state.grab_id;
-
- drag->keyboard_grab.data = drag;
- drag->keyboard_grab.interface = &data_device_keyboard_drag_interface;
-
- wlr_seat_keyboard_start_grab(seat, &drag->keyboard_grab);
-
- if (drag->is_pointer_grab) {
- wlr_seat_pointer_clear_focus(seat);
- wlr_seat_pointer_start_grab(seat, &drag->pointer_grab);
- } else {
- assert(point);
- wlr_seat_touch_start_grab(seat, &drag->touch_grab);
- drag_set_focus(drag, point->surface, point->sx, point->sy);
- }
-
- seat->drag = drag; // TODO: unset this thing somewhere
- seat->drag_serial = serial;
-
- seat->drag_source = source;
- if (source != NULL) {
- seat->drag_source_destroy.notify = seat_handle_drag_source_destroy;
- wl_signal_add(&source->events.destroy, &seat->drag_source_destroy);
- }
-
- wlr_signal_emit_safe(&seat->events.start_drag, drag);
-
- return true;
-}
-
-static void data_device_start_drag(struct wl_client *client,
- struct wl_resource *device_resource,
- struct wl_resource *source_resource,
- struct wl_resource *origin_resource, struct wl_resource *icon_resource,
- uint32_t serial) {
- struct wlr_seat_client *seat_client =
- seat_client_from_data_device_resource(device_resource);
- struct wlr_surface *origin = wlr_surface_from_resource(origin_resource);
- struct wlr_data_source *source = NULL;
- struct wlr_surface *icon = NULL;
-
- if (source_resource) {
- struct client_data_source *client_source =
- client_data_source_from_resource(source_resource);
- source = (struct wlr_data_source *)client_source;
- }
-
- if (icon_resource) {
- icon = wlr_surface_from_resource(icon_resource);
- }
- if (icon) {
- if (wlr_surface_set_role(icon, "wl_data_device-icon",
- icon_resource, WL_DATA_DEVICE_ERROR_ROLE) < 0) {
- return;
- }
- }
-
- if (!seat_client_start_drag(seat_client, source, icon, origin, serial)) {
- wl_resource_post_no_memory(device_resource);
- return;
- }
-
- if (source) {
- source->seat_client = seat_client;
- }
-}
-
-static const struct wl_data_device_interface data_device_impl = {
- .start_drag = data_device_start_drag,
- .set_selection = data_device_set_selection,
- .release = data_device_release,
-};
-
-static void data_device_destroy(struct wl_resource *resource) {
- wl_list_remove(wl_resource_get_link(resource));
-}
-
-
-struct client_data_source {
- struct wlr_data_source source;
- struct wlr_data_source_impl impl;
- struct wl_resource *resource;
-};
-
-static void client_data_source_accept(struct wlr_data_source *wlr_source,
- uint32_t serial, const char *mime_type);
-
-static struct client_data_source *client_data_source_from_wlr_data_source(
- struct wlr_data_source *wlr_source) {
- assert(wlr_source->impl->accept == client_data_source_accept);
- return (struct client_data_source *)wlr_source;
-}
-
-static void client_data_source_accept(struct wlr_data_source *wlr_source,
- uint32_t serial, const char *mime_type) {
- struct client_data_source *source =
- client_data_source_from_wlr_data_source(wlr_source);
- wl_data_source_send_target(source->resource, mime_type);
-}
-
-static void client_data_source_send(struct wlr_data_source *wlr_source,
- const char *mime_type, int32_t fd) {
- struct client_data_source *source =
- client_data_source_from_wlr_data_source(wlr_source);
- wl_data_source_send_send(source->resource, mime_type, fd);
- close(fd);
-}
-
-static void client_data_source_cancel(struct wlr_data_source *wlr_source) {
- struct client_data_source *source =
- client_data_source_from_wlr_data_source(wlr_source);
- wl_data_source_send_cancelled(source->resource);
-}
-
-static void client_data_source_dnd_drop(struct wlr_data_source *wlr_source) {
- struct client_data_source *source =
- client_data_source_from_wlr_data_source(wlr_source);
- assert(wl_resource_get_version(source->resource) >=
- WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION);
- wl_data_source_send_dnd_drop_performed(source->resource);
-}
-
-static void client_data_source_dnd_finish(struct wlr_data_source *wlr_source) {
- struct client_data_source *source =
- client_data_source_from_wlr_data_source(wlr_source);
- assert(wl_resource_get_version(source->resource) >=
- WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION);
- wl_data_source_send_dnd_finished(source->resource);
-}
-
-static void client_data_source_dnd_action(struct wlr_data_source *wlr_source,
- enum wl_data_device_manager_dnd_action action) {
- struct client_data_source *source =
- client_data_source_from_wlr_data_source(wlr_source);
- assert(wl_resource_get_version(source->resource) >=
- WL_DATA_SOURCE_ACTION_SINCE_VERSION);
- wl_data_source_send_action(source->resource, action);
-}
-
-static void data_source_destroy(struct wl_client *client,
- struct wl_resource *resource) {
- wl_resource_destroy(resource);
-}
-
-static struct client_data_source *client_data_source_create(
- struct wl_resource *source_resource) {
- struct client_data_source *source =
- calloc(1, sizeof(struct client_data_source));
- if (source == NULL) {
- return NULL;
- }
-
- source->resource = source_resource;
-
- source->impl.accept = client_data_source_accept;
- source->impl.send = client_data_source_send;
- source->impl.cancel = client_data_source_cancel;
-
- if (wl_resource_get_version(source->resource) >=
- WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION) {
- source->impl.dnd_drop = client_data_source_dnd_drop;
- }
- if (wl_resource_get_version(source->resource) >=
- WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) {
- source->impl.dnd_finish = client_data_source_dnd_finish;
- }
- if (wl_resource_get_version(source->resource) >=
- WL_DATA_SOURCE_ACTION_SINCE_VERSION) {
- source->impl.dnd_action = client_data_source_dnd_action;
- }
-
- wlr_data_source_init(&source->source, &source->impl);
- return source;
-}
-
-static void data_source_set_actions(struct wl_client *client,
- struct wl_resource *resource, uint32_t dnd_actions) {
- struct client_data_source *source =
- client_data_source_from_resource(resource);
-
- if (source->source.actions >= 0) {
- wl_resource_post_error(source->resource,
- WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
- "cannot set actions more than once");
- return;
- }
-
- if (dnd_actions & ~ALL_ACTIONS) {
- wl_resource_post_error(source->resource,
- WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
- "invalid action mask %x", dnd_actions);
- return;
- }
-
- if (source->source.seat_client) {
- wl_resource_post_error(source->resource,
- WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
- "invalid action change after "
- "wl_data_device.start_drag");
- return;
- }
-
- source->source.actions = dnd_actions;
-}
-
-static void data_source_offer(struct wl_client *client,
- struct wl_resource *resource, const char *mime_type) {
- struct client_data_source *source =
- client_data_source_from_resource(resource);
-
- char **p = wl_array_add(&source->source.mime_types, sizeof(*p));
- if (p) {
- *p = strdup(mime_type);
- }
- if (!p || !*p) {
- if (p) {
- source->source.mime_types.size -= sizeof(*p);
- }
- wl_resource_post_no_memory(resource);
- }
-}
-
-static const struct wl_data_source_interface data_source_impl = {
- .offer = data_source_offer,
- .destroy = data_source_destroy,
- .set_actions = data_source_set_actions,
-};
-
-static void data_source_resource_handle_destroy(struct wl_resource *resource) {
- struct client_data_source *source =
- client_data_source_from_resource(resource);
- wlr_data_source_finish(&source->source);
- free(source);
-}
-
-void wlr_data_source_init(struct wlr_data_source *source,
- const struct wlr_data_source_impl *impl) {
- assert(impl->send);
-
- source->impl = impl;
- wl_array_init(&source->mime_types);
- wl_signal_init(&source->events.destroy);
- source->actions = -1;
-}
-
-void wlr_data_source_finish(struct wlr_data_source *source) {
- if (source == NULL) {
- return;
- }
-
- wlr_signal_emit_safe(&source->events.destroy, source);
-
- char **p;
- wl_array_for_each(p, &source->mime_types) {
- free(*p);
- }
- wl_array_release(&source->mime_types);
-}
-
-void wlr_data_source_send(struct wlr_data_source *source, const char *mime_type,
- int32_t fd) {
- source->impl->send(source, mime_type, fd);
-}
-
-void wlr_data_source_accept(struct wlr_data_source *source, uint32_t serial,
- const char *mime_type) {
- source->accepted = (mime_type != NULL);
- if (source->impl->accept) {
- source->impl->accept(source, serial, mime_type);
- }
-}
-
-void wlr_data_source_cancel(struct wlr_data_source *source) {
- if (source->impl->cancel) {
- source->impl->cancel(source);
- }
-}
-
-void wlr_data_source_dnd_drop(struct wlr_data_source *source) {
- if (source->impl->dnd_drop) {
- source->impl->dnd_drop(source);
- }
-}
-
-void wlr_data_source_dnd_finish(struct wlr_data_source *source) {
- if (source->impl->dnd_finish) {
- source->impl->dnd_finish(source);
- }
-}
-
-void wlr_data_source_dnd_action(struct wlr_data_source *source,
- enum wl_data_device_manager_dnd_action action) {
- source->current_dnd_action = action;
- if (source->impl->dnd_action) {
- source->impl->dnd_action(source, action);
- }
-}
-
-
-void data_device_manager_get_data_device(struct wl_client *client,
- struct wl_resource *manager_resource, uint32_t id,
- struct wl_resource *seat_resource) {
- struct wlr_seat_client *seat_client =
- wlr_seat_client_from_resource(seat_resource);
-
- struct wl_resource *resource = wl_resource_create(client,
- &wl_data_device_interface, wl_resource_get_version(manager_resource),
- id);
- if (resource == NULL) {
- wl_resource_post_no_memory(manager_resource);
- return;
- }
- wl_resource_set_implementation(resource, &data_device_impl, seat_client,
- &data_device_destroy);
- wl_list_insert(&seat_client->data_devices, wl_resource_get_link(resource));
-}
-
-static void data_device_manager_create_data_source(struct wl_client *client,
- struct wl_resource *resource, uint32_t id) {
- struct wl_resource *source_resource = wl_resource_create(client,
- &wl_data_source_interface, wl_resource_get_version(resource), id);
- if (source_resource == NULL) {
- wl_resource_post_no_memory(resource);
- return;
- }
-
- struct client_data_source *source =
- client_data_source_create(source_resource);
- if (source == NULL) {
- wl_resource_destroy(source_resource);
- wl_resource_post_no_memory(resource);
- return;
- }
-
- wl_resource_set_implementation(source_resource, &data_source_impl,
- source, data_source_resource_handle_destroy);
-}
-
-static const struct wl_data_device_manager_interface
- data_device_manager_impl = {
- .create_data_source = data_device_manager_create_data_source,
- .get_data_device = data_device_manager_get_data_device,
-};
-
-static void data_device_manager_bind(struct wl_client *client,
- void *data, uint32_t version, uint32_t id) {
- struct wl_resource *resource = wl_resource_create(client,
- &wl_data_device_manager_interface,
- version, id);
- if (resource == NULL) {
- wl_client_post_no_memory(client);
- return;
- }
-
- wl_resource_set_implementation(resource, &data_device_manager_impl,
- NULL, NULL);
-}
-
-void wlr_data_device_manager_destroy(struct wlr_data_device_manager *manager) {
- if (!manager) {
- return;
- }
- wl_list_remove(&manager->display_destroy.link);
- // TODO: free wl_resources
- wl_global_destroy(manager->global);
- free(manager);
-}
-
-static void handle_display_destroy(struct wl_listener *listener, void *data) {
- struct wlr_data_device_manager *manager =
- wl_container_of(listener, manager, display_destroy);
- wlr_data_device_manager_destroy(manager);
-}
-
-struct wlr_data_device_manager *wlr_data_device_manager_create(
- struct wl_display *display) {
- struct wlr_data_device_manager *manager =
- calloc(1, sizeof(struct wlr_data_device_manager));
- if (manager == NULL) {
- wlr_log(L_ERROR, "could not create data device manager");
- return NULL;
- }
-
- manager->global =
- wl_global_create(display, &wl_data_device_manager_interface,
- 3, NULL, data_device_manager_bind);
- if (!manager->global) {
- wlr_log(L_ERROR, "could not create data device manager wl global");
- free(manager);
- return NULL;
- }
-
- manager->display_destroy.notify = handle_display_destroy;
- wl_display_add_destroy_listener(display, &manager->display_destroy);
-
- return manager;
-}
diff --git a/types/wlr_seat.c b/types/wlr_seat.c
deleted file mode 100644
index f77a492d..00000000
--- a/types/wlr_seat.c
+++ /dev/null
@@ -1,1271 +0,0 @@
-#define _POSIX_C_SOURCE 200809L
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <wayland-server.h>
-#include <wlr/types/wlr_data_device.h>
-#include <wlr/types/wlr_input_device.h>
-#include <wlr/types/wlr_primary_selection.h>
-#include <wlr/types/wlr_seat.h>
-#include <wlr/util/log.h>
-#include "util/signal.h"
-
-static void resource_destroy(struct wl_client *client,
- struct wl_resource *resource) {
- wl_resource_destroy(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);
- }
-}
-
-static const struct wl_pointer_interface wl_pointer_impl;
-
-static struct wlr_seat_client *seat_client_from_pointer_resource(
- struct wl_resource *resource) {
- assert(wl_resource_instance_of(resource, &wl_pointer_interface,
- &wl_pointer_impl));
- return wl_resource_get_user_data(resource);
-}
-
-static void wl_pointer_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 wlr_seat_client *seat_client =
- seat_client_from_pointer_resource(pointer_resource);
- struct wlr_surface *surface = NULL;
- if (surface_resource != NULL) {
- surface = wlr_surface_from_resource(surface_resource);
-
- if (wlr_surface_set_role(surface, "wl_pointer-cursor", surface_resource,
- WL_POINTER_ERROR_ROLE) < 0) {
- return;
- }
- }
-
- struct wlr_seat_pointer_request_set_cursor_event *event =
- calloc(1, sizeof(struct wlr_seat_pointer_request_set_cursor_event));
- if (event == NULL) {
- return;
- }
- event->seat_client = seat_client;
- event->surface = surface;
- event->serial = serial;
- event->hotspot_x = hotspot_x;
- event->hotspot_y = hotspot_y;
-
- wlr_signal_emit_safe(&seat_client->seat->events.request_set_cursor, event);
-
- free(event);
-}
-
-static const struct wl_pointer_interface wl_pointer_impl = {
- .set_cursor = wl_pointer_set_cursor,
- .release = resource_destroy,
-};
-
-static void wl_pointer_destroy(struct wl_resource *resource) {
- wl_list_remove(wl_resource_get_link(resource));
-}
-
-static void wl_seat_get_pointer(struct wl_client *client,
- struct wl_resource *seat_resource, uint32_t id) {
- struct wlr_seat_client *seat_client =
- wlr_seat_client_from_resource(seat_resource);
- if (!(seat_client->seat->capabilities & WL_SEAT_CAPABILITY_POINTER)) {
- return;
- }
-
- struct wl_resource *resource = wl_resource_create(client,
- &wl_pointer_interface, wl_resource_get_version(seat_resource), id);
- if (resource == NULL) {
- wl_resource_post_no_memory(seat_resource);
- return;
- }
- wl_resource_set_implementation(resource, &wl_pointer_impl, seat_client,
- &wl_pointer_destroy);
- wl_list_insert(&seat_client->pointers, wl_resource_get_link(resource));
-}
-
-static const struct wl_keyboard_interface wl_keyboard_impl = {
- .release = resource_destroy,
-};
-
-static void wl_keyboard_destroy(struct wl_resource *resource) {
- wl_list_remove(wl_resource_get_link(resource));
-}
-
-static void seat_client_send_keymap(struct wlr_seat_client *client,
- struct wlr_keyboard *keyboard) {
- if (!keyboard) {
- return;
- }
-
- // TODO: We should probably lift all of the keys set by the other
- // keyboard
- struct wl_resource *resource;
- wl_resource_for_each(resource, &client->keyboards) {
- wl_keyboard_send_keymap(resource,
- WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keyboard->keymap_fd,
- keyboard->keymap_size);
- }
-}
-
-static void seat_client_send_repeat_info(struct wlr_seat_client *client,
- struct wlr_keyboard *keyboard) {
- if (!keyboard) {
- return;
- }
-
- struct wl_resource *resource;
- wl_resource_for_each(resource, &client->keyboards) {
- if (wl_resource_get_version(resource) >=
- WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) {
- wl_keyboard_send_repeat_info(resource,
- keyboard->repeat_info.rate, keyboard->repeat_info.delay);
- }
- }
-}
-
-static void wl_seat_get_keyboard(struct wl_client *client,
- struct wl_resource *seat_resource, uint32_t id) {
- struct wlr_seat_client *seat_client =
- wlr_seat_client_from_resource(seat_resource);
- if (!(seat_client->seat->capabilities & WL_SEAT_CAPABILITY_KEYBOARD)) {
- return;
- }
-
- struct wl_resource *resource = wl_resource_create(client,
- &wl_keyboard_interface, wl_resource_get_version(seat_resource), id);
- if (resource == NULL) {
- wl_resource_post_no_memory(seat_resource);
- return;
- }
- wl_resource_set_implementation(resource, &wl_keyboard_impl, seat_client,
- &wl_keyboard_destroy);
- wl_list_insert(&seat_client->keyboards, wl_resource_get_link(resource));
-
- struct wlr_keyboard *keyboard = seat_client->seat->keyboard_state.keyboard;
- seat_client_send_keymap(seat_client, keyboard);
- seat_client_send_repeat_info(seat_client, keyboard);
-
- // TODO possibly handle the case where this keyboard needs an enter
- // right away
-}
-
-static const struct wl_touch_interface wl_touch_impl = {
- .release = resource_destroy,
-};
-
-static void wl_touch_destroy(struct wl_resource *resource) {
- wl_list_remove(wl_resource_get_link(resource));
-}
-
-static void wl_seat_get_touch(struct wl_client *client,
- struct wl_resource *seat_resource, uint32_t id) {
- struct wlr_seat_client *seat_client =
- wlr_seat_client_from_resource(seat_resource);
- if (!(seat_client->seat->capabilities & WL_SEAT_CAPABILITY_TOUCH)) {
- return;
- }
-
- struct wl_resource *resource = wl_resource_create(client,
- &wl_touch_interface, wl_resource_get_version(seat_resource), id);
- if (resource == NULL) {
- wl_resource_post_no_memory(seat_resource);
- return;
- }
- wl_resource_set_implementation(resource, &wl_touch_impl, seat_client,
- &wl_touch_destroy);
- wl_list_insert(&seat_client->touches, wl_resource_get_link(resource));
-}
-
-static void seat_client_resource_destroy(struct wl_resource *seat_resource) {
- struct wlr_seat_client *client =
- wlr_seat_client_from_resource(seat_resource);
- wlr_signal_emit_safe(&client->events.destroy, client);
-
- if (client == client->seat->pointer_state.focused_client) {
- client->seat->pointer_state.focused_client = NULL;
- }
- if (client == client->seat->keyboard_state.focused_client) {
- client->seat->keyboard_state.focused_client = NULL;
- }
-
- struct wl_resource *resource, *tmp;
- wl_resource_for_each_safe(resource, tmp, &client->pointers) {
- wl_resource_destroy(resource);
- }
- wl_resource_for_each_safe(resource, tmp, &client->keyboards) {
- wl_resource_destroy(resource);
- }
- wl_resource_for_each_safe(resource, tmp, &client->touches) {
- wl_resource_destroy(resource);
- }
- wl_resource_for_each_safe(resource, tmp, &client->data_devices) {
- wl_resource_destroy(resource);
- }
- wl_resource_for_each_safe(resource, tmp, &client->primary_selection_devices) {
- wl_resource_destroy(resource);
- }
-
- wl_list_remove(&client->link);
- free(client);
-}
-
-struct wl_seat_interface wl_seat_impl = {
- .get_pointer = wl_seat_get_pointer,
- .get_keyboard = wl_seat_get_keyboard,
- .get_touch = wl_seat_get_touch,
- .release = resource_destroy,
-};
-
-static void wl_seat_bind(struct wl_client *client, void *_wlr_seat,
- uint32_t version, uint32_t id) {
- struct wlr_seat *wlr_seat = _wlr_seat;
- assert(client && wlr_seat);
-
- struct wlr_seat_client *seat_client =
- calloc(1, sizeof(struct wlr_seat_client));
- if (seat_client == NULL) {
- wl_client_post_no_memory(client);
- return;
- }
- seat_client->wl_resource =
- wl_resource_create(client, &wl_seat_interface, version, id);
- if (seat_client->wl_resource == NULL) {
- free(seat_client);
- wl_client_post_no_memory(client);
- return;
- }
- seat_client->client = client;
- seat_client->seat = wlr_seat;
- wl_list_init(&seat_client->pointers);
- wl_list_init(&seat_client->keyboards);
- wl_list_init(&seat_client->touches);
- wl_list_init(&seat_client->data_devices);
- wl_list_init(&seat_client->primary_selection_devices);
- wl_resource_set_implementation(seat_client->wl_resource, &wl_seat_impl,
- seat_client, seat_client_resource_destroy);
- wl_list_insert(&wlr_seat->clients, &seat_client->link);
- if (version >= WL_SEAT_NAME_SINCE_VERSION) {
- wl_seat_send_name(seat_client->wl_resource, wlr_seat->name);
- }
- wl_seat_send_capabilities(seat_client->wl_resource, wlr_seat->capabilities);
- wl_signal_init(&seat_client->events.destroy);
-}
-
-static void default_pointer_enter(struct wlr_seat_pointer_grab *grab,
- struct wlr_surface *surface, double sx, double sy) {
- wlr_seat_pointer_enter(grab->seat, surface, sx, sy);
-}
-
-static void default_pointer_motion(struct wlr_seat_pointer_grab *grab,
- uint32_t time, double sx, double sy) {
- wlr_seat_pointer_send_motion(grab->seat, time, sx, sy);
-}
-
-static uint32_t default_pointer_button(struct wlr_seat_pointer_grab *grab,
- uint32_t time, uint32_t button, uint32_t state) {
- return wlr_seat_pointer_send_button(grab->seat, time, button, state);
-}
-
-static void default_pointer_axis(struct wlr_seat_pointer_grab *grab,
- uint32_t time, enum wlr_axis_orientation orientation, double value) {
- wlr_seat_pointer_send_axis(grab->seat, time, orientation, value);
-}
-
-static void default_pointer_cancel(struct wlr_seat_pointer_grab *grab) {
- // cannot be cancelled
-}
-
-static const struct wlr_pointer_grab_interface default_pointer_grab_impl = {
- .enter = default_pointer_enter,
- .motion = default_pointer_motion,
- .button = default_pointer_button,
- .axis = default_pointer_axis,
- .cancel = default_pointer_cancel,
-};
-
-static void default_keyboard_enter(struct wlr_seat_keyboard_grab *grab,
- struct wlr_surface *surface, uint32_t keycodes[], size_t num_keycodes,
- struct wlr_keyboard_modifiers *modifiers) {
- wlr_seat_keyboard_enter(grab->seat, surface, keycodes, num_keycodes, modifiers);
-}
-
-static void default_keyboard_key(struct wlr_seat_keyboard_grab *grab,
- uint32_t time, uint32_t key, uint32_t state) {
- wlr_seat_keyboard_send_key(grab->seat, time, key, state);
-}
-
-static void default_keyboard_modifiers(struct wlr_seat_keyboard_grab *grab,
- struct wlr_keyboard_modifiers *modifiers) {
- wlr_seat_keyboard_send_modifiers(grab->seat, modifiers);
-}
-
-static void default_keyboard_cancel(struct wlr_seat_keyboard_grab *grab) {
- // cannot be cancelled
-}
-
-static const struct wlr_keyboard_grab_interface default_keyboard_grab_impl = {
- .enter = default_keyboard_enter,
- .key = default_keyboard_key,
- .modifiers = default_keyboard_modifiers,
- .cancel = default_keyboard_cancel,
-};
-
-static uint32_t default_touch_down(struct wlr_seat_touch_grab *grab, uint32_t time,
- struct wlr_touch_point *point) {
- return wlr_seat_touch_send_down(grab->seat, point->surface, time,
- point->touch_id, point->sx, point->sy);
-}
-
-static void default_touch_up(struct wlr_seat_touch_grab *grab, uint32_t time,
- struct wlr_touch_point *point) {
- wlr_seat_touch_send_up(grab->seat, time, point->touch_id);
-}
-
-static void default_touch_motion(struct wlr_seat_touch_grab *grab,
- uint32_t time, struct wlr_touch_point *point) {
- if (!point->focus_surface || point->focus_surface == point->surface) {
- wlr_seat_touch_send_motion(grab->seat, time, point->touch_id, point->sx,
- point->sy);
- }
-}
-
-static void default_touch_enter(struct wlr_seat_touch_grab *grab,
- uint32_t time, struct wlr_touch_point *point) {
- // not handled by default
-}
-
-static void default_touch_cancel(struct wlr_seat_touch_grab *grab) {
- // cannot be cancelled
-}
-
-static const struct wlr_touch_grab_interface default_touch_grab_impl = {
- .down = default_touch_down,
- .up = default_touch_up,
- .motion = default_touch_motion,
- .enter = default_touch_enter,
- .cancel = default_touch_cancel,
-};
-
-
-void wlr_seat_destroy(struct wlr_seat *seat) {
- if (!seat) {
- return;
- }
-
- wlr_signal_emit_safe(&seat->events.destroy, seat);
-
- wl_list_remove(&seat->display_destroy.link);
-
- if (seat->selection_source) {
- wl_list_remove(&seat->selection_source_destroy.link);
- wlr_data_source_cancel(seat->selection_source);
- seat->selection_source = NULL;
- }
- if (seat->primary_selection_source) {
- seat->primary_selection_source->cancel(seat->primary_selection_source);
- seat->primary_selection_source = NULL;
- wl_list_remove(&seat->primary_selection_source_destroy.link);
- }
-
- struct wlr_seat_client *client, *tmp;
- wl_list_for_each_safe(client, tmp, &seat->clients, link) {
- // will destroy other resources as well
- wl_resource_destroy(client->wl_resource);
- }
-
- wl_global_destroy(seat->wl_global);
- free(seat->pointer_state.default_grab);
- free(seat->keyboard_state.default_grab);
- free(seat->touch_state.default_grab);
- free(seat->name);
- free(seat);
-}
-
-static void handle_display_destroy(struct wl_listener *listener, void *data) {
- struct wlr_seat *seat =
- wl_container_of(listener, seat, display_destroy);
- wlr_seat_destroy(seat);
-}
-
-struct wlr_seat *wlr_seat_create(struct wl_display *display, const char *name) {
- struct wlr_seat *wlr_seat = calloc(1, sizeof(struct wlr_seat));
- if (!wlr_seat) {
- return NULL;
- }
-
- // pointer state
- wlr_seat->pointer_state.seat = wlr_seat;
- wl_list_init(&wlr_seat->pointer_state.surface_destroy.link);
- wl_list_init(&wlr_seat->pointer_state.resource_destroy.link);
-
- struct wlr_seat_pointer_grab *pointer_grab =
- calloc(1, sizeof(struct wlr_seat_pointer_grab));
- if (!pointer_grab) {
- free(wlr_seat);
- return NULL;
- }
- pointer_grab->interface = &default_pointer_grab_impl;
- pointer_grab->seat = wlr_seat;
- wlr_seat->pointer_state.default_grab = pointer_grab;
- wlr_seat->pointer_state.grab = pointer_grab;
-
- // keyboard state
- struct wlr_seat_keyboard_grab *keyboard_grab =
- calloc(1, sizeof(struct wlr_seat_keyboard_grab));
- if (!keyboard_grab) {
- free(pointer_grab);
- free(wlr_seat);
- return NULL;
- }
- keyboard_grab->interface = &default_keyboard_grab_impl;
- keyboard_grab->seat = wlr_seat;
- wlr_seat->keyboard_state.default_grab = keyboard_grab;
- wlr_seat->keyboard_state.grab = keyboard_grab;
-
- wlr_seat->keyboard_state.seat = wlr_seat;
- wl_list_init(&wlr_seat->keyboard_state.resource_destroy.link);
- wl_list_init(
- &wlr_seat->keyboard_state.surface_destroy.link);
-
- // touch state
- struct wlr_seat_touch_grab *touch_grab =
- calloc(1, sizeof(struct wlr_seat_touch_grab));
- if (!touch_grab) {
- free(pointer_grab);
- free(keyboard_grab);
- free(wlr_seat);
- return NULL;
- }
- touch_grab->interface = &default_touch_grab_impl;
- touch_grab->seat = wlr_seat;
- wlr_seat->touch_state.default_grab = touch_grab;
- wlr_seat->touch_state.grab = touch_grab;
-
- wlr_seat->touch_state.seat = wlr_seat;
- wl_list_init(&wlr_seat->touch_state.touch_points);
-
- struct wl_global *wl_global = wl_global_create(display,
- &wl_seat_interface, 6, wlr_seat, wl_seat_bind);
- if (!wl_global) {
- free(wlr_seat);
- return NULL;
- }
- wlr_seat->wl_global = wl_global;
- wlr_seat->display = display;
- wlr_seat->name = strdup(name);
- wl_list_init(&wlr_seat->clients);
- wl_list_init(&wlr_seat->drag_icons);
-
- wl_signal_init(&wlr_seat->events.start_drag);
- wl_signal_init(&wlr_seat->events.new_drag_icon);
-
- wl_signal_init(&wlr_seat->events.request_set_cursor);
-
- wl_signal_init(&wlr_seat->events.selection);
- wl_signal_init(&wlr_seat->events.primary_selection);
-
- wl_signal_init(&wlr_seat->events.pointer_grab_begin);
- wl_signal_init(&wlr_seat->events.pointer_grab_end);
-
- wl_signal_init(&wlr_seat->events.keyboard_grab_begin);
- wl_signal_init(&wlr_seat->events.keyboard_grab_end);
-
- wl_signal_init(&wlr_seat->events.touch_grab_begin);
- wl_signal_init(&wlr_seat->events.touch_grab_end);
-
- wl_signal_init(&wlr_seat->events.destroy);
-
- wlr_seat->display_destroy.notify = handle_display_destroy;
- wl_display_add_destroy_listener(display, &wlr_seat->display_destroy);
-
- return wlr_seat;
-}
-
-struct wlr_seat_client *wlr_seat_client_for_wl_client(struct wlr_seat *wlr_seat,
- struct wl_client *wl_client) {
- assert(wlr_seat);
- struct wlr_seat_client *seat_client;
- wl_list_for_each(seat_client, &wlr_seat->clients, link) {
- if (seat_client->client == wl_client) {
- return seat_client;
- }
- }
- return NULL;
-}
-
-void wlr_seat_set_capabilities(struct wlr_seat *wlr_seat,
- uint32_t capabilities) {
- wlr_seat->capabilities = capabilities;
- struct wlr_seat_client *client;
- wl_list_for_each(client, &wlr_seat->clients, link) {
- wl_seat_send_capabilities(client->wl_resource, capabilities);
- }
-}
-
-void wlr_seat_set_name(struct wlr_seat *wlr_seat, const char *name) {
- free(wlr_seat->name);
- wlr_seat->name = strdup(name);
- struct wlr_seat_client *client;
- wl_list_for_each(client, &wlr_seat->clients, link) {
- wl_seat_send_name(client->wl_resource, name);
- }
-}
-
-bool wlr_seat_pointer_surface_has_focus(struct wlr_seat *wlr_seat,
- struct wlr_surface *surface) {
- return surface == wlr_seat->pointer_state.focused_surface;
-}
-
-static void pointer_surface_destroy_notify(struct wl_listener *listener,
- void *data) {
- struct wlr_seat_pointer_state *state = wl_container_of(
- listener, state, surface_destroy);
- wl_list_remove(&state->surface_destroy.link);
- wl_list_init(&state->surface_destroy.link);
- wlr_seat_pointer_clear_focus(state->seat);
-}
-
-static void pointer_resource_destroy_notify(struct wl_listener *listener,
- void *data) {
- struct wlr_seat_pointer_state *state = wl_container_of(
- listener, state, resource_destroy);
- wl_list_remove(&state->resource_destroy.link);
- wl_list_init(&state->resource_destroy.link);
- wlr_seat_pointer_clear_focus(state->seat);
-}
-
-void wlr_seat_pointer_enter(struct wlr_seat *wlr_seat,
- struct wlr_surface *surface, double sx, double sy) {
- assert(wlr_seat);
-
- if (wlr_seat->pointer_state.focused_surface == surface) {
- // this surface already got an enter notify
- return;
- }
-
- struct wlr_seat_client *client = NULL;
- if (surface) {
- struct wl_client *wl_client = wl_resource_get_client(surface->resource);
- client = wlr_seat_client_for_wl_client(wlr_seat, wl_client);
- }
-
- struct wlr_seat_client *focused_client =
- wlr_seat->pointer_state.focused_client;
- struct wlr_surface *focused_surface =
- wlr_seat->pointer_state.focused_surface;
-
- // leave the previously entered surface
- if (focused_client != NULL && focused_surface != NULL) {
- uint32_t serial = wl_display_next_serial(wlr_seat->display);
- struct wl_resource *resource;
- wl_resource_for_each(resource, &focused_client->pointers) {
- wl_pointer_send_leave(resource, serial, focused_surface->resource);
- pointer_send_frame(resource);
- }
- }
-
- // enter the current surface
- if (client != NULL && surface != NULL) {
- uint32_t serial = wl_display_next_serial(wlr_seat->display);
- struct wl_resource *resource;
- wl_resource_for_each(resource, &client->pointers) {
- wl_pointer_send_enter(resource, serial, surface->resource,
- wl_fixed_from_double(sx), wl_fixed_from_double(sy));
- pointer_send_frame(resource);
- }
- }
-
- // reinitialize the focus destroy events
- wl_list_remove(&wlr_seat->pointer_state.surface_destroy.link);
- wl_list_init(&wlr_seat->pointer_state.surface_destroy.link);
- wl_list_remove(&wlr_seat->pointer_state.resource_destroy.link);
- wl_list_init(&wlr_seat->pointer_state.resource_destroy.link);
- if (surface != NULL) {
- wl_signal_add(&surface->events.destroy,
- &wlr_seat->pointer_state.surface_destroy);
- wl_resource_add_destroy_listener(surface->resource,
- &wlr_seat->pointer_state.resource_destroy);
- wlr_seat->pointer_state.resource_destroy.notify =
- pointer_resource_destroy_notify;
- wlr_seat->pointer_state.surface_destroy.notify =
- pointer_surface_destroy_notify;
- }
-
- wlr_seat->pointer_state.focused_client = client;
- wlr_seat->pointer_state.focused_surface = surface;
-
- // TODO: send focus change event
-}
-
-void wlr_seat_pointer_clear_focus(struct wlr_seat *wlr_seat) {
- wlr_seat_pointer_enter(wlr_seat, NULL, 0, 0);
-}
-
-void wlr_seat_pointer_send_motion(struct wlr_seat *wlr_seat, uint32_t time,
- double sx, double sy) {
- struct wlr_seat_client *client = wlr_seat->pointer_state.focused_client;
- if (client == NULL) {
- return;
- }
-
- struct wl_resource *resource;
- wl_resource_for_each(resource, &client->pointers) {
- wl_pointer_send_motion(resource, time, wl_fixed_from_double(sx),
- wl_fixed_from_double(sy));
- pointer_send_frame(resource);
- }
-}
-
-uint32_t wlr_seat_pointer_send_button(struct wlr_seat *wlr_seat, uint32_t time,
- uint32_t button, uint32_t state) {
- struct wlr_seat_client *client = wlr_seat->pointer_state.focused_client;
- if (client == NULL) {
- return 0;
- }
-
- uint32_t serial = wl_display_next_serial(wlr_seat->display);
- struct wl_resource *resource;
- wl_resource_for_each(resource, &client->pointers) {
- wl_pointer_send_button(resource, serial, time, button, state);
- pointer_send_frame(resource);
- }
- return serial;
-}
-
-void wlr_seat_pointer_send_axis(struct wlr_seat *wlr_seat, uint32_t time,
- enum wlr_axis_orientation orientation, double value) {
- struct wlr_seat_client *client = wlr_seat->pointer_state.focused_client;
- if (client == NULL) {
- return;
- }
-
- struct wl_resource *resource;
- wl_resource_for_each(resource, &client->pointers) {
- if (value) {
- wl_pointer_send_axis(resource, time, orientation,
- wl_fixed_from_double(value));
- } else if (wl_resource_get_version(resource) >=
- WL_POINTER_AXIS_STOP_SINCE_VERSION) {
- wl_pointer_send_axis_stop(resource, time, orientation);
- }
- pointer_send_frame(resource);
- }
-}
-
-void wlr_seat_pointer_start_grab(struct wlr_seat *wlr_seat,
- struct wlr_seat_pointer_grab *grab) {
- assert(wlr_seat);
- grab->seat = wlr_seat;
- assert(grab->seat);
- wlr_seat->pointer_state.grab = grab;
-
- wlr_signal_emit_safe(&wlr_seat->events.pointer_grab_begin, grab);
-}
-
-void wlr_seat_pointer_end_grab(struct wlr_seat *wlr_seat) {
- struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab;
- if (grab != wlr_seat->pointer_state.default_grab) {
- wlr_seat->pointer_state.grab = wlr_seat->pointer_state.default_grab;
- wlr_signal_emit_safe(&wlr_seat->events.pointer_grab_end, grab);
- if (grab->interface->cancel) {
- grab->interface->cancel(grab);
- }
- }
-}
-
-void wlr_seat_pointer_notify_enter(struct wlr_seat *wlr_seat,
- struct wlr_surface *surface, double sx, double sy) {
- struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab;
- grab->interface->enter(grab, surface, sx, sy);
-}
-
-void wlr_seat_pointer_notify_motion(struct wlr_seat *wlr_seat, uint32_t time,
- double sx, double sy) {
- clock_gettime(CLOCK_MONOTONIC, &wlr_seat->last_event);
- struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab;
- grab->interface->motion(grab, time, sx, sy);
-}
-
-uint32_t wlr_seat_pointer_notify_button(struct wlr_seat *wlr_seat,
- uint32_t time, uint32_t button, uint32_t state) {
- clock_gettime(CLOCK_MONOTONIC, &wlr_seat->last_event);
- if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
- if (wlr_seat->pointer_state.button_count == 0) {
- wlr_seat->pointer_state.grab_button = button;
- wlr_seat->pointer_state.grab_time = time;
- }
- wlr_seat->pointer_state.button_count++;
- } else {
- wlr_seat->pointer_state.button_count--;
- }
-
- struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab;
- uint32_t serial = grab->interface->button(grab, time, button, state);
-
- if (serial && wlr_seat->pointer_state.button_count == 1) {
- wlr_seat->pointer_state.grab_serial = serial;
- }
-
- return serial;
-}
-
-void wlr_seat_pointer_notify_axis(struct wlr_seat *wlr_seat, uint32_t time,
- enum wlr_axis_orientation orientation, double value) {
- clock_gettime(CLOCK_MONOTONIC, &wlr_seat->last_event);
- struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab;
- grab->interface->axis(grab, time, orientation, value);
-}
-
-bool wlr_seat_pointer_has_grab(struct wlr_seat *seat) {
- return seat->pointer_state.grab->interface != &default_pointer_grab_impl;
-}
-
-void wlr_seat_keyboard_send_key(struct wlr_seat *wlr_seat, uint32_t time,
- uint32_t key, uint32_t state) {
- struct wlr_seat_client *client = wlr_seat->keyboard_state.focused_client;
- if (!client) {
- return;
- }
-
- uint32_t serial = wl_display_next_serial(wlr_seat->display);
- struct wl_resource *resource;
- wl_resource_for_each(resource, &client->keyboards) {
- wl_keyboard_send_key(resource, serial, time, key, state);
- }
-}
-
-static void handle_keyboard_keymap(struct wl_listener *listener, void *data) {
- struct wlr_seat_keyboard_state *state =
- wl_container_of(listener, state, keyboard_keymap);
- struct wlr_seat_client *client;
- struct wlr_keyboard *keyboard = data;
- if (keyboard == state->keyboard) {
- wl_list_for_each(client, &state->seat->clients, link) {
- seat_client_send_keymap(client, state->keyboard);
- }
- }
-}
-
-static void handle_keyboard_repeat_info(struct wl_listener *listener,
- void *data) {
- struct wlr_seat_keyboard_state *state =
- wl_container_of(listener, state, keyboard_repeat_info);
- struct wlr_seat_client *client;
- wl_list_for_each(client, &state->seat->clients, link) {
- seat_client_send_repeat_info(client, state->keyboard);
- }
-}
-
-static void handle_keyboard_destroy(struct wl_listener *listener, void *data) {
- struct wlr_seat_keyboard_state *state =
- wl_container_of(listener, state, keyboard_destroy);
- state->keyboard = NULL;
-}
-
-void wlr_seat_set_keyboard(struct wlr_seat *seat,
- struct wlr_input_device *device) {
- // TODO call this on device key event before the event reaches the
- // compositor and set a pending keyboard and then send the new keyboard
- // state on the next keyboard notify event.
- struct wlr_keyboard *keyboard = (device ? device->keyboard : NULL);
- if (seat->keyboard_state.keyboard == keyboard) {
- return;
- }
-
- if (seat->keyboard_state.keyboard) {
- wl_list_remove(&seat->keyboard_state.keyboard_destroy.link);
- wl_list_remove(&seat->keyboard_state.keyboard_keymap.link);
- wl_list_remove(&seat->keyboard_state.keyboard_repeat_info.link);
- seat->keyboard_state.keyboard = NULL;
- }
-
- if (keyboard) {
- assert(device->type == WLR_INPUT_DEVICE_KEYBOARD);
- seat->keyboard_state.keyboard = keyboard;
-
- wl_signal_add(&device->events.destroy,
- &seat->keyboard_state.keyboard_destroy);
- seat->keyboard_state.keyboard_destroy.notify = handle_keyboard_destroy;
- wl_signal_add(&device->keyboard->events.keymap,
- &seat->keyboard_state.keyboard_keymap);
- seat->keyboard_state.keyboard_keymap.notify = handle_keyboard_keymap;
- wl_signal_add(&device->keyboard->events.repeat_info,
- &seat->keyboard_state.keyboard_repeat_info);
- seat->keyboard_state.keyboard_repeat_info.notify =
- handle_keyboard_repeat_info;
-
- struct wlr_seat_client *client;
- wl_list_for_each(client, &seat->clients, link) {
- seat_client_send_keymap(client, keyboard);
- seat_client_send_repeat_info(client, keyboard);
- }
-
- wlr_seat_keyboard_send_modifiers(seat, &keyboard->modifiers);
- } else {
- seat->keyboard_state.keyboard = NULL;
- }
-}
-
-struct wlr_keyboard *wlr_seat_get_keyboard(struct wlr_seat *seat) {
- return seat->keyboard_state.keyboard;
-}
-
-void wlr_seat_keyboard_start_grab(struct wlr_seat *wlr_seat,
- struct wlr_seat_keyboard_grab *grab) {
- grab->seat = wlr_seat;
- wlr_seat->keyboard_state.grab = grab;
-
- wlr_signal_emit_safe(&wlr_seat->events.keyboard_grab_begin, grab);
-}
-
-void wlr_seat_keyboard_end_grab(struct wlr_seat *wlr_seat) {
- struct wlr_seat_keyboard_grab *grab = wlr_seat->keyboard_state.grab;
-
- if (grab != wlr_seat->keyboard_state.default_grab) {
- wlr_seat->keyboard_state.grab = wlr_seat->keyboard_state.default_grab;
- wlr_signal_emit_safe(&wlr_seat->events.keyboard_grab_end, grab);
- if (grab->interface->cancel) {
- grab->interface->cancel(grab);
- }
- }
-}
-
-static void keyboard_surface_destroy_notify(struct wl_listener *listener,
- void *data) {
- struct wlr_seat_keyboard_state *state = wl_container_of(
- listener, state, surface_destroy);
- wl_list_remove(&state->surface_destroy.link);
- wl_list_init(&state->surface_destroy.link);
- wlr_seat_keyboard_clear_focus(state->seat);
-}
-
-static void keyboard_resource_destroy_notify(struct wl_listener *listener,
- void *data) {
- struct wlr_seat_keyboard_state *state = wl_container_of(
- listener, state, resource_destroy);
- wl_list_remove(&state->resource_destroy.link);
- wl_list_init(&state->resource_destroy.link);
- wlr_seat_keyboard_clear_focus(state->seat);
-}
-
-void wlr_seat_keyboard_send_modifiers(struct wlr_seat *seat,
- struct wlr_keyboard_modifiers *modifiers) {
- struct wlr_seat_client *client = seat->keyboard_state.focused_client;
- if (client == NULL) {
- return;
- }
-
- uint32_t serial = wl_display_next_serial(seat->display);
- struct wl_resource *resource;
- wl_resource_for_each(resource, &client->keyboards) {
- if (modifiers == NULL) {
- 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);
- }
- }
-}
-
-void wlr_seat_keyboard_enter(struct wlr_seat *seat,
- struct wlr_surface *surface, uint32_t keycodes[], size_t num_keycodes,
- struct wlr_keyboard_modifiers *modifiers) {
- if (seat->keyboard_state.focused_surface == surface) {
- // this surface already got an enter notify
- return;
- }
-
- struct wlr_seat_client *client = NULL;
-
- if (surface) {
- struct wl_client *wl_client = wl_resource_get_client(surface->resource);
- client = wlr_seat_client_for_wl_client(seat, wl_client);
- }
-
- struct wlr_seat_client *focused_client =
- seat->keyboard_state.focused_client;
- struct wlr_surface *focused_surface =
- seat->keyboard_state.focused_surface;
-
- // leave the previously entered surface
- if (focused_client != NULL && focused_surface != NULL) {
- uint32_t serial = wl_display_next_serial(seat->display);
- struct wl_resource *resource;
- wl_resource_for_each(resource, &focused_client->keyboards) {
- wl_keyboard_send_leave(resource, serial, focused_surface->resource);
- }
- }
-
- // enter the current surface
- if (client != NULL) {
- struct wl_array keys;
- wl_array_init(&keys);
- for (size_t i = 0; i < num_keycodes; ++i) {
- uint32_t *p = wl_array_add(&keys, sizeof(uint32_t));
- if (!p) {
- wlr_log(L_ERROR, "Cannot allocate memory, skipping keycode: %d\n",
- keycodes[i]);
- continue;
- }
- *p = keycodes[i];
- }
- uint32_t serial = wl_display_next_serial(seat->display);
- struct wl_resource *resource;
- wl_resource_for_each(resource, &client->keyboards) {
- wl_keyboard_send_enter(resource, serial, surface->resource, &keys);
- }
- wl_array_release(&keys);
-
- wlr_seat_client_send_selection(client);
- wlr_seat_client_send_primary_selection(client);
- }
-
- // reinitialize the focus destroy events
- wl_list_remove(&seat->keyboard_state.surface_destroy.link);
- wl_list_init(&seat->keyboard_state.surface_destroy.link);
- wl_list_remove(&seat->keyboard_state.resource_destroy.link);
- wl_list_init(&seat->keyboard_state.resource_destroy.link);
- if (surface) {
- wl_signal_add(&surface->events.destroy,
- &seat->keyboard_state.surface_destroy);
- wl_resource_add_destroy_listener(surface->resource,
- &seat->keyboard_state.resource_destroy);
- seat->keyboard_state.resource_destroy.notify =
- keyboard_resource_destroy_notify;
- seat->keyboard_state.surface_destroy.notify =
- keyboard_surface_destroy_notify;
- }
-
- seat->keyboard_state.focused_client = client;
- seat->keyboard_state.focused_surface = surface;
-
- if (client != NULL) {
- // tell new client about any modifier change last,
- // as it targets seat->keyboard_state.focused_client
- wlr_seat_keyboard_send_modifiers(seat, modifiers);
- }
-}
-
-void wlr_seat_keyboard_notify_enter(struct wlr_seat *seat,
- struct wlr_surface *surface, uint32_t keycodes[], size_t num_keycodes,
- struct wlr_keyboard_modifiers *modifiers) {
- struct wlr_seat_keyboard_grab *grab = seat->keyboard_state.grab;
- grab->interface->enter(grab, surface, keycodes, num_keycodes, modifiers);
-}
-
-void wlr_seat_keyboard_clear_focus(struct wlr_seat *seat) {
- // TODO respect grabs here?
- wlr_seat_keyboard_enter(seat, NULL, NULL, 0, NULL);
-}
-
-bool wlr_seat_keyboard_has_grab(struct wlr_seat *seat) {
- return seat->keyboard_state.grab->interface != &default_keyboard_grab_impl;
-}
-
-void wlr_seat_keyboard_notify_modifiers(struct wlr_seat *seat,
- struct wlr_keyboard_modifiers *modifiers) {
- clock_gettime(CLOCK_MONOTONIC, &seat->last_event);
- struct wlr_seat_keyboard_grab *grab = seat->keyboard_state.grab;
- grab->interface->modifiers(grab, modifiers);
-}
-
-void wlr_seat_keyboard_notify_key(struct wlr_seat *seat, uint32_t time,
- uint32_t key, uint32_t state) {
- clock_gettime(CLOCK_MONOTONIC, &seat->last_event);
- struct wlr_seat_keyboard_grab *grab = seat->keyboard_state.grab;
- grab->interface->key(grab, time, key, state);
-}
-
-void wlr_seat_touch_start_grab(struct wlr_seat *wlr_seat,
- struct wlr_seat_touch_grab *grab) {
- grab->seat = wlr_seat;
- wlr_seat->touch_state.grab = grab;
-
- wlr_signal_emit_safe(&wlr_seat->events.touch_grab_begin, grab);
-}
-
-void wlr_seat_touch_end_grab(struct wlr_seat *wlr_seat) {
- struct wlr_seat_touch_grab *grab = wlr_seat->touch_state.grab;
-
- if (grab != wlr_seat->touch_state.default_grab) {
- wlr_seat->touch_state.grab = wlr_seat->touch_state.default_grab;
- wlr_signal_emit_safe(&wlr_seat->events.touch_grab_end, grab);
- if (grab->interface->cancel) {
- grab->interface->cancel(grab);
- }
- }
-}
-
-static void touch_point_clear_focus(struct wlr_touch_point *point) {
- if (point->focus_surface) {
- wl_list_remove(&point->focus_surface_destroy.link);
- point->focus_client = NULL;
- point->focus_surface = NULL;
- }
-}
-
-static void touch_point_destroy(struct wlr_touch_point *point) {
- wlr_signal_emit_safe(&point->events.destroy, point);
-
- touch_point_clear_focus(point);
- wl_list_remove(&point->surface_destroy.link);
- wl_list_remove(&point->resource_destroy.link);
- wl_list_remove(&point->link);
- free(point);
-}
-static void handle_touch_point_resource_destroy(struct wl_listener *listener,
- void *data) {
- struct wlr_touch_point *point =
- wl_container_of(listener, point, resource_destroy);
- touch_point_destroy(point);
-}
-
-static void handle_touch_point_surface_destroy(struct wl_listener *listener,
- void *data) {
- struct wlr_touch_point *point =
- wl_container_of(listener, point, surface_destroy);
- touch_point_destroy(point);
-}
-
-static struct wlr_touch_point *touch_point_create(
- struct wlr_seat *seat, int32_t touch_id,
- struct wlr_surface *surface, double sx, double sy) {
- struct wl_client *wl_client = wl_resource_get_client(surface->resource);
- struct wlr_seat_client *client = wlr_seat_client_for_wl_client(seat, wl_client);
-
- if (client == NULL || wl_list_empty(&client->touches)) {
- // touch points are not valid without a connected client with touch
- return NULL;
- }
-
- struct wlr_touch_point *point = calloc(1, sizeof(struct wlr_touch_point));
- if (!point) {
- return NULL;
- }
-
- point->touch_id = touch_id;
- point->surface = surface;
- point->client = client;
-
- point->sx = sx;
- point->sy = sy;
-
- wl_signal_init(&point->events.destroy);
-
- wl_signal_add(&surface->events.destroy, &point->surface_destroy);
- point->surface_destroy.notify = handle_touch_point_surface_destroy;
- wl_resource_add_destroy_listener(surface->resource,
- &point->resource_destroy);
- point->resource_destroy.notify = handle_touch_point_resource_destroy;
-
- wl_list_insert(&seat->touch_state.touch_points, &point->link);
-
- return point;
-}
-
-struct wlr_touch_point *wlr_seat_touch_get_point(
- struct wlr_seat *seat, int32_t touch_id) {
- struct wlr_touch_point *point = NULL;
- wl_list_for_each(point, &seat->touch_state.touch_points, link) {
- if (point->touch_id == touch_id) {
- return point;
- }
- }
-
- return NULL;
-}
-
-uint32_t wlr_seat_touch_notify_down(struct wlr_seat *seat,
- struct wlr_surface *surface, uint32_t time, int32_t touch_id, double sx,
- double sy) {
- clock_gettime(CLOCK_MONOTONIC, &seat->last_event);
- struct wlr_seat_touch_grab *grab = seat->touch_state.grab;
- struct wlr_touch_point *point =
- touch_point_create(seat, touch_id, surface, sx, sy);
- if (!point) {
- wlr_log(L_ERROR, "could not create touch point");
- return 0;
- }
-
- uint32_t serial = grab->interface->down(grab, time, point);
-
- if (serial && wlr_seat_touch_num_points(seat) == 1) {
- seat->touch_state.grab_serial = serial;
- seat->touch_state.grab_id = touch_id;
- }
-
- return serial;
-}
-
-void wlr_seat_touch_notify_up(struct wlr_seat *seat, uint32_t time,
- int32_t touch_id) {
- clock_gettime(CLOCK_MONOTONIC, &seat->last_event);
- struct wlr_seat_touch_grab *grab = seat->touch_state.grab;
- struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id);
- if (!point) {
- wlr_log(L_ERROR, "got touch up for unknown touch point");
- return;
- }
-
- grab->interface->up(grab, time, point);
-
- touch_point_destroy(point);
-}
-
-void wlr_seat_touch_notify_motion(struct wlr_seat *seat, uint32_t time,
- int32_t touch_id, double sx, double sy) {
- clock_gettime(CLOCK_MONOTONIC, &seat->last_event);
- struct wlr_seat_touch_grab *grab = seat->touch_state.grab;
- struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id);
- if (!point) {
- wlr_log(L_ERROR, "got touch motion for unknown touch point");
- return;
- }
-
- point->sx = sx;
- point->sy = sy;
-
- grab->interface->motion(grab, time, point);
-}
-
-static void handle_point_focus_destroy(struct wl_listener *listener,
- void *data) {
- struct wlr_touch_point *point =
- wl_container_of(listener, point, focus_surface_destroy);
- touch_point_clear_focus(point);
-}
-
-static void touch_point_set_focus(struct wlr_touch_point *point,
- struct wlr_surface *surface, double sx, double sy) {
- if (point->focus_surface == surface) {
- return;
- }
-
- touch_point_clear_focus(point);
-
- if (surface && surface->resource) {
- struct wlr_seat_client *client =
- wlr_seat_client_for_wl_client(point->client->seat,
- wl_resource_get_client(surface->resource));
-
- if (client && !wl_list_empty(&client->touches)) {
- wl_signal_add(&surface->events.destroy, &point->focus_surface_destroy);
- point->focus_surface_destroy.notify = handle_point_focus_destroy;
- point->focus_surface = surface;
- point->focus_client = client;
- point->sx = sx;
- point->sy = sy;
- }
- }
-}
-
-void wlr_seat_touch_point_focus(struct wlr_seat *seat,
- struct wlr_surface *surface, uint32_t time, int32_t touch_id, double sx,
- double sy) {
- assert(surface);
- struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id);
- if (!point) {
- wlr_log(L_ERROR, "got touch point focus for unknown touch point");
- return;
- }
- struct wlr_surface *focus = point->focus_surface;
- touch_point_set_focus(point, surface, sx, sy);
-
- if (focus != point->focus_surface) {
- struct wlr_seat_touch_grab *grab = seat->touch_state.grab;
- grab->interface->enter(grab, time, point);
- }
-}
-
-void wlr_seat_touch_point_clear_focus(struct wlr_seat *seat, uint32_t time,
- int32_t touch_id) {
- struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id);
- if (!point) {
- wlr_log(L_ERROR, "got touch point focus for unknown touch point");
- return;
- }
-
- touch_point_clear_focus(point);
-}
-
-uint32_t wlr_seat_touch_send_down(struct wlr_seat *seat,
- struct wlr_surface *surface, uint32_t time, int32_t touch_id, double sx,
- double sy) {
- struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id);
- if (!point) {
- wlr_log(L_ERROR, "got touch down for unknown touch point");
- return 0;
- }
-
- uint32_t serial = wl_display_next_serial(seat->display);
- struct wl_resource *resource;
- wl_resource_for_each(resource, &point->client->touches) {
- wl_touch_send_down(resource, serial, time, surface->resource,
- touch_id, wl_fixed_from_double(sx), wl_fixed_from_double(sy));
- wl_touch_send_frame(resource);
- }
-
- return serial;
-}
-
-void wlr_seat_touch_send_up(struct wlr_seat *seat, uint32_t time, int32_t touch_id) {
- struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id);
- if (!point) {
- wlr_log(L_ERROR, "got touch up for unknown touch point");
- return;
- }
-
- uint32_t serial = wl_display_next_serial(seat->display);
- struct wl_resource *resource;
- wl_resource_for_each(resource, &point->client->touches) {
- wl_touch_send_up(resource, serial, time, touch_id);
- wl_touch_send_frame(resource);
- }
-}
-
-void wlr_seat_touch_send_motion(struct wlr_seat *seat, uint32_t time, int32_t touch_id,
- double sx, double sy) {
- struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id);
- if (!point) {
- wlr_log(L_ERROR, "got touch motion for unknown touch point");
- return;
- }
-
- struct wl_resource *resource;
- wl_resource_for_each(resource, &point->client->touches) {
- wl_touch_send_motion(resource, time, touch_id, wl_fixed_from_double(sx),
- wl_fixed_from_double(sy));
- wl_touch_send_frame(resource);
- }
-}
-
-int wlr_seat_touch_num_points(struct wlr_seat *seat) {
- return wl_list_length(&seat->touch_state.touch_points);
-}
-
-bool wlr_seat_touch_has_grab(struct wlr_seat *seat) {
- return seat->touch_state.grab->interface != &default_touch_grab_impl;
-}
-
-bool wlr_seat_validate_grab_serial(struct wlr_seat *seat, uint32_t serial) {
- return true;
- //return serial == seat->pointer_state.grab_serial ||
- // serial == seat->touch_state.grab_serial;
-}
-
-struct wlr_seat_client *wlr_seat_client_from_resource(
- struct wl_resource *resource) {
- assert(wl_resource_instance_of(resource, &wl_seat_interface,
- &wl_seat_impl));
- return wl_resource_get_user_data(resource);
-}