[PATCH weston 2/3] Implement pointer locking and confinement

Arnaud Vrac rawoul at gmail.com
Wed Jun 8 15:46:18 UTC 2016


Hi Jonas,

On Tue, Mar 15, 2016 at 2:14 PM, Jonas Ådahl <jadahl at gmail.com> wrote:

> This patch implements the wp_pointer_constraints protocol used for
> locking or confining a pointer. It consists of a new global object with
> two requests; one for locking the surface to a position, one for
> confining the pointer to a given region.
>
> In this patch, only the locking part is fully implemented as in
> specified in the protocol, while confinement is only implemented for
> when the union of the passed region and the input region of the confined
> surface is a single rectangle.
>
> Note that the pointer constraints protocol is still unstable and as
> such has the unstable protocol naming conventions applied.
>
> Signed-off-by: Jonas Ådahl <jadahl at gmail.com>
> Acked-by: Peter Hutterer <peter.hutterer at who-t.net>
> ---
>
> The changes since last version include:
>
> * Updated to the new protocol:
>   - Added oneshot vs persistent constraint lifetime
>   - Changed the constraint creation input from wl_seat to wl_pointer
>
>
>  Makefile.am               |   4 +-
>  src/compositor.c          |  11 +
>  src/compositor.h          |  44 +++
>  src/input.c               | 850
> ++++++++++++++++++++++++++++++++++++++++++++--
>  xwayland/window-manager.c |   3 +-
>  5 files changed, 888 insertions(+), 24 deletions(-)
>
> diff --git a/Makefile.am b/Makefile.am
> index 9a6bd9b..12ecc3c 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -128,7 +128,9 @@ nodist_weston_SOURCES =
>      \
>         protocol/linux-dmabuf-unstable-v1-protocol.c    \
>         protocol/linux-dmabuf-unstable-v1-server-protocol.h             \
>         protocol/relative-pointer-unstable-v1-protocol.c                \
> -       protocol/relative-pointer-unstable-v1-server-protocol.h
> +       protocol/relative-pointer-unstable-v1-server-protocol.h         \
> +       protocol/pointer-constraints-unstable-v1-protocol.c             \
> +       protocol/pointer-constraints-unstable-v1-server-protocol.h
>
>  BUILT_SOURCES += $(nodist_weston_SOURCES)
>
> diff --git a/src/compositor.c b/src/compositor.c
> index 68ce600..e2492db 100644
> --- a/src/compositor.c
> +++ b/src/compositor.c
> @@ -586,6 +586,7 @@ weston_surface_create(struct weston_compositor
> *compositor)
>                 return NULL;
>
>         wl_signal_init(&surface->destroy_signal);
> +       wl_signal_init(&surface->commit_signal);
>
>         surface->compositor = compositor;
>         surface->ref_count = 1;
> @@ -612,6 +613,8 @@ weston_surface_create(struct weston_compositor
> *compositor)
>         weston_matrix_init(&surface->buffer_to_surface_matrix);
>         weston_matrix_init(&surface->surface_to_buffer_matrix);
>
> +       wl_list_init(&surface->pointer_constraints);
> +
>         return surface;
>  }
>
> @@ -1928,6 +1931,7 @@ weston_surface_destroy(struct weston_surface
> *surface)
>  {
>         struct weston_frame_callback *cb, *next;
>         struct weston_view *ev, *nv;
> +       struct weston_pointer_constraint *constraint, *next_constraint;
>
>         if (--surface->ref_count > 0)
>                 return;
> @@ -1955,6 +1959,11 @@ weston_surface_destroy(struct weston_surface
> *surface)
>
>         weston_presentation_feedback_discard_list(&surface->feedback_list);
>
> +       wl_list_for_each_safe(constraint, next_constraint,
> +                             &surface->pointer_constraints,
> +                             link)
> +               weston_pointer_constraint_destroy(constraint);
> +
>         free(surface);
>  }
>
> @@ -2926,6 +2935,8 @@ weston_surface_commit_state(struct weston_surface
> *surface,
>         wl_list_insert_list(&surface->feedback_list,
>                             &state->feedback_list);
>         wl_list_init(&state->feedback_list);
> +
> +       wl_signal_emit(&surface->commit_signal, surface);
>  }
>
>  static void
> diff --git a/src/compositor.h b/src/compositor.h
> index ad98c67..20d2467 100644
> --- a/src/compositor.h
> +++ b/src/compositor.h
> @@ -45,6 +45,8 @@ extern "C" {
>  #include "zalloc.h"
>  #include "timeline-object.h"
>
> +#include "pointer-constraints-unstable-v1-server-protocol.h"
> +
>

This header is not installed so it should not be included here, since
compositor.h is installed.


>  struct weston_transform {
>         struct weston_matrix matrix;
>         struct wl_list link;
> @@ -58,6 +60,7 @@ struct weston_output;
>  struct input_method;
>  struct weston_pointer;
>  struct linux_dmabuf_buffer;
> +struct weston_pointer_constraint;
>
>  enum weston_keyboard_modifier {
>         MODIFIER_CTRL = (1 << 0),
> @@ -368,6 +371,7 @@ struct weston_pointer {
>         struct wl_listener focus_resource_listener;
>         struct wl_signal focus_signal;
>         struct wl_signal motion_signal;
> +       struct wl_signal destroy_signal;
>
>         struct weston_view *sprite;
>         struct wl_listener sprite_destroy_listener;
> @@ -449,6 +453,9 @@ void
>  weston_pointer_set_default_grab(struct weston_pointer *pointer,
>                 const struct weston_pointer_grab_interface *interface);
>
> +void
> +weston_pointer_constraint_destroy(struct weston_pointer_constraint
> *constraint);
> +
>  struct weston_keyboard *
>  weston_keyboard_create(void);
>  void
> @@ -790,6 +797,8 @@ struct weston_compositor {
>
>         unsigned int activate_serial;
>
> +       struct wl_global *pointer_constraints;
> +
>         int exit_code;
>
>         void *user_data;
> @@ -989,10 +998,42 @@ struct weston_surface_state {
>         struct weston_buffer_viewport buffer_viewport;
>  };
>
> +struct weston_surface_activation_data {
> +       struct weston_surface *surface;
> +       struct weston_seat *seat;
> +};
> +
> +struct weston_pointer_constraint {
> +       struct wl_list link;
> +
> +       struct weston_surface *surface;
> +       struct weston_view *view;
> +       struct wl_resource *resource;
> +       struct weston_pointer_grab grab;
> +       struct weston_pointer *pointer;
> +       enum zwp_pointer_constraints_v1_lifetime lifetime;
>

Replace "enum zwp_pointer_constraints_v1_lifetime" by uint32_t to avoid
needing the problematic header include ?


> +
> +       pixman_region32_t region;
> +       pixman_region32_t region_pending;
> +       bool region_is_pending;
> +
> +       wl_fixed_t hint_x;
> +       wl_fixed_t hint_y;
> +       wl_fixed_t hint_x_pending;
> +       wl_fixed_t hint_y_pending;
> +       bool hint_is_pending;
> +
> +       struct wl_listener pointer_destroy_listener;
> +       struct wl_listener surface_destroy_listener;
> +       struct wl_listener surface_commit_listener;
> +       struct wl_listener surface_activate_listener;
> +};
> +
>  struct weston_surface {
>         struct wl_resource *resource;
>         struct wl_signal destroy_signal; /* callback argument: this
> surface */
>         struct weston_compositor *compositor;
> +       struct wl_signal commit_signal;
>
>         /** Damage in local coordinates from the client, for tex upload. */
>         pixman_region32_t damage;
> @@ -1072,6 +1113,9 @@ struct weston_surface {
>         const char *role_name;
>
>         struct weston_timeline_object timeline;
> +
> +       /* An list of per seat pointer constraints. */
> +       struct wl_list pointer_constraints;
>  };
>
>  struct weston_subsurface {
> diff --git a/src/input.c b/src/input.c
> index b5a3273..f141c25 100644
> --- a/src/input.c
> +++ b/src/input.c
> @@ -25,6 +25,7 @@
>
>  #include "config.h"
>
> +#include <stdbool.h>
>  #include <stdlib.h>
>  #include <stdint.h>
>  #include <string.h>
> @@ -38,6 +39,15 @@
>  #include "shared/os-compatibility.h"
>  #include "compositor.h"
>  #include "protocol/relative-pointer-unstable-v1-server-protocol.h"
> +#include "protocol/pointer-constraints-unstable-v1-server-protocol.h"
> +
> +enum pointer_constraint_type {
> +       POINTER_CONSTRAINT_TYPE_LOCK,
> +       POINTER_CONSTRAINT_TYPE_CONFINE,
> +};
> +
> +static void
> +maybe_warp_confined_pointer(struct weston_pointer_constraint *constraint);
>
>  static void
>  empty_region(pixman_region32_t *region)
> @@ -46,6 +56,13 @@ empty_region(pixman_region32_t *region)
>         pixman_region32_init(region);
>  }
>
> +static void
> +region_init_infinite(pixman_region32_t *region)
> +{
> +       pixman_region32_init_rect(region, INT32_MIN, INT32_MIN,
> +                                 UINT32_MAX, UINT32_MAX);
> +}
> +
>  static struct weston_pointer_client *
>  weston_pointer_client_create(struct wl_client *client)
>  {
> @@ -340,12 +357,25 @@ weston_pointer_send_relative_motion(struct
> weston_pointer *pointer,
>  }
>
>  static void
> +weston_pointer_send_motion(struct weston_pointer *pointer, uint32_t time,
> +                          wl_fixed_t sx, wl_fixed_t sy)
> +{
> +       struct wl_list *resource_list;
> +       struct wl_resource *resource;
> +
> +       if (!pointer->focus_client)
> +               return;
> +
> +       resource_list = &pointer->focus_client->pointer_resources;
> +       wl_resource_for_each(resource, resource_list)
> +               wl_pointer_send_motion(resource, time, sx, sy);
> +}
> +
> +static void
>  default_grab_pointer_motion(struct weston_pointer_grab *grab, uint32_t
> time,
>                             struct weston_pointer_motion_event *event)
>  {
>         struct weston_pointer *pointer = grab->pointer;
> -       struct wl_list *resource_list;
> -       struct wl_resource *resource;
>         wl_fixed_t x, y;
>         wl_fixed_t old_sx = pointer->sx;
>         wl_fixed_t old_sy = pointer->sy;
> @@ -358,44 +388,51 @@ default_grab_pointer_motion(struct
> weston_pointer_grab *grab, uint32_t time,
>
>         weston_pointer_move(pointer, event);
>
> -       if (pointer->focus_client &&
> -           (old_sx != pointer->sx || old_sy != pointer->sy)) {
> -               resource_list = &pointer->focus_client->pointer_resources;
> -               wl_resource_for_each(resource, resource_list) {
> -                       wl_pointer_send_motion(resource, time,
> -                                              pointer->sx, pointer->sy);
> -               }
> +       if (old_sx != pointer->sx || old_sy != pointer->sy) {
> +               weston_pointer_send_motion(pointer, time,
> +                                          pointer->sx, pointer->sy);
>         }
>
>         weston_pointer_send_relative_motion(pointer, time, event);
>  }
>
>  static void
> -default_grab_pointer_button(struct weston_pointer_grab *grab,
> -                           uint32_t time, uint32_t button, uint32_t
> state_w)
> +weston_pointer_send_button(struct weston_pointer *pointer,
> +                          uint32_t time, uint32_t button, uint32_t
> state_w)
>  {
> -       struct weston_pointer *pointer = grab->pointer;
> -       struct weston_compositor *compositor = pointer->seat->compositor;
> -       struct weston_view *view;
> +       struct wl_display *display = pointer->seat->compositor->wl_display;
> +       struct wl_list *resource_list;
>         struct wl_resource *resource;
>         uint32_t serial;
> -       enum wl_pointer_button_state state = state_w;
> -       struct wl_display *display = compositor->wl_display;
> -       wl_fixed_t sx, sy;
> -       struct wl_list *resource_list = NULL;
>
> -       if (pointer->focus_client)
> -               resource_list = &pointer->focus_client->pointer_resources;
> +       if (!pointer->focus_client)
> +               return;
> +
> +       resource_list = &pointer->focus_client->pointer_resources;
>         if (resource_list && !wl_list_empty(resource_list)) {
>                 resource_list = &pointer->focus_client->pointer_resources;
>                 serial = wl_display_next_serial(display);
> -               wl_resource_for_each(resource, resource_list)
> +               wl_resource_for_each(resource, resource_list) {
>                         wl_pointer_send_button(resource,
>                                                serial,
>                                                time,
>                                                button,
>                                                state_w);
> +               }
>         }
> +}
> +
> +static void
> +default_grab_pointer_button(struct weston_pointer_grab *grab,
> +                           uint32_t time, uint32_t button, uint32_t
> state_w)
> +{
> +       struct weston_pointer *pointer = grab->pointer;
> +       struct weston_compositor *compositor = pointer->seat->compositor;
> +       struct weston_view *view;
> +       enum wl_pointer_button_state state = state_w;
> +       wl_fixed_t sx, sy;
> +
> +       weston_pointer_send_button(pointer, time, button, state_w);
>
>         if (pointer->button_count == 0 &&
>             state == WL_POINTER_BUTTON_STATE_RELEASED) {
> @@ -792,6 +829,7 @@ weston_pointer_create(struct weston_seat *seat)
>         wl_signal_init(&pointer->motion_signal);
>         wl_signal_init(&pointer->focus_signal);
>         wl_list_init(&pointer->focus_view_listener.link);
> +       wl_signal_init(&pointer->destroy_signal);
>
>         pointer->sprite_destroy_listener.notify =
> pointer_handle_sprite_destroy;
>
> @@ -813,6 +851,8 @@ weston_pointer_create(struct weston_seat *seat)
>  WL_EXPORT void
>  weston_pointer_destroy(struct weston_pointer *pointer)
>  {
> +       wl_signal_emit(&pointer->destroy_signal, pointer);
> +
>         if (pointer->sprite)
>                 pointer_unmap_sprite(pointer);
>
> @@ -1382,6 +1422,7 @@ weston_surface_activate(struct weston_surface
> *surface,
>  {
>         struct weston_compositor *compositor = seat->compositor;
>         struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
> +       struct weston_surface_activation_data activation_data;
>
>         inc_activate_serial(compositor);
>
> @@ -1390,7 +1431,11 @@ weston_surface_activate(struct weston_surface
> *surface,
>                 wl_data_device_set_keyboard_focus(seat);
>         }
>
> -       wl_signal_emit(&compositor->activate_signal, surface);
> +       activation_data = (struct weston_surface_activation_data) {
> +               .surface = surface,
> +               .seat = seat,
> +       };
> +       wl_signal_emit(&compositor->activate_signal, &activation_data);
>  }
>
>  WL_EXPORT void
> @@ -2897,6 +2942,70 @@ weston_seat_get_pointer(struct weston_seat *seat)
>         return NULL;
>  }
>
> +static const struct zwp_locked_pointer_v1_interface
> locked_pointer_interface;
> +static const struct zwp_confined_pointer_v1_interface
> confined_pointer_interface;
> +
> +static enum pointer_constraint_type
> +pointer_constraint_get_type(struct weston_pointer_constraint *constraint)
> +{
> +       if (wl_resource_instance_of(constraint->resource,
> +                                   &zwp_locked_pointer_v1_interface,
> +                                   &locked_pointer_interface)) {
> +               return POINTER_CONSTRAINT_TYPE_LOCK;
> +       } else if (wl_resource_instance_of(constraint->resource,
> +
> &zwp_confined_pointer_v1_interface,
> +                                          &confined_pointer_interface)) {
> +               return POINTER_CONSTRAINT_TYPE_CONFINE;
> +       }
> +
> +       abort();
> +       return 0;
> +}
> +
> +static void
> +pointer_constraint_notify_activated(struct weston_pointer_constraint
> *constraint)
> +{
> +       struct wl_resource *resource = constraint->resource;
> +
> +       switch (pointer_constraint_get_type(constraint)) {
> +       case POINTER_CONSTRAINT_TYPE_LOCK:
> +               zwp_locked_pointer_v1_send_locked(resource);
> +               break;
> +       case POINTER_CONSTRAINT_TYPE_CONFINE:
> +               zwp_confined_pointer_v1_send_confined(resource);
> +               break;
> +       }
> +}
> +
> +static void
> +pointer_constraint_notify_deactivated(struct weston_pointer_constraint
> *constraint)
> +{
> +       struct wl_resource *resource = constraint->resource;
> +
> +       switch (pointer_constraint_get_type(constraint)) {
> +       case POINTER_CONSTRAINT_TYPE_LOCK:
> +               zwp_locked_pointer_v1_send_unlocked(resource);
> +               break;
> +       case POINTER_CONSTRAINT_TYPE_CONFINE:
> +               zwp_confined_pointer_v1_send_unconfined(resource);
> +               break;
> +       }
> +}
> +
> +static struct weston_pointer_constraint *
> +get_pointer_constraint_for_pointer(struct weston_surface *surface,
> +                                  struct weston_pointer *pointer)
> +{
> +       struct weston_pointer_constraint *constraint;
> +
> +       wl_list_for_each(constraint, &surface->pointer_constraints, link) {
> +               if (constraint->pointer == pointer)
> +                       return constraint;
> +       }
> +
> +       return NULL;
> +}
> +
>  /** Get a seat's touch pointer
>   *
>   * \param seat The seat to query
> @@ -2919,6 +3028,698 @@ weston_seat_get_touch(struct weston_seat *seat)
>         return NULL;
>  }
>
> +static void
> +enable_pointer_constraint(struct weston_pointer_constraint *constraint,
> +                         struct weston_view *view)
> +{
> +       assert(constraint->view == NULL);
> +       constraint->view = view;
> +       pointer_constraint_notify_activated(constraint);
> +       weston_pointer_start_grab(constraint->pointer, &constraint->grab);
> +}
> +
> +static bool
> +is_pointer_constraint_enabled(struct weston_pointer_constraint
> *constraint)
> +{
> +       return constraint->view != NULL;
> +}
> +
> +static void
> +weston_pointer_constraint_disable(struct weston_pointer_constraint
> *constraint)
> +{
> +       constraint->view = NULL;
> +       pointer_constraint_notify_deactivated(constraint);
> +       weston_pointer_end_grab(constraint->grab.pointer);
> +}
> +
> +void
> +weston_pointer_constraint_destroy(struct weston_pointer_constraint
> *constraint)
> +{
> +       if (is_pointer_constraint_enabled(constraint))
> +               weston_pointer_constraint_disable(constraint);
> +
> +       wl_list_remove(&constraint->pointer_destroy_listener.link);
> +       wl_list_remove(&constraint->surface_destroy_listener.link);
> +       wl_list_remove(&constraint->surface_commit_listener.link);
> +       wl_list_remove(&constraint->surface_activate_listener.link);
> +
> +       wl_resource_set_user_data(constraint->resource, NULL);
> +       pixman_region32_fini(&constraint->region);
> +       wl_list_remove(&constraint->link);
> +       free(constraint);
> +}
> +
> +static void
> +disable_pointer_constraint(struct weston_pointer_constraint *constraint)
> +{
> +       switch (constraint->lifetime) {
> +       case ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT:
> +               weston_pointer_constraint_destroy(constraint);
> +               break;
> +       case ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT:
> +               weston_pointer_constraint_disable(constraint);
> +               break;
> +       }
> +}
> +
> +static bool
> +is_within_constraint_region(struct weston_pointer_constraint *constraint,
> +                           wl_fixed_t sx, wl_fixed_t sy)
> +{
> +       struct weston_surface *surface = constraint->surface;
> +       pixman_region32_t constraint_region;
> +       bool result;
> +
> +       pixman_region32_init(&constraint_region);
> +       pixman_region32_intersect(&constraint_region,
> +                                 &surface->input,
> +                                 &constraint->region);
> +       result = pixman_region32_contains_point(&constraint_region,
> +                                               wl_fixed_to_int(sx),
> +                                               wl_fixed_to_int(sy),
> +                                               NULL);
> +       pixman_region32_fini(&constraint_region);
> +
> +       return result;
> +}
> +
> +static void
> +maybe_enable_pointer_constraint(struct weston_pointer_constraint
> *constraint)
> +{
> +       struct weston_surface *surface = constraint->surface;
> +       struct weston_view *vit;
> +       struct weston_view *view = NULL;
> +       struct weston_pointer *pointer = constraint->pointer;
> +       struct weston_keyboard *keyboard;
> +       struct weston_seat *seat = pointer->seat;
> +       int32_t x, y;
> +
> +       /* Postpone if no view of the surface was most recently clicked. */
> +       wl_list_for_each(vit, &surface->views, surface_link) {
> +               if (vit->click_to_activate_serial ==
> +                   surface->compositor->activate_serial) {
> +                       view = vit;
> +               }
> +       }
> +       if (view == NULL)
> +               return;
> +
> +       /* Postpone if surface doesn't have keyboard focus. */
> +       keyboard = weston_seat_get_keyboard(seat);
> +       if (!keyboard || keyboard->focus != surface)
> +               return;
> +
> +       /* Postpone constraint if the pointer is not within the
> +        * constraint region.
> +        */
> +       weston_view_from_global(view,
> +                               wl_fixed_to_int(pointer->x),
> +                               wl_fixed_to_int(pointer->y),
> +                               &x, &y);
> +       if (!is_within_constraint_region(constraint,
> +                                        wl_fixed_from_int(x),
> +                                        wl_fixed_from_int(y)))
> +               return;
> +
> +       enable_pointer_constraint(constraint, view);
> +}
> +
> +static void
> +locked_pointer_grab_pointer_focus(struct weston_pointer_grab *grab)
> +{
> +}
> +
> +static void
> +locked_pointer_grab_pointer_motion(struct weston_pointer_grab *grab,
> +                                  uint32_t time,
> +                                  struct weston_pointer_motion_event
> *event)
> +{
> +       weston_pointer_send_relative_motion(grab->pointer, time, event);
> +}
> +
> +static void
> +locked_pointer_grab_pointer_button(struct weston_pointer_grab *grab,
> +                                  uint32_t time,
> +                                  uint32_t button,
> +                                  uint32_t state_w)
> +{
> +       weston_pointer_send_button(grab->pointer, time, button, state_w);
> +}
> +
> +static void
> +locked_pointer_grab_pointer_axis(struct weston_pointer_grab *grab,
> +                                uint32_t time,
> +                                struct weston_pointer_axis_event *event)
> +{
> +       weston_pointer_send_axis(grab->pointer, time, event);
> +}
> +
> +static void
> +locked_pointer_grab_pointer_axis_source(struct weston_pointer_grab *grab,
> +                                       uint32_t source)
> +{
> +       weston_pointer_send_axis_source(grab->pointer, source);
> +}
> +
> +static void
> +locked_pointer_grab_pointer_frame(struct weston_pointer_grab *grab)
> +{
> +       weston_pointer_send_frame(grab->pointer);
> +}
> +
> +static void
> +locked_pointer_grab_pointer_cancel(struct weston_pointer_grab *grab)
> +{
> +       struct weston_pointer_constraint *constraint =
> +               container_of(grab, struct weston_pointer_constraint, grab);
> +
> +       disable_pointer_constraint(constraint);
> +}
> +
> +static const struct weston_pointer_grab_interface
> +                               locked_pointer_grab_interface = {
> +       locked_pointer_grab_pointer_focus,
> +       locked_pointer_grab_pointer_motion,
> +       locked_pointer_grab_pointer_button,
> +       locked_pointer_grab_pointer_axis,
> +       locked_pointer_grab_pointer_axis_source,
> +       locked_pointer_grab_pointer_frame,
> +       locked_pointer_grab_pointer_cancel,
> +};
> +
> +static void
> +pointer_constraint_constrain_resource_destroyed(struct wl_resource
> *resource)
> +{
> +       struct weston_pointer_constraint *constraint =
> +               wl_resource_get_user_data(resource);
> +
> +       if (!constraint)
> +               return;
> +
> +       weston_pointer_constraint_destroy(constraint);
> +}
> +
> +static void
> +pointer_constraint_surface_activate(struct wl_listener *listener, void
> *data)
> +{
> +       struct weston_surface_activation_data *activation = data;
> +       struct weston_pointer *pointer;
> +       struct weston_surface *focus = activation->surface;
> +       struct weston_pointer_constraint *constraint =
> +               container_of(listener, struct weston_pointer_constraint,
> +                            surface_activate_listener);
> +       bool is_constraint_surface;
> +
> +       pointer = weston_seat_get_pointer(activation->seat);
> +       if (!pointer)
> +               return;
> +
> +       is_constraint_surface =
> +               get_pointer_constraint_for_pointer(focus, pointer) ==
> constraint;
> +
> +       if (is_constraint_surface &&
> +           !is_pointer_constraint_enabled(constraint))
> +               maybe_enable_pointer_constraint(constraint);
> +       else if (!is_constraint_surface &&
> +                is_pointer_constraint_enabled(constraint))
> +               disable_pointer_constraint(constraint);
> +}
> +
> +static void
> +pointer_constraint_pointer_destroyed(struct wl_listener *listener, void
> *data)
> +{
> +       struct weston_pointer_constraint *constraint =
> +               container_of(listener, struct weston_pointer_constraint,
> +                            pointer_destroy_listener);
> +
> +       weston_pointer_constraint_destroy(constraint);
> +}
> +
> +static void
> +pointer_constraint_surface_destroyed(struct wl_listener *listener, void
> *data)
> +{
> +       struct weston_pointer_constraint *constraint =
> +               container_of(listener, struct weston_pointer_constraint,
> +                            surface_destroy_listener);
> +
> +       weston_pointer_constraint_destroy(constraint);
> +}
> +
> +static void
> +pointer_constraint_surface_committed(struct wl_listener *listener, void
> *data)
> +{
> +       struct weston_pointer_constraint *constraint =
> +               container_of(listener, struct weston_pointer_constraint,
> +                            surface_commit_listener);
> +
> +       if (constraint->region_is_pending) {
> +               constraint->region_is_pending = false;
> +               pixman_region32_copy(&constraint->region,
> +                                    &constraint->region_pending);
> +               pixman_region32_fini(&constraint->region_pending);
> +               pixman_region32_init(&constraint->region_pending);
> +       }
> +
> +       if (constraint->hint_is_pending) {
> +               constraint->hint_is_pending = false;
> +
> +               constraint->hint_is_pending = true;
> +               constraint->hint_x = constraint->hint_x_pending;
> +               constraint->hint_y = constraint->hint_y_pending;
> +       }
> +
> +       if (pointer_constraint_get_type(constraint) ==
> +           POINTER_CONSTRAINT_TYPE_CONFINE &&
> +           is_pointer_constraint_enabled(constraint))
> +               maybe_warp_confined_pointer(constraint);
> +}
> +
> +static struct weston_pointer_constraint *
> +weston_pointer_constraint_create(struct weston_surface *surface,
> +                                struct weston_pointer *pointer,
> +                                struct weston_region *region,
> +                                enum zwp_pointer_constraints_v1_lifetime
> lifetime,
> +                                struct wl_resource *cr,
> +                                const struct
> weston_pointer_grab_interface *grab_interface)
> +{
> +       struct weston_pointer_constraint *constraint;
> +
> +       constraint = zalloc(sizeof *constraint);
> +       if (!constraint)
> +               return NULL;
> +
> +       constraint->lifetime = lifetime;
> +       pixman_region32_init(&constraint->region);
> +       pixman_region32_init(&constraint->region_pending);
> +       wl_list_insert(&surface->pointer_constraints, &constraint->link);
> +       constraint->surface = surface;
> +       constraint->pointer = pointer;
> +       constraint->resource = cr;
> +       constraint->grab.interface = grab_interface;
> +       if (region) {
> +               pixman_region32_copy(&constraint->region,
> +                                    &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_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,
> +                                    &region->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,
> +                                    &region->region);
> +       } else {
> +               pixman_region32_fini(&constraint->region_pending);
> +               region_init_infinite(&constraint->region_pending);
> +       }
> +       constraint->region_is_pending = true;
> +}
> +
> +static const struct zwp_confined_pointer_v1_interface
> confined_pointer_interface = {
> +       confined_pointer_destroy,
> +       confined_pointer_set_region,
> +};
> +
> +static void
> +pointer_constraints_confine_pointer(struct wl_client *client,
> +                                   struct wl_resource *resource,
> +                                   uint32_t id,
> +                                   struct wl_resource *surface_resource,
> +                                   struct wl_resource *pointer_resource,
> +                                   struct wl_resource *region_resource,
> +                                   uint32_t lifetime)
> +{
> +       struct weston_surface *surface =
> +               wl_resource_get_user_data(surface_resource);
> +       struct weston_pointer *pointer =
> wl_resource_get_user_data(pointer_resource);
> +       struct weston_region *region = region_resource ?
> +               wl_resource_get_user_data(region_resource) : NULL;
> +
> +       init_pointer_constraint(resource, id, surface, pointer, region,
> lifetime,
> +                               &zwp_confined_pointer_v1_interface,
> +                               &confined_pointer_interface,
> +                               &confined_pointer_grab_interface);
> +}
> +
> +static const struct zwp_pointer_constraints_v1_interface
> pointer_constraints_interface = {
> +       pointer_constraints_destroy,
> +       pointer_constraints_lock_pointer,
> +       pointer_constraints_confine_pointer,
> +};
> +
> +static void
> +bind_pointer_constraints(struct wl_client *client, void *data,
> +                        uint32_t version, uint32_t id)
> +{
> +       struct wl_resource *resource;
> +
> +       resource = wl_resource_create(client,
> +
>  &zwp_pointer_constraints_v1_interface,
> +                                     1, id);
> +
> +       wl_resource_set_implementation(resource,
> &pointer_constraints_interface,
> +                                      NULL, NULL);
> +}
> +
>  int
>  weston_input_init(struct weston_compositor *compositor)
>  {
> @@ -2927,5 +3728,10 @@ weston_input_init(struct weston_compositor
> *compositor)
>                               compositor, bind_relative_pointer_manager))
>                 return -1;
>
> +       if (!wl_global_create(compositor->wl_display,
> +                             &zwp_pointer_constraints_v1_interface, 1,
> +                             NULL, bind_pointer_constraints))
> +               return -1;
> +
>         return 0;
>  }
> diff --git a/xwayland/window-manager.c b/xwayland/window-manager.c
> index f6f92bd..49d974e 100644
> --- a/xwayland/window-manager.c
> +++ b/xwayland/window-manager.c
> @@ -778,7 +778,8 @@ weston_wm_send_focus_window(struct weston_wm *wm,
>  static void
>  weston_wm_window_activate(struct wl_listener *listener, void *data)
>  {
> -       struct weston_surface *surface = data;
> +       struct weston_surface_activation_data *activation_data = data;
> +       struct weston_surface *surface = activation_data->surface;
>         struct weston_wm_window *window = NULL;
>         struct weston_wm *wm =
>                 container_of(listener, struct weston_wm,
> activate_listener);
> --
> 2.4.3
>

Regards,

-- 
Arnaud
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/wayland-devel/attachments/20160608/1de122b8/attachment-0001.html>


More information about the wayland-devel mailing list