new/yocto/meta-rockchip/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad_1.20/0031-waylandsink-Support-pointer-and-touch.patch

420 lines
12 KiB
Diff
Raw Permalink Normal View History

2025-05-10 21:58:58 +08:00
From aba56acd328d0843eaa69401e951f95fc6e56eaf Mon Sep 17 00:00:00 2001
From: Jeffy Chen <jeffy.chen@rock-chips.com>
Date: Thu, 5 May 2022 17:56:46 +0800
Subject: [PATCH 31/35] waylandsink: Support pointer and touch
Based on weston's client window and simple-egl.
Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
---
ext/wayland/meson.build | 3 +-
ext/wayland/wldisplay.c | 278 ++++++++++++++++++++++++++++++++++++++++
ext/wayland/wldisplay.h | 8 ++
ext/wayland/wlwindow.c | 4 +
4 files changed, 292 insertions(+), 1 deletion(-)
diff --git a/ext/wayland/meson.build b/ext/wayland/meson.build
index a3ffb70..c8a32da 100644
--- a/ext/wayland/meson.build
+++ b/ext/wayland/meson.build
@@ -37,12 +37,13 @@ if use_wayland
command : [wl_scanner, 'client-header', '@INPUT@', '@OUTPUT@'])]
endforeach
+ wl_cursor_dep = dependency('wayland-cursor')
gstwaylandsink = library('gstwaylandsink',
wl_sources + protocols_files,
c_args : gst_plugins_bad_args + ['-DGST_USE_UNSTABLE_API'],
include_directories : [configinc],
dependencies : [gst_dep, gstvideo_dep, gstwayland_dep, gstallocators_dep,
- wl_client_dep, wl_protocol_dep, libdrm_dep],
+ wl_client_dep, wl_protocol_dep, wl_cursor_dep, libdrm_dep],
install : true,
install_dir : plugins_install_dir,
)
diff --git a/ext/wayland/wldisplay.c b/ext/wayland/wldisplay.c
index fcf2853..701ee5e 100644
--- a/ext/wayland/wldisplay.c
+++ b/ext/wayland/wldisplay.c
@@ -24,9 +24,11 @@
#include "wldisplay.h"
#include "wlbuffer.h"
+#include "wlwindow.h"
#include "wlvideoformat.h"
#include <errno.h>
+#include <linux/input.h>
GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug);
#define GST_CAT_DEFAULT gstwayland_debug
@@ -35,6 +37,18 @@ G_DEFINE_TYPE (GstWlDisplay, gst_wl_display, G_TYPE_OBJECT);
static void gst_wl_display_finalize (GObject * gobject);
+struct input
+{
+ GstWlDisplay *display;
+ struct wl_seat *seat;
+ struct wl_pointer *pointer;
+ struct wl_touch *touch;
+
+ void *pointer_focus;
+
+ struct wl_list link;
+};
+
static void
gst_wl_display_class_init (GstWlDisplayClass * klass)
{
@@ -58,6 +72,29 @@ gst_wl_ref_wl_buffer (gpointer key, gpointer value, gpointer user_data)
g_object_ref (value);
}
+static void
+input_destroy (struct input *input)
+{
+ if (input->touch)
+ wl_touch_destroy (input->touch);
+ if (input->pointer)
+ wl_pointer_destroy (input->pointer);
+
+ wl_list_remove (&input->link);
+ wl_seat_destroy (input->seat);
+ free (input);
+}
+
+static void
+display_destroy_inputs (GstWlDisplay * self)
+{
+ struct input *tmp;
+ struct input *input;
+
+ wl_list_for_each_safe (input, tmp, &self->input_list, link)
+ input_destroy (input);
+}
+
static void
gst_wl_display_finalize (GObject * gobject)
{
@@ -67,6 +104,14 @@ gst_wl_display_finalize (GObject * gobject)
if (self->thread)
g_thread_join (self->thread);
+ display_destroy_inputs (self);
+
+ if (self->cursor_surface)
+ wl_surface_destroy (self->cursor_surface);
+
+ if (self->cursor_theme)
+ wl_cursor_theme_destroy (self->cursor_theme);
+
/* to avoid buffers being unregistered from another thread
* at the same time, take their ownership */
g_mutex_lock (&self->buffers_mutex);
@@ -223,6 +268,225 @@ static const struct xdg_wm_base_listener xdg_wm_base_listener = {
handle_xdg_wm_base_ping
};
+static void
+display_set_cursor (GstWlDisplay *self, struct wl_pointer *pointer,
+ uint32_t serial)
+{
+ struct wl_buffer *buffer;
+ struct wl_cursor_image *image;
+
+ if (!self->default_cursor)
+ return;
+
+ if (!self->cursor_surface) {
+ self->cursor_surface =
+ wl_compositor_create_surface (self->compositor);
+ if (!self->cursor_surface)
+ return;
+ }
+
+ image = self->default_cursor->images[0];
+ buffer = wl_cursor_image_get_buffer (image);
+ if (!buffer)
+ return;
+
+ wl_pointer_set_cursor (pointer, serial,
+ self->cursor_surface, image->hotspot_x, image->hotspot_y);
+ wl_surface_attach (self->cursor_surface, buffer, 0, 0);
+ wl_surface_damage (self->cursor_surface, 0, 0,
+ image->width, image->height);
+ wl_surface_commit (self->cursor_surface);
+}
+
+static void
+pointer_handle_enter (void *data, struct wl_pointer *pointer,
+ uint32_t serial, struct wl_surface *surface,
+ wl_fixed_t sx_w, wl_fixed_t sy_w)
+{
+ struct input *input = data;
+ GstWlDisplay *display = input->display;
+ GstWlWindow *window;
+
+ if (!surface) {
+ /* enter event for a window we've just destroyed */
+ return;
+ }
+
+ if (surface != display->touch_surface) {
+ /* Ignoring input event from other surfaces */
+ return;
+ }
+
+ window = wl_surface_get_user_data (surface);
+ if (!window || !gst_wl_window_is_toplevel (window)) {
+ /* Ignoring input event from subsurface */
+ return;
+ }
+
+ input->pointer_focus = window;
+ display_set_cursor (window->display, pointer, serial);
+}
+
+static void
+pointer_handle_leave (void *data, struct wl_pointer *pointer,
+ uint32_t serial, struct wl_surface *surface)
+{
+ struct input *input = data;
+
+ if (input->pointer_focus) {
+ input->pointer_focus = NULL;
+ wl_pointer_set_cursor (pointer, serial, NULL, 0, 0);
+ }
+}
+
+static void
+pointer_handle_motion (void *data, struct wl_pointer *pointer,
+ uint32_t time, wl_fixed_t sx, wl_fixed_t sy)
+{
+}
+
+static void
+pointer_handle_button (void *data, struct wl_pointer *pointer, uint32_t serial,
+ uint32_t time, uint32_t button, uint32_t state)
+{
+ struct input *input = data;
+ GstWlWindow *window;
+
+ window = input->pointer_focus;
+ if (!window)
+ return;
+
+ if (button == BTN_LEFT && state == WL_POINTER_BUTTON_STATE_PRESSED) {
+ if (window->display->xdg_wm_base)
+ xdg_toplevel_move (window->xdg_toplevel, input->seat, serial);
+ else
+ wl_shell_surface_move (window->wl_shell_surface, input->seat, serial);
+ }
+}
+
+static void
+pointer_handle_axis(void *data, struct wl_pointer *wl_pointer,
+ uint32_t time, uint32_t axis, wl_fixed_t value)
+{
+}
+
+static const struct wl_pointer_listener pointer_listener = {
+ pointer_handle_enter,
+ pointer_handle_leave,
+ pointer_handle_motion,
+ pointer_handle_button,
+ pointer_handle_axis,
+};
+
+static void
+touch_handle_down (void *data, struct wl_touch *wl_touch,
+ uint32_t serial, uint32_t time, struct wl_surface *surface,
+ int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
+{
+ struct input *input = data;
+ GstWlDisplay *display = input->display;
+ GstWlWindow *window;
+
+ if (!surface) {
+ /* enter event for a window we've just destroyed */
+ return;
+ }
+
+ if (surface != display->touch_surface) {
+ /* Ignoring input event from other surfaces */
+ return;
+ }
+
+ window = wl_surface_get_user_data (surface);
+ if (!window || !gst_wl_window_is_toplevel (window)) {
+ /* Ignoring input event from subsurface */
+ return;
+ }
+
+ if (window->display->xdg_wm_base)
+ xdg_toplevel_move (window->xdg_toplevel, input->seat, serial);
+ else
+ wl_shell_surface_move (window->wl_shell_surface, input->seat, serial);
+}
+
+static void
+touch_handle_up (void *data, struct wl_touch *wl_touch,
+ uint32_t serial, uint32_t time, int32_t id)
+{
+}
+
+static void
+touch_handle_motion (void *data, struct wl_touch *wl_touch,
+ uint32_t time, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
+{
+}
+
+static void
+touch_handle_frame (void *data, struct wl_touch *wl_touch)
+{
+}
+
+static void
+touch_handle_cancel (void *data, struct wl_touch *wl_touch)
+{
+}
+
+static const struct wl_touch_listener touch_listener = {
+ touch_handle_down,
+ touch_handle_up,
+ touch_handle_motion,
+ touch_handle_frame,
+ touch_handle_cancel,
+};
+
+static void
+seat_handle_capabilities (void *data, struct wl_seat *seat,
+ enum wl_seat_capability caps)
+{
+ struct input *input = data;
+
+ if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) {
+ input->pointer = wl_seat_get_pointer (seat);
+ wl_pointer_add_listener (input->pointer, &pointer_listener, input);
+ } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) {
+ wl_pointer_destroy (input->pointer);
+ input->pointer = NULL;
+ }
+
+ if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !input->touch) {
+ input->touch = wl_seat_get_touch (seat);
+ wl_touch_add_listener (input->touch, &touch_listener, input);
+ } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && input->touch) {
+ wl_touch_destroy (input->touch);
+ input->touch = NULL;
+ }
+}
+
+static const struct wl_seat_listener seat_listener = {
+ seat_handle_capabilities,
+};
+
+static void
+display_add_input (GstWlDisplay *self, uint32_t id)
+{
+ struct input *input;
+
+ input = calloc (1, sizeof (*input));
+ if (input == NULL) {
+ GST_ERROR ("Error out of memory");
+ return;
+ }
+
+ input->display = self;
+
+ input->seat = wl_registry_bind (self->registry, id, &wl_seat_interface, 1);
+
+ wl_seat_add_listener (input->seat, &seat_listener, input);
+ wl_seat_set_user_data (input->seat, input);
+
+ wl_list_insert(self->input_list.prev, &input->link);
+}
+
static void
registry_handle_global (void *data, struct wl_registry *registry,
uint32_t id, const char *interface, uint32_t version)
@@ -247,6 +511,18 @@ registry_handle_global (void *data, struct wl_registry *registry,
} else if (g_strcmp0 (interface, "wl_shm") == 0) {
self->shm = wl_registry_bind (registry, id, &wl_shm_interface, 1);
wl_shm_add_listener (self->shm, &shm_listener, self);
+
+ self->cursor_theme = wl_cursor_theme_load (NULL, 32, self->shm);
+ if (!self->cursor_theme) {
+ GST_ERROR ("Error loading default cursor theme");
+ } else {
+ self->default_cursor =
+ wl_cursor_theme_get_cursor (self->cursor_theme, "left_ptr");
+ if (!self->default_cursor)
+ GST_ERROR ("Error loading default left cursor pointer");
+ }
+ } else if (g_strcmp0 (interface, "wl_seat") == 0) {
+ display_add_input (self, id);
} else if (g_strcmp0 (interface, "wp_viewporter") == 0) {
self->viewporter =
wl_registry_bind (registry, id, &wp_viewporter_interface, 1);
@@ -337,6 +613,8 @@ gst_wl_display_new_existing (struct wl_display * display,
self->display_wrapper = wl_proxy_create_wrapper (display);
self->own_display = take_ownership;
+ wl_list_init (&self->input_list);
+
self->queue = wl_display_create_queue (self->display);
wl_proxy_set_queue ((struct wl_proxy *) self->display_wrapper, self->queue);
self->registry = wl_display_get_registry (self->display_wrapper);
diff --git a/ext/wayland/wldisplay.h b/ext/wayland/wldisplay.h
index 29c15f6..8914d31 100644
--- a/ext/wayland/wldisplay.h
+++ b/ext/wayland/wldisplay.h
@@ -24,6 +24,7 @@
#include <gst/gst.h>
#include <gst/video/video.h>
#include <wayland-client.h>
+#include <wayland-cursor.h>
#include "xdg-shell-client-protocol.h"
#include "viewporter-client-protocol.h"
#include "linux-dmabuf-unstable-v1-client-protocol.h"
@@ -50,6 +51,13 @@ struct _GstWlDisplay
struct wl_display *display_wrapper;
struct wl_event_queue *queue;
+ struct wl_list input_list;
+
+ struct wl_cursor_theme *cursor_theme;
+ struct wl_cursor *default_cursor;
+ struct wl_surface *cursor_surface;
+ struct wl_surface *touch_surface;
+
/* globals */
struct wl_registry *registry;
struct wl_compositor *compositor;
diff --git a/ext/wayland/wlwindow.c b/ext/wayland/wlwindow.c
index 2ba0eee..9917beb 100644
--- a/ext/wayland/wlwindow.c
+++ b/ext/wayland/wlwindow.c
@@ -205,6 +205,8 @@ gst_wl_window_new_internal (GstWlDisplay * display, GMutex * render_lock)
window->area_surface = wl_compositor_create_surface (display->compositor);
window->video_surface = wl_compositor_create_surface (display->compositor);
+ display->touch_surface = window->area_surface;
+
window->area_surface_wrapper = wl_proxy_create_wrapper (window->area_surface);
window->video_surface_wrapper =
wl_proxy_create_wrapper (window->video_surface);
@@ -308,6 +310,8 @@ gst_wl_window_new_toplevel (GstWlDisplay * display, const GstVideoInfo * info,
window = gst_wl_window_new_internal (display, render_lock);
+ wl_surface_set_user_data (window->area_surface, window);
+
/* Check which protocol we will use (in order of preference) */
if (display->xdg_wm_base) {
gint64 timeout;
--
2.20.1