1From 75c7ee95b6d561ee0030cfe5d7680b1fb48041b1 Mon Sep 17 00:00:00 2001 2From: Jeffy Chen <jeffy.chen@rock-chips.com> 3Date: Thu, 5 May 2022 17:56:46 +0800 4Subject: [PATCH 32/41] waylandsink: Support pointer and touch 5 6Based on weston's client window and simple-egl. 7 8Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com> 9--- 10 gst-libs/gst/wayland/gstwldisplay.c | 293 ++++++++++++++++++++++++++++ 11 gst-libs/gst/wayland/gstwldisplay.h | 4 + 12 gst-libs/gst/wayland/gstwlwindow.c | 17 ++ 13 gst-libs/gst/wayland/gstwlwindow.h | 4 + 14 gst-libs/gst/wayland/meson.build | 7 +- 15 5 files changed, 322 insertions(+), 3 deletions(-) 16 17diff --git a/gst-libs/gst/wayland/gstwldisplay.c b/gst-libs/gst/wayland/gstwldisplay.c 18index 3e11211..b860a8c 100644 19--- a/gst-libs/gst/wayland/gstwldisplay.c 20+++ b/gst-libs/gst/wayland/gstwldisplay.c 21@@ -23,6 +23,7 @@ 22 #endif 23 24 #include "gstwldisplay.h" 25+#include "gstwlwindow.h" 26 27 #include "fullscreen-shell-unstable-v1-client-protocol.h" 28 #include "linux-dmabuf-unstable-v1-client-protocol.h" 29@@ -30,6 +31,9 @@ 30 #include "xdg-shell-client-protocol.h" 31 32 #include <errno.h> 33+#include <linux/input.h> 34+ 35+#include <wayland-cursor.h> 36 37 #define GST_CAT_DEFAULT gst_wl_display_debug 38 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); 39@@ -41,6 +45,13 @@ typedef struct _GstWlDisplayPrivate 40 struct wl_display *display_wrapper; 41 struct wl_event_queue *queue; 42 43+ struct wl_list input_list; 44+ 45+ struct wl_cursor_theme *cursor_theme; 46+ struct wl_cursor *default_cursor; 47+ struct wl_surface *cursor_surface; 48+ struct wl_surface *touch_surface; 49+ 50 /* globals */ 51 struct wl_registry *registry; 52 struct wl_compositor *compositor; 53@@ -72,6 +83,14 @@ G_DEFINE_TYPE_WITH_CODE (GstWlDisplay, gst_wl_display, G_TYPE_OBJECT, 54 "wldisplay", 0, "wldisplay library"); 55 ); 56 57+void 58+gst_wl_display_set_touch_surface (GstWlDisplay * self, 59+ struct wl_surface *touch_surface) 60+{ 61+ GstWlDisplayPrivate *priv = gst_wl_display_get_instance_private (self); 62+ priv->touch_surface = touch_surface; 63+} 64+ 65 gboolean 66 gst_wl_display_support_afbc (GstWlDisplay * self) 67 { 68@@ -88,6 +107,18 @@ gst_wl_display_support_nv12_10le40 (GstWlDisplay * self) 69 70 static void gst_wl_display_finalize (GObject * gobject); 71 72+struct input 73+{ 74+ GstWlDisplay *display; 75+ struct wl_seat *seat; 76+ struct wl_pointer *pointer; 77+ struct wl_touch *touch; 78+ 79+ void *pointer_focus; 80+ 81+ struct wl_list link; 82+}; 83+ 84 static void 85 gst_wl_display_class_init (GstWlDisplayClass * klass) 86 { 87@@ -117,6 +148,30 @@ gst_wl_ref_wl_buffer (gpointer key, gpointer value, gpointer user_data) 88 g_object_ref (value); 89 } 90 91+static void 92+input_destroy (struct input *input) 93+{ 94+ if (input->touch) 95+ wl_touch_destroy (input->touch); 96+ if (input->pointer) 97+ wl_pointer_destroy (input->pointer); 98+ 99+ wl_list_remove (&input->link); 100+ wl_seat_destroy (input->seat); 101+ free (input); 102+} 103+ 104+static void 105+display_destroy_inputs (GstWlDisplay * self) 106+{ 107+ GstWlDisplayPrivate *priv = gst_wl_display_get_instance_private (self); 108+ struct input *tmp; 109+ struct input *input; 110+ 111+ wl_list_for_each_safe (input, tmp, &priv->input_list, link) 112+ input_destroy (input); 113+} 114+ 115 static void 116 gst_wl_display_finalize (GObject * gobject) 117 { 118@@ -127,6 +182,14 @@ gst_wl_display_finalize (GObject * gobject) 119 if (priv->thread) 120 g_thread_join (priv->thread); 121 122+ display_destroy_inputs (self); 123+ 124+ if (priv->cursor_surface) 125+ wl_surface_destroy (priv->cursor_surface); 126+ 127+ if (priv->cursor_theme) 128+ wl_cursor_theme_destroy (priv->cursor_theme); 129+ 130 /* to avoid buffers being unregistered from another thread 131 * at the same time, take their ownership */ 132 g_mutex_lock (&priv->buffers_mutex); 133@@ -284,6 +347,222 @@ static const struct xdg_wm_base_listener xdg_wm_base_listener = { 134 handle_xdg_wm_base_ping 135 }; 136 137+static void 138+display_set_cursor (GstWlDisplay *self, struct wl_pointer *pointer, 139+ uint32_t serial) 140+{ 141+ GstWlDisplayPrivate *priv = gst_wl_display_get_instance_private (self); 142+ struct wl_buffer *buffer; 143+ struct wl_cursor_image *image; 144+ 145+ if (!priv->default_cursor) 146+ return; 147+ 148+ if (!priv->cursor_surface) { 149+ priv->cursor_surface = 150+ wl_compositor_create_surface (priv->compositor); 151+ if (!priv->cursor_surface) 152+ return; 153+ } 154+ 155+ image = priv->default_cursor->images[0]; 156+ buffer = wl_cursor_image_get_buffer (image); 157+ if (!buffer) 158+ return; 159+ 160+ wl_pointer_set_cursor (pointer, serial, 161+ priv->cursor_surface, image->hotspot_x, image->hotspot_y); 162+ wl_surface_attach (priv->cursor_surface, buffer, 0, 0); 163+ wl_surface_damage (priv->cursor_surface, 0, 0, 164+ image->width, image->height); 165+ wl_surface_commit (priv->cursor_surface); 166+} 167+ 168+static void 169+pointer_handle_enter (void *data, struct wl_pointer *pointer, 170+ uint32_t serial, struct wl_surface *surface, 171+ wl_fixed_t sx_w, wl_fixed_t sy_w) 172+{ 173+ struct input *input = data; 174+ GstWlDisplay *self = input->display; 175+ GstWlDisplayPrivate *priv = gst_wl_display_get_instance_private (self); 176+ GstWlWindow *window; 177+ 178+ if (!surface) { 179+ /* enter event for a window we've just destroyed */ 180+ return; 181+ } 182+ 183+ if (surface != priv->touch_surface) { 184+ /* Ignoring input event from other surfaces */ 185+ return; 186+ } 187+ 188+ window = wl_surface_get_user_data (surface); 189+ if (!window || !gst_wl_window_is_toplevel (window)) { 190+ /* Ignoring input event from subsurface */ 191+ return; 192+ } 193+ 194+ input->pointer_focus = window; 195+ display_set_cursor (self, pointer, serial); 196+} 197+ 198+static void 199+pointer_handle_leave (void *data, struct wl_pointer *pointer, 200+ uint32_t serial, struct wl_surface *surface) 201+{ 202+ struct input *input = data; 203+ 204+ if (input->pointer_focus) { 205+ input->pointer_focus = NULL; 206+ wl_pointer_set_cursor (pointer, serial, NULL, 0, 0); 207+ } 208+} 209+ 210+static void 211+pointer_handle_motion (void *data, struct wl_pointer *pointer, 212+ uint32_t time, wl_fixed_t sx, wl_fixed_t sy) 213+{ 214+} 215+ 216+static void 217+pointer_handle_button (void *data, struct wl_pointer *pointer, uint32_t serial, 218+ uint32_t time, uint32_t button, uint32_t state) 219+{ 220+ struct input *input = data; 221+ GstWlWindow *window; 222+ 223+ window = input->pointer_focus; 224+ if (!window) 225+ return; 226+ 227+ if (button == BTN_LEFT && state == WL_POINTER_BUTTON_STATE_PRESSED) 228+ gst_wl_window_toplevel_move (window, input->seat, serial); 229+} 230+ 231+static void 232+pointer_handle_axis (void *data, struct wl_pointer *wl_pointer, 233+ uint32_t time, uint32_t axis, wl_fixed_t value) 234+{ 235+} 236+ 237+static const struct wl_pointer_listener pointer_listener = { 238+ pointer_handle_enter, 239+ pointer_handle_leave, 240+ pointer_handle_motion, 241+ pointer_handle_button, 242+ pointer_handle_axis, 243+}; 244+ 245+static void 246+touch_handle_down (void *data, struct wl_touch *wl_touch, 247+ uint32_t serial, uint32_t time, struct wl_surface *surface, 248+ int32_t id, wl_fixed_t x_w, wl_fixed_t y_w) 249+{ 250+ struct input *input = data; 251+ GstWlDisplay *self = input->display; 252+ GstWlDisplayPrivate *priv = gst_wl_display_get_instance_private (self); 253+ GstWlWindow *window; 254+ 255+ if (!surface) { 256+ /* enter event for a window we've just destroyed */ 257+ return; 258+ } 259+ 260+ if (surface != priv->touch_surface) { 261+ /* Ignoring input event from other surfaces */ 262+ return; 263+ } 264+ 265+ window = wl_surface_get_user_data (surface); 266+ if (!window || !gst_wl_window_is_toplevel (window)) { 267+ /* Ignoring input event from subsurface */ 268+ return; 269+ } 270+ 271+ gst_wl_window_toplevel_move (window, input->seat, serial); 272+} 273+ 274+static void 275+touch_handle_up (void *data, struct wl_touch *wl_touch, 276+ uint32_t serial, uint32_t time, int32_t id) 277+{ 278+} 279+ 280+static void 281+touch_handle_motion (void *data, struct wl_touch *wl_touch, 282+ uint32_t time, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w) 283+{ 284+} 285+ 286+static void 287+touch_handle_frame (void *data, struct wl_touch *wl_touch) 288+{ 289+} 290+ 291+static void 292+touch_handle_cancel (void *data, struct wl_touch *wl_touch) 293+{ 294+} 295+ 296+static const struct wl_touch_listener touch_listener = { 297+ touch_handle_down, 298+ touch_handle_up, 299+ touch_handle_motion, 300+ touch_handle_frame, 301+ touch_handle_cancel, 302+}; 303+ 304+static void 305+seat_handle_capabilities (void *data, struct wl_seat *seat, 306+ enum wl_seat_capability caps) 307+{ 308+ struct input *input = data; 309+ 310+ if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) { 311+ input->pointer = wl_seat_get_pointer (seat); 312+ wl_pointer_add_listener (input->pointer, &pointer_listener, input); 313+ } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) { 314+ wl_pointer_destroy (input->pointer); 315+ input->pointer = NULL; 316+ } 317+ 318+ if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !input->touch) { 319+ input->touch = wl_seat_get_touch (seat); 320+ wl_touch_add_listener (input->touch, &touch_listener, input); 321+ } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && input->touch) { 322+ wl_touch_destroy (input->touch); 323+ input->touch = NULL; 324+ } 325+} 326+ 327+static const struct wl_seat_listener seat_listener = { 328+ seat_handle_capabilities, 329+}; 330+ 331+static void 332+display_add_input (GstWlDisplay *self, uint32_t id) 333+{ 334+ GstWlDisplayPrivate *priv = gst_wl_display_get_instance_private (self); 335+ struct input *input; 336+ 337+ input = calloc (1, sizeof (*input)); 338+ if (input == NULL) { 339+ GST_ERROR ("Error out of memory"); 340+ return; 341+ } 342+ 343+ input->display = self; 344+ 345+ input->seat = wl_registry_bind (priv->registry, id, &wl_seat_interface, 1); 346+ 347+ wl_seat_add_listener (input->seat, &seat_listener, input); 348+ wl_seat_set_user_data (input->seat, input); 349+ 350+ wl_list_insert (priv->input_list.prev, &input->link); 351+} 352+ 353 static void 354 registry_handle_global (void *data, struct wl_registry *registry, 355 uint32_t id, const char *interface, uint32_t version) 356@@ -307,6 +586,18 @@ registry_handle_global (void *data, struct wl_registry *registry, 357 } else if (g_strcmp0 (interface, "wl_shm") == 0) { 358 priv->shm = wl_registry_bind (registry, id, &wl_shm_interface, 1); 359 wl_shm_add_listener (priv->shm, &shm_listener, self); 360+ 361+ priv->cursor_theme = wl_cursor_theme_load (NULL, 32, priv->shm); 362+ if (!priv->cursor_theme) { 363+ GST_ERROR ("Error loading default cursor theme"); 364+ } else { 365+ priv->default_cursor = 366+ wl_cursor_theme_get_cursor (priv->cursor_theme, "left_ptr"); 367+ if (!priv->default_cursor) 368+ GST_ERROR ("Error loading default left cursor pointer"); 369+ } 370+ } else if (g_strcmp0 (interface, "wl_seat") == 0) { 371+ display_add_input (self, id); 372 } else if (g_strcmp0 (interface, "wp_viewporter") == 0) { 373 priv->viewporter = 374 wl_registry_bind (registry, id, &wp_viewporter_interface, 1); 375@@ -400,6 +691,8 @@ gst_wl_display_new_existing (struct wl_display * display, 376 priv->display_wrapper = wl_proxy_create_wrapper (display); 377 priv->own_display = take_ownership; 378 379+ wl_list_init (&priv->input_list); 380+ 381 priv->queue = wl_display_create_queue (priv->display); 382 wl_proxy_set_queue ((struct wl_proxy *) priv->display_wrapper, priv->queue); 383 priv->registry = wl_display_get_registry (priv->display_wrapper); 384diff --git a/gst-libs/gst/wayland/gstwldisplay.h b/gst-libs/gst/wayland/gstwldisplay.h 385index c130b79..c6b4c8d 100644 386--- a/gst-libs/gst/wayland/gstwldisplay.h 387+++ b/gst-libs/gst/wayland/gstwldisplay.h 388@@ -35,6 +35,10 @@ struct _GstWlDisplay 389 GObject parent_instance; 390 }; 391 392+GST_WL_API 393+void gst_wl_display_set_touch_surface (GstWlDisplay * self, 394+ struct wl_surface *touch_surface); 395+ 396 GST_WL_API 397 gboolean gst_wl_display_support_afbc (GstWlDisplay * self); 398 399diff --git a/gst-libs/gst/wayland/gstwlwindow.c b/gst-libs/gst/wayland/gstwlwindow.c 400index df60a67..f55778d 100644 401--- a/gst-libs/gst/wayland/gstwlwindow.c 402+++ b/gst-libs/gst/wayland/gstwlwindow.c 403@@ -96,6 +96,19 @@ static void gst_wl_window_finalize (GObject * gobject); 404 405 static void gst_wl_window_update_borders (GstWlWindow * self); 406 407+void 408+gst_wl_window_toplevel_move (GstWlWindow * self, 409+ struct wl_seat *seat, uint32_t serial) 410+{ 411+ GstWlWindowPrivate *priv; 412+ 413+ if (!gst_wl_window_is_toplevel (self)) 414+ return; 415+ 416+ priv = gst_wl_window_get_instance_private (self); 417+ xdg_toplevel_move (priv->xdg_toplevel, seat, serial); 418+} 419+ 420 static void 421 handle_xdg_toplevel_close (void *data, struct xdg_toplevel *xdg_toplevel) 422 { 423@@ -227,6 +240,8 @@ gst_wl_window_new_internal (GstWlDisplay * display, GMutex * render_lock) 424 priv->area_surface = wl_compositor_create_surface (compositor); 425 priv->video_surface = wl_compositor_create_surface (compositor); 426 427+ gst_wl_display_set_touch_surface (display, priv->area_surface); 428+ 429 priv->area_surface_wrapper = wl_proxy_create_wrapper (priv->area_surface); 430 priv->video_surface_wrapper = wl_proxy_create_wrapper (priv->video_surface); 431 432@@ -368,6 +383,8 @@ gst_wl_window_new_toplevel (GstWlDisplay * display, const GstVideoInfo * info, 433 self = gst_wl_window_new_internal (display, render_lock); 434 priv = gst_wl_window_get_instance_private (self); 435 436+ wl_surface_set_user_data (priv->area_surface, self); 437+ 438 xdg_wm_base = gst_wl_display_get_xdg_wm_base (display); 439 fullscreen_shell = gst_wl_display_get_fullscreen_shell_v1 (display); 440 441diff --git a/gst-libs/gst/wayland/gstwlwindow.h b/gst-libs/gst/wayland/gstwlwindow.h 442index 8f02f00..9425666 100644 443--- a/gst-libs/gst/wayland/gstwlwindow.h 444+++ b/gst-libs/gst/wayland/gstwlwindow.h 445@@ -47,6 +47,10 @@ struct _GstWlWindow 446 GObject parent_instance; 447 }; 448 449+GST_WL_API 450+void gst_wl_window_toplevel_move (GstWlWindow * self, 451+ struct wl_seat *seat, uint32_t serial); 452+ 453 GST_WL_API 454 void gst_wl_window_ensure_crop (GstWlWindow * self, 455 gint x, gint y, gint w, gint h); 456diff --git a/gst-libs/gst/wayland/meson.build b/gst-libs/gst/wayland/meson.build 457index 3aa63cb..9c958d7 100644 458--- a/gst-libs/gst/wayland/meson.build 459+++ b/gst-libs/gst/wayland/meson.build 460@@ -1,10 +1,11 @@ 461 wl_req = '>= 1.15' 462 wl_client_dep = dependency('wayland-client', version: wl_req, required: get_option('wayland')) 463+wl_cursor_dep = dependency('wayland-cursor', version: wl_req, required: get_option('wayland')) 464 libdrm_dep = dependency('libdrm', version: '>= 2.4.55', required: get_option('wayland')) 465 wl_protocol_dep = dependency('wayland-protocols', version: wl_req, required: get_option('wayland')) 466 wl_scanner = find_program('wayland-scanner', required: get_option('wayland')) 467 # Also used in ext/wayland 468-use_wayland = wl_protocol_dep.found() and wl_client_dep.found() and wl_scanner.found() and libdrm_dep.found() 469+use_wayland = wl_protocol_dep.found() and wl_client_dep.found() and wl_cursor_dep.found() and wl_scanner.found() and libdrm_dep.found() 470 471 if use_wayland 472 wl_sources = [ 473@@ -74,7 +75,7 @@ if use_wayland 474 darwin_versions : osxversion, 475 install : true, 476 dependencies : [gst_dep, gstallocators_dep, gstvideo_dep, libdrm_dep, 477- wl_client_dep, wl_protocol_dep] 478+ wl_client_dep, wl_cursor_dep, wl_protocol_dep] 479 ) 480 481 pkg_name = 'gstreamer-wayland-1.0' 482@@ -90,7 +91,7 @@ if use_wayland 483 gstwayland_dep = declare_dependency(link_with : gstwayland, 484 include_directories : [libsinc], 485 dependencies : [gst_dep, gstallocators_dep, gstvideo_dep, libdrm_dep, 486- wl_client_dep, wl_protocol_dep]) 487+ wl_client_dep, wl_cursor_dep, wl_protocol_dep]) 488 489 install_headers(wl_headers, subdir: 'gstreamer-1.0/gst/wayland') 490 meson.override_dependency(pkg_name, gstwayland_dep) 491-- 4922.20.1 493 494