[PATCH weston 2/3] Implement pointer locking and confinement
Arnaud Vrac
rawoul at gmail.com
Wed Jun 8 15:46:18 UTC 2016
Hi Jonas,
On Tue, Mar 15, 2016 at 2:14 PM, Jonas Ådahl <jadahl at gmail.com> wrote:
> This patch implements the wp_pointer_constraints protocol used for
> locking or confining a pointer. It consists of a new global object with
> two requests; one for locking the surface to a position, one for
> confining the pointer to a given region.
>
> In this patch, only the locking part is fully implemented as in
> specified in the protocol, while confinement is only implemented for
> when the union of the passed region and the input region of the confined
> surface is a single rectangle.
>
> Note that the pointer constraints protocol is still unstable and as
> such has the unstable protocol naming conventions applied.
>
> Signed-off-by: Jonas Ådahl <jadahl at gmail.com>
> Acked-by: Peter Hutterer <peter.hutterer at who-t.net>
> ---
>
> The changes since last version include:
>
> * Updated to the new protocol:
> - Added oneshot vs persistent constraint lifetime
> - Changed the constraint creation input from wl_seat to wl_pointer
>
>
> Makefile.am | 4 +-
> src/compositor.c | 11 +
> src/compositor.h | 44 +++
> src/input.c | 850
> ++++++++++++++++++++++++++++++++++++++++++++--
> xwayland/window-manager.c | 3 +-
> 5 files changed, 888 insertions(+), 24 deletions(-)
>
> diff --git a/Makefile.am b/Makefile.am
> index 9a6bd9b..12ecc3c 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -128,7 +128,9 @@ nodist_weston_SOURCES =
> \
> protocol/linux-dmabuf-unstable-v1-protocol.c \
> protocol/linux-dmabuf-unstable-v1-server-protocol.h \
> protocol/relative-pointer-unstable-v1-protocol.c \
> - protocol/relative-pointer-unstable-v1-server-protocol.h
> + protocol/relative-pointer-unstable-v1-server-protocol.h \
> + protocol/pointer-constraints-unstable-v1-protocol.c \
> + protocol/pointer-constraints-unstable-v1-server-protocol.h
>
> BUILT_SOURCES += $(nodist_weston_SOURCES)
>
> diff --git a/src/compositor.c b/src/compositor.c
> index 68ce600..e2492db 100644
> --- a/src/compositor.c
> +++ b/src/compositor.c
> @@ -586,6 +586,7 @@ weston_surface_create(struct weston_compositor
> *compositor)
> return NULL;
>
> wl_signal_init(&surface->destroy_signal);
> + wl_signal_init(&surface->commit_signal);
>
> surface->compositor = compositor;
> surface->ref_count = 1;
> @@ -612,6 +613,8 @@ weston_surface_create(struct weston_compositor
> *compositor)
> weston_matrix_init(&surface->buffer_to_surface_matrix);
> weston_matrix_init(&surface->surface_to_buffer_matrix);
>
> + wl_list_init(&surface->pointer_constraints);
> +
> return surface;
> }
>
> @@ -1928,6 +1931,7 @@ weston_surface_destroy(struct weston_surface
> *surface)
> {
> struct weston_frame_callback *cb, *next;
> struct weston_view *ev, *nv;
> + struct weston_pointer_constraint *constraint, *next_constraint;
>
> if (--surface->ref_count > 0)
> return;
> @@ -1955,6 +1959,11 @@ weston_surface_destroy(struct weston_surface
> *surface)
>
> weston_presentation_feedback_discard_list(&surface->feedback_list);
>
> + wl_list_for_each_safe(constraint, next_constraint,
> + &surface->pointer_constraints,
> + link)
> + weston_pointer_constraint_destroy(constraint);
> +
> free(surface);
> }
>
> @@ -2926,6 +2935,8 @@ weston_surface_commit_state(struct weston_surface
> *surface,
> wl_list_insert_list(&surface->feedback_list,
> &state->feedback_list);
> wl_list_init(&state->feedback_list);
> +
> + wl_signal_emit(&surface->commit_signal, surface);
> }
>
> static void
> diff --git a/src/compositor.h b/src/compositor.h
> index ad98c67..20d2467 100644
> --- a/src/compositor.h
> +++ b/src/compositor.h
> @@ -45,6 +45,8 @@ extern "C" {
> #include "zalloc.h"
> #include "timeline-object.h"
>
> +#include "pointer-constraints-unstable-v1-server-protocol.h"
> +
>
This header is not installed so it should not be included here, since
compositor.h is installed.
> struct weston_transform {
> struct weston_matrix matrix;
> struct wl_list link;
> @@ -58,6 +60,7 @@ struct weston_output;
> struct input_method;
> struct weston_pointer;
> struct linux_dmabuf_buffer;
> +struct weston_pointer_constraint;
>
> enum weston_keyboard_modifier {
> MODIFIER_CTRL = (1 << 0),
> @@ -368,6 +371,7 @@ struct weston_pointer {
> struct wl_listener focus_resource_listener;
> struct wl_signal focus_signal;
> struct wl_signal motion_signal;
> + struct wl_signal destroy_signal;
>
> struct weston_view *sprite;
> struct wl_listener sprite_destroy_listener;
> @@ -449,6 +453,9 @@ void
> weston_pointer_set_default_grab(struct weston_pointer *pointer,
> const struct weston_pointer_grab_interface *interface);
>
> +void
> +weston_pointer_constraint_destroy(struct weston_pointer_constraint
> *constraint);
> +
> struct weston_keyboard *
> weston_keyboard_create(void);
> void
> @@ -790,6 +797,8 @@ struct weston_compositor {
>
> unsigned int activate_serial;
>
> + struct wl_global *pointer_constraints;
> +
> int exit_code;
>
> void *user_data;
> @@ -989,10 +998,42 @@ struct weston_surface_state {
> struct weston_buffer_viewport buffer_viewport;
> };
>
> +struct weston_surface_activation_data {
> + struct weston_surface *surface;
> + struct weston_seat *seat;
> +};
> +
> +struct weston_pointer_constraint {
> + struct wl_list link;
> +
> + struct weston_surface *surface;
> + struct weston_view *view;
> + struct wl_resource *resource;
> + struct weston_pointer_grab grab;
> + struct weston_pointer *pointer;
> + enum zwp_pointer_constraints_v1_lifetime lifetime;
>
Replace "enum zwp_pointer_constraints_v1_lifetime" by uint32_t to avoid
needing the problematic header include ?
> +
> + pixman_region32_t region;
> + pixman_region32_t region_pending;
> + bool region_is_pending;
> +
> + wl_fixed_t hint_x;
> + wl_fixed_t hint_y;
> + wl_fixed_t hint_x_pending;
> + wl_fixed_t hint_y_pending;
> + bool hint_is_pending;
> +
> + struct wl_listener pointer_destroy_listener;
> + struct wl_listener surface_destroy_listener;
> + struct wl_listener surface_commit_listener;
> + struct wl_listener surface_activate_listener;
> +};
> +
> struct weston_surface {
> struct wl_resource *resource;
> struct wl_signal destroy_signal; /* callback argument: this
> surface */
> struct weston_compositor *compositor;
> + struct wl_signal commit_signal;
>
> /** Damage in local coordinates from the client, for tex upload. */
> pixman_region32_t damage;
> @@ -1072,6 +1113,9 @@ struct weston_surface {
> const char *role_name;
>
> struct weston_timeline_object timeline;
> +
> + /* An list of per seat pointer constraints. */
> + struct wl_list pointer_constraints;
> };
>
> struct weston_subsurface {
> diff --git a/src/input.c b/src/input.c
> index b5a3273..f141c25 100644
> --- a/src/input.c
> +++ b/src/input.c
> @@ -25,6 +25,7 @@
>
> #include "config.h"
>
> +#include <stdbool.h>
> #include <stdlib.h>
> #include <stdint.h>
> #include <string.h>
> @@ -38,6 +39,15 @@
> #include "shared/os-compatibility.h"
> #include "compositor.h"
> #include "protocol/relative-pointer-unstable-v1-server-protocol.h"
> +#include "protocol/pointer-constraints-unstable-v1-server-protocol.h"
> +
> +enum pointer_constraint_type {
> + POINTER_CONSTRAINT_TYPE_LOCK,
> + POINTER_CONSTRAINT_TYPE_CONFINE,
> +};
> +
> +static void
> +maybe_warp_confined_pointer(struct weston_pointer_constraint *constraint);
>
> static void
> empty_region(pixman_region32_t *region)
> @@ -46,6 +56,13 @@ empty_region(pixman_region32_t *region)
> pixman_region32_init(region);
> }
>
> +static void
> +region_init_infinite(pixman_region32_t *region)
> +{
> + pixman_region32_init_rect(region, INT32_MIN, INT32_MIN,
> + UINT32_MAX, UINT32_MAX);
> +}
> +
> static struct weston_pointer_client *
> weston_pointer_client_create(struct wl_client *client)
> {
> @@ -340,12 +357,25 @@ weston_pointer_send_relative_motion(struct
> weston_pointer *pointer,
> }
>
> static void
> +weston_pointer_send_motion(struct weston_pointer *pointer, uint32_t time,
> + wl_fixed_t sx, wl_fixed_t sy)
> +{
> + struct wl_list *resource_list;
> + struct wl_resource *resource;
> +
> + if (!pointer->focus_client)
> + return;
> +
> + resource_list = &pointer->focus_client->pointer_resources;
> + wl_resource_for_each(resource, resource_list)
> + wl_pointer_send_motion(resource, time, sx, sy);
> +}
> +
> +static void
> default_grab_pointer_motion(struct weston_pointer_grab *grab, uint32_t
> time,
> struct weston_pointer_motion_event *event)
> {
> struct weston_pointer *pointer = grab->pointer;
> - struct wl_list *resource_list;
> - struct wl_resource *resource;
> wl_fixed_t x, y;
> wl_fixed_t old_sx = pointer->sx;
> wl_fixed_t old_sy = pointer->sy;
> @@ -358,44 +388,51 @@ default_grab_pointer_motion(struct
> weston_pointer_grab *grab, uint32_t time,
>
> weston_pointer_move(pointer, event);
>
> - if (pointer->focus_client &&
> - (old_sx != pointer->sx || old_sy != pointer->sy)) {
> - resource_list = &pointer->focus_client->pointer_resources;
> - wl_resource_for_each(resource, resource_list) {
> - wl_pointer_send_motion(resource, time,
> - pointer->sx, pointer->sy);
> - }
> + if (old_sx != pointer->sx || old_sy != pointer->sy) {
> + weston_pointer_send_motion(pointer, time,
> + pointer->sx, pointer->sy);
> }
>
> weston_pointer_send_relative_motion(pointer, time, event);
> }
>
> static void
> -default_grab_pointer_button(struct weston_pointer_grab *grab,
> - uint32_t time, uint32_t button, uint32_t
> state_w)
> +weston_pointer_send_button(struct weston_pointer *pointer,
> + uint32_t time, uint32_t button, uint32_t
> state_w)
> {
> - struct weston_pointer *pointer = grab->pointer;
> - struct weston_compositor *compositor = pointer->seat->compositor;
> - struct weston_view *view;
> + struct wl_display *display = pointer->seat->compositor->wl_display;
> + struct wl_list *resource_list;
> struct wl_resource *resource;
> uint32_t serial;
> - enum wl_pointer_button_state state = state_w;
> - struct wl_display *display = compositor->wl_display;
> - wl_fixed_t sx, sy;
> - struct wl_list *resource_list = NULL;
>
> - if (pointer->focus_client)
> - resource_list = &pointer->focus_client->pointer_resources;
> + if (!pointer->focus_client)
> + return;
> +
> + resource_list = &pointer->focus_client->pointer_resources;
> if (resource_list && !wl_list_empty(resource_list)) {
> resource_list = &pointer->focus_client->pointer_resources;
> serial = wl_display_next_serial(display);
> - wl_resource_for_each(resource, resource_list)
> + wl_resource_for_each(resource, resource_list) {
> wl_pointer_send_button(resource,
> serial,
> time,
> button,
> state_w);
> + }
> }
> +}
> +
> +static void
> +default_grab_pointer_button(struct weston_pointer_grab *grab,
> + uint32_t time, uint32_t button, uint32_t
> state_w)
> +{
> + struct weston_pointer *pointer = grab->pointer;
> + struct weston_compositor *compositor = pointer->seat->compositor;
> + struct weston_view *view;
> + enum wl_pointer_button_state state = state_w;
> + wl_fixed_t sx, sy;
> +
> + weston_pointer_send_button(pointer, time, button, state_w);
>
> if (pointer->button_count == 0 &&
> state == WL_POINTER_BUTTON_STATE_RELEASED) {
> @@ -792,6 +829,7 @@ weston_pointer_create(struct weston_seat *seat)
> wl_signal_init(&pointer->motion_signal);
> wl_signal_init(&pointer->focus_signal);
> wl_list_init(&pointer->focus_view_listener.link);
> + wl_signal_init(&pointer->destroy_signal);
>
> pointer->sprite_destroy_listener.notify =
> pointer_handle_sprite_destroy;
>
> @@ -813,6 +851,8 @@ weston_pointer_create(struct weston_seat *seat)
> WL_EXPORT void
> weston_pointer_destroy(struct weston_pointer *pointer)
> {
> + wl_signal_emit(&pointer->destroy_signal, pointer);
> +
> if (pointer->sprite)
> pointer_unmap_sprite(pointer);
>
> @@ -1382,6 +1422,7 @@ weston_surface_activate(struct weston_surface
> *surface,
> {
> struct weston_compositor *compositor = seat->compositor;
> struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
> + struct weston_surface_activation_data activation_data;
>
> inc_activate_serial(compositor);
>
> @@ -1390,7 +1431,11 @@ weston_surface_activate(struct weston_surface
> *surface,
> wl_data_device_set_keyboard_focus(seat);
> }
>
> - wl_signal_emit(&compositor->activate_signal, surface);
> + activation_data = (struct weston_surface_activation_data) {
> + .surface = surface,
> + .seat = seat,
> + };
> + wl_signal_emit(&compositor->activate_signal, &activation_data);
> }
>
> WL_EXPORT void
> @@ -2897,6 +2942,70 @@ weston_seat_get_pointer(struct weston_seat *seat)
> return NULL;
> }
>
> +static const struct zwp_locked_pointer_v1_interface
> locked_pointer_interface;
> +static const struct zwp_confined_pointer_v1_interface
> confined_pointer_interface;
> +
> +static enum pointer_constraint_type
> +pointer_constraint_get_type(struct weston_pointer_constraint *constraint)
> +{
> + if (wl_resource_instance_of(constraint->resource,
> + &zwp_locked_pointer_v1_interface,
> + &locked_pointer_interface)) {
> + return POINTER_CONSTRAINT_TYPE_LOCK;
> + } else if (wl_resource_instance_of(constraint->resource,
> +
> &zwp_confined_pointer_v1_interface,
> + &confined_pointer_interface)) {
> + return POINTER_CONSTRAINT_TYPE_CONFINE;
> + }
> +
> + abort();
> + return 0;
> +}
> +
> +static void
> +pointer_constraint_notify_activated(struct weston_pointer_constraint
> *constraint)
> +{
> + struct wl_resource *resource = constraint->resource;
> +
> + switch (pointer_constraint_get_type(constraint)) {
> + case POINTER_CONSTRAINT_TYPE_LOCK:
> + zwp_locked_pointer_v1_send_locked(resource);
> + break;
> + case POINTER_CONSTRAINT_TYPE_CONFINE:
> + zwp_confined_pointer_v1_send_confined(resource);
> + break;
> + }
> +}
> +
> +static void
> +pointer_constraint_notify_deactivated(struct weston_pointer_constraint
> *constraint)
> +{
> + struct wl_resource *resource = constraint->resource;
> +
> + switch (pointer_constraint_get_type(constraint)) {
> + case POINTER_CONSTRAINT_TYPE_LOCK:
> + zwp_locked_pointer_v1_send_unlocked(resource);
> + break;
> + case POINTER_CONSTRAINT_TYPE_CONFINE:
> + zwp_confined_pointer_v1_send_unconfined(resource);
> + break;
> + }
> +}
> +
> +static struct weston_pointer_constraint *
> +get_pointer_constraint_for_pointer(struct weston_surface *surface,
> + struct weston_pointer *pointer)
> +{
> + struct weston_pointer_constraint *constraint;
> +
> + wl_list_for_each(constraint, &surface->pointer_constraints, link) {
> + if (constraint->pointer == pointer)
> + return constraint;
> + }
> +
> + return NULL;
> +}
> +
> /** Get a seat's touch pointer
> *
> * \param seat The seat to query
> @@ -2919,6 +3028,698 @@ weston_seat_get_touch(struct weston_seat *seat)
> return NULL;
> }
>
> +static void
> +enable_pointer_constraint(struct weston_pointer_constraint *constraint,
> + struct weston_view *view)
> +{
> + assert(constraint->view == NULL);
> + constraint->view = view;
> + pointer_constraint_notify_activated(constraint);
> + weston_pointer_start_grab(constraint->pointer, &constraint->grab);
> +}
> +
> +static bool
> +is_pointer_constraint_enabled(struct weston_pointer_constraint
> *constraint)
> +{
> + return constraint->view != NULL;
> +}
> +
> +static void
> +weston_pointer_constraint_disable(struct weston_pointer_constraint
> *constraint)
> +{
> + constraint->view = NULL;
> + pointer_constraint_notify_deactivated(constraint);
> + weston_pointer_end_grab(constraint->grab.pointer);
> +}
> +
> +void
> +weston_pointer_constraint_destroy(struct weston_pointer_constraint
> *constraint)
> +{
> + if (is_pointer_constraint_enabled(constraint))
> + weston_pointer_constraint_disable(constraint);
> +
> + wl_list_remove(&constraint->pointer_destroy_listener.link);
> + wl_list_remove(&constraint->surface_destroy_listener.link);
> + wl_list_remove(&constraint->surface_commit_listener.link);
> + wl_list_remove(&constraint->surface_activate_listener.link);
> +
> + wl_resource_set_user_data(constraint->resource, NULL);
> + pixman_region32_fini(&constraint->region);
> + wl_list_remove(&constraint->link);
> + free(constraint);
> +}
> +
> +static void
> +disable_pointer_constraint(struct weston_pointer_constraint *constraint)
> +{
> + switch (constraint->lifetime) {
> + case ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT:
> + weston_pointer_constraint_destroy(constraint);
> + break;
> + case ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT:
> + weston_pointer_constraint_disable(constraint);
> + break;
> + }
> +}
> +
> +static bool
> +is_within_constraint_region(struct weston_pointer_constraint *constraint,
> + wl_fixed_t sx, wl_fixed_t sy)
> +{
> + struct weston_surface *surface = constraint->surface;
> + pixman_region32_t constraint_region;
> + bool result;
> +
> + pixman_region32_init(&constraint_region);
> + pixman_region32_intersect(&constraint_region,
> + &surface->input,
> + &constraint->region);
> + result = pixman_region32_contains_point(&constraint_region,
> + wl_fixed_to_int(sx),
> + wl_fixed_to_int(sy),
> + NULL);
> + pixman_region32_fini(&constraint_region);
> +
> + return result;
> +}
> +
> +static void
> +maybe_enable_pointer_constraint(struct weston_pointer_constraint
> *constraint)
> +{
> + struct weston_surface *surface = constraint->surface;
> + struct weston_view *vit;
> + struct weston_view *view = NULL;
> + struct weston_pointer *pointer = constraint->pointer;
> + struct weston_keyboard *keyboard;
> + struct weston_seat *seat = pointer->seat;
> + int32_t x, y;
> +
> + /* Postpone if no view of the surface was most recently clicked. */
> + wl_list_for_each(vit, &surface->views, surface_link) {
> + if (vit->click_to_activate_serial ==
> + surface->compositor->activate_serial) {
> + view = vit;
> + }
> + }
> + if (view == NULL)
> + return;
> +
> + /* Postpone if surface doesn't have keyboard focus. */
> + keyboard = weston_seat_get_keyboard(seat);
> + if (!keyboard || keyboard->focus != surface)
> + return;
> +
> + /* Postpone constraint if the pointer is not within the
> + * constraint region.
> + */
> + weston_view_from_global(view,
> + wl_fixed_to_int(pointer->x),
> + wl_fixed_to_int(pointer->y),
> + &x, &y);
> + if (!is_within_constraint_region(constraint,
> + wl_fixed_from_int(x),
> + wl_fixed_from_int(y)))
> + return;
> +
> + enable_pointer_constraint(constraint, view);
> +}
> +
> +static void
> +locked_pointer_grab_pointer_focus(struct weston_pointer_grab *grab)
> +{
> +}
> +
> +static void
> +locked_pointer_grab_pointer_motion(struct weston_pointer_grab *grab,
> + uint32_t time,
> + struct weston_pointer_motion_event
> *event)
> +{
> + weston_pointer_send_relative_motion(grab->pointer, time, event);
> +}
> +
> +static void
> +locked_pointer_grab_pointer_button(struct weston_pointer_grab *grab,
> + uint32_t time,
> + uint32_t button,
> + uint32_t state_w)
> +{
> + weston_pointer_send_button(grab->pointer, time, button, state_w);
> +}
> +
> +static void
> +locked_pointer_grab_pointer_axis(struct weston_pointer_grab *grab,
> + uint32_t time,
> + struct weston_pointer_axis_event *event)
> +{
> + weston_pointer_send_axis(grab->pointer, time, event);
> +}
> +
> +static void
> +locked_pointer_grab_pointer_axis_source(struct weston_pointer_grab *grab,
> + uint32_t source)
> +{
> + weston_pointer_send_axis_source(grab->pointer, source);
> +}
> +
> +static void
> +locked_pointer_grab_pointer_frame(struct weston_pointer_grab *grab)
> +{
> + weston_pointer_send_frame(grab->pointer);
> +}
> +
> +static void
> +locked_pointer_grab_pointer_cancel(struct weston_pointer_grab *grab)
> +{
> + struct weston_pointer_constraint *constraint =
> + container_of(grab, struct weston_pointer_constraint, grab);
> +
> + disable_pointer_constraint(constraint);
> +}
> +
> +static const struct weston_pointer_grab_interface
> + locked_pointer_grab_interface = {
> + locked_pointer_grab_pointer_focus,
> + locked_pointer_grab_pointer_motion,
> + locked_pointer_grab_pointer_button,
> + locked_pointer_grab_pointer_axis,
> + locked_pointer_grab_pointer_axis_source,
> + locked_pointer_grab_pointer_frame,
> + locked_pointer_grab_pointer_cancel,
> +};
> +
> +static void
> +pointer_constraint_constrain_resource_destroyed(struct wl_resource
> *resource)
> +{
> + struct weston_pointer_constraint *constraint =
> + wl_resource_get_user_data(resource);
> +
> + if (!constraint)
> + return;
> +
> + weston_pointer_constraint_destroy(constraint);
> +}
> +
> +static void
> +pointer_constraint_surface_activate(struct wl_listener *listener, void
> *data)
> +{
> + struct weston_surface_activation_data *activation = data;
> + struct weston_pointer *pointer;
> + struct weston_surface *focus = activation->surface;
> + struct weston_pointer_constraint *constraint =
> + container_of(listener, struct weston_pointer_constraint,
> + surface_activate_listener);
> + bool is_constraint_surface;
> +
> + pointer = weston_seat_get_pointer(activation->seat);
> + if (!pointer)
> + return;
> +
> + is_constraint_surface =
> + get_pointer_constraint_for_pointer(focus, pointer) ==
> constraint;
> +
> + if (is_constraint_surface &&
> + !is_pointer_constraint_enabled(constraint))
> + maybe_enable_pointer_constraint(constraint);
> + else if (!is_constraint_surface &&
> + is_pointer_constraint_enabled(constraint))
> + disable_pointer_constraint(constraint);
> +}
> +
> +static void
> +pointer_constraint_pointer_destroyed(struct wl_listener *listener, void
> *data)
> +{
> + struct weston_pointer_constraint *constraint =
> + container_of(listener, struct weston_pointer_constraint,
> + pointer_destroy_listener);
> +
> + weston_pointer_constraint_destroy(constraint);
> +}
> +
> +static void
> +pointer_constraint_surface_destroyed(struct wl_listener *listener, void
> *data)
> +{
> + struct weston_pointer_constraint *constraint =
> + container_of(listener, struct weston_pointer_constraint,
> + surface_destroy_listener);
> +
> + weston_pointer_constraint_destroy(constraint);
> +}
> +
> +static void
> +pointer_constraint_surface_committed(struct wl_listener *listener, void
> *data)
> +{
> + struct weston_pointer_constraint *constraint =
> + container_of(listener, struct weston_pointer_constraint,
> + surface_commit_listener);
> +
> + if (constraint->region_is_pending) {
> + constraint->region_is_pending = false;
> + pixman_region32_copy(&constraint->region,
> + &constraint->region_pending);
> + pixman_region32_fini(&constraint->region_pending);
> + pixman_region32_init(&constraint->region_pending);
> + }
> +
> + if (constraint->hint_is_pending) {
> + constraint->hint_is_pending = false;
> +
> + constraint->hint_is_pending = true;
> + constraint->hint_x = constraint->hint_x_pending;
> + constraint->hint_y = constraint->hint_y_pending;
> + }
> +
> + if (pointer_constraint_get_type(constraint) ==
> + POINTER_CONSTRAINT_TYPE_CONFINE &&
> + is_pointer_constraint_enabled(constraint))
> + maybe_warp_confined_pointer(constraint);
> +}
> +
> +static struct weston_pointer_constraint *
> +weston_pointer_constraint_create(struct weston_surface *surface,
> + struct weston_pointer *pointer,
> + struct weston_region *region,
> + enum zwp_pointer_constraints_v1_lifetime
> lifetime,
> + struct wl_resource *cr,
> + const struct
> weston_pointer_grab_interface *grab_interface)
> +{
> + struct weston_pointer_constraint *constraint;
> +
> + constraint = zalloc(sizeof *constraint);
> + if (!constraint)
> + return NULL;
> +
> + constraint->lifetime = lifetime;
> + pixman_region32_init(&constraint->region);
> + pixman_region32_init(&constraint->region_pending);
> + wl_list_insert(&surface->pointer_constraints, &constraint->link);
> + constraint->surface = surface;
> + constraint->pointer = pointer;
> + constraint->resource = cr;
> + constraint->grab.interface = grab_interface;
> + if (region) {
> + pixman_region32_copy(&constraint->region,
> + ®ion->region);
> + } else {
> + pixman_region32_fini(&constraint->region);
> + region_init_infinite(&constraint->region);
> + }
> +
> + constraint->surface_activate_listener.notify =
> + pointer_constraint_surface_activate;
> + constraint->surface_destroy_listener.notify =
> + pointer_constraint_surface_destroyed;
> + constraint->surface_commit_listener.notify =
> + pointer_constraint_surface_committed;
> + constraint->pointer_destroy_listener.notify =
> + pointer_constraint_pointer_destroyed;
> +
> + wl_signal_add(&surface->compositor->activate_signal,
> + &constraint->surface_activate_listener);
> + wl_signal_add(&pointer->destroy_signal,
> + &constraint->pointer_destroy_listener);
> + wl_signal_add(&surface->destroy_signal,
> + &constraint->surface_destroy_listener);
> + wl_signal_add(&surface->commit_signal,
> + &constraint->surface_commit_listener);
> +
> + return constraint;
> +}
> +
> +static void
> +init_pointer_constraint(struct wl_resource *pointer_constraints_resource,
> + uint32_t id,
> + struct weston_surface *surface,
> + struct weston_pointer *pointer,
> + struct weston_region *region,
> + enum zwp_pointer_constraints_v1_lifetime lifetime,
> + const struct wl_interface *interface,
> + const void *implementation,
> + const struct weston_pointer_grab_interface
> *grab_interface)
> +{
> + struct wl_client *client =
> + wl_resource_get_client(pointer_constraints_resource);
> + struct wl_resource *cr;
> + struct weston_pointer_constraint *constraint;
> +
> + if (get_pointer_constraint_for_pointer(surface, pointer)) {
> + wl_resource_post_error(pointer_constraints_resource,
> +
> ZWP_POINTER_CONSTRAINTS_V1_ERROR_ALREADY_CONSTRAINED,
> + "the pointer has a lock/confine
> request on this surface");
> + return;
> + }
> +
> + cr = wl_resource_create(client, interface,
> +
> wl_resource_get_version(pointer_constraints_resource),
> + id);
> + if (cr == NULL) {
> + wl_client_post_no_memory(client);
> + return;
> + }
> +
> + constraint = weston_pointer_constraint_create(surface, pointer,
> + region, lifetime,
> + cr, grab_interface);
> + if (constraint == NULL) {
> + wl_client_post_no_memory(client);
> + return;
> + }
> +
> + wl_resource_set_implementation(cr, implementation, constraint,
> +
> pointer_constraint_constrain_resource_destroyed);
> +
> + maybe_enable_pointer_constraint(constraint);
> +}
> +
> +static void
> +pointer_constraints_destroy(struct wl_client *client,
> + struct wl_resource *resource)
> +{
> + wl_resource_destroy(resource);
> +}
> +
> +static void
> +locked_pointer_destroy(struct wl_client *client,
> + struct wl_resource *resource)
> +{
> + struct weston_pointer_constraint *constraint =
> + wl_resource_get_user_data(resource);
> + wl_fixed_t x, y;
> +
> + if (constraint && constraint->view && constraint->hint_is_pending
> &&
> + is_within_constraint_region(constraint,
> + constraint->hint_x,
> + constraint->hint_y)) {
> + weston_view_to_global_fixed(constraint->view,
> + constraint->hint_x,
> + constraint->hint_y,
> + &x, &y);
> + weston_pointer_move_to(constraint->pointer, x, y);
> + }
> + wl_resource_destroy(resource);
> +}
> +
> +static void
> +locked_pointer_set_cursor_position_hint(struct wl_client *client,
> + struct wl_resource *resource,
> + wl_fixed_t surface_x,
> + wl_fixed_t surface_y)
> +{
> + struct weston_pointer_constraint *constraint =
> + wl_resource_get_user_data(resource);
> +
> + /* Ignore a set cursor hint that was sent after the lock was
> cancelled.
> + */
> + if (!constraint->resource ||
> + constraint->resource != resource)
> + return;
> +
> + constraint->hint_is_pending = true;
> + constraint->hint_x_pending = surface_x;
> + constraint->hint_y_pending = surface_y;
> +}
> +
> +static void
> +locked_pointer_set_region(struct wl_client *client,
> + struct wl_resource *resource,
> + struct wl_resource *region_resource)
> +{
> + struct weston_pointer_constraint *constraint =
> + wl_resource_get_user_data(resource);
> + struct weston_region *region = region_resource ?
> + wl_resource_get_user_data(region_resource) : NULL;
> +
> + if (region) {
> + pixman_region32_copy(&constraint->region_pending,
> + ®ion->region);
> + } else {
> + pixman_region32_fini(&constraint->region_pending);
> + region_init_infinite(&constraint->region_pending);
> + }
> + constraint->region_is_pending = true;
> +}
> +
> +
> +static const struct zwp_locked_pointer_v1_interface
> locked_pointer_interface = {
> + locked_pointer_destroy,
> + locked_pointer_set_cursor_position_hint,
> + locked_pointer_set_region,
> +};
> +
> +static void
> +pointer_constraints_lock_pointer(struct wl_client *client,
> + struct wl_resource *resource,
> + uint32_t id,
> + struct wl_resource *surface_resource,
> + struct wl_resource *pointer_resource,
> + struct wl_resource *region_resource,
> + uint32_t lifetime)
> +{
> + struct weston_surface *surface =
> + wl_resource_get_user_data(surface_resource);
> + struct weston_pointer *pointer =
> wl_resource_get_user_data(pointer_resource);
> + struct weston_region *region = region_resource ?
> + wl_resource_get_user_data(region_resource) : NULL;
> +
> + init_pointer_constraint(resource, id, surface, pointer, region,
> lifetime,
> + &zwp_locked_pointer_v1_interface,
> + &locked_pointer_interface,
> + &locked_pointer_grab_interface);
> +}
> +
> +static void
> +confined_pointer_grab_pointer_focus(struct weston_pointer_grab *grab)
> +{
> +}
> +
> +static void
> +weston_pointer_clamp_event_to_region(struct weston_pointer *pointer,
> + struct weston_pointer_motion_event
> *event,
> + pixman_region32_t *region,
> + wl_fixed_t *clamped_x,
> + wl_fixed_t *clamped_y)
> +{
> + wl_fixed_t x, y;
> + wl_fixed_t sx, sy;
> + wl_fixed_t min_sx = wl_fixed_from_int(region->extents.x1);
> + wl_fixed_t max_sx = wl_fixed_from_int(region->extents.x2 - 1);
> + wl_fixed_t max_sy = wl_fixed_from_int(region->extents.y2 - 1);
> + wl_fixed_t min_sy = wl_fixed_from_int(region->extents.y1);
> +
> + weston_pointer_motion_to_abs(pointer, event, &x, &y);
> + weston_view_from_global_fixed(pointer->focus, x, y, &sx, &sy);
> +
> + if (sx < min_sx)
> + sx = min_sx;
> + else if (sx > max_sx)
> + sx = max_sx;
> +
> + if (sy < min_sy)
> + sy = min_sy;
> + else if (sy > max_sy)
> + sy = max_sy;
> +
> + weston_view_to_global_fixed(pointer->focus, sx, sy,
> + clamped_x, clamped_y);
> +}
> +
> +static void
> +maybe_warp_confined_pointer(struct weston_pointer_constraint *constraint)
> +{
> + wl_fixed_t x;
> + wl_fixed_t y;
> + wl_fixed_t sx;
> + wl_fixed_t sy;
> +
> + weston_view_from_global_fixed(constraint->view,
> + constraint->pointer->x,
> + constraint->pointer->y,
> + &sx,
> + &sy);
> +
> + if (!is_within_constraint_region(constraint, sx, sy)) {
> + pixman_region32_t *region = &constraint->region;
> + wl_fixed_t min_sx = wl_fixed_from_int(region->extents.x1);
> + wl_fixed_t max_sx = wl_fixed_from_int(region->extents.x2 -
> 1);
> + wl_fixed_t max_sy = wl_fixed_from_int(region->extents.y2 -
> 1);
> + wl_fixed_t min_sy = wl_fixed_from_int(region->extents.y1);
> +
> + if (sx < min_sx)
> + sx = min_sx;
> + else if (sx > max_sx)
> + sx = max_sx;
> +
> + if (sy < min_sy)
> + sy = min_sy;
> + else if (sy > max_sy)
> + sy = max_sy;
> +
> + weston_view_to_global_fixed(constraint->view, sx, sy, &x,
> &y);
> + weston_pointer_move_to(constraint->pointer, x, y);
> + }
> +}
> +
> +static void
> +confined_pointer_grab_pointer_motion(struct weston_pointer_grab *grab,
> + uint32_t time,
> + struct weston_pointer_motion_event
> *event)
> +{
> + struct weston_pointer_constraint *constraint =
> + container_of(grab, struct weston_pointer_constraint, grab);
> + struct weston_pointer *pointer = grab->pointer;
> + struct weston_surface *surface;
> + wl_fixed_t x, y;
> + wl_fixed_t old_sx = pointer->sx;
> + wl_fixed_t old_sy = pointer->sy;
> + pixman_region32_t confine_region;
> +
> + assert(pointer->focus);
> + assert(pointer->focus->surface == constraint->surface);
> +
> + surface = pointer->focus->surface;
> +
> + pixman_region32_init(&confine_region);
> + pixman_region32_intersect(&confine_region,
> + &surface->input,
> + &constraint->region);
> + weston_pointer_clamp_event_to_region(pointer, event,
> + &confine_region, &x, &y);
> + weston_pointer_move_to(pointer, x, y);
> + pixman_region32_fini(&confine_region);
> +
> + weston_view_from_global_fixed(pointer->focus, x, y,
> + &pointer->sx, &pointer->sy);
> +
> + if (old_sx != pointer->sx || old_sy != pointer->sy) {
> + weston_pointer_send_motion(pointer, time,
> + pointer->sx, pointer->sy);
> + }
> +
> + weston_pointer_send_relative_motion(pointer, time, event);
> +}
> +
> +static void
> +confined_pointer_grab_pointer_button(struct weston_pointer_grab *grab,
> + uint32_t time,
> + uint32_t button,
> + uint32_t state_w)
> +{
> + weston_pointer_send_button(grab->pointer, time, button, state_w);
> +}
> +
> +static void
> +confined_pointer_grab_pointer_axis(struct weston_pointer_grab *grab,
> + uint32_t time,
> + struct weston_pointer_axis_event *event)
> +{
> + weston_pointer_send_axis(grab->pointer, time, event);
> +}
> +
> +static void
> +confined_pointer_grab_pointer_axis_source(struct weston_pointer_grab
> *grab,
> + uint32_t source)
> +{
> + weston_pointer_send_axis_source(grab->pointer, source);
> +}
> +
> +static void
> +confined_pointer_grab_pointer_frame(struct weston_pointer_grab *grab)
> +{
> + weston_pointer_send_frame(grab->pointer);
> +}
> +
> +static void
> +confined_pointer_grab_pointer_cancel(struct weston_pointer_grab *grab)
> +{
> + struct weston_pointer_constraint *constraint =
> + container_of(grab, struct weston_pointer_constraint, grab);
> +
> + disable_pointer_constraint(constraint);
> +}
> +
> +static const struct weston_pointer_grab_interface
> + confined_pointer_grab_interface = {
> + confined_pointer_grab_pointer_focus,
> + confined_pointer_grab_pointer_motion,
> + confined_pointer_grab_pointer_button,
> + confined_pointer_grab_pointer_axis,
> + confined_pointer_grab_pointer_axis_source,
> + confined_pointer_grab_pointer_frame,
> + confined_pointer_grab_pointer_cancel,
> +};
> +
> +static void
> +confined_pointer_destroy(struct wl_client *client,
> + struct wl_resource *resource)
> +{
> + wl_resource_destroy(resource);
> +}
> +
> +static void
> +confined_pointer_set_region(struct wl_client *client,
> + struct wl_resource *resource,
> + struct wl_resource *region_resource)
> +{
> + struct weston_pointer_constraint *constraint =
> + wl_resource_get_user_data(resource);
> + struct weston_region *region = region_resource ?
> + wl_resource_get_user_data(region_resource) : NULL;
> +
> + if (region) {
> + pixman_region32_copy(&constraint->region_pending,
> + ®ion->region);
> + } else {
> + pixman_region32_fini(&constraint->region_pending);
> + region_init_infinite(&constraint->region_pending);
> + }
> + constraint->region_is_pending = true;
> +}
> +
> +static const struct zwp_confined_pointer_v1_interface
> confined_pointer_interface = {
> + confined_pointer_destroy,
> + confined_pointer_set_region,
> +};
> +
> +static void
> +pointer_constraints_confine_pointer(struct wl_client *client,
> + struct wl_resource *resource,
> + uint32_t id,
> + struct wl_resource *surface_resource,
> + struct wl_resource *pointer_resource,
> + struct wl_resource *region_resource,
> + uint32_t lifetime)
> +{
> + struct weston_surface *surface =
> + wl_resource_get_user_data(surface_resource);
> + struct weston_pointer *pointer =
> wl_resource_get_user_data(pointer_resource);
> + struct weston_region *region = region_resource ?
> + wl_resource_get_user_data(region_resource) : NULL;
> +
> + init_pointer_constraint(resource, id, surface, pointer, region,
> lifetime,
> + &zwp_confined_pointer_v1_interface,
> + &confined_pointer_interface,
> + &confined_pointer_grab_interface);
> +}
> +
> +static const struct zwp_pointer_constraints_v1_interface
> pointer_constraints_interface = {
> + pointer_constraints_destroy,
> + pointer_constraints_lock_pointer,
> + pointer_constraints_confine_pointer,
> +};
> +
> +static void
> +bind_pointer_constraints(struct wl_client *client, void *data,
> + uint32_t version, uint32_t id)
> +{
> + struct wl_resource *resource;
> +
> + resource = wl_resource_create(client,
> +
> &zwp_pointer_constraints_v1_interface,
> + 1, id);
> +
> + wl_resource_set_implementation(resource,
> &pointer_constraints_interface,
> + NULL, NULL);
> +}
> +
> int
> weston_input_init(struct weston_compositor *compositor)
> {
> @@ -2927,5 +3728,10 @@ weston_input_init(struct weston_compositor
> *compositor)
> compositor, bind_relative_pointer_manager))
> return -1;
>
> + if (!wl_global_create(compositor->wl_display,
> + &zwp_pointer_constraints_v1_interface, 1,
> + NULL, bind_pointer_constraints))
> + return -1;
> +
> return 0;
> }
> diff --git a/xwayland/window-manager.c b/xwayland/window-manager.c
> index f6f92bd..49d974e 100644
> --- a/xwayland/window-manager.c
> +++ b/xwayland/window-manager.c
> @@ -778,7 +778,8 @@ weston_wm_send_focus_window(struct weston_wm *wm,
> static void
> weston_wm_window_activate(struct wl_listener *listener, void *data)
> {
> - struct weston_surface *surface = data;
> + struct weston_surface_activation_data *activation_data = data;
> + struct weston_surface *surface = activation_data->surface;
> struct weston_wm_window *window = NULL;
> struct weston_wm *wm =
> container_of(listener, struct weston_wm,
> activate_listener);
> --
> 2.4.3
>
Regards,
--
Arnaud
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/wayland-devel/attachments/20160608/1de122b8/attachment-0001.html>
More information about the wayland-devel
mailing list