1From aba56acd328d0843eaa69401e951f95fc6e56eaf 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 31/35] 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 ext/wayland/meson.build | 3 +- 11 ext/wayland/wldisplay.c | 278 ++++++++++++++++++++++++++++++++++++++++ 12 ext/wayland/wldisplay.h | 8 ++ 13 ext/wayland/wlwindow.c | 4 + 14 4 files changed, 292 insertions(+), 1 deletion(-) 15 16diff --git a/ext/wayland/meson.build b/ext/wayland/meson.build 17index a3ffb70..c8a32da 100644 18--- a/ext/wayland/meson.build 19+++ b/ext/wayland/meson.build 20@@ -37,12 +37,13 @@ if use_wayland 21 command : [wl_scanner, 'client-header', '@INPUT@', '@OUTPUT@'])] 22 endforeach 23 24+ wl_cursor_dep = dependency('wayland-cursor') 25 gstwaylandsink = library('gstwaylandsink', 26 wl_sources + protocols_files, 27 c_args : gst_plugins_bad_args + ['-DGST_USE_UNSTABLE_API'], 28 include_directories : [configinc], 29 dependencies : [gst_dep, gstvideo_dep, gstwayland_dep, gstallocators_dep, 30- wl_client_dep, wl_protocol_dep, libdrm_dep], 31+ wl_client_dep, wl_protocol_dep, wl_cursor_dep, libdrm_dep], 32 install : true, 33 install_dir : plugins_install_dir, 34 ) 35diff --git a/ext/wayland/wldisplay.c b/ext/wayland/wldisplay.c 36index fcf2853..701ee5e 100644 37--- a/ext/wayland/wldisplay.c 38+++ b/ext/wayland/wldisplay.c 39@@ -24,9 +24,11 @@ 40 41 #include "wldisplay.h" 42 #include "wlbuffer.h" 43+#include "wlwindow.h" 44 #include "wlvideoformat.h" 45 46 #include <errno.h> 47+#include <linux/input.h> 48 49 GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug); 50 #define GST_CAT_DEFAULT gstwayland_debug 51@@ -35,6 +37,18 @@ G_DEFINE_TYPE (GstWlDisplay, gst_wl_display, G_TYPE_OBJECT); 52 53 static void gst_wl_display_finalize (GObject * gobject); 54 55+struct input 56+{ 57+ GstWlDisplay *display; 58+ struct wl_seat *seat; 59+ struct wl_pointer *pointer; 60+ struct wl_touch *touch; 61+ 62+ void *pointer_focus; 63+ 64+ struct wl_list link; 65+}; 66+ 67 static void 68 gst_wl_display_class_init (GstWlDisplayClass * klass) 69 { 70@@ -58,6 +72,29 @@ gst_wl_ref_wl_buffer (gpointer key, gpointer value, gpointer user_data) 71 g_object_ref (value); 72 } 73 74+static void 75+input_destroy (struct input *input) 76+{ 77+ if (input->touch) 78+ wl_touch_destroy (input->touch); 79+ if (input->pointer) 80+ wl_pointer_destroy (input->pointer); 81+ 82+ wl_list_remove (&input->link); 83+ wl_seat_destroy (input->seat); 84+ free (input); 85+} 86+ 87+static void 88+display_destroy_inputs (GstWlDisplay * self) 89+{ 90+ struct input *tmp; 91+ struct input *input; 92+ 93+ wl_list_for_each_safe (input, tmp, &self->input_list, link) 94+ input_destroy (input); 95+} 96+ 97 static void 98 gst_wl_display_finalize (GObject * gobject) 99 { 100@@ -67,6 +104,14 @@ gst_wl_display_finalize (GObject * gobject) 101 if (self->thread) 102 g_thread_join (self->thread); 103 104+ display_destroy_inputs (self); 105+ 106+ if (self->cursor_surface) 107+ wl_surface_destroy (self->cursor_surface); 108+ 109+ if (self->cursor_theme) 110+ wl_cursor_theme_destroy (self->cursor_theme); 111+ 112 /* to avoid buffers being unregistered from another thread 113 * at the same time, take their ownership */ 114 g_mutex_lock (&self->buffers_mutex); 115@@ -223,6 +268,225 @@ static const struct xdg_wm_base_listener xdg_wm_base_listener = { 116 handle_xdg_wm_base_ping 117 }; 118 119+static void 120+display_set_cursor (GstWlDisplay *self, struct wl_pointer *pointer, 121+ uint32_t serial) 122+{ 123+ struct wl_buffer *buffer; 124+ struct wl_cursor_image *image; 125+ 126+ if (!self->default_cursor) 127+ return; 128+ 129+ if (!self->cursor_surface) { 130+ self->cursor_surface = 131+ wl_compositor_create_surface (self->compositor); 132+ if (!self->cursor_surface) 133+ return; 134+ } 135+ 136+ image = self->default_cursor->images[0]; 137+ buffer = wl_cursor_image_get_buffer (image); 138+ if (!buffer) 139+ return; 140+ 141+ wl_pointer_set_cursor (pointer, serial, 142+ self->cursor_surface, image->hotspot_x, image->hotspot_y); 143+ wl_surface_attach (self->cursor_surface, buffer, 0, 0); 144+ wl_surface_damage (self->cursor_surface, 0, 0, 145+ image->width, image->height); 146+ wl_surface_commit (self->cursor_surface); 147+} 148+ 149+static void 150+pointer_handle_enter (void *data, struct wl_pointer *pointer, 151+ uint32_t serial, struct wl_surface *surface, 152+ wl_fixed_t sx_w, wl_fixed_t sy_w) 153+{ 154+ struct input *input = data; 155+ GstWlDisplay *display = input->display; 156+ GstWlWindow *window; 157+ 158+ if (!surface) { 159+ /* enter event for a window we've just destroyed */ 160+ return; 161+ } 162+ 163+ if (surface != display->touch_surface) { 164+ /* Ignoring input event from other surfaces */ 165+ return; 166+ } 167+ 168+ window = wl_surface_get_user_data (surface); 169+ if (!window || !gst_wl_window_is_toplevel (window)) { 170+ /* Ignoring input event from subsurface */ 171+ return; 172+ } 173+ 174+ input->pointer_focus = window; 175+ display_set_cursor (window->display, pointer, serial); 176+} 177+ 178+static void 179+pointer_handle_leave (void *data, struct wl_pointer *pointer, 180+ uint32_t serial, struct wl_surface *surface) 181+{ 182+ struct input *input = data; 183+ 184+ if (input->pointer_focus) { 185+ input->pointer_focus = NULL; 186+ wl_pointer_set_cursor (pointer, serial, NULL, 0, 0); 187+ } 188+} 189+ 190+static void 191+pointer_handle_motion (void *data, struct wl_pointer *pointer, 192+ uint32_t time, wl_fixed_t sx, wl_fixed_t sy) 193+{ 194+} 195+ 196+static void 197+pointer_handle_button (void *data, struct wl_pointer *pointer, uint32_t serial, 198+ uint32_t time, uint32_t button, uint32_t state) 199+{ 200+ struct input *input = data; 201+ GstWlWindow *window; 202+ 203+ window = input->pointer_focus; 204+ if (!window) 205+ return; 206+ 207+ if (button == BTN_LEFT && state == WL_POINTER_BUTTON_STATE_PRESSED) { 208+ if (window->display->xdg_wm_base) 209+ xdg_toplevel_move (window->xdg_toplevel, input->seat, serial); 210+ else 211+ wl_shell_surface_move (window->wl_shell_surface, input->seat, serial); 212+ } 213+} 214+ 215+static void 216+pointer_handle_axis(void *data, struct wl_pointer *wl_pointer, 217+ uint32_t time, uint32_t axis, wl_fixed_t value) 218+{ 219+} 220+ 221+static const struct wl_pointer_listener pointer_listener = { 222+ pointer_handle_enter, 223+ pointer_handle_leave, 224+ pointer_handle_motion, 225+ pointer_handle_button, 226+ pointer_handle_axis, 227+}; 228+ 229+static void 230+touch_handle_down (void *data, struct wl_touch *wl_touch, 231+ uint32_t serial, uint32_t time, struct wl_surface *surface, 232+ int32_t id, wl_fixed_t x_w, wl_fixed_t y_w) 233+{ 234+ struct input *input = data; 235+ GstWlDisplay *display = input->display; 236+ GstWlWindow *window; 237+ 238+ if (!surface) { 239+ /* enter event for a window we've just destroyed */ 240+ return; 241+ } 242+ 243+ if (surface != display->touch_surface) { 244+ /* Ignoring input event from other surfaces */ 245+ return; 246+ } 247+ 248+ window = wl_surface_get_user_data (surface); 249+ if (!window || !gst_wl_window_is_toplevel (window)) { 250+ /* Ignoring input event from subsurface */ 251+ return; 252+ } 253+ 254+ if (window->display->xdg_wm_base) 255+ xdg_toplevel_move (window->xdg_toplevel, input->seat, serial); 256+ else 257+ wl_shell_surface_move (window->wl_shell_surface, input->seat, serial); 258+} 259+ 260+static void 261+touch_handle_up (void *data, struct wl_touch *wl_touch, 262+ uint32_t serial, uint32_t time, int32_t id) 263+{ 264+} 265+ 266+static void 267+touch_handle_motion (void *data, struct wl_touch *wl_touch, 268+ uint32_t time, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w) 269+{ 270+} 271+ 272+static void 273+touch_handle_frame (void *data, struct wl_touch *wl_touch) 274+{ 275+} 276+ 277+static void 278+touch_handle_cancel (void *data, struct wl_touch *wl_touch) 279+{ 280+} 281+ 282+static const struct wl_touch_listener touch_listener = { 283+ touch_handle_down, 284+ touch_handle_up, 285+ touch_handle_motion, 286+ touch_handle_frame, 287+ touch_handle_cancel, 288+}; 289+ 290+static void 291+seat_handle_capabilities (void *data, struct wl_seat *seat, 292+ enum wl_seat_capability caps) 293+{ 294+ struct input *input = data; 295+ 296+ if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) { 297+ input->pointer = wl_seat_get_pointer (seat); 298+ wl_pointer_add_listener (input->pointer, &pointer_listener, input); 299+ } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) { 300+ wl_pointer_destroy (input->pointer); 301+ input->pointer = NULL; 302+ } 303+ 304+ if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !input->touch) { 305+ input->touch = wl_seat_get_touch (seat); 306+ wl_touch_add_listener (input->touch, &touch_listener, input); 307+ } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && input->touch) { 308+ wl_touch_destroy (input->touch); 309+ input->touch = NULL; 310+ } 311+} 312+ 313+static const struct wl_seat_listener seat_listener = { 314+ seat_handle_capabilities, 315+}; 316+ 317+static void 318+display_add_input (GstWlDisplay *self, uint32_t id) 319+{ 320+ struct input *input; 321+ 322+ input = calloc (1, sizeof (*input)); 323+ if (input == NULL) { 324+ GST_ERROR ("Error out of memory"); 325+ return; 326+ } 327+ 328+ input->display = self; 329+ 330+ input->seat = wl_registry_bind (self->registry, id, &wl_seat_interface, 1); 331+ 332+ wl_seat_add_listener (input->seat, &seat_listener, input); 333+ wl_seat_set_user_data (input->seat, input); 334+ 335+ wl_list_insert(self->input_list.prev, &input->link); 336+} 337+ 338 static void 339 registry_handle_global (void *data, struct wl_registry *registry, 340 uint32_t id, const char *interface, uint32_t version) 341@@ -247,6 +511,18 @@ registry_handle_global (void *data, struct wl_registry *registry, 342 } else if (g_strcmp0 (interface, "wl_shm") == 0) { 343 self->shm = wl_registry_bind (registry, id, &wl_shm_interface, 1); 344 wl_shm_add_listener (self->shm, &shm_listener, self); 345+ 346+ self->cursor_theme = wl_cursor_theme_load (NULL, 32, self->shm); 347+ if (!self->cursor_theme) { 348+ GST_ERROR ("Error loading default cursor theme"); 349+ } else { 350+ self->default_cursor = 351+ wl_cursor_theme_get_cursor (self->cursor_theme, "left_ptr"); 352+ if (!self->default_cursor) 353+ GST_ERROR ("Error loading default left cursor pointer"); 354+ } 355+ } else if (g_strcmp0 (interface, "wl_seat") == 0) { 356+ display_add_input (self, id); 357 } else if (g_strcmp0 (interface, "wp_viewporter") == 0) { 358 self->viewporter = 359 wl_registry_bind (registry, id, &wp_viewporter_interface, 1); 360@@ -337,6 +613,8 @@ gst_wl_display_new_existing (struct wl_display * display, 361 self->display_wrapper = wl_proxy_create_wrapper (display); 362 self->own_display = take_ownership; 363 364+ wl_list_init (&self->input_list); 365+ 366 self->queue = wl_display_create_queue (self->display); 367 wl_proxy_set_queue ((struct wl_proxy *) self->display_wrapper, self->queue); 368 self->registry = wl_display_get_registry (self->display_wrapper); 369diff --git a/ext/wayland/wldisplay.h b/ext/wayland/wldisplay.h 370index 29c15f6..8914d31 100644 371--- a/ext/wayland/wldisplay.h 372+++ b/ext/wayland/wldisplay.h 373@@ -24,6 +24,7 @@ 374 #include <gst/gst.h> 375 #include <gst/video/video.h> 376 #include <wayland-client.h> 377+#include <wayland-cursor.h> 378 #include "xdg-shell-client-protocol.h" 379 #include "viewporter-client-protocol.h" 380 #include "linux-dmabuf-unstable-v1-client-protocol.h" 381@@ -50,6 +51,13 @@ struct _GstWlDisplay 382 struct wl_display *display_wrapper; 383 struct wl_event_queue *queue; 384 385+ struct wl_list input_list; 386+ 387+ struct wl_cursor_theme *cursor_theme; 388+ struct wl_cursor *default_cursor; 389+ struct wl_surface *cursor_surface; 390+ struct wl_surface *touch_surface; 391+ 392 /* globals */ 393 struct wl_registry *registry; 394 struct wl_compositor *compositor; 395diff --git a/ext/wayland/wlwindow.c b/ext/wayland/wlwindow.c 396index 2ba0eee..9917beb 100644 397--- a/ext/wayland/wlwindow.c 398+++ b/ext/wayland/wlwindow.c 399@@ -205,6 +205,8 @@ gst_wl_window_new_internal (GstWlDisplay * display, GMutex * render_lock) 400 window->area_surface = wl_compositor_create_surface (display->compositor); 401 window->video_surface = wl_compositor_create_surface (display->compositor); 402 403+ display->touch_surface = window->area_surface; 404+ 405 window->area_surface_wrapper = wl_proxy_create_wrapper (window->area_surface); 406 window->video_surface_wrapper = 407 wl_proxy_create_wrapper (window->video_surface); 408@@ -308,6 +310,8 @@ gst_wl_window_new_toplevel (GstWlDisplay * display, const GstVideoInfo * info, 409 410 window = gst_wl_window_new_internal (display, render_lock); 411 412+ wl_surface_set_user_data (window->area_surface, window); 413+ 414 /* Check which protocol we will use (in order of preference) */ 415 if (display->xdg_wm_base) { 416 gint64 timeout; 417-- 4182.20.1 419 420