[weston,15/17] clients: Add API for pointer locking and pointer confinement

Submitted by Jonas Ådahl on Dec. 2, 2014, 1:49 p.m.

Details

Message ID 1417528165-9319-16-git-send-email-jadahl@gmail.com
State Superseded
Delegated to: Daniel Stone
Headers show

Not browsing as part of any series.

Commit Message

Jonas Ådahl Dec. 2, 2014, 1:49 p.m.
Signed-off-by: Jonas Ådahl <jadahl@gmail.com>
---
 Makefile.am      |   6 +-
 clients/window.c | 294 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 clients/window.h |  62 ++++++++++++
 3 files changed, 361 insertions(+), 1 deletion(-)

Patch hide | download patch | download mbox

diff --git a/Makefile.am b/Makefile.am
index 8adc343..b32d61e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -449,7 +449,11 @@  nodist_libtoytoolkit_la_SOURCES =			\
 	protocol/presentation_timing-protocol.c		\
 	protocol/presentation_timing-client-protocol.h	\
 	protocol/xdg-shell-protocol.c			\
-	protocol/xdg-shell-client-protocol.h
+	protocol/xdg-shell-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 5099004..fd2df82 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>
@@ -68,6 +69,8 @@  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 "window.h"
@@ -91,6 +94,8 @@  struct display {
 	struct text_cursor_position *text_cursor_position;
 	struct workspace_manager *workspace_manager;
 	struct xdg_shell *xdg_shell;
+	struct _wl_relative_pointer_manager *relative_pointer_manager;
+	struct _wl_pointer_lock *pointer_lock;
 	EGLDisplay dpy;
 	EGLConfig argb_config;
 	EGLContext argb_ctx;
@@ -243,6 +248,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;
@@ -255,6 +262,17 @@  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;
+
 	void *user_data;
 	struct wl_list link;
 };
@@ -4367,6 +4385,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);
@@ -4408,6 +4463,236 @@  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,
+			       wl_fixed_t dx, wl_fixed_t dy,
+			       wl_fixed_t dx_noaccel, wl_fixed_t dy_noaccel)
+{
+	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_fixed_to_double(dx),
+				wl_fixed_to_double(dy),
+				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,
+		      uint32_t serial)
+{
+	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->seat);
+	_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,
+						    window->display->serial,
+						    wl_fixed_from_double(x),
+						    wl_fixed_from_double(y));
+}
+
+static void
+confined_pointer_confined(void *data,
+			  struct _wl_confined_pointer *confined_pointer,
+			  uint32_t serial)
+{
+	struct input *input = data;
+	struct window *window = input->pointer_focus;
+
+	if (window->pointer_confined_handler) {
+		window->pointer_confined_handler(window,
+						 input,
+						 window->user_data);
+	}
+}
+
+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);
+	}
+}
+
+static const struct _wl_confined_pointer_listener confined_pointer_listener = {
+	confined_pointer_confined,
+	confined_pointer_unconfined,
+};
+
+int
+window_confine_pointer(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;
+
+	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;
+}
+
+static void
 surface_enter(void *data,
 	      struct wl_surface *wl_surface, struct wl_output *wl_output)
 {
@@ -5234,6 +5519,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 5247f19..f6e415d 100644
--- a/clients/window.h
+++ b/clients/window.h
@@ -222,6 +222,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);
@@ -351,6 +374,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(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);
 
@@ -429,6 +470,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 *