<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>
+ ®ion->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>
+ ®ion->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>
+ ®ion->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>