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