[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,
> +				     &region->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,
> +				     &region->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,
> +				     &region->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