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