[PATCH weston v4 13/20] clients: Add API for pointer locking and pointer confinement
Peter Hutterer
peter.hutterer at who-t.net
Thu Nov 19 20:44:27 PST 2015
On Tue, Nov 17, 2015 at 06:10:59PM +0800, Jonas Ådahl wrote:
> Signed-off-by: Jonas Ådahl <jadahl at gmail.com>
> Reviewed-by: Bryce Harrington <bryce at osg.samsung.com>
> ---
>
> Changes since v3:
>
> Uses the XML file from wayland-protocols.
>
> Updated implementation given interface renaming.
>
> Updated implementation given protocol changes (see protocol patch).
>
>
> Makefile.am | 6 +-
> clients/window.c | 326 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
> clients/window.h | 62 +++++++++++
> 3 files changed, 393 insertions(+), 1 deletion(-)
>
> diff --git a/Makefile.am b/Makefile.am
> index a640d74..42e91cb 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -559,7 +559,11 @@ nodist_libtoytoolkit_la_SOURCES = \
> protocol/xdg-shell-unstable-v5-protocol.c \
> protocol/xdg-shell-unstable-v5-client-protocol.h \
> protocol/ivi-application-protocol.c \
> - protocol/ivi-application-client-protocol.h
> + protocol/ivi-application-client-protocol.h \
> + protocol/pointer-constraints-unstable-v1-protocol.c \
> + protocol/pointer-constraints-unstable-v1-client-protocol.h \
> + protocol/relative-pointer-unstable-v1-protocol.c \
> + protocol/relative-pointer-unstable-v1-client-protocol.h
>
> BUILT_SOURCES += $(nodist_libtoytoolkit_la_SOURCES)
>
> diff --git a/clients/window.c b/clients/window.c
> index f9797a2..6f5ca85 100644
> --- a/clients/window.c
> +++ b/clients/window.c
> @@ -24,6 +24,7 @@
>
> #include "config.h"
>
> +#include <stdbool.h>
> #include <stdint.h>
> #include <stdio.h>
> #include <stdlib.h>
> @@ -70,6 +71,8 @@ typedef void *EGLContext;
> #include "shared/helpers.h"
> #include "xdg-shell-unstable-v5-client-protocol.h"
> #include "text-cursor-position-client-protocol.h"
> +#include "pointer-constraints-unstable-v1-client-protocol.h"
> +#include "relative-pointer-unstable-v1-client-protocol.h"
> #include "shared/os-compatibility.h"
>
> #include "window.h"
> @@ -78,6 +81,9 @@ typedef void *EGLContext;
> #include "ivi-application-client-protocol.h"
> #define IVI_SURFACE_ID 9000
>
> +#define ZWP_RELATIVE_POINTER_MANAGER_V1_VERSION 1
> +#define ZWP_POINTER_CONSTRAINTS_V1_VERSION 1
> +
> struct shm_pool;
>
> struct global {
> @@ -97,6 +103,8 @@ struct display {
> struct text_cursor_position *text_cursor_position;
> struct xdg_shell *xdg_shell;
> struct ivi_application *ivi_application; /* ivi style shell */
> + struct zwp_relative_pointer_manager_v1 *relative_pointer_manager;
> + struct zwp_pointer_constraints_v1 *pointer_constraints;
> EGLDisplay dpy;
> EGLConfig argb_config;
> EGLContext argb_ctx;
> @@ -245,6 +253,8 @@ struct window {
> window_output_handler_t output_handler;
> window_state_changed_handler_t state_changed_handler;
>
> + window_locked_pointer_motion_handler_t locked_pointer_motion_handler;
> +
> struct surface *main_surface;
> struct xdg_surface *xdg_surface;
> struct xdg_popup *xdg_popup;
> @@ -259,6 +269,19 @@ struct window {
> /* struct surface::link, contains also main_surface */
> struct wl_list subsurface_list;
>
> + struct zwp_relative_pointer_v1 *relative_pointer;
> + struct zwp_locked_pointer_v1 *locked_pointer;
> + struct input *locked_input;
> + bool pointer_locked;
> + locked_pointer_locked_handler_t pointer_locked_handler;
> + locked_pointer_unlocked_handler_t pointer_unlocked_handler;
> + confined_pointer_confined_handler_t pointer_confined_handler;
> + confined_pointer_unconfined_handler_t pointer_unconfined_handler;
> +
> + struct zwp_confined_pointer_v1 *confined_pointer;
> + struct widget *confined_widget;
> + bool confined;
> +
> void *user_data;
> struct wl_list link;
> };
> @@ -3911,6 +3934,22 @@ window_do_resize(struct window *window)
>
> if (!window->fullscreen && !window->maximized)
> window->saved_allocation = window->pending_allocation;
> +
> + if (window->confined && window->confined_widget) {
> + struct wl_compositor *compositor = window->display->compositor;
> + struct wl_region *region;
> + struct widget *widget = window->confined_widget;
> +
> + region = wl_compositor_create_region(compositor);
> + wl_region_add(region,
> + widget->allocation.x,
> + widget->allocation.y,
> + widget->allocation.width,
> + widget->allocation.height);
> + zwp_confined_pointer_v1_set_region(window->confined_pointer,
> + region);
> + wl_region_destroy(region);
> + }
> }
>
> static void
> @@ -4440,6 +4479,43 @@ window_set_state_changed_handler(struct window *window,
> }
>
> void
> +window_set_pointer_locked_handler(struct window *window,
> + locked_pointer_locked_handler_t locked)
> +{
> + window->pointer_locked_handler = locked;
> +}
> +
> +void
> +window_set_pointer_unlocked_handler(struct window *window,
> + locked_pointer_unlocked_handler_t unlocked)
> +{
> + window->pointer_unlocked_handler = unlocked;
> +}
is it necessary to have these as separate functions? why not have a
set_locked_handler that takes the locked and unlocked handlers both?
same for confined/unconfined.
> +
> +void
> +window_set_pointer_confined_handler(
> + struct window *window, confined_pointer_confined_handler_t confined)
indentation doesn't look right
> +{
> + window->pointer_confined_handler = confined;
> +}
> +
> +void
> +window_set_pointer_unconfined_handler(
> + struct window *window,
> + confined_pointer_unconfined_handler_t unconfined)
same here
> +{
> + window->pointer_unconfined_handler = unconfined;
> +}
> +
> +void
> +window_set_locked_pointer_motion_handler(
> + struct window *window,
> + window_locked_pointer_motion_handler_t handler)
> +{
> + window->locked_pointer_motion_handler = handler;
> +}
> +
> +void
> window_set_title(struct window *window, const char *title)
> {
> free(window->title);
> @@ -4481,6 +4557,244 @@ window_damage(struct window *window, int32_t x, int32_t y,
> }
>
> static void
> +relative_pointer_handle_motion(void *data, struct zwp_relative_pointer_v1 *pointer,
> + uint32_t utime_most,
> + uint32_t utime_least,
hi/lo
> + wl_fixed_t dx,
> + wl_fixed_t dy,
> + wl_fixed_t dx_unaccel,
> + wl_fixed_t dy_unaccel)
> +{
> + struct input *input = data;
> + struct window *window = input->pointer_focus;
> + uint32_t time = (((uint64_t) utime_most) << 32 | utime_least) / 1000;
s/time/ms/ to make it obvious that's intended here. also, your bikeshed is
the wrong colour! :)
> +
> + if (window->locked_pointer_motion_handler &&
> + window->pointer_locked) {
> + window->locked_pointer_motion_handler(
> + window, input, time,
> + wl_fixed_to_double(dx),
> + wl_fixed_to_double(dy),
> + window->user_data);
> + }
> +}
> +
> +static const struct zwp_relative_pointer_v1_listener relative_pointer_listener = {
> + relative_pointer_handle_motion,
> +};
> +
> +static void
> +locked_pointer_locked(void *data,
> + struct zwp_locked_pointer_v1 *locked_pointer)
> +{
> + struct input *input = data;
> + struct window *window = input->pointer_focus;
> +
> + window->pointer_locked = true;
> +
> + if (window->pointer_locked_handler) {
> + window->pointer_locked_handler(window,
> + input,
> + window->user_data);
> + }
> +}
> +
> +static void
> +locked_pointer_unlocked(void *data,
> + struct zwp_locked_pointer_v1 *locked_pointer)
> +{
> + struct input *input = data;
> + struct window *window = input->pointer_focus;
> +
> + window_unlock_pointer(window);
> +
> + if (window->pointer_unlocked_handler) {
> + window->pointer_unlocked_handler(window,
> + input,
> + window->user_data);
> + }
> +}
> +
> +static const struct zwp_locked_pointer_v1_listener locked_pointer_listener = {
> + locked_pointer_locked,
> + locked_pointer_unlocked,
> +};
> +
> +int
> +window_lock_pointer(struct window *window, struct input *input)
> +{
> + struct zwp_relative_pointer_manager_v1 *relative_pointer_manager =
> + window->display->relative_pointer_manager;
> + struct zwp_pointer_constraints_v1 *pointer_constraints =
> + window->display->pointer_constraints;
> + struct zwp_relative_pointer_v1 *relative_pointer;
> + struct zwp_locked_pointer_v1 *locked_pointer;
> +
> + if (!window->display->relative_pointer_manager)
> + return -1;
> +
> + if (!window->display->pointer_constraints)
> + return -1;
> +
> + if (window->locked_pointer)
> + return -1;
> +
> + if (window->confined_pointer)
> + return -1;
> +
> + if (!input->pointer)
> + return -1;
> +
> + relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(
> + relative_pointer_manager, input->pointer);
> + zwp_relative_pointer_v1_add_listener(relative_pointer,
> + &relative_pointer_listener,
> + input);
> +
> + locked_pointer =
> + zwp_pointer_constraints_v1_lock_pointer(pointer_constraints,
> + window->main_surface->surface,
> + input->seat,
> + NULL);
> + zwp_locked_pointer_v1_add_listener(locked_pointer,
> + &locked_pointer_listener,
> + input);
> +
> + window->locked_input = input;
> + window->locked_pointer = locked_pointer;
> + window->relative_pointer = relative_pointer;
> +
> + return 0;
> +}
> +
> +void
> +window_unlock_pointer(struct window *window)
> +{
> + if (!window->locked_pointer)
> + return;
> +
> + zwp_locked_pointer_v1_destroy(window->locked_pointer);
> + zwp_relative_pointer_v1_destroy(window->relative_pointer);
> + window->locked_pointer = NULL;
> + window->relative_pointer = NULL;
> + window->pointer_locked = false;
> + window->locked_input = NULL;
> +}
> +
> +void
> +widget_set_locked_pointer_cursor_hint(struct widget *widget,
> + float x, float y)
> +{
> + struct window *window = widget->window;
> +
> + if (!window->locked_pointer)
> + return;
> +
> + zwp_locked_pointer_v1_set_cursor_position_hint(window->locked_pointer,
> + wl_fixed_from_double(x),
> + wl_fixed_from_double(y));
> + wl_surface_commit(window->main_surface->surface);
> +}
> +
> +static void
> +confined_pointer_confined(void *data,
> + struct zwp_confined_pointer_v1 *confined_pointer)
> +{
> + struct input *input = data;
> + struct window *window = input->pointer_focus;
> +
> + if (window->pointer_confined_handler) {
> + window->pointer_confined_handler(window,
> + input,
> + window->user_data);
> + }
> + window->confined = true;
> +}
> +
> +static void
> +confined_pointer_unconfined(void *data,
> + struct zwp_confined_pointer_v1 *confined_pointer)
> +{
> + struct input *input = data;
> + struct window *window = input->pointer_focus;
> +
> + window_unconfine_pointer(window);
> +
> + if (window->pointer_unconfined_handler) {
> + window->pointer_unconfined_handler(window,
> + input,
> + window->user_data);
> + }
> + window->confined = false;
for the locked_pointer you set the bool before sending the event, here you
set it after. is this intentional?
rest looks good.
Cheers,
Peter
> +}
> +
> +static const struct zwp_confined_pointer_v1_listener confined_pointer_listener = {
> + confined_pointer_confined,
> + confined_pointer_unconfined,
> +};
> +
> +int
> +window_confine_pointer_to_widget(struct window *window,
> + struct widget *widget,
> + struct input *input)
> +{
> + struct zwp_pointer_constraints_v1 *pointer_constraints =
> + window->display->pointer_constraints;
> + struct zwp_confined_pointer_v1 *confined_pointer;
> + struct wl_compositor *compositor = window->display->compositor;
> + struct wl_region *region = NULL;
> +
> + if (!window->display->pointer_constraints)
> + return -1;
> +
> + if (window->locked_pointer)
> + return -1;
> +
> + if (window->confined_pointer)
> + return -1;
> +
> + if (!input->pointer)
> + return -1;
> +
> + if (widget) {
> + region = wl_compositor_create_region(compositor);
> + wl_region_add(region,
> + widget->allocation.x,
> + widget->allocation.y,
> + widget->allocation.width,
> + widget->allocation.height);
> + }
> +
> + confined_pointer =
> + zwp_pointer_constraints_v1_confine_pointer(pointer_constraints,
> + window->main_surface->surface,
> + input->seat,
> + region);
> + if (region)
> + wl_region_destroy(region);
> +
> + zwp_confined_pointer_v1_add_listener(confined_pointer,
> + &confined_pointer_listener,
> + input);
> +
> + window->confined_pointer = confined_pointer;
> + window->confined_widget = widget;
> +
> + return 0;
> +}
> +
> +void
> +window_unconfine_pointer(struct window *window)
> +{
> + if (!window->confined_pointer)
> + return;
> +
> + zwp_confined_pointer_v1_destroy(window->confined_pointer);
> + window->confined_pointer = NULL;
> + window->confined = false;
> +}
> +
> +static void
> surface_enter(void *data,
> struct wl_surface *wl_surface, struct wl_output *wl_output)
> {
> @@ -5321,6 +5635,18 @@ registry_handle_global(void *data, struct wl_registry *registry, uint32_t id,
> display_add_output(d, id);
> } else if (strcmp(interface, "wl_seat") == 0) {
> display_add_input(d, id, version);
> + } else if (strcmp(interface, "zwp_relative_pointer_manager_v1") == 0 &&
> + version == ZWP_RELATIVE_POINTER_MANAGER_V1_VERSION) {
> + d->relative_pointer_manager =
> + wl_registry_bind(registry, id,
> + &zwp_relative_pointer_manager_v1_interface,
> + 1);
> + } else if (strcmp(interface, "zwp_pointer_constraints_v1") == 0 &&
> + version == ZWP_POINTER_CONSTRAINTS_V1_VERSION) {
> + d->pointer_constraints =
> + wl_registry_bind(registry, id,
> + &zwp_pointer_constraints_v1_interface,
> + 1);
> } else if (strcmp(interface, "wl_shm") == 0) {
> d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
> wl_shm_add_listener(d->shm, &shm_listener, d);
> diff --git a/clients/window.h b/clients/window.h
> index b61a62a..42cf492 100644
> --- a/clients/window.h
> +++ b/clients/window.h
> @@ -218,6 +218,29 @@ typedef void (*window_output_handler_t)(struct window *window, struct output *ou
> typedef void (*window_state_changed_handler_t)(struct window *window,
> void *data);
>
> +
> +typedef void (*window_locked_pointer_motion_handler_t)(struct window *window,
> + struct input *input,
> + uint32_t time,
> + float x, float y,
> + void *data);
> +
> +typedef void (*locked_pointer_locked_handler_t)(struct window *window,
> + struct input *input,
> + void *data);
> +
> +typedef void (*locked_pointer_unlocked_handler_t)(struct window *window,
> + struct input *input,
> + void *data);
> +
> +typedef void (*confined_pointer_confined_handler_t)(struct window *window,
> + struct input *input,
> + void *data);
> +
> +typedef void (*confined_pointer_unconfined_handler_t)(struct window *window,
> + struct input *input,
> + void *data);
> +
> typedef void (*widget_resize_handler_t)(struct widget *widget,
> int32_t width, int32_t height,
> void *data);
> @@ -347,6 +370,24 @@ void
> window_damage(struct window *window, int32_t x, int32_t y,
> int32_t width, int32_t height);
>
> +int
> +window_lock_pointer(struct window *window, struct input *input);
> +
> +void
> +window_unlock_pointer(struct window *window);
> +
> +void
> +widget_set_locked_pointer_cursor_hint(struct widget *widget,
> + float x, float y);
> +
> +int
> +window_confine_pointer_to_widget(struct window *window,
> + struct widget *widget,
> + struct input *input);
> +
> +void
> +window_unconfine_pointer(struct window *window);
> +
> cairo_surface_t *
> window_get_surface(struct window *window);
>
> @@ -425,6 +466,27 @@ window_set_state_changed_handler(struct window *window,
> window_state_changed_handler_t handler);
>
> void
> +window_set_pointer_locked_handler(struct window *window,
> + locked_pointer_locked_handler_t locked);
> +
> +void
> +window_set_pointer_unlocked_handler(struct window *window,
> + locked_pointer_unlocked_handler_t unlocked);
> +
> +void
> +window_set_pointer_confined_handler(
> + struct window *window, confined_pointer_confined_handler_t confined);
> +
> +void
> +window_set_pointer_unconfined_handler(
> + struct window *window,
> + confined_pointer_unconfined_handler_t unconfined);
> +
> +void
> +window_set_locked_pointer_motion_handler(
> + struct window *window, window_locked_pointer_motion_handler_t handler);
> +
> +void
> window_set_title(struct window *window, const char *title);
>
> const char *
> --
> 2.4.3
>
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel
>
More information about the wayland-devel
mailing list