From a9b334ebb5d1c944a9ebf903023c4881e4dea638 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Wed, 16 Jun 2021 22:53:45 +0200 Subject: debug-gui: pointer locking on Wayland MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the pointer constraints protocol to lock the pointer on Wayland. Signed-off-by: José Expósito --- .gitlab-ci.yml | 2 +- .gitlab-ci/config.yml | 1 + meson.build | 27 ++++++++ tools/libinput-debug-gui.c | 154 +++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 172 insertions(+), 12 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 46f5d18f..a1707f30 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -92,7 +92,7 @@ variables: UBUNTU_PACKAGES: 'git gcc g++ pkg-config meson check libudev-dev libevdev-dev doxygen graphviz python3-sphinx python3-recommonmark python3-sphinx-rtd-theme python3-pytest-xdist libwacom-dev libcairo2-dev libgtk-3-dev libglib2.0-dev libmtdev-dev' ARCH_PACKAGES: 'git gcc pkgconfig meson check libsystemd libevdev doxygen graphviz python-sphinx python-recommonmark python-sphinx_rtd_theme python-pytest-xdist libwacom gtk3 mtdev diffutils' ALPINE_PACKAGES: 'git gcc build-base pkgconfig meson check-dev eudev-dev libevdev-dev libwacom-dev cairo-dev gtk+3.0-dev mtdev-dev bash' - FREEBSD_PACKAGES: 'git pkgconf meson libepoll-shim libudev-devd libevdev libwacom gtk3 libmtdev bash' + FREEBSD_PACKAGES: 'git pkgconf meson libepoll-shim libudev-devd libevdev libwacom gtk3 libmtdev bash wayland' ############################ end of package lists ############################# # these tags should be updated each time the list of packages is updated diff --git a/.gitlab-ci/config.yml b/.gitlab-ci/config.yml index 8d42abc9..1104aa73 100644 --- a/.gitlab-ci/config.yml +++ b/.gitlab-ci/config.yml @@ -149,6 +149,7 @@ distributions: - gtk3 - libmtdev - bash + - wayland build: extra_variables: - "MESON_ARGS: '-Dtests=false -Ddocumentation=false' # doxygen drags down too many deps" diff --git a/meson.build b/meson.build index 9db3283f..cdc21c66 100644 --- a/meson.build +++ b/meson.build @@ -559,12 +559,39 @@ if get_option('debug-gui') dep_cairo = dependency('cairo') dep_glib = dependency('glib-2.0') + dep_wayland_client = dependency('wayland-client', required : false) + dep_wayland_protocols = dependency('wayland-protocols', required : false) debug_gui_sources = [ 'tools/libinput-debug-gui.c' ] + + if dep_wayland_client.found() and dep_wayland_protocols.found() + wayland_scanner = find_program('wayland-scanner') + wlproto_dir = dep_wayland_protocols.get_pkgconfig_variable('pkgdatadir') + + proto_name = 'pointer-constraints-unstable-v1' + input = files(join_paths(wlproto_dir, 'unstable/pointer-constraints/@0@.xml'.format(proto_name))) + + wayland_headers = custom_target('@0@ client header'.format(proto_name), + input: input, + output: '@0@-client-protocol.h'.format(proto_name), + command: [wayland_scanner, 'client-header', '@INPUT@', '@OUTPUT@'], + ) + + wayland_sources = custom_target('@0@ source'.format(proto_name), + input: input, + output: '@0@-protocol.c'.format(proto_name), + command: [wayland_scanner, 'private-code', '@INPUT@', '@OUTPUT@'], + ) + + debug_gui_sources += [ wayland_headers, wayland_sources ] + endif + deps_debug_gui = [ dep_gtk, dep_cairo, dep_glib, + dep_wayland_client, + dep_wayland_protocols, ] + deps_tools executable('libinput-debug-gui', debug_gui_sources, diff --git a/tools/libinput-debug-gui.c b/tools/libinput-debug-gui.c index 22afa6a8..460fd3c7 100644 --- a/tools/libinput-debug-gui.c +++ b/tools/libinput-debug-gui.c @@ -48,6 +48,16 @@ #include "shared.h" +#ifdef GDK_WINDOWING_WAYLAND + #include + #include "pointer-constraints-unstable-v1-client-protocol.h" + #if HAVE_GTK4 + #include + #else + #include + #endif +#endif + #define clip(val_, min_, max_) min((max_), max((min_), (val_))) enum touch_state { @@ -100,6 +110,16 @@ struct window { /* abs position */ struct point abs; + /* Wayland and X11 pointer locking */ + struct { + bool locked; + +#ifdef GDK_WINDOWING_WAYLAND + struct zwp_pointer_constraints_v1 *wayland_pointer_constraints; + struct zwp_locked_pointer_v1 *wayland_locked_pointer; +#endif + } lock_pointer; + /* scroll bar positions */ struct { double vx, vy; @@ -181,6 +201,125 @@ struct window { struct libinput_device *devices[50]; }; +#ifdef GDK_WINDOWING_WAYLAND +static void +wayland_registry_global(void *data, + struct wl_registry *registry, + uint32_t name, + const char *interface, + uint32_t version) +{ + struct window *w = data; + + if (!g_strcmp0(interface, "zwp_pointer_constraints_v1")) { + w->lock_pointer.wayland_pointer_constraints = + wl_registry_bind(registry, + name, + &zwp_pointer_constraints_v1_interface, + 1); + } +} + +static void +wayland_registry_global_remove(void *data, + struct wl_registry *wl_registry, + uint32_t name) +{ + +} + +struct wl_registry_listener registry_listener = { + wayland_registry_global, + wayland_registry_global_remove +}; + +static bool +wayland_lock_pointer(struct window *w) +{ + GdkDisplay *gdk_display; + GdkSeat *gdk_seat; + GdkDevice *gdk_device; + struct wl_display *display; + struct wl_registry *registry; + struct wl_pointer *wayland_pointer; + struct wl_surface *surface; + + w->lock_pointer.wayland_pointer_constraints = NULL; + + gdk_display = gdk_display_get_default(); + display = gdk_wayland_display_get_wl_display(gdk_display); + + gdk_seat = gdk_display_get_default_seat(gdk_display); + gdk_device = gdk_seat_get_pointer(gdk_seat); + wayland_pointer = gdk_wayland_device_get_wl_pointer(gdk_device); + + registry = wl_display_get_registry(display); + wl_registry_add_listener(registry, ®istry_listener, w); + wl_display_roundtrip(display); + + if (!w->lock_pointer.wayland_pointer_constraints) + return false; + +#if HAVE_GTK4 + GtkNative *window = gtk_widget_get_native(w->win); + GdkSurface *gdk_surface = gtk_native_get_surface(window); + surface = gdk_wayland_surface_get_wl_surface(gdk_surface); +#else + GdkWindow *window = gtk_widget_get_window(w->win); + surface = gdk_wayland_window_get_wl_surface(window); +#endif + + w->lock_pointer.wayland_locked_pointer = + zwp_pointer_constraints_v1_lock_pointer(w->lock_pointer.wayland_pointer_constraints, + surface, + wayland_pointer, + NULL, + ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); + + return true; +} + +static void +wayland_unlock_pointer(struct window *w) +{ + w->lock_pointer.wayland_pointer_constraints = NULL; + zwp_locked_pointer_v1_destroy(w->lock_pointer.wayland_locked_pointer); +} + +static inline bool +backend_is_wayland(void) +{ + return GDK_IS_WAYLAND_DISPLAY(gdk_display_get_default()); +} +#endif /* GDK_WINDOWING_WAYLAND */ + +static bool +window_lock_pointer(struct window *w) +{ + w->lock_pointer.locked = false; + +#ifdef GDK_WINDOWING_WAYLAND + if (backend_is_wayland()) + w->lock_pointer.locked = wayland_lock_pointer(w); +#endif + + return w->lock_pointer.locked; +} + +static void +window_unlock_pointer(struct window *w) +{ + if (!w->lock_pointer.locked) + return; + + w->lock_pointer.locked = false; + +#ifdef GDK_WINDOWING_WAYLAND + if (backend_is_wayland()) + wayland_unlock_pointer(w); +#endif +} + LIBINPUT_ATTRIBUTE_PRINTF(1, 2) static inline void msg(const char *fmt, ...) @@ -852,6 +991,8 @@ map_event_cb(GtkDrawingArea *widget, int width, int height, gpointer data) NULL); gtk_widget_set_cursor_from_name(w->win, "none"); + + window_lock_pointer(w); } #else static void @@ -859,7 +1000,6 @@ map_event_cb(GtkWidget *widget, GdkEvent *event, gpointer data) { struct window *w = data; GdkDisplay *display; - GdkSeat *seat; GdkWindow *window; window_place_ui_elements(widget, w); @@ -873,16 +1013,7 @@ map_event_cb(GtkWidget *widget, GdkEvent *event, gpointer data) gdk_cursor_new_for_display(display, GDK_BLANK_CURSOR)); - seat = gdk_display_get_default_seat(display); - gdk_seat_grab(seat, - window, - GDK_SEAT_CAPABILITY_ALL_POINTING, - FALSE, /* owner-events */ - NULL, /* cursor */ - NULL, /* triggering event */ - NULL, /* prepare_func */ - NULL /* prepare_func_data */ - ); + window_lock_pointer(w); } #endif @@ -1781,6 +1912,7 @@ main(int argc, char **argv) w.event_loop = g_main_loop_new(NULL, FALSE); g_main_loop_run(w.event_loop); + window_unlock_pointer(&w); window_cleanup(&w); libinput_unref(li); -- cgit v1.2.1