[PATCH weston v4 12/20] Implement pointer locking and confinement
Peter Hutterer
peter.hutterer at who-t.net
Wed Nov 18 21:36:10 PST 2015
On Tue, Nov 17, 2015 at 06:10:58PM +0800, Jonas Ådahl 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>
> ---
>
> Changes since v3:
>
> Uses the XML file from wayland-protocols.
>
> Updated implementation given interface renaming.
>
> Updated implementation given protocol changes (see protocol patch).
>
>
> Makefile.am | 4 +-
> src/compositor.c | 11 +
> src/compositor.h | 41 +++
> src/input.c | 794 ++++++++++++++++++++++++++++++++++++++++++++--
> xwayland/window-manager.c | 3 +-
> 5 files changed, 829 insertions(+), 24 deletions(-)
>
> diff --git a/Makefile.am b/Makefile.am
> index 08a3444..a640d74 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 12bd18e..23f54de 100644
> --- a/src/compositor.c
> +++ b/src/compositor.c
> @@ -584,6 +584,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;
> @@ -610,6 +611,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;
> }
>
> @@ -1820,6 +1823,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;
> @@ -1847,6 +1851,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);
> }
>
> @@ -2761,6 +2770,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 46a4d1f..4b27197 100644
> --- a/src/compositor.h
> +++ b/src/compositor.h
> @@ -58,6 +58,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),
> @@ -350,6 +351,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;
> @@ -424,6 +426,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
> @@ -764,6 +769,8 @@ struct weston_compositor {
>
> unsigned int activate_serial;
>
> + struct wl_global *pointer_constraints;
> +
> int exit_code;
>
> void *user_data;
> @@ -961,10 +968,41 @@ 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;
> + pixman_region32_t region;
> + pixman_region32_t pending_region;
> + bool pending_region_set;
> + struct wl_resource *resource;
> + struct weston_pointer_grab grab;
> + struct weston_pointer *pointer;
> +
> + bool pending_hint_set;
> + wl_fixed_t pending_x_hint;
> + wl_fixed_t pending_y_hint;
> + bool hint_set;
> + wl_fixed_t x_hint;
> + wl_fixed_t y_hint;
> +
this is bikeshedding, but a more obivous naming scheme may be:
region
region_pending
region_is_pending
hint_x_pending
hint_y_pending
hint_is_pending
hint_x
hint_y
hint_is_set
mostly because I first read "region_set" as "a set of regions" and confused
myself. or alternatively take what you have now and just rename "set" to
"isset"
> + 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;
> @@ -1044,6 +1082,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 97bffab..81cdd6f 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)
> {
> @@ -341,12 +358,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;
> @@ -359,44 +389,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) {
> @@ -722,6 +759,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;
>
> @@ -743,6 +781,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);
>
> @@ -1310,6 +1350,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);
>
> @@ -1318,7 +1359,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
> @@ -2796,6 +2841,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
> @@ -2818,6 +2927,642 @@ 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;
> +}
> +
> +void
> +weston_pointer_constraint_destroy(struct weston_pointer_constraint *constraint)
> +{
> + if (is_pointer_constraint_enabled(constraint)) {
> + pointer_constraint_notify_deactivated(constraint);
> + weston_pointer_end_grab(constraint->grab.pointer);
> + }
> +
> + 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)
> +{
> + weston_pointer_constraint_destroy(constraint);
> +}
> +
> +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 constrain
typo: constraint, and the linebreaks here are a bit odd, move constraint to
the second line.
> + * 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, uint32_t axis, wl_fixed_t value)
> +{
> + weston_pointer_send_axis(grab->pointer, time, axis, value);
> +}
> +
> +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_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;
> +
> + disable_pointer_constraint(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);
> +
> + disable_pointer_constraint(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);
> +
> + disable_pointer_constraint(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->pending_region_set) {
> + constraint->pending_region_set = false;
> + pixman_region32_copy(&constraint->region,
> + &constraint->pending_region);
> + pixman_region32_fini(&constraint->pending_region);
> + pixman_region32_init(&constraint->pending_region);
> + }
> +
> + if (constraint->pending_hint_set) {
> + constraint->pending_hint_set = false;
> +
> + constraint->hint_set = true;
> + constraint->x_hint = constraint->pending_x_hint;
> + constraint->y_hint = constraint->pending_y_hint;
> + }
> +
> + 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,
> + 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;
> +
> + pixman_region32_init(&constraint->region);
> + pixman_region32_init(&constraint->pending_region);
> + 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_seat *seat,
> + struct weston_region *region,
> + 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 weston_pointer *pointer = weston_seat_get_pointer(seat);
> + 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 as already requested to be "
> + "locked or confined on that surface");
typo, but I'd write "the pointer already has a lock/confine request on this
surface" anyway.
> + return;
> + }
> +
> + cr = wl_resource_create(client, interface,
> + wl_resource_get_version(pointer_constraints_resource),
> + id);
indentation
> + if (cr == NULL) {
> + wl_client_post_no_memory(client);
> + return;
> + }
> +
> + constraint = weston_pointer_constraint_create(surface, pointer, region,
> + 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
> +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_hint = constraint->x_hint;
> + wl_fixed_t y_hint = constraint->y_hint;
> + wl_fixed_t x, y;
> +
> + if (constraint->view && constraint->hint_set &&
> + is_within_constraint_region(constraint, x_hint, y_hint)) {
> + weston_view_to_global_fixed(constraint->view,
> + x_hint, y_hint,
> + &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 already sent after the lock
drop the 'already'
I started getting a bit blurry-eyed towards the end, but the patch looks
good.
Acked-by: Peter Hutterer <peter.hutterer at who-t.net>
Cheers,
Peter
> + * was cancelled. */
> + if (!constraint->resource ||
> + constraint->resource != resource)
> + return;
> +
> + constraint->pending_hint_set = true;
> + constraint->pending_x_hint = surface_x;
> + constraint->pending_y_hint = 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->pending_region,
> + ®ion->region);
> + } else {
> + pixman_region32_fini(&constraint->pending_region);
> + region_init_infinite(&constraint->pending_region);
> + }
> + constraint->pending_region_set = 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 *seat_resource,
> + struct wl_resource *region_resource)
> +{
> + struct weston_surface *surface =
> + wl_resource_get_user_data(surface_resource);
> + struct weston_seat *seat = wl_resource_get_user_data(seat_resource);
> + struct weston_region *region = region_resource ?
> + wl_resource_get_user_data(region_resource) : NULL;
> +
> + init_pointer_constraint(resource, id, surface, seat, region,
> + &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,
> + uint32_t axis,
> + wl_fixed_t value)
> +{
> + weston_pointer_send_axis(grab->pointer, time, axis, value);
> +}
> +
> +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_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->pending_region,
> + ®ion->region);
> + } else {
> + pixman_region32_fini(&constraint->pending_region);
> + region_init_infinite(&constraint->pending_region);
> + }
> + constraint->pending_region_set = 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 *seat_resource,
> + struct wl_resource *region_resource)
> +{
> + struct weston_surface *surface =
> + wl_resource_get_user_data(surface_resource);
> + struct weston_seat *seat = wl_resource_get_user_data(seat_resource);
> + struct weston_region *region = region_resource ?
> + wl_resource_get_user_data(region_resource) : NULL;
> +
> + init_pointer_constraint(resource, id, surface, seat, region,
> + &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_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)
> {
> @@ -2826,5 +3571,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 9398d24..242e614 100644
> --- a/xwayland/window-manager.c
> +++ b/xwayland/window-manager.c
> @@ -775,7 +775,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
>
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel
>
More information about the wayland-devel
mailing list