diff options
Diffstat (limited to 'waltham-transmitter/transmitter-plugin/input.c')
-rw-r--r-- | waltham-transmitter/transmitter-plugin/input.c | 1317 |
1 files changed, 1317 insertions, 0 deletions
diff --git a/waltham-transmitter/transmitter-plugin/input.c b/waltham-transmitter/transmitter-plugin/input.c new file mode 100644 index 0000000..e00546b --- /dev/null +++ b/waltham-transmitter/transmitter-plugin/input.c @@ -0,0 +1,1317 @@ +/* + * 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 "compositor.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, + uint32_t 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, + uint32_t 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, + uint32_t 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, + uint32_t 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, + uint32_t time, + int touch_id, + wl_fixed_t x, + wl_fixed_t y) +{ +} + +static void +touch_grab_up_handler(struct weston_touch_grab *grab, + uint32_t time, + int touch_id) +{ +} + +static void +touch_grab_motion_handler(struct weston_touch_grab *grab, + uint32_t 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, +}; + + +/* 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. + */ +static 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 wl_client *client; + 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); + 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; + + time = weston_compositor_get_time(); + + 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; +} |