[PATCH v3 weston] clients: Add API for pointer locking and pointer confinement
Jonas Ådahl
jadahl at gmail.com
Thu Jun 25 21:37:54 PDT 2015
Signed-off-by: Jonas Ådahl <jadahl at gmail.com>
---
Changes since v2:
* Automatically update the lock/confine region when window is resized.
Makefile.am | 6 +-
clients/window.c | 316 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
clients/window.h | 62 +++++++++++
3 files changed, 383 insertions(+), 1 deletion(-)
diff --git a/Makefile.am b/Makefile.am
index 201b780..9ddbbe9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -497,7 +497,11 @@ nodist_libtoytoolkit_la_SOURCES = \
protocol/xdg-shell-protocol.c \
protocol/xdg-shell-client-protocol.h \
protocol/ivi-application-protocol.c \
- protocol/ivi-application-client-protocol.h
+ protocol/ivi-application-client-protocol.h \
+ protocol/pointer-lock-protocol.c \
+ protocol/pointer-lock-client-protocol.h \
+ protocol/relative-pointer-protocol.c \
+ protocol/relative-pointer-client-protocol.h
BUILT_SOURCES += $(nodist_libtoytoolkit_la_SOURCES)
diff --git a/clients/window.c b/clients/window.c
index 81e007b..a468ad0 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -23,6 +23,7 @@
#include "config.h"
+#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -69,7 +70,10 @@ typedef void *EGLContext;
#include "xdg-shell-client-protocol.h"
#include "text-cursor-position-client-protocol.h"
#include "workspaces-client-protocol.h"
+#include "pointer-lock-client-protocol.h"
+#include "relative-pointer-client-protocol.h"
#include "../shared/os-compatibility.h"
+#include "../shared/util.h"
#include "window.h"
@@ -97,6 +101,8 @@ struct display {
struct workspace_manager *workspace_manager;
struct xdg_shell *xdg_shell;
struct ivi_application *ivi_application; /* ivi style shell */
+ struct _wl_relative_pointer_manager *relative_pointer_manager;
+ struct _wl_pointer_lock *pointer_lock;
EGLDisplay dpy;
EGLConfig argb_config;
EGLContext argb_ctx;
@@ -249,6 +255,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;
@@ -263,6 +271,19 @@ struct window {
/* struct surface::link, contains also main_surface */
struct wl_list subsurface_list;
+ struct _wl_relative_pointer *relative_pointer;
+ struct _wl_locked_pointer *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 _wl_confined_pointer *confined_pointer;
+ struct widget *confined_widget;
+ bool confined;
+
void *user_data;
struct wl_list link;
};
@@ -3872,6 +3893,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);
+ _wl_confined_pointer_set_region(window->confined_pointer,
+ region);
+ wl_region_destroy(region);
+ }
}
static void
@@ -4403,6 +4440,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;
+}
+
+void
+window_set_pointer_confined_handler(
+ struct window *window, confined_pointer_confined_handler_t confined)
+{
+ window->pointer_confined_handler = confined;
+}
+
+void
+window_set_pointer_unconfined_handler(
+ struct window *window,
+ confined_pointer_unconfined_handler_t unconfined)
+{
+ 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);
@@ -4444,6 +4518,239 @@ window_damage(struct window *window, int32_t x, int32_t y,
}
static void
+relative_pointer_handle_motion(void *data, struct _wl_relative_pointer *pointer,
+ uint32_t time,
+ int32_t dx_int, int32_t dx_frac,
+ int32_t dy_int, int32_t dy_frac,
+ int32_t dx_unaccel_int, int32_t dx_unaccel_frac,
+ int32_t dy_unaccel_int, int32_t dy_unaccel_frac)
+{
+ struct input *input = data;
+ struct window *window = input->pointer_focus;
+
+ if (window->locked_pointer_motion_handler &&
+ window->pointer_locked) {
+ window->locked_pointer_motion_handler(
+ window, input, time,
+ wl_double_fixed_to_double(dx_int, dx_frac),
+ wl_double_fixed_to_double(dy_int, dy_frac),
+ window->user_data);
+ }
+}
+
+static const struct _wl_relative_pointer_listener relative_pointer_listener = {
+ relative_pointer_handle_motion,
+};
+
+static void
+locked_pointer_locked(void *data,
+ struct _wl_locked_pointer *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 _wl_locked_pointer *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 _wl_locked_pointer_listener locked_pointer_listener = {
+ locked_pointer_locked,
+ locked_pointer_unlocked,
+};
+
+int
+window_lock_pointer(struct window *window, struct input *input)
+{
+ struct _wl_relative_pointer_manager *relative_pointer_manager =
+ window->display->relative_pointer_manager;
+ struct _wl_pointer_lock *pointer_lock = window->display->pointer_lock;
+ struct _wl_relative_pointer *relative_pointer;
+ struct _wl_locked_pointer *locked_pointer;
+
+ if (!window->display->relative_pointer_manager)
+ return -1;
+
+ if (!window->display->pointer_lock)
+ return -1;
+
+ if (window->locked_pointer)
+ return -1;
+
+ if (window->confined_pointer)
+ return -1;
+
+ if (!input->pointer)
+ return -1;
+
+ relative_pointer = _wl_relative_pointer_manager_get_relative_pointer(
+ relative_pointer_manager, input->pointer);
+ _wl_relative_pointer_add_listener(relative_pointer,
+ &relative_pointer_listener,
+ input);
+
+ locked_pointer =
+ _wl_pointer_lock_lock_pointer(pointer_lock,
+ window->main_surface->surface,
+ input->seat,
+ NULL);
+ _wl_locked_pointer_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;
+
+ _wl_locked_pointer_destroy(window->locked_pointer);
+ _wl_relative_pointer_release(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;
+
+ _wl_locked_pointer_set_cursor_position_hint(window->locked_pointer,
+ wl_fixed_from_double(x),
+ wl_fixed_from_double(y));
+}
+
+static void
+confined_pointer_confined(void *data,
+ struct _wl_confined_pointer *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 _wl_confined_pointer *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;
+}
+
+static const struct _wl_confined_pointer_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 _wl_pointer_lock *pointer_lock = window->display->pointer_lock;
+ struct _wl_confined_pointer *confined_pointer;
+ struct wl_compositor *compositor = window->display->compositor;
+ struct wl_region *region = NULL;
+
+ if (!window->display->pointer_lock)
+ 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 =
+ _wl_pointer_lock_confine_pointer(pointer_lock,
+ window->main_surface->surface,
+ input->seat,
+ region);
+ if (region)
+ wl_region_destroy(region);
+
+ _wl_confined_pointer_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;
+
+ _wl_confined_pointer_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)
{
@@ -5285,6 +5592,15 @@ registry_handle_global(void *data, struct wl_registry *registry, uint32_t id,
} else if (strcmp(interface, "wl_seat") == 0) {
d->seat_version = version;
display_add_input(d, id);
+ } else if (strcmp(interface, "_wl_relative_pointer_manager") == 0) {
+ d->relative_pointer_manager =
+ wl_registry_bind(registry, id,
+ &_wl_relative_pointer_manager_interface,
+ 1);
+ } else if (strcmp(interface, "_wl_pointer_lock") == 0) {
+ d->pointer_lock = wl_registry_bind(registry, id,
+ &_wl_pointer_lock_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 0686c3f..c62a6db 100644
--- a/clients/window.h
+++ b/clients/window.h
@@ -223,6 +223,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);
@@ -352,6 +375,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);
@@ -430,6 +471,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.1.4
More information about the wayland-devel
mailing list