322 lines
12 KiB
Diff
322 lines
12 KiB
Diff
|
From 19e0922572cee7bda989a82407208eac8a41b47f Mon Sep 17 00:00:00 2001
|
||
|
From: Francesco Giudici <fgiudici@redhat.com>
|
||
|
Date: Tue, 28 Mar 2017 15:07:16 +0200
|
||
|
Subject: [PATCH 6/9] wayland: add wayland-extensions functions
|
||
|
|
||
|
add utilities to lock the pointer to a window and to get relative mouse
|
||
|
movement in Wayland. This is made possible thanks to the wayland
|
||
|
protocols introduced in the previous commit.
|
||
|
|
||
|
Code freely taken and adapted from Christophe Fergeau branch:
|
||
|
https://gitlab.freedesktop.org/teuf/spice-gtk/-/tree/wayland
|
||
|
|
||
|
Signed-off-by: Francesco Giudici <fgiudici@redhat.com>
|
||
|
Acked-by: Frediano Ziglio <fziglio@redhat.com>
|
||
|
(cherry picked from commit 59d5c92c74da0f452b9104191bb752c33d26ec77)
|
||
|
---
|
||
|
src/meson.build | 5 +
|
||
|
src/wayland-extensions.c | 235 +++++++++++++++++++++++++++++++++++++++
|
||
|
src/wayland-extensions.h | 32 ++++++
|
||
|
3 files changed, 272 insertions(+)
|
||
|
create mode 100644 src/wayland-extensions.c
|
||
|
create mode 100644 src/wayland-extensions.h
|
||
|
|
||
|
diff --git a/src/meson.build b/src/meson.build
|
||
|
index bdd2239..16810a7 100644
|
||
|
--- a/src/meson.build
|
||
|
+++ b/src/meson.build
|
||
|
@@ -374,6 +374,11 @@ if spice_gtk_has_gtk
|
||
|
message('@0@ @1@: @2@ -> @3@'.format(prog_scanner, output_type, xml_path, output_file))
|
||
|
endforeach
|
||
|
endforeach
|
||
|
+
|
||
|
+ spice_client_gtk_sources += [
|
||
|
+ 'wayland-extensions.c',
|
||
|
+ 'wayland-extensions.h',
|
||
|
+ ]
|
||
|
endif
|
||
|
|
||
|
#
|
||
|
diff --git a/src/wayland-extensions.c b/src/wayland-extensions.c
|
||
|
new file mode 100644
|
||
|
index 0000000..64b5139
|
||
|
--- /dev/null
|
||
|
+++ b/src/wayland-extensions.c
|
||
|
@@ -0,0 +1,235 @@
|
||
|
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||
|
+/*
|
||
|
+ Copyright (C) 2017 Red Hat, Inc.
|
||
|
+
|
||
|
+ This library is free software; you can redistribute it and/or
|
||
|
+ modify it under the terms of the GNU Lesser General Public
|
||
|
+ License as published by the Free Software Foundation; either
|
||
|
+ version 2.1 of the License, or (at your option) any later version.
|
||
|
+
|
||
|
+ This library is distributed in the hope that it will be useful,
|
||
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
+ Lesser General Public License for more details.
|
||
|
+
|
||
|
+ You should have received a copy of the GNU Lesser General Public
|
||
|
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||
|
+*/
|
||
|
+
|
||
|
+#include <config.h>
|
||
|
+
|
||
|
+#include <stdint.h>
|
||
|
+#include <string.h>
|
||
|
+
|
||
|
+#include <gtk/gtk.h>
|
||
|
+
|
||
|
+#include <gdk/gdkwayland.h>
|
||
|
+#include "pointer-constraints-unstable-v1-client-protocol.h"
|
||
|
+#include "relative-pointer-unstable-v1-client-protocol.h"
|
||
|
+
|
||
|
+#include "wayland-extensions.h"
|
||
|
+
|
||
|
+static void *
|
||
|
+gtk_wl_registry_bind(GtkWidget *widget,
|
||
|
+ uint32_t name,
|
||
|
+ const struct wl_interface *interface,
|
||
|
+ uint32_t version)
|
||
|
+{
|
||
|
+ GdkDisplay *gdk_display = gtk_widget_get_display(widget);
|
||
|
+ struct wl_display *display;
|
||
|
+ struct wl_registry *registry;
|
||
|
+
|
||
|
+ if (!GDK_IS_WAYLAND_DISPLAY(gdk_display)) {
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ display = gdk_wayland_display_get_wl_display(gdk_display);
|
||
|
+ registry = wl_display_get_registry(display);
|
||
|
+
|
||
|
+ return wl_registry_bind(registry, name, interface, version);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+gtk_wl_registry_add_listener(GtkWidget *widget, const struct wl_registry_listener *listener)
|
||
|
+{
|
||
|
+ GdkDisplay *gdk_display = gtk_widget_get_display(widget);
|
||
|
+ struct wl_display *display;
|
||
|
+ struct wl_registry *registry;
|
||
|
+
|
||
|
+ if (!GDK_IS_WAYLAND_DISPLAY(gdk_display)) {
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ display = gdk_wayland_display_get_wl_display(gdk_display);
|
||
|
+ registry = wl_display_get_registry(display);
|
||
|
+ wl_registry_add_listener(registry, listener, widget);
|
||
|
+ wl_display_roundtrip(display);
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+static void
|
||
|
+registry_handle_global(void *data,
|
||
|
+ struct wl_registry *registry,
|
||
|
+ uint32_t name,
|
||
|
+ const char *interface,
|
||
|
+ uint32_t version)
|
||
|
+{
|
||
|
+ GtkWidget *widget = GTK_WIDGET(data);
|
||
|
+
|
||
|
+ if (strcmp(interface, "zwp_relative_pointer_manager_v1") == 0) {
|
||
|
+ struct zwp_relative_pointer_manager_v1 *relative_pointer_manager;
|
||
|
+ relative_pointer_manager = gtk_wl_registry_bind(widget, name,
|
||
|
+ &zwp_relative_pointer_manager_v1_interface,
|
||
|
+ 1);
|
||
|
+ g_object_set_data_full(G_OBJECT(widget),
|
||
|
+ "zwp_relative_pointer_manager_v1",
|
||
|
+ relative_pointer_manager,
|
||
|
+ (GDestroyNotify)zwp_relative_pointer_manager_v1_destroy);
|
||
|
+ } else if (strcmp(interface, "zwp_pointer_constraints_v1") == 0) {
|
||
|
+ struct zwp_pointer_constraints_v1 *pointer_constraints;
|
||
|
+ pointer_constraints = gtk_wl_registry_bind(widget, name,
|
||
|
+ &zwp_pointer_constraints_v1_interface,
|
||
|
+ 1);
|
||
|
+ g_object_set_data_full(G_OBJECT(widget),
|
||
|
+ "zwp_pointer_constraints_v1",
|
||
|
+ pointer_constraints,
|
||
|
+ (GDestroyNotify)zwp_pointer_constraints_v1_destroy);
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+registry_handle_global_remove(void *data,
|
||
|
+ struct wl_registry *registry,
|
||
|
+ uint32_t name)
|
||
|
+{
|
||
|
+}
|
||
|
+
|
||
|
+static const struct wl_registry_listener registry_listener = {
|
||
|
+ registry_handle_global,
|
||
|
+ registry_handle_global_remove
|
||
|
+};
|
||
|
+
|
||
|
+void
|
||
|
+spice_wayland_extensions_init(GtkWidget *widget)
|
||
|
+{
|
||
|
+ g_return_if_fail(GTK_IS_WIDGET(widget));
|
||
|
+
|
||
|
+ gtk_wl_registry_add_listener(widget, ®istry_listener);
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+static GdkDevice *
|
||
|
+spice_gdk_window_get_pointing_device(GdkWindow *window)
|
||
|
+{
|
||
|
+ GdkDisplay *gdk_display = gdk_window_get_display(window);
|
||
|
+
|
||
|
+ return gdk_seat_get_pointer(gdk_display_get_default_seat(gdk_display));
|
||
|
+}
|
||
|
+
|
||
|
+static struct zwp_relative_pointer_v1_listener relative_pointer_listener;
|
||
|
+
|
||
|
+// NOTE this API works only on a single widget per application
|
||
|
+int
|
||
|
+spice_wayland_extensions_enable_relative_pointer(GtkWidget *widget,
|
||
|
+ void (*cb)(void *,
|
||
|
+ struct zwp_relative_pointer_v1 *,
|
||
|
+ uint32_t, uint32_t,
|
||
|
+ wl_fixed_t, wl_fixed_t, wl_fixed_t, wl_fixed_t))
|
||
|
+{
|
||
|
+ struct zwp_relative_pointer_v1 *relative_pointer;
|
||
|
+
|
||
|
+ g_return_val_if_fail(GTK_IS_WIDGET(widget), -1);
|
||
|
+
|
||
|
+ relative_pointer = g_object_get_data(G_OBJECT(widget), "zwp_relative_pointer_v1");
|
||
|
+
|
||
|
+ if (relative_pointer == NULL) {
|
||
|
+ struct zwp_relative_pointer_manager_v1 *relative_pointer_manager;
|
||
|
+ GdkWindow *window = gtk_widget_get_window(widget);
|
||
|
+ struct wl_pointer *pointer;
|
||
|
+
|
||
|
+ relative_pointer_manager = g_object_get_data(G_OBJECT(widget), "zwp_relative_pointer_manager_v1");
|
||
|
+ if (relative_pointer_manager == NULL)
|
||
|
+ return -1;
|
||
|
+
|
||
|
+ pointer = gdk_wayland_device_get_wl_pointer(spice_gdk_window_get_pointing_device(window));
|
||
|
+ relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(relative_pointer_manager,
|
||
|
+ pointer);
|
||
|
+
|
||
|
+ relative_pointer_listener.relative_motion = cb;
|
||
|
+ zwp_relative_pointer_v1_add_listener(relative_pointer,
|
||
|
+ &relative_pointer_listener,
|
||
|
+ widget);
|
||
|
+
|
||
|
+ g_object_set_data_full(G_OBJECT(widget),
|
||
|
+ "zwp_relative_pointer_v1",
|
||
|
+ relative_pointer,
|
||
|
+ (GDestroyNotify)zwp_relative_pointer_v1_destroy);
|
||
|
+ }
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+int spice_wayland_extensions_disable_relative_pointer(GtkWidget *widget)
|
||
|
+{
|
||
|
+ g_return_val_if_fail(GTK_IS_WIDGET(widget), -1);
|
||
|
+
|
||
|
+ /* This will call zwp_relative_pointer_v1_destroy() and stop relative
|
||
|
+ * movement */
|
||
|
+ g_object_set_data(G_OBJECT(widget), "zwp_relative_pointer_v1", NULL);
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static struct zwp_locked_pointer_v1_listener locked_pointer_listener;
|
||
|
+
|
||
|
+// NOTE this API works only on a single widget per application
|
||
|
+int
|
||
|
+spice_wayland_extensions_lock_pointer(GtkWidget *widget,
|
||
|
+ void (*lock_cb)(void *, struct zwp_locked_pointer_v1 *),
|
||
|
+ void (*unlock_cb)(void *, struct zwp_locked_pointer_v1 *))
|
||
|
+{
|
||
|
+ struct zwp_pointer_constraints_v1 *pointer_constraints;
|
||
|
+ struct zwp_locked_pointer_v1 *locked_pointer;
|
||
|
+ GdkWindow *window;
|
||
|
+ struct wl_pointer *pointer;
|
||
|
+
|
||
|
+ g_return_val_if_fail(GTK_IS_WIDGET(widget), -1);
|
||
|
+
|
||
|
+ pointer_constraints = g_object_get_data(G_OBJECT(widget), "zwp_pointer_constraints_v1");
|
||
|
+ locked_pointer = g_object_get_data(G_OBJECT(widget), "zwp_locked_pointer_v1");
|
||
|
+ if (locked_pointer != NULL) {
|
||
|
+ /* A previous lock already in place */
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ window = gtk_widget_get_window(widget);
|
||
|
+ pointer = gdk_wayland_device_get_wl_pointer(spice_gdk_window_get_pointing_device(window));
|
||
|
+ locked_pointer = zwp_pointer_constraints_v1_lock_pointer(pointer_constraints,
|
||
|
+ gdk_wayland_window_get_wl_surface(window),
|
||
|
+ pointer,
|
||
|
+ NULL,
|
||
|
+ ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
|
||
|
+ if (lock_cb || unlock_cb) {
|
||
|
+ locked_pointer_listener.locked = lock_cb;
|
||
|
+ locked_pointer_listener.unlocked = unlock_cb;
|
||
|
+ zwp_locked_pointer_v1_add_listener(locked_pointer,
|
||
|
+ &locked_pointer_listener,
|
||
|
+ widget);
|
||
|
+ }
|
||
|
+ g_object_set_data_full(G_OBJECT(widget),
|
||
|
+ "zwp_locked_pointer_v1",
|
||
|
+ locked_pointer,
|
||
|
+ (GDestroyNotify)zwp_locked_pointer_v1_destroy);
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+int
|
||
|
+spice_wayland_extensions_unlock_pointer(GtkWidget *widget)
|
||
|
+{
|
||
|
+ g_return_val_if_fail(GTK_IS_WIDGET(widget), -1);
|
||
|
+
|
||
|
+ g_object_set_data(G_OBJECT(widget), "zwp_locked_pointer_v1", NULL);
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
diff --git a/src/wayland-extensions.h b/src/wayland-extensions.h
|
||
|
new file mode 100644
|
||
|
index 0000000..bf34044
|
||
|
--- /dev/null
|
||
|
+++ b/src/wayland-extensions.h
|
||
|
@@ -0,0 +1,32 @@
|
||
|
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||
|
+/*
|
||
|
+ Copyright (C) 2017 Red Hat, Inc.
|
||
|
+
|
||
|
+ This library is free software; you can redistribute it and/or
|
||
|
+ modify it under the terms of the GNU Lesser General Public
|
||
|
+ License as published by the Free Software Foundation; either
|
||
|
+ version 2.1 of the License, or (at your option) any later version.
|
||
|
+
|
||
|
+ This library is distributed in the hope that it will be useful,
|
||
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
+ Lesser General Public License for more details.
|
||
|
+
|
||
|
+ You should have received a copy of the GNU Lesser General Public
|
||
|
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||
|
+*/
|
||
|
+#pragma once
|
||
|
+
|
||
|
+#include <gtk/gtk.h>
|
||
|
+
|
||
|
+void spice_wayland_extensions_init(GtkWidget *widget);
|
||
|
+int spice_wayland_extensions_enable_relative_pointer(GtkWidget *widget,
|
||
|
+ void (*cb)(void *,
|
||
|
+ struct zwp_relative_pointer_v1 *,
|
||
|
+ uint32_t, uint32_t,
|
||
|
+ wl_fixed_t, wl_fixed_t, wl_fixed_t, wl_fixed_t));
|
||
|
+int spice_wayland_extensions_disable_relative_pointer(GtkWidget *widget);
|
||
|
+int spice_wayland_extensions_lock_pointer(GtkWidget *widget,
|
||
|
+ void (*lock_cb)(void *, struct zwp_locked_pointer_v1 *),
|
||
|
+ void (*unlock_cb)(void *, struct zwp_locked_pointer_v1 *));
|
||
|
+int spice_wayland_extensions_unlock_pointer(GtkWidget *widget);
|
||
|
--
|
||
|
2.26.2
|
||
|
|