Hi Jonas, On Tue, Mar 15, 2016 at 2:14 PM, Jonas Ådahl <jad...@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 <jad...@gmail.com> > Acked-by: Peter Hutterer <peter.hutte...@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
_______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/wayland-devel