summaryrefslogtreecommitdiffstats
path: root/transmitter-plugin/input.c
diff options
context:
space:
mode:
authorMarius Vlad <marius.vlad@collabora.com>2020-10-16 00:05:51 +0300
committerMarius Vlad <marius.vlad@collabora.com>2020-10-20 00:14:19 +0300
commit0e79ab59165bf925f1288476dad66109aa01b3fa (patch)
treecbabf8c3649c014fc996b97a753ec4e51e9f7949 /transmitter-plugin/input.c
parent13e791f0158ca79a0cfdb00613f69eaaf255da55 (diff)
Add waltham-transmitter-plugin
This adds the waltham-transmiter-plugin, which is a copy-pasta version of the wayland-ivi-plugins developed by ADIT-J. It has been split into a different repository. The major change from the initial version is the fact that remote output has been completely removed, and it only takes care of remote input. The renderer side has been moved/migrated into attic/ directory for further posterity. Bug-AGL: 3601 Signed-off-by: Marius Vlad <marius.vlad@collabora.com> Change-Id: Ifc1a6f58567d8b86cbe6e84dc1de79246dd95435
Diffstat (limited to 'transmitter-plugin/input.c')
-rw-r--r--transmitter-plugin/input.c1333
1 files changed, 1333 insertions, 0 deletions
diff --git a/transmitter-plugin/input.c b/transmitter-plugin/input.c
new file mode 100644
index 0000000..8fb543c
--- /dev/null
+++ b/transmitter-plugin/input.c
@@ -0,0 +1,1333 @@
+/*
+ * Copyright (C) 2017 Advanced Driver Information Technology Joint Venture GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+/* for fake stuff */
+#include <math.h>
+
+#include <wayland-client.h>
+#include <libweston/libweston.h>
+
+#include <weston.h>
+#include "plugin.h"
+#include "transmitter_api.h"
+
+/** @file
+ *
+ * This is an implementation of a remote input.
+ *
+ * Request wl_data_device_manager.get_data_device would need to be blocked,
+ * except maybe it's not necessary, we just "forget" to forward data to/from
+ * the remote wl_seat. It might still work inside the local compositor.
+ *
+ * weston_compositor_set_default_pointer_grab() will break our pointer
+ * implementation, but no in-tree code is calling it.
+ */
+
+/* XXX: all functions and variables with a name, and things marked with a
+ * comment, containing the word "fake" are mockups that need to be
+ * removed from the final implementation.
+ */
+
+static void
+pointer_focus_grab_handler(struct weston_pointer_grab *grab)
+{
+ /* No-op:
+ *
+ * Weston internal events do not change the focus.
+ */
+}
+
+static void
+pointer_motion_grab_handler(struct weston_pointer_grab *grab,
+ const struct timespec *time,
+ struct weston_pointer_motion_event *event)
+{
+ weston_log("Unexpected! %s(pointer=%p, ...)\n",
+ __func__, grab->pointer);
+}
+
+static void
+pointer_button_grab_handler(struct weston_pointer_grab *grab,
+ const struct timespec *time,
+ uint32_t button,
+ uint32_t state)
+{
+ weston_log("Unexpected! %s(pointer=%p, ...)\n",
+ __func__, grab->pointer);
+}
+
+static void
+pointer_axis_grab_handler(struct weston_pointer_grab *grab,
+ const struct timespec *time,
+ struct weston_pointer_axis_event *event)
+{
+ weston_log("Unexpected! %s(pointer=%p, ...)\n",
+ __func__, grab->pointer);
+}
+
+static void
+pointer_axis_source_grab_handler(struct weston_pointer_grab *grab,
+ uint32_t source)
+{
+ weston_log("Unexpected! %s(pointer=%p, ...)\n",
+ __func__, grab->pointer);
+}
+
+static void
+pointer_frame_grab_handler(struct weston_pointer_grab *grab)
+{
+ weston_log("Unexpected! %s(pointer=%p, ...)\n",
+ __func__, grab->pointer);
+}
+
+static void
+pointer_cancel_grab_handler(struct weston_pointer_grab *grab)
+{
+ weston_log("Unexpected! %s(pointer=%p, ...)\n",
+ __func__, grab->pointer);
+}
+
+/* These handlers would be called from the notify_*() functions in src/input.c.
+ * However, as we do not use the low level input notify_*() functions that
+ * backends drive, these are mostly uncalled, except the focus handler which
+ * weston core generates internally.
+ */
+static const struct weston_pointer_grab_interface pointer_grab_impl = {
+ pointer_focus_grab_handler,
+ pointer_motion_grab_handler,
+ pointer_button_grab_handler,
+ pointer_axis_grab_handler,
+ pointer_axis_source_grab_handler,
+ pointer_frame_grab_handler,
+ pointer_cancel_grab_handler,
+};
+
+static void
+keyboard_grab_key(struct weston_keyboard_grab *grab,
+ const struct timespec *time,
+ uint32_t key,
+ uint32_t state)
+{
+}
+
+static void
+keyboard_grab_modifiers(struct weston_keyboard_grab *grab,
+ uint32_t serial,
+ uint32_t mods_depressed,
+ uint32_t mods_latched,
+ uint32_t mods_locked,
+ uint32_t group)
+{
+}
+
+static void
+keyboard_grab_cancel(struct weston_keyboard_grab *grab)
+{
+}
+
+static const struct weston_keyboard_grab_interface keyborad_grab_impl = {
+ keyboard_grab_key,
+ keyboard_grab_modifiers,
+ keyboard_grab_cancel
+};
+
+static void
+touch_grab_down_handler(struct weston_touch_grab *grab,
+ const struct timespec *time,
+ int touch_id,
+ wl_fixed_t x,
+ wl_fixed_t y)
+{
+}
+
+static void
+touch_grab_up_handler(struct weston_touch_grab *grab,
+ const struct timespec *time,
+ int touch_id)
+{
+}
+
+static void
+touch_grab_motion_handler(struct weston_touch_grab *grab,
+ const struct timespec *time,
+ int touch_id,
+ wl_fixed_t x,
+ wl_fixed_t y)
+{
+}
+
+static void
+touch_grab_frame_handler(struct weston_touch_grab *grab)
+{
+}
+
+static void
+touch_grab_cancel_handler(struct weston_touch_grab *grab)
+{
+}
+
+static const struct weston_touch_grab_interface touch_grab_impl = {
+ touch_grab_down_handler,
+ touch_grab_up_handler,
+ touch_grab_motion_handler,
+ touch_grab_frame_handler,
+ touch_grab_cancel_handler,
+};
+
+static struct weston_pointer_client *
+weston_pointer_get_pointer_client(struct weston_pointer *pointer,
+ struct wl_client *client)
+{
+ struct weston_pointer_client *pointer_client;
+
+ wl_list_for_each(pointer_client, &pointer->pointer_clients, link) {
+ if (pointer_client->client == client)
+ return pointer_client;
+ }
+
+ return NULL;
+}
+
+/* The different ways to get pointer focus on a remoted surface:
+ *
+ * 1. Transmitter seat has pointer. The client has wl_pointer. Transmitter
+ * receives pointer.enter. (transmitter_seat_pointer_enter())
+ *
+ * 2. Transmitter seat has pointer. Transmitter has received pointer.enter.
+ * The client calls wl_seat.get_pointer. => send enter only on the new
+ * wl_pointer. (seat_get_pointer_handler())
+ *
+ * 3. Client has wl_pointer. Transmitter seat adds pointer capability.
+ * Transmitter receives pointer.enter. wl_pointer MUST NOT enter,
+ * specified by wl_seat.capabilities.
+ *
+ * By definition, Transmitter cannot receive pointer.enter without having
+ * pointer capability in the seat, so no other combinations are possible.
+ *
+ * The same applies to wl_keyboard and wl_touch.
+ */
+
+/* Implementor notes:
+ *
+ * The handling of all of wl_pointer, wl_keyboard and wl_touch should be
+ * similar. To make it work, we need to add a signal to each of the
+ * wl_seat.get_pointer, wl_seat.get_keyboard, and wl_seat.get_touch request
+ * handlers in Weston core. Otherwise we cannot implement the case 2 of gaining
+ * input device focus.
+ *
+ * However, weston_keyboard::focus is a weston_surface, not a weston_view, so
+ * we may be able to leverage more of the core implementation and maybe do
+ * without the wl_seat.get_keyboard signal. Weston_touch uses a weston_view, so
+ * that is similar to weston_pointer.
+ *
+ * It might be useful to convert weston_keyboard and weston_touch to use a
+ * similar thing as weston_pointer_client, in case it makes things more
+ * consistent. It might also fix issues when a client has multiple copies of a
+ * wl_keyboard or a wl_touch, but that is getting off-topic.
+ *
+ * This file shows which part of the Weston input path we skip and where we
+ * hook in. We skip everything starting from the notify_*() API used by
+ * backends, and stub out the grab handlers. Instead of actual grab handlers,
+ * we have our own network protocol events handlers. They do much of the same
+ * as normal grab handlers would do, except focus is pre-given, and we do not
+ * have weston_view for the focus surfaces, so we need to bypass core code
+ * dealing with those.
+ *
+ * Our remote seat implementation will leave many struct members unused and
+ * replicate some from weston_pointer, weston_keyboard, and weston_touch.
+ * Weston core must be kept out from the focus handling business, because we
+ * will send enter/leave events ourselves, and focus assignments are given
+ * to us from the remote, they cannot be changed at will by the local Weston.
+ */
+
+/** Callback from the protocol request handler for wl_seat.get_pointer
+ *
+ * The Weston core handler never sees focus set on the weston_pointer,
+ * so it won't send wl_pointer.enter nor set focus_client. It does call
+ * weston_pointer_ensure_pointer_client() though.
+ */
+void
+seat_get_pointer_handler(struct wl_listener *listener, void *data)
+{
+ struct wl_resource *new_pointer = data;
+ struct weston_transmitter_seat *seat;
+ struct wl_resource *surface;
+ struct weston_pointer_client *pointer_client;
+ struct wl_client *client;
+ struct weston_pointer *pointer;
+
+ seat = wl_container_of(listener, seat, get_pointer_listener);
+ if (!seat->pointer_focus)
+ return;
+
+ client = wl_resource_get_client(new_pointer);
+ surface = seat->pointer_focus->surface->resource;
+
+ if (wl_resource_get_client(surface) != client)
+ return;
+
+ pointer = weston_seat_get_pointer(seat->base);
+ assert(pointer); /* guaranteed by having pointer_focus */
+ pointer_client = weston_pointer_get_pointer_client(pointer, client);
+
+ if (!pointer->focus_client)
+ pointer->focus_client = pointer_client;
+ else
+ assert(pointer->focus_client == pointer_client);
+
+ wl_pointer_send_enter(new_pointer, pointer->focus_serial, surface,
+ seat->pointer_surface_x, seat->pointer_surface_y);
+
+ if (wl_resource_get_version(new_pointer) >=
+ WL_POINTER_FRAME_SINCE_VERSION)
+ wl_pointer_send_frame(new_pointer);
+}
+
+static void
+transmitter_seat_create_pointer(struct weston_transmitter_seat *seat)
+{
+ struct weston_pointer *pointer;
+
+ seat->pointer_phase = 0.0;
+ seat->pointer_surface_x = wl_fixed_from_int(-1000000);
+ seat->pointer_surface_y = wl_fixed_from_int(-1000000);
+ seat->pointer_focus = NULL;
+ wl_list_init(&seat->pointer_focus_destroy_listener.link);
+
+ weston_seat_init_pointer(seat->base);
+
+ pointer = weston_seat_get_pointer(seat->base);
+
+ /* not exported:
+ * weston_pointer_set_default_grab(pointer, &pointer_grab_impl); */
+ pointer->default_grab.interface = &pointer_grab_impl;
+
+ /* Changes to local outputs are irrelevant. */
+ wl_list_remove(&pointer->output_destroy_listener.link);
+ wl_list_init(&pointer->output_destroy_listener.link);
+
+ weston_log("Transmitter created pointer=%p for seat %p\n",
+ pointer, seat->base);
+}
+
+static void
+seat_pointer_focus_destroy_handler(struct wl_listener *listener, void *data)
+{
+ struct weston_transmitter_surface *txs = data;
+ struct weston_transmitter_seat *seat;
+
+ seat = wl_container_of(listener, seat, pointer_focus_destroy_listener);
+ assert(seat->pointer_focus == txs);
+
+ seat->pointer_focus = NULL;
+}
+
+void
+transmitter_seat_pointer_enter(struct weston_transmitter_seat *seat,
+ uint32_t serial,
+ struct weston_transmitter_surface *txs,
+ wl_fixed_t surface_x,
+ wl_fixed_t surface_y)
+{
+ struct weston_pointer *pointer;
+ struct wl_list *focus_resource_list;
+ struct wl_resource *resource;
+
+ pointer = weston_seat_get_pointer(seat->base);
+ assert(pointer);
+
+ assert(txs->surface);
+ //struct wl_client *client = wl_resource_get_client(txs->surface->resource);
+
+ seat->pointer_focus = txs;
+ seat->pointer_focus_destroy_listener.notify =
+ seat_pointer_focus_destroy_handler;
+ wl_signal_add(&txs->destroy_signal,
+ &seat->pointer_focus_destroy_listener);
+
+ /* If pointer-focus gets destroyed, txs will get destroyed, the
+ * remote surface object is destroyed, and the remote will send a
+ * leave and a frame.
+ */
+
+ seat->pointer_surface_x = surface_x;
+ seat->pointer_surface_y = surface_y;
+
+ pointer->focus_serial = serial;
+
+ /* pointer->focus is not used, because it is a weston_view, while
+ * remoted surfaces have no views.
+ *
+ * pointer->x,y are not used because they are in global coordinates.
+ * Remoted surfaces are not in the global space at all, so there are
+ * no such coordinates.
+ */
+
+ if (!pointer->focus_client)
+ return;
+
+ focus_resource_list = &pointer->focus_client->pointer_resources;
+ wl_resource_for_each(resource, focus_resource_list) {
+ wl_pointer_send_enter(resource,
+ serial,
+ txs->surface->resource,
+ surface_x, surface_y);
+ }
+}
+
+void
+transmitter_seat_pointer_leave(struct weston_transmitter_seat *seat,
+ uint32_t serial,
+ struct weston_transmitter_surface *txs)
+{
+ struct weston_pointer *pointer;
+ struct wl_list *focus_resource_list;
+ struct wl_resource *surface_resource;
+ struct wl_resource *resource;
+
+ if (txs != seat->pointer_focus) {
+ weston_log("Transmitter Warning: pointer leave for %p, expected %p\n",
+ txs, seat->pointer_focus);
+ }
+
+ seat->pointer_focus = NULL;
+ wl_list_remove(&seat->pointer_focus_destroy_listener.link);
+ wl_list_init(&seat->pointer_focus_destroy_listener.link);
+
+ if (!txs)
+ return;
+ assert(txs->surface);
+ surface_resource = txs->surface->resource;
+
+ pointer = weston_seat_get_pointer(seat->base);
+ assert(pointer);
+ if (!pointer->focus_client)
+ return;
+
+ focus_resource_list = &pointer->focus_client->pointer_resources;
+ wl_resource_for_each(resource, focus_resource_list)
+ wl_pointer_send_leave(resource, serial, surface_resource);
+
+ /* Do not reset pointer->focus_client, because we need to be able
+ * to send a following 'frame' event in
+ * transmitter_seat_pointer_frame().
+ */
+}
+
+void
+transmitter_seat_pointer_motion(struct weston_transmitter_seat *seat,
+ uint32_t time,
+ wl_fixed_t surface_x,
+ wl_fixed_t surface_y)
+{
+ struct weston_pointer *pointer;
+ struct wl_list *focus_resource_list;
+ struct wl_resource *resource;
+ struct weston_transmitter_surface *txs;
+
+ pointer = weston_seat_get_pointer(seat->base);
+ assert(pointer);
+
+ seat->pointer_surface_x = surface_x;
+ seat->pointer_surface_y = surface_y;
+
+ if (!pointer->focus_client)
+ return;
+
+ txs = seat->pointer_focus;
+ if (txs)
+ assert(wl_resource_get_client(txs->surface->resource) ==
+ pointer->focus_client->client);
+
+ focus_resource_list = &pointer->focus_client->pointer_resources;
+ wl_resource_for_each(resource, focus_resource_list) {
+ wl_pointer_send_motion(resource, time,
+ surface_x, surface_y);
+ }
+}
+
+void
+transmitter_seat_pointer_button(struct weston_transmitter_seat *seat,
+ uint32_t serial,
+ uint32_t time,
+ uint32_t button,
+ uint32_t state)
+{
+ struct weston_pointer *pointer;
+ struct wl_list *focus_resource_list;
+ struct wl_resource *resource;
+ struct weston_transmitter_surface *txs;
+
+ pointer = weston_seat_get_pointer(seat->base);
+ assert(pointer);
+
+ if (!pointer->focus_client)
+ return;
+
+ txs = seat->pointer_focus;
+ if (txs)
+ assert(wl_resource_get_client(txs->surface->resource) ==
+ pointer->focus_client->client);
+
+ focus_resource_list = &pointer->focus_client->pointer_resources;
+ wl_resource_for_each(resource, focus_resource_list) {
+ wl_pointer_send_button(resource, serial, time,
+ button, state);
+ }
+}
+
+void
+transmitter_seat_pointer_axis(struct weston_transmitter_seat *seat,
+ uint32_t time,
+ uint32_t axis,
+ wl_fixed_t value)
+{
+ struct weston_pointer *pointer;
+ struct wl_list *focus_resource_list;
+ struct wl_resource *resource;
+ struct weston_transmitter_surface *txs;
+
+ pointer = weston_seat_get_pointer(seat->base);
+ assert(pointer);
+
+ if (!pointer->focus_client)
+ return;
+
+ txs = seat->pointer_focus;
+ if (txs)
+ assert(wl_resource_get_client(txs->surface->resource) ==
+ pointer->focus_client->client);
+
+ focus_resource_list = &pointer->focus_client->pointer_resources;
+ wl_resource_for_each(resource, focus_resource_list) {
+ wl_pointer_send_axis(resource, time,
+ axis, value);
+ }
+}
+
+void
+transmitter_seat_pointer_frame(struct weston_transmitter_seat *seat)
+{
+ struct weston_pointer *pointer;
+
+ pointer = weston_seat_get_pointer(seat->base);
+ if (pointer)
+ weston_pointer_send_frame(pointer);
+}
+
+void
+transmitter_seat_pointer_axis_source(struct weston_transmitter_seat *seat,
+ uint32_t axis_source)
+{
+ /* ToDo : implement axis event handling */
+}
+
+void
+transmitter_seat_pointer_axis_stop(struct weston_transmitter_seat *seat,
+ uint32_t time,
+ uint32_t axis)
+{
+ /* ToDo : implement axis event handling */
+}
+
+void
+transmitter_seat_pointer_axis_discrete(struct weston_transmitter_seat *seat,
+ uint32_t axis,
+ int32_t discrete)
+{
+ /* ToDo : implement axis event handling */
+}
+
+static void
+transmitter_seat_create_keyboard(struct weston_transmitter_seat *seat)
+{
+ struct weston_keyboard *keyboard;
+
+ seat->keyboard_focus = NULL;
+ weston_seat_init_keyboard(seat->base, NULL);
+
+ keyboard = weston_seat_get_keyboard(seat->base);
+
+ keyboard->default_grab.interface = &keyborad_grab_impl;
+
+ weston_log("Transmitter created keyboard=%p for seat %p\n",
+ keyboard, seat->base);
+}
+
+static void
+transmitter_seat_keyboard_enter(struct weston_transmitter_seat *seat,
+ uint32_t serial,
+ struct weston_transmitter_surface *txs,
+ struct wl_array *keys)
+{
+ struct weston_keyboard *keyboard;
+ struct wl_resource *resource = NULL;
+ struct wl_resource *surface_resource;
+
+ keyboard = weston_seat_get_keyboard(seat->base);
+ assert(keyboard);
+
+ assert(txs->surface);
+ surface_resource = txs->surface->resource;
+
+ seat->keyboard_focus = txs;
+ wl_array_copy(&keyboard->keys, keys);
+
+ wl_resource_for_each(resource, &keyboard->resource_list) {
+ if (wl_resource_get_client(resource) == wl_resource_get_client(surface_resource)) {
+ wl_keyboard_send_enter(resource,
+ serial,
+ surface_resource,
+ &keyboard->keys);
+ }
+ }
+}
+
+static void
+transmitter_seat_keyboard_leave(struct weston_transmitter_seat *seat,
+ uint32_t serial,
+ struct weston_transmitter_surface *txs)
+{
+ struct weston_keyboard *keyboard;
+ struct wl_resource *resource = NULL;
+ struct wl_resource *surface_resource;
+
+ keyboard = weston_seat_get_keyboard(seat->base);
+ assert(keyboard);
+
+ assert(txs->surface);
+ surface_resource = txs->surface->resource;
+
+ wl_resource_for_each(resource, &keyboard->resource_list) {
+ if (wl_resource_get_client(resource) == wl_resource_get_client(surface_resource)) {
+ wl_keyboard_send_leave(resource,
+ serial,
+ surface_resource);
+ }
+ }
+}
+
+static void
+transmitter_seat_keyboard_key(struct weston_transmitter_seat *seat,
+ uint32_t serial,
+ uint32_t time,
+ uint32_t key,
+ uint32_t state)
+{
+ struct weston_keyboard *keyboard;
+ struct wl_resource *resource = NULL;
+
+ keyboard = weston_seat_get_keyboard(seat->base);
+ assert(keyboard);
+
+ wl_resource_for_each(resource, &keyboard->resource_list) {
+ if (wl_resource_get_client(resource) ==
+ wl_resource_get_client(seat->keyboard_focus->surface->resource)) {
+ wl_keyboard_send_key(resource,
+ serial,
+ time,
+ key,
+ state);
+ }
+ }
+}
+
+static void
+transmitter_seat_create_touch(struct weston_transmitter_seat *seat)
+{
+ struct weston_touch *touch;
+
+ seat->touch_focus = NULL;
+ weston_seat_init_touch(seat->base);
+
+ touch = weston_seat_get_touch(seat->base);
+
+ touch->default_grab.interface = &touch_grab_impl;
+
+ weston_log("Transmitter created touch=%p for seat %p\n",
+ touch, seat->base);
+}
+
+static void
+transmitter_seat_touch_down (struct weston_transmitter_seat *seat,
+ uint32_t serial,
+ uint32_t time,
+ struct weston_transmitter_surface *txs,
+ int32_t touch_id,
+ wl_fixed_t x,
+ wl_fixed_t y)
+{
+ struct weston_touch *touch;
+ struct wl_resource *resource = NULL;
+ struct wl_resource *surface_resource;
+
+ touch = weston_seat_get_touch(seat->base);
+ assert(touch);
+
+ assert(txs->surface);
+ surface_resource = txs->surface->resource;
+
+ seat->touch_focus = txs;
+
+ wl_resource_for_each(resource, &touch->resource_list) {
+ if (wl_resource_get_client(resource) == wl_resource_get_client(surface_resource)) {
+ wl_touch_send_down(resource, serial, time,
+ surface_resource,
+ touch_id, x, y);
+ }
+ }
+}
+
+static void
+transmitter_seat_touch_up (struct weston_transmitter_seat *seat,
+ uint32_t serial,
+ uint32_t time,
+ int32_t touch_id)
+{
+ struct weston_touch *touch;
+ struct wl_resource *resource = NULL;
+
+ touch = weston_seat_get_touch(seat->base);
+ assert(touch);
+
+ wl_resource_for_each(resource, &touch->resource_list) {
+ if (wl_resource_get_client(resource) ==
+ wl_resource_get_client(seat->touch_focus->surface->resource)) {
+ wl_touch_send_up(resource, serial, time, touch_id);
+ }
+ }
+}
+
+static void
+transmitter_seat_touch_motion (struct weston_transmitter_seat *seat,
+ uint32_t time,
+ int32_t touch_id,
+ wl_fixed_t x,
+ wl_fixed_t y)
+{
+ struct weston_touch *touch;
+ struct wl_resource *resource = NULL;
+
+ touch = weston_seat_get_touch(seat->base);
+ assert(touch);
+
+ wl_resource_for_each(resource, &touch->resource_list) {
+ if (wl_resource_get_client(resource) ==
+ wl_resource_get_client(seat->touch_focus->surface->resource)) {
+ wl_touch_send_motion(resource, time, touch_id, x, y);
+ }
+ }
+}
+
+static void
+transmitter_seat_touch_frame (struct weston_transmitter_seat *seat)
+{
+ struct weston_touch *touch;
+ struct wl_resource *resource = NULL;
+
+ touch = weston_seat_get_touch(seat->base);
+ assert(touch);
+
+ wl_resource_for_each(resource, &touch->resource_list) {
+ if (wl_resource_get_client(resource) ==
+ wl_resource_get_client(seat->touch_focus->surface->resource)) {
+ wl_touch_send_frame(resource);
+ }
+ }
+}
+
+static void
+transmitter_seat_touch_cancel (struct weston_transmitter_seat *seat)
+{
+ struct weston_touch *touch;
+ struct wl_resource *resource = NULL;
+
+ touch = weston_seat_get_touch(seat->base);
+ assert(touch);
+
+ wl_resource_for_each(resource, &touch->resource_list) {
+ if (wl_resource_get_client(resource) ==
+ wl_resource_get_client(seat->touch_focus->surface->resource)) {
+ wl_touch_send_cancel(resource);
+ }
+ }
+}
+
+static char *
+make_seat_name(struct weston_transmitter_remote *remote, const char *name)
+{
+ char *str;
+
+ if (asprintf(&str, "transmitter-%s-%s", remote->addr, name) < 0)
+ return NULL;
+
+ return str;
+}
+
+void
+transmitter_seat_destroy(struct weston_transmitter_seat *seat)
+{
+ wl_list_remove(&seat->link);
+
+ weston_log("Transmitter destroy seat=%p\n", seat->base);
+
+ wl_list_remove(&seat->get_pointer_listener.link);
+ wl_list_remove(&seat->pointer_focus_destroy_listener.link);
+
+ if (seat->pointer_timer)
+ wl_event_source_remove(seat->pointer_timer);
+
+ free(seat);
+}
+
+static void
+pointer_handle_enter(struct wthp_pointer *wthp_pointer,
+ uint32_t serial,
+ struct wthp_surface *surface,
+ wth_fixed_t surface_x,
+ wth_fixed_t surface_y)
+{
+ struct waltham_display *dpy =
+ wth_object_get_user_data((struct wth_object *)wthp_pointer);
+ struct weston_transmitter_remote *remote = dpy->remote;
+ struct wl_list *seat_list = &remote->seat_list;
+ struct weston_transmitter_seat *seat;
+ struct weston_transmitter_surface *txs;
+
+ seat = wl_container_of(seat_list->next, seat, link);
+
+ wl_list_for_each(txs, &remote->surface_list, link)
+ {
+ if (txs->wthp_surf == surface) {
+ if (txs != seat->pointer_focus)
+ transmitter_seat_pointer_leave(seat, serial, seat->pointer_focus);
+ transmitter_seat_pointer_enter(seat, serial, txs,
+ surface_x, surface_y);
+ }
+ }
+}
+
+static void
+pointer_handle_leave(struct wthp_pointer *wthp_pointer,
+ uint32_t serial,
+ struct wthp_surface *surface)
+{
+ struct waltham_display *dpy =
+ wth_object_get_user_data((struct wth_object *)wthp_pointer);
+ struct weston_transmitter_remote *remote = dpy->remote;
+ struct wl_list *seat_list = &remote->seat_list;
+ struct weston_transmitter_seat *seat;
+ struct weston_transmitter_surface *txs;
+
+ seat = wl_container_of(seat_list->next, seat, link);
+
+ wl_list_for_each(txs, &remote->surface_list, link)
+ {
+ if (txs->wthp_surf == surface) {
+ transmitter_seat_pointer_leave(seat, serial, txs);
+ }
+ }
+}
+
+static void
+pointer_handle_motion(struct wthp_pointer *wthp_pointer,
+ uint32_t time,
+ wth_fixed_t surface_x,
+ wth_fixed_t surface_y)
+{
+ struct waltham_display *dpy =
+ wth_object_get_user_data((struct wth_object *)wthp_pointer);
+ struct weston_transmitter_remote *remote = dpy->remote;
+ struct wl_list *seat_list = &remote->seat_list;
+ struct weston_transmitter_seat *seat;
+
+ seat = wl_container_of(seat_list->next, seat, link);
+
+ transmitter_seat_pointer_motion(seat, time,
+ surface_x,
+ surface_y);
+}
+
+static void
+pointer_handle_button(struct wthp_pointer *wthp_pointer,
+ uint32_t serial,
+ uint32_t time,
+ uint32_t button,
+ uint32_t state)
+{
+ struct waltham_display *dpy =
+ wth_object_get_user_data((struct wth_object *)wthp_pointer);
+ struct weston_transmitter_remote *remote = dpy->remote;
+ struct wl_list *seat_list = &remote->seat_list;
+ struct weston_transmitter_seat *seat;
+
+ seat = wl_container_of(seat_list->next, seat, link);
+
+ transmitter_seat_pointer_button(seat, serial,
+ time, button,
+ state);
+}
+
+static void
+pointer_handle_axis(struct wthp_pointer *wthp_pointer,
+ uint32_t time,
+ uint32_t axis, wth_fixed_t value)
+{
+ struct waltham_display *dpy =
+ wth_object_get_user_data((struct wth_object *)wthp_pointer);
+ struct weston_transmitter_remote *remote = dpy->remote;
+ struct wl_list *seat_list = &remote->seat_list;
+ struct weston_transmitter_seat *seat;
+
+ seat = wl_container_of(seat_list->next, seat, link);
+
+ transmitter_seat_pointer_axis(seat, time,
+ axis, value);
+}
+
+static void
+pointer_handle_frame(struct wthp_pointer *wthp_pointer)
+{
+ /* ToDo : implement pointer handle frame */
+}
+
+static void
+pointer_handle_axis_source(struct wthp_pointer *wthp_pointer,
+ uint32_t axis_source)
+{
+ /* ToDo : implement pointer handle axis source */
+}
+
+static void
+pointer_handle_axis_stop(struct wthp_pointer *wthp_pointer,
+ uint32_t time,
+ uint32_t axis)
+{
+ /* ToDo : implement pointer handle axis stop */
+}
+
+static void
+pointer_handle_axis_discrete(struct wthp_pointer *wthp_pointer,
+ uint32_t axis,
+ int32_t discrete)
+{
+ /* ToDo : implement pointer handle axis discrete */
+}
+
+static const struct wthp_pointer_listener pointer_listener = {
+ pointer_handle_enter,
+ pointer_handle_leave,
+ pointer_handle_motion,
+ pointer_handle_button,
+ pointer_handle_axis,
+ pointer_handle_frame,
+ pointer_handle_axis_source,
+ pointer_handle_axis_stop,
+ pointer_handle_axis_discrete
+};
+
+static void
+keyboard_handle_keymap(struct wthp_keyboard * wthp_keyboard,
+ uint32_t format,
+ uint32_t keymap_sz,
+ void * keymap)
+{
+ /* ToDo : implement keyboard handle keymap */
+}
+
+static void
+keyboard_handle_enter(struct wthp_keyboard *wthp_keyboard,
+ uint32_t serial,
+ struct wthp_surface *surface,
+ struct wth_array *keys)
+{
+ struct waltham_display *dpy =
+ wth_object_get_user_data((struct wth_object *)wthp_keyboard);
+ struct weston_transmitter_remote *remote = dpy->remote;
+ struct wl_list *seat_list = &remote->seat_list;
+ struct weston_transmitter_seat *seat;
+ struct weston_transmitter_surface *txs;
+ struct wl_array *wl_key = (struct wl_array *)malloc(sizeof(struct wl_array));
+
+ wl_key->size = keys->size;
+ wl_key->alloc = keys->alloc;
+ wl_key->data = keys->data;
+
+ seat = wl_container_of(seat_list->next, seat, link);
+
+ wl_list_for_each(txs, &remote->surface_list, link)
+ {
+ if (txs->wthp_surf == surface) {
+ //transmitter_seat_keyboard_enter(seat, serial, txs, keys);
+ transmitter_seat_keyboard_enter(seat, serial, txs, wl_key);
+ }
+ }
+ free(wl_key);
+}
+
+static void
+keyboard_handle_leave(struct wthp_keyboard *wthp_keyboard,
+ uint32_t serial,
+ struct wthp_surface *surface)
+{
+ struct waltham_display *dpy =
+ wth_object_get_user_data((struct wth_object *)wthp_keyboard);
+ struct weston_transmitter_remote *remote = dpy->remote;
+ struct wl_list *seat_list = &remote->seat_list;
+ struct weston_transmitter_seat *seat;
+ struct weston_transmitter_surface *txs;
+
+ seat = wl_container_of(seat_list->next, seat, link);
+
+ wl_list_for_each(txs, &remote->surface_list, link)
+ {
+ if (txs->wthp_surf == surface) {
+ transmitter_seat_keyboard_leave(seat, serial, txs);
+ }
+ }
+}
+
+static void
+keyboard_handle_key(struct wthp_keyboard *wthp_keyboard,
+ uint32_t serial,
+ uint32_t time,
+ uint32_t key,
+ uint32_t state)
+{
+ struct waltham_display *dpy =
+ wth_object_get_user_data((struct wth_object *)wthp_keyboard);
+ struct weston_transmitter_remote *remote = dpy->remote;
+ struct wl_list *seat_list = &remote->seat_list;
+ struct weston_transmitter_seat *seat;
+
+ seat = wl_container_of(seat_list->next, seat, link);
+
+ transmitter_seat_keyboard_key(seat, serial, time, key, state);
+}
+
+static void
+keyboard_handle_modifiers(struct wthp_keyboard *wthp_keyboard,
+ uint32_t serial,
+ uint32_t mods_depressed,
+ uint32_t mods_latched,
+ uint32_t mods_locked,
+ uint32_t group)
+{
+ weston_log("keyboard_handle_modifiers\n");
+}
+
+static void
+keyboard_handle_repeat_info(struct wthp_keyboard *wthp_keyboard,
+ int32_t rate,
+ int32_t delay)
+{
+ weston_log("keyboard_handle_repeat_info\n");
+}
+
+static const struct wthp_keyboard_listener keyboard_listener = {
+ keyboard_handle_keymap,
+ keyboard_handle_enter,
+ keyboard_handle_leave,
+ keyboard_handle_key,
+ keyboard_handle_modifiers,
+ keyboard_handle_repeat_info
+};
+
+static void
+touch_handle_down (struct wthp_touch * wthp_touch,
+ uint32_t serial,
+ uint32_t time,
+ struct wthp_surface * surface,
+ int32_t id,
+ wth_fixed_t x,
+ wth_fixed_t y)
+{
+ struct waltham_display *dpy =
+ wth_object_get_user_data((struct wth_object *)wthp_touch);
+ struct weston_transmitter_remote *remote = dpy->remote;
+ struct wl_list *seat_list = &remote->seat_list;
+ struct weston_transmitter_seat *seat;
+ struct weston_transmitter_surface *txs;
+
+ seat = wl_container_of(seat_list->next, seat, link);
+
+ wl_list_for_each(txs, &remote->surface_list, link)
+ {
+ if (txs->wthp_surf == surface) {
+ transmitter_seat_touch_down(seat, serial, time,
+ txs, id, x, y);
+ }
+ }
+}
+
+static void
+touch_handle_up (struct wthp_touch * wthp_touch,
+ uint32_t serial,
+ uint32_t time,
+ int32_t id)
+{
+ struct waltham_display *dpy =
+ wth_object_get_user_data((struct wth_object *)wthp_touch);
+ struct weston_transmitter_remote *remote = dpy->remote;
+ struct wl_list *seat_list = &remote->seat_list;
+ struct weston_transmitter_seat *seat;
+
+ seat = wl_container_of(seat_list->next, seat, link);
+
+ transmitter_seat_touch_up(seat, serial, time, id);
+}
+
+static void
+touch_handle_motion (struct wthp_touch * wthp_touch,
+ uint32_t time,
+ int32_t id,
+ wth_fixed_t x,
+ wth_fixed_t y)
+{
+ struct waltham_display *dpy =
+ wth_object_get_user_data((struct wth_object *)wthp_touch);
+ struct weston_transmitter_remote *remote = dpy->remote;
+ struct wl_list *seat_list = &remote->seat_list;
+ struct weston_transmitter_seat *seat;
+
+ seat = wl_container_of(seat_list->next, seat, link);
+
+ transmitter_seat_touch_motion(seat, time, id, x, y);
+}
+
+
+static void
+touch_handle_frame (struct wthp_touch * wthp_touch)
+{
+ struct waltham_display *dpy =
+ wth_object_get_user_data((struct wth_object *)wthp_touch);
+ struct weston_transmitter_remote *remote = dpy->remote;
+ struct wl_list *seat_list = &remote->seat_list;
+ struct weston_transmitter_seat *seat;
+
+ seat = wl_container_of(seat_list->next, seat, link);
+
+ transmitter_seat_touch_frame(seat);
+}
+
+static void
+touch_handle_cancel (struct wthp_touch * wthp_touch)
+{
+ struct waltham_display *dpy =
+ wth_object_get_user_data((struct wth_object *)wthp_touch);
+ struct weston_transmitter_remote *remote = dpy->remote;
+ struct wl_list *seat_list = &remote->seat_list;
+ struct weston_transmitter_seat *seat;
+
+ seat = wl_container_of(seat_list->next, seat, link);
+
+ transmitter_seat_touch_cancel(seat);
+}
+
+
+static const struct wthp_touch_listener touch_listener = {
+ touch_handle_down,
+ touch_handle_up,
+ touch_handle_motion,
+ touch_handle_frame,
+ touch_handle_cancel
+};
+
+void
+seat_capabilities(struct wthp_seat *wthp_seat,
+ enum wthp_seat_capability caps)
+{
+ struct waltham_display *dpy = wth_object_get_user_data((struct wth_object *)wthp_seat);
+
+ weston_log("seat_capabilities\n");
+
+ if ((caps & WTHP_SEAT_CAPABILITY_POINTER) && !dpy->pointer)
+ {
+ weston_log("WTHP_SEAT_CAPABILITY_POINTER\n");
+ dpy->pointer = wthp_seat_get_pointer(dpy->seat);
+ wthp_pointer_set_listener(dpy->pointer, &pointer_listener, dpy);
+ }
+ if ((caps & WTHP_SEAT_CAPABILITY_KEYBOARD) && !dpy->keyboard)
+ {
+ weston_log("WTHP_SEAT_CAPABILITY_KEYBOARD\n");
+ dpy->keyboard = wthp_seat_get_keyboard(dpy->seat);
+ wthp_keyboard_set_listener(dpy->keyboard, &keyboard_listener, dpy);
+ }
+ if ((caps & WTHP_SEAT_CAPABILITY_TOUCH) && !dpy->touch)
+ {
+ weston_log("WTHP_SEAT_CAPABILITY_TOUCH\n");
+ dpy->touch = wthp_seat_get_touch(dpy->seat);
+ wthp_touch_set_listener(dpy->touch, &touch_listener, dpy);
+ }
+}
+
+int
+transmitter_remote_create_seat(struct weston_transmitter_remote *remote)
+{
+ struct weston_transmitter_seat *seat = NULL;
+ char *name = NULL;
+ struct weston_seat *weston_seat = NULL;
+
+ seat = zalloc(sizeof *seat);
+ if (!seat)
+ goto fail;
+
+ wl_list_init(&seat->get_pointer_listener.link);
+ wl_list_init(&seat->pointer_focus_destroy_listener.link);
+
+ /* XXX: get the name from remote */
+ name = make_seat_name(remote, "default");
+ if (!name)
+ goto fail;
+
+
+ if (wl_list_empty(&remote->transmitter->compositor->seat_list)) {
+ weston_seat = zalloc(sizeof *weston_seat);
+ if (!weston_seat)
+ goto fail;
+
+ weston_seat_init(weston_seat, remote->transmitter->compositor, name);
+ seat->base = weston_seat;
+ weston_log("Transmitter created seat=%p \n", &seat->base);
+ } else {
+ wl_list_for_each(weston_seat, &remote->transmitter->compositor->seat_list, link) {
+ weston_log("Transmitter weston_seat %p\n", weston_seat);
+ seat->base = weston_seat;
+ }
+ }
+
+ free(name);
+#if DEBUG
+ weston_seat_init(&seat->base, remote->transmitter->compositor, name);
+ free(name);
+
+ /* Hide the weston_seat from the rest of Weston, there are too many
+ * things making assumptions:
+ * - backends assume they control all seats
+ * - shells assume they control all input foci
+ * We do not want either to mess with our seat.
+ */
+ wl_list_remove(&seat->base.link);
+ wl_list_init(&seat->base.link);
+
+ /* The weston_compositor::seat_created_signal has already been
+ * emitted. Shells use it to subscribe to focus changes, but we should
+ * never handle focus with weston core... except maybe with keyboard.
+ * text-backend.c will also act on the new seat.
+ * It is possible weston_seat_init() needs to be split to fix this
+ * properly.
+ */
+
+ weston_log("Transmitter created seat=%p '%s'\n",
+ &seat->base, seat->base.seat_name);
+#endif
+
+ /* XXX: mirror remote capabilities */
+ transmitter_seat_create_pointer(seat);
+ transmitter_seat_create_keyboard(seat);
+ transmitter_seat_create_touch(seat);
+
+ wl_list_insert(&remote->seat_list, &seat->link);
+
+ return 0;
+
+fail:
+ free(seat);
+ free(name);
+
+ return -1;
+}
+
+static void
+fake_pointer_get_position(struct weston_transmitter_seat *seat, double step,
+ wl_fixed_t *x, wl_fixed_t *y)
+{
+ double s, c;
+
+ seat->pointer_phase += step;
+ while (seat->pointer_phase > 2.0 * M_PI)
+ seat->pointer_phase -= 2.0 * M_PI;
+
+ sincos(seat->pointer_phase, &s, &c);
+ *x = wl_fixed_from_double(100.0 + 50.0 * c);
+ *y = wl_fixed_from_double(100.0 + 50.0 * s);
+}
+
+static int
+fake_pointer_timer_handler(void *data)
+{
+ struct weston_transmitter_seat *seat = data;
+ wl_fixed_t x, y;
+ uint32_t time;
+ struct timespec timespec;
+
+ weston_compositor_get_time(&timespec);
+ time=timespec.tv_sec * 1000 + timespec.tv_nsec / 1000000;
+
+ fake_pointer_get_position(seat, 18.0 / 180.0 * M_PI, &x, &y);
+ transmitter_seat_pointer_motion(seat, time, x, y);
+ transmitter_seat_pointer_frame(seat);
+
+ wl_event_source_timer_update(seat->pointer_timer, 100);
+
+ return 0;
+}
+
+int
+transmitter_seat_fake_pointer_input(struct weston_transmitter_seat *seat,
+ struct weston_transmitter_surface *txs)
+{
+ struct wl_event_loop *loop;
+ wl_fixed_t x, y;
+ uint32_t serial = 5;
+
+ /* remove focus from earlier surface */
+ transmitter_seat_pointer_leave(seat, serial++, seat->pointer_focus);
+ transmitter_seat_pointer_frame(seat);
+
+ /* set pointer focus to surface */
+ fake_pointer_get_position(seat, 0.0, &x, &y);
+ transmitter_seat_pointer_enter(seat, serial++, txs, x, y);
+ transmitter_seat_pointer_frame(seat);
+
+ if (!seat->pointer_timer) {
+ /* schedule timer for motion */
+ loop = wl_display_get_event_loop(seat->base->compositor->wl_display);
+ seat->pointer_timer = wl_event_loop_add_timer(loop,
+ fake_pointer_timer_handler, seat);
+ wl_event_source_timer_update(seat->pointer_timer, 100);
+ }
+
+ /* XXX: if the now focused surface disappears, we should call
+ * transmitter_seat_pointer_leave() as part of the mockup. Otherwise
+ * you get a "Transmitter Warning: no pointer->focus_client?".
+ */
+
+ return 0;
+}