1a46c0ec8Sopenharmony_ci/*
2a46c0ec8Sopenharmony_ci * Copyright © 2014 Red Hat, Inc.
3a46c0ec8Sopenharmony_ci *
4a46c0ec8Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5a46c0ec8Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6a46c0ec8Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7a46c0ec8Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8a46c0ec8Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9a46c0ec8Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10a46c0ec8Sopenharmony_ci *
11a46c0ec8Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12a46c0ec8Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13a46c0ec8Sopenharmony_ci * Software.
14a46c0ec8Sopenharmony_ci *
15a46c0ec8Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16a46c0ec8Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17a46c0ec8Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18a46c0ec8Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19a46c0ec8Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20a46c0ec8Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21a46c0ec8Sopenharmony_ci * DEALINGS IN THE SOFTWARE.
22a46c0ec8Sopenharmony_ci */
23a46c0ec8Sopenharmony_ci#include <config.h>
24a46c0ec8Sopenharmony_ci
25a46c0ec8Sopenharmony_ci#include <linux/input.h>
26a46c0ec8Sopenharmony_ci
27a46c0ec8Sopenharmony_ci#include <assert.h>
28a46c0ec8Sopenharmony_ci#include <cairo.h>
29a46c0ec8Sopenharmony_ci#include <errno.h>
30a46c0ec8Sopenharmony_ci#include <fcntl.h>
31a46c0ec8Sopenharmony_ci#include <getopt.h>
32a46c0ec8Sopenharmony_ci#include <math.h>
33a46c0ec8Sopenharmony_ci#include <stdio.h>
34a46c0ec8Sopenharmony_ci#include <stdlib.h>
35a46c0ec8Sopenharmony_ci#include <stdarg.h>
36a46c0ec8Sopenharmony_ci#include <string.h>
37a46c0ec8Sopenharmony_ci#include <unistd.h>
38a46c0ec8Sopenharmony_ci
39a46c0ec8Sopenharmony_ci#include <gtk/gtk.h>
40a46c0ec8Sopenharmony_ci#include <glib.h>
41a46c0ec8Sopenharmony_ci#include <glib-unix.h>
42a46c0ec8Sopenharmony_ci#include <libevdev/libevdev.h>
43a46c0ec8Sopenharmony_ci
44a46c0ec8Sopenharmony_ci#include <libinput.h>
45a46c0ec8Sopenharmony_ci#include "util-strings.h"
46a46c0ec8Sopenharmony_ci#include "util-macros.h"
47a46c0ec8Sopenharmony_ci#include "util-list.h"
48a46c0ec8Sopenharmony_ci
49a46c0ec8Sopenharmony_ci#include "shared.h"
50a46c0ec8Sopenharmony_ci
51a46c0ec8Sopenharmony_ci#if HAVE_GTK_WAYLAND
52a46c0ec8Sopenharmony_ci	#include <wayland-client.h>
53a46c0ec8Sopenharmony_ci	#include "pointer-constraints-unstable-v1-client-protocol.h"
54a46c0ec8Sopenharmony_ci	#if HAVE_GTK4
55a46c0ec8Sopenharmony_ci		#include <gdk/wayland/gdkwayland.h>
56a46c0ec8Sopenharmony_ci	#else
57a46c0ec8Sopenharmony_ci		#include <gdk/gdkwayland.h>
58a46c0ec8Sopenharmony_ci	#endif
59a46c0ec8Sopenharmony_ci#endif
60a46c0ec8Sopenharmony_ci
61a46c0ec8Sopenharmony_ci#if HAVE_GTK_X11
62a46c0ec8Sopenharmony_ci	#include <X11/X.h>
63a46c0ec8Sopenharmony_ci	#include <X11/Xlib.h>
64a46c0ec8Sopenharmony_ci	#if HAVE_GTK4
65a46c0ec8Sopenharmony_ci		#include <gdk/x11/gdkx.h>
66a46c0ec8Sopenharmony_ci	#else
67a46c0ec8Sopenharmony_ci		#include <gdk/gdkx.h>
68a46c0ec8Sopenharmony_ci	#endif
69a46c0ec8Sopenharmony_ci#endif
70a46c0ec8Sopenharmony_ci
71a46c0ec8Sopenharmony_ci#define clip(val_, min_, max_) min((max_), max((min_), (val_)))
72a46c0ec8Sopenharmony_ci
73a46c0ec8Sopenharmony_cienum touch_state {
74a46c0ec8Sopenharmony_ci	TOUCH_ACTIVE,
75a46c0ec8Sopenharmony_ci	TOUCH_ENDED,
76a46c0ec8Sopenharmony_ci	TOUCH_CANCELLED,
77a46c0ec8Sopenharmony_ci};
78a46c0ec8Sopenharmony_ci
79a46c0ec8Sopenharmony_cistruct touch {
80a46c0ec8Sopenharmony_ci	enum touch_state state;
81a46c0ec8Sopenharmony_ci	int x, y;
82a46c0ec8Sopenharmony_ci};
83a46c0ec8Sopenharmony_ci
84a46c0ec8Sopenharmony_cistruct point {
85a46c0ec8Sopenharmony_ci	double x, y;
86a46c0ec8Sopenharmony_ci};
87a46c0ec8Sopenharmony_ci
88a46c0ec8Sopenharmony_cistruct evdev_device {
89a46c0ec8Sopenharmony_ci	struct list node;
90a46c0ec8Sopenharmony_ci	struct libevdev *evdev;
91a46c0ec8Sopenharmony_ci	struct libinput_device *libinput_device;
92a46c0ec8Sopenharmony_ci	int fd;
93a46c0ec8Sopenharmony_ci	guint source_id;
94a46c0ec8Sopenharmony_ci};
95a46c0ec8Sopenharmony_ci
96a46c0ec8Sopenharmony_cistruct window {
97a46c0ec8Sopenharmony_ci	bool grab;
98a46c0ec8Sopenharmony_ci	struct tools_options options;
99a46c0ec8Sopenharmony_ci	struct list evdev_devices;
100a46c0ec8Sopenharmony_ci
101a46c0ec8Sopenharmony_ci	GMainLoop *event_loop;
102a46c0ec8Sopenharmony_ci
103a46c0ec8Sopenharmony_ci	GtkWidget *win;
104a46c0ec8Sopenharmony_ci	GtkWidget *area;
105a46c0ec8Sopenharmony_ci	int width, height; /* of window */
106a46c0ec8Sopenharmony_ci
107a46c0ec8Sopenharmony_ci	/* sprite position */
108a46c0ec8Sopenharmony_ci	struct point pointer;
109a46c0ec8Sopenharmony_ci	struct point unaccelerated;
110a46c0ec8Sopenharmony_ci
111a46c0ec8Sopenharmony_ci	/* these are for the delta coordinates, but they're not
112a46c0ec8Sopenharmony_ci	 * deltas, they are converted into abs positions */
113a46c0ec8Sopenharmony_ci	size_t ndeltas;
114a46c0ec8Sopenharmony_ci	struct point deltas[64];
115a46c0ec8Sopenharmony_ci
116a46c0ec8Sopenharmony_ci	/* abs position */
117a46c0ec8Sopenharmony_ci	struct point abs;
118a46c0ec8Sopenharmony_ci
119a46c0ec8Sopenharmony_ci	/* Wayland and X11 pointer locking */
120a46c0ec8Sopenharmony_ci	struct {
121a46c0ec8Sopenharmony_ci		bool locked;
122a46c0ec8Sopenharmony_ci
123a46c0ec8Sopenharmony_ci#if HAVE_GTK_WAYLAND
124a46c0ec8Sopenharmony_ci		struct zwp_pointer_constraints_v1 *wayland_pointer_constraints;
125a46c0ec8Sopenharmony_ci		struct zwp_locked_pointer_v1 *wayland_locked_pointer;
126a46c0ec8Sopenharmony_ci#endif
127a46c0ec8Sopenharmony_ci	} lock_pointer;
128a46c0ec8Sopenharmony_ci
129a46c0ec8Sopenharmony_ci	/* scroll bar positions */
130a46c0ec8Sopenharmony_ci	struct {
131a46c0ec8Sopenharmony_ci		double vx, vy;
132a46c0ec8Sopenharmony_ci		double hx, hy;
133a46c0ec8Sopenharmony_ci
134a46c0ec8Sopenharmony_ci		double vx_discrete, vy_discrete;
135a46c0ec8Sopenharmony_ci		double hx_discrete, hy_discrete;
136a46c0ec8Sopenharmony_ci	} scroll;
137a46c0ec8Sopenharmony_ci
138a46c0ec8Sopenharmony_ci	/* touch positions */
139a46c0ec8Sopenharmony_ci	struct touch touches[32];
140a46c0ec8Sopenharmony_ci
141a46c0ec8Sopenharmony_ci	/* l/m/r mouse buttons */
142a46c0ec8Sopenharmony_ci	struct {
143a46c0ec8Sopenharmony_ci		bool l, m, r;
144a46c0ec8Sopenharmony_ci		bool other;
145a46c0ec8Sopenharmony_ci		const char *other_name;
146a46c0ec8Sopenharmony_ci	} buttons;
147a46c0ec8Sopenharmony_ci
148a46c0ec8Sopenharmony_ci	/* touchpad swipe */
149a46c0ec8Sopenharmony_ci	struct {
150a46c0ec8Sopenharmony_ci		int nfingers;
151a46c0ec8Sopenharmony_ci		double x, y;
152a46c0ec8Sopenharmony_ci	} swipe;
153a46c0ec8Sopenharmony_ci
154a46c0ec8Sopenharmony_ci	struct {
155a46c0ec8Sopenharmony_ci		int nfingers;
156a46c0ec8Sopenharmony_ci		double scale;
157a46c0ec8Sopenharmony_ci		double angle;
158a46c0ec8Sopenharmony_ci		double x, y;
159a46c0ec8Sopenharmony_ci	} pinch;
160a46c0ec8Sopenharmony_ci
161a46c0ec8Sopenharmony_ci	struct {
162a46c0ec8Sopenharmony_ci		int nfingers;
163a46c0ec8Sopenharmony_ci		bool active;
164a46c0ec8Sopenharmony_ci	} hold;
165a46c0ec8Sopenharmony_ci
166a46c0ec8Sopenharmony_ci	struct {
167a46c0ec8Sopenharmony_ci		double x, y;
168a46c0ec8Sopenharmony_ci		double x_in, y_in;
169a46c0ec8Sopenharmony_ci		double x_down, y_down;
170a46c0ec8Sopenharmony_ci		double x_up, y_up;
171a46c0ec8Sopenharmony_ci		double pressure;
172a46c0ec8Sopenharmony_ci		double distance;
173a46c0ec8Sopenharmony_ci		double tilt_x, tilt_y;
174a46c0ec8Sopenharmony_ci		double rotation;
175a46c0ec8Sopenharmony_ci		double size_major, size_minor;
176a46c0ec8Sopenharmony_ci		bool is_down;
177a46c0ec8Sopenharmony_ci
178a46c0ec8Sopenharmony_ci		/* these are for the delta coordinates, but they're not
179a46c0ec8Sopenharmony_ci		 * deltas, they are converted into abs positions */
180a46c0ec8Sopenharmony_ci		size_t ndeltas;
181a46c0ec8Sopenharmony_ci		struct point deltas[64];
182a46c0ec8Sopenharmony_ci	} tool;
183a46c0ec8Sopenharmony_ci
184a46c0ec8Sopenharmony_ci	struct {
185a46c0ec8Sopenharmony_ci		struct {
186a46c0ec8Sopenharmony_ci			double position;
187a46c0ec8Sopenharmony_ci			int number;
188a46c0ec8Sopenharmony_ci		} ring;
189a46c0ec8Sopenharmony_ci		struct {
190a46c0ec8Sopenharmony_ci			double position;
191a46c0ec8Sopenharmony_ci			int number;
192a46c0ec8Sopenharmony_ci		} strip;
193a46c0ec8Sopenharmony_ci	} pad;
194a46c0ec8Sopenharmony_ci
195a46c0ec8Sopenharmony_ci	struct {
196a46c0ec8Sopenharmony_ci		int rel_x, rel_y; /* REL_X/Y */
197a46c0ec8Sopenharmony_ci		int x, y;	  /* ABS_X/Y */
198a46c0ec8Sopenharmony_ci		struct {
199a46c0ec8Sopenharmony_ci			int x, y; /* ABS_MT_POSITION_X/Y */
200a46c0ec8Sopenharmony_ci			bool active;
201a46c0ec8Sopenharmony_ci		} slots[16];
202a46c0ec8Sopenharmony_ci		unsigned int slot; /* ABS_MT_SLOT */
203a46c0ec8Sopenharmony_ci		/* So we know when to re-fetch the abs axes */
204a46c0ec8Sopenharmony_ci		uintptr_t device, last_device;
205a46c0ec8Sopenharmony_ci	} evdev;
206a46c0ec8Sopenharmony_ci
207a46c0ec8Sopenharmony_ci	struct libinput_device *devices[50];
208a46c0ec8Sopenharmony_ci};
209a46c0ec8Sopenharmony_ci
210a46c0ec8Sopenharmony_ci#if HAVE_GTK_WAYLAND
211a46c0ec8Sopenharmony_cistatic void
212a46c0ec8Sopenharmony_ciwayland_registry_global(void *data,
213a46c0ec8Sopenharmony_ci			struct wl_registry *registry,
214a46c0ec8Sopenharmony_ci			uint32_t name,
215a46c0ec8Sopenharmony_ci			const char *interface,
216a46c0ec8Sopenharmony_ci			uint32_t version)
217a46c0ec8Sopenharmony_ci{
218a46c0ec8Sopenharmony_ci	struct window *w = data;
219a46c0ec8Sopenharmony_ci
220a46c0ec8Sopenharmony_ci	if (!g_strcmp0(interface, "zwp_pointer_constraints_v1")) {
221a46c0ec8Sopenharmony_ci		w->lock_pointer.wayland_pointer_constraints =
222a46c0ec8Sopenharmony_ci			wl_registry_bind(registry,
223a46c0ec8Sopenharmony_ci					 name,
224a46c0ec8Sopenharmony_ci					 &zwp_pointer_constraints_v1_interface,
225a46c0ec8Sopenharmony_ci					 1);
226a46c0ec8Sopenharmony_ci        }
227a46c0ec8Sopenharmony_ci}
228a46c0ec8Sopenharmony_ci
229a46c0ec8Sopenharmony_cistatic void
230a46c0ec8Sopenharmony_ciwayland_registry_global_remove(void *data,
231a46c0ec8Sopenharmony_ci			       struct wl_registry *wl_registry,
232a46c0ec8Sopenharmony_ci			       uint32_t name)
233a46c0ec8Sopenharmony_ci{
234a46c0ec8Sopenharmony_ci
235a46c0ec8Sopenharmony_ci}
236a46c0ec8Sopenharmony_ci
237a46c0ec8Sopenharmony_cistruct wl_registry_listener registry_listener = {
238a46c0ec8Sopenharmony_ci	wayland_registry_global,
239a46c0ec8Sopenharmony_ci	wayland_registry_global_remove
240a46c0ec8Sopenharmony_ci};
241a46c0ec8Sopenharmony_ci
242a46c0ec8Sopenharmony_cistatic bool
243a46c0ec8Sopenharmony_ciwayland_lock_pointer(struct window *w)
244a46c0ec8Sopenharmony_ci{
245a46c0ec8Sopenharmony_ci	GdkDisplay *gdk_display;
246a46c0ec8Sopenharmony_ci	GdkSeat *gdk_seat;
247a46c0ec8Sopenharmony_ci	GdkDevice *gdk_device;
248a46c0ec8Sopenharmony_ci	struct wl_display *display;
249a46c0ec8Sopenharmony_ci	struct wl_registry *registry;
250a46c0ec8Sopenharmony_ci	struct wl_pointer *wayland_pointer;
251a46c0ec8Sopenharmony_ci	struct wl_surface *surface;
252a46c0ec8Sopenharmony_ci
253a46c0ec8Sopenharmony_ci	w->lock_pointer.wayland_pointer_constraints = NULL;
254a46c0ec8Sopenharmony_ci
255a46c0ec8Sopenharmony_ci	gdk_display = gdk_display_get_default();
256a46c0ec8Sopenharmony_ci	display = gdk_wayland_display_get_wl_display(gdk_display);
257a46c0ec8Sopenharmony_ci
258a46c0ec8Sopenharmony_ci	gdk_seat = gdk_display_get_default_seat(gdk_display);
259a46c0ec8Sopenharmony_ci	gdk_device = gdk_seat_get_pointer(gdk_seat);
260a46c0ec8Sopenharmony_ci	wayland_pointer = gdk_wayland_device_get_wl_pointer(gdk_device);
261a46c0ec8Sopenharmony_ci
262a46c0ec8Sopenharmony_ci	registry = wl_display_get_registry(display);
263a46c0ec8Sopenharmony_ci	wl_registry_add_listener(registry, &registry_listener, w);
264a46c0ec8Sopenharmony_ci	wl_display_roundtrip(display);
265a46c0ec8Sopenharmony_ci
266a46c0ec8Sopenharmony_ci	if (!w->lock_pointer.wayland_pointer_constraints)
267a46c0ec8Sopenharmony_ci		return false;
268a46c0ec8Sopenharmony_ci
269a46c0ec8Sopenharmony_ci#if HAVE_GTK4
270a46c0ec8Sopenharmony_ci	GtkNative *window = gtk_widget_get_native(w->win);
271a46c0ec8Sopenharmony_ci	GdkSurface *gdk_surface = gtk_native_get_surface(window);
272a46c0ec8Sopenharmony_ci	surface = gdk_wayland_surface_get_wl_surface(gdk_surface);
273a46c0ec8Sopenharmony_ci#else
274a46c0ec8Sopenharmony_ci	GdkWindow *window = gtk_widget_get_window(w->win);
275a46c0ec8Sopenharmony_ci	surface = gdk_wayland_window_get_wl_surface(window);
276a46c0ec8Sopenharmony_ci#endif
277a46c0ec8Sopenharmony_ci
278a46c0ec8Sopenharmony_ci	w->lock_pointer.wayland_locked_pointer =
279a46c0ec8Sopenharmony_ci		zwp_pointer_constraints_v1_lock_pointer(w->lock_pointer.wayland_pointer_constraints,
280a46c0ec8Sopenharmony_ci							surface,
281a46c0ec8Sopenharmony_ci							wayland_pointer,
282a46c0ec8Sopenharmony_ci							NULL,
283a46c0ec8Sopenharmony_ci							ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
284a46c0ec8Sopenharmony_ci
285a46c0ec8Sopenharmony_ci	return true;
286a46c0ec8Sopenharmony_ci}
287a46c0ec8Sopenharmony_ci
288a46c0ec8Sopenharmony_cistatic void
289a46c0ec8Sopenharmony_ciwayland_unlock_pointer(struct window *w)
290a46c0ec8Sopenharmony_ci{
291a46c0ec8Sopenharmony_ci	w->lock_pointer.wayland_pointer_constraints = NULL;
292a46c0ec8Sopenharmony_ci	zwp_locked_pointer_v1_destroy(w->lock_pointer.wayland_locked_pointer);
293a46c0ec8Sopenharmony_ci}
294a46c0ec8Sopenharmony_ci
295a46c0ec8Sopenharmony_cistatic inline bool
296a46c0ec8Sopenharmony_cibackend_is_wayland(void)
297a46c0ec8Sopenharmony_ci{
298a46c0ec8Sopenharmony_ci	return GDK_IS_WAYLAND_DISPLAY(gdk_display_get_default());
299a46c0ec8Sopenharmony_ci}
300a46c0ec8Sopenharmony_ci#endif /* HAVE_GTK_WAYLAND */
301a46c0ec8Sopenharmony_ci
302a46c0ec8Sopenharmony_ci#if HAVE_GTK_X11
303a46c0ec8Sopenharmony_cistatic bool
304a46c0ec8Sopenharmony_cix_lock_pointer(struct window *w)
305a46c0ec8Sopenharmony_ci{
306a46c0ec8Sopenharmony_ci	Display *x_display;
307a46c0ec8Sopenharmony_ci	Window x_win;
308a46c0ec8Sopenharmony_ci	int result;
309a46c0ec8Sopenharmony_ci
310a46c0ec8Sopenharmony_ci	x_display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
311a46c0ec8Sopenharmony_ci
312a46c0ec8Sopenharmony_ci#if HAVE_GTK4
313a46c0ec8Sopenharmony_ci	GtkNative *window = gtk_widget_get_native(w->win);
314a46c0ec8Sopenharmony_ci	GdkSurface *surface = gtk_native_get_surface(window);
315a46c0ec8Sopenharmony_ci	x_win = GDK_SURFACE_XID(surface);
316a46c0ec8Sopenharmony_ci#else
317a46c0ec8Sopenharmony_ci	GdkWindow *window = gtk_widget_get_window(w->win);
318a46c0ec8Sopenharmony_ci	x_win = GDK_WINDOW_XID(window);
319a46c0ec8Sopenharmony_ci#endif
320a46c0ec8Sopenharmony_ci
321a46c0ec8Sopenharmony_ci	result = XGrabPointer(x_display, x_win,
322a46c0ec8Sopenharmony_ci			      False, NoEventMask,
323a46c0ec8Sopenharmony_ci			      GrabModeAsync, GrabModeAsync,
324a46c0ec8Sopenharmony_ci			      x_win,
325a46c0ec8Sopenharmony_ci			      None,
326a46c0ec8Sopenharmony_ci			      CurrentTime);
327a46c0ec8Sopenharmony_ci	return (result == GrabSuccess);
328a46c0ec8Sopenharmony_ci}
329a46c0ec8Sopenharmony_ci
330a46c0ec8Sopenharmony_cistatic void
331a46c0ec8Sopenharmony_cix_unlock_pointer(struct window *w)
332a46c0ec8Sopenharmony_ci{
333a46c0ec8Sopenharmony_ci	Display *x_display;
334a46c0ec8Sopenharmony_ci
335a46c0ec8Sopenharmony_ci	x_display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
336a46c0ec8Sopenharmony_ci
337a46c0ec8Sopenharmony_ci	XUngrabPointer(x_display, CurrentTime);
338a46c0ec8Sopenharmony_ci}
339a46c0ec8Sopenharmony_ci
340a46c0ec8Sopenharmony_cistatic inline bool
341a46c0ec8Sopenharmony_cibackend_is_x11(void)
342a46c0ec8Sopenharmony_ci{
343a46c0ec8Sopenharmony_ci	return GDK_IS_X11_DISPLAY(gdk_display_get_default());
344a46c0ec8Sopenharmony_ci}
345a46c0ec8Sopenharmony_ci#endif /* HAVE_GTK_X11 */
346a46c0ec8Sopenharmony_ci
347a46c0ec8Sopenharmony_cistatic bool
348a46c0ec8Sopenharmony_ciwindow_lock_pointer(struct window *w)
349a46c0ec8Sopenharmony_ci{
350a46c0ec8Sopenharmony_ci	if (w->lock_pointer.locked)
351a46c0ec8Sopenharmony_ci		return true;
352a46c0ec8Sopenharmony_ci
353a46c0ec8Sopenharmony_ci#if HAVE_GTK_WAYLAND
354a46c0ec8Sopenharmony_ci	if (backend_is_wayland())
355a46c0ec8Sopenharmony_ci		w->lock_pointer.locked = wayland_lock_pointer(w);
356a46c0ec8Sopenharmony_ci#endif
357a46c0ec8Sopenharmony_ci
358a46c0ec8Sopenharmony_ci#if HAVE_GTK_X11
359a46c0ec8Sopenharmony_ci	if (backend_is_x11())
360a46c0ec8Sopenharmony_ci		w->lock_pointer.locked = x_lock_pointer(w);
361a46c0ec8Sopenharmony_ci#endif
362a46c0ec8Sopenharmony_ci
363a46c0ec8Sopenharmony_ci	return w->lock_pointer.locked;
364a46c0ec8Sopenharmony_ci}
365a46c0ec8Sopenharmony_ci
366a46c0ec8Sopenharmony_cistatic void
367a46c0ec8Sopenharmony_ciwindow_unlock_pointer(struct window *w)
368a46c0ec8Sopenharmony_ci{
369a46c0ec8Sopenharmony_ci	if (!w->lock_pointer.locked)
370a46c0ec8Sopenharmony_ci		return;
371a46c0ec8Sopenharmony_ci
372a46c0ec8Sopenharmony_ci	w->lock_pointer.locked = false;
373a46c0ec8Sopenharmony_ci
374a46c0ec8Sopenharmony_ci#if HAVE_GTK_WAYLAND
375a46c0ec8Sopenharmony_ci	if (backend_is_wayland())
376a46c0ec8Sopenharmony_ci		wayland_unlock_pointer(w);
377a46c0ec8Sopenharmony_ci#endif
378a46c0ec8Sopenharmony_ci
379a46c0ec8Sopenharmony_ci#if HAVE_GTK_X11
380a46c0ec8Sopenharmony_ci	if (backend_is_x11())
381a46c0ec8Sopenharmony_ci		x_unlock_pointer(w);
382a46c0ec8Sopenharmony_ci#endif
383a46c0ec8Sopenharmony_ci}
384a46c0ec8Sopenharmony_ci
385a46c0ec8Sopenharmony_ciLIBINPUT_ATTRIBUTE_PRINTF(1, 2)
386a46c0ec8Sopenharmony_cistatic inline void
387a46c0ec8Sopenharmony_cimsg(const char *fmt, ...)
388a46c0ec8Sopenharmony_ci{
389a46c0ec8Sopenharmony_ci	va_list args;
390a46c0ec8Sopenharmony_ci	printf("info: ");
391a46c0ec8Sopenharmony_ci
392a46c0ec8Sopenharmony_ci	va_start(args, fmt);
393a46c0ec8Sopenharmony_ci	vprintf(fmt, args);
394a46c0ec8Sopenharmony_ci	va_end(args);
395a46c0ec8Sopenharmony_ci}
396a46c0ec8Sopenharmony_ci
397a46c0ec8Sopenharmony_cistatic inline void
398a46c0ec8Sopenharmony_cidraw_evdev_rel(struct window *w, cairo_t *cr)
399a46c0ec8Sopenharmony_ci{
400a46c0ec8Sopenharmony_ci	int center_x, center_y;
401a46c0ec8Sopenharmony_ci
402a46c0ec8Sopenharmony_ci	cairo_save(cr);
403a46c0ec8Sopenharmony_ci	cairo_set_source_rgb(cr, .2, .2, .8);
404a46c0ec8Sopenharmony_ci	center_x = w->width/2 - 400;
405a46c0ec8Sopenharmony_ci	center_y = w->height/2;
406a46c0ec8Sopenharmony_ci
407a46c0ec8Sopenharmony_ci	cairo_arc(cr, center_x, center_y, 10, 0, 2 * M_PI);
408a46c0ec8Sopenharmony_ci	cairo_stroke(cr);
409a46c0ec8Sopenharmony_ci
410a46c0ec8Sopenharmony_ci	if (w->evdev.rel_x) {
411a46c0ec8Sopenharmony_ci		int dir = w->evdev.rel_x > 0 ? 1 : -1;
412a46c0ec8Sopenharmony_ci		for (int i = 0; i < abs(w->evdev.rel_x); i++) {
413a46c0ec8Sopenharmony_ci			cairo_move_to(cr,
414a46c0ec8Sopenharmony_ci				      center_x + (i + 1) * 20 * dir,
415a46c0ec8Sopenharmony_ci				      center_y - 20);
416a46c0ec8Sopenharmony_ci			cairo_rel_line_to(cr, 0, 40);
417a46c0ec8Sopenharmony_ci			cairo_rel_line_to(cr, 20 * dir, -20);
418a46c0ec8Sopenharmony_ci			cairo_rel_line_to(cr, -20 * dir, -20);
419a46c0ec8Sopenharmony_ci			cairo_fill(cr);
420a46c0ec8Sopenharmony_ci		}
421a46c0ec8Sopenharmony_ci        }
422a46c0ec8Sopenharmony_ci
423a46c0ec8Sopenharmony_ci	if (w->evdev.rel_y) {
424a46c0ec8Sopenharmony_ci		int dir = w->evdev.rel_y > 0 ? 1 : -1;
425a46c0ec8Sopenharmony_ci		for (int i = 0; i < abs(w->evdev.rel_y); i++) {
426a46c0ec8Sopenharmony_ci			cairo_move_to(cr,
427a46c0ec8Sopenharmony_ci				      center_x - 20,
428a46c0ec8Sopenharmony_ci				      center_y + (i + 1) * 20 * dir);
429a46c0ec8Sopenharmony_ci			cairo_rel_line_to(cr, 40, 0);
430a46c0ec8Sopenharmony_ci			cairo_rel_line_to(cr, -20, 20 * dir);
431a46c0ec8Sopenharmony_ci			cairo_rel_line_to(cr, -20, -20 * dir);
432a46c0ec8Sopenharmony_ci			cairo_fill(cr);
433a46c0ec8Sopenharmony_ci		}
434a46c0ec8Sopenharmony_ci        }
435a46c0ec8Sopenharmony_ci
436a46c0ec8Sopenharmony_ci	cairo_restore(cr);
437a46c0ec8Sopenharmony_ci}
438a46c0ec8Sopenharmony_ci
439a46c0ec8Sopenharmony_cistatic inline void
440a46c0ec8Sopenharmony_cidraw_evdev_abs(struct window *w, cairo_t *cr)
441a46c0ec8Sopenharmony_ci{
442a46c0ec8Sopenharmony_ci	static const struct input_absinfo *ax = NULL, *ay = NULL;
443a46c0ec8Sopenharmony_ci	const int normalized_width = 200;
444a46c0ec8Sopenharmony_ci	int outline_width = normalized_width,
445a46c0ec8Sopenharmony_ci	    outline_height = normalized_width * 0.75;
446a46c0ec8Sopenharmony_ci	int center_x, center_y;
447a46c0ec8Sopenharmony_ci	int width, height;
448a46c0ec8Sopenharmony_ci	int x, y;
449a46c0ec8Sopenharmony_ci
450a46c0ec8Sopenharmony_ci	cairo_save(cr);
451a46c0ec8Sopenharmony_ci
452a46c0ec8Sopenharmony_ci	center_x = w->width/2 + 400;
453a46c0ec8Sopenharmony_ci	center_y = w->height/2;
454a46c0ec8Sopenharmony_ci
455a46c0ec8Sopenharmony_ci	/* Always the outline even if we didn't get any abs events yet so it
456a46c0ec8Sopenharmony_ci	 * doesn't just appear out of nowhere */
457a46c0ec8Sopenharmony_ci	if (w->evdev.device == 0)
458a46c0ec8Sopenharmony_ci		goto draw_outline;
459a46c0ec8Sopenharmony_ci
460a46c0ec8Sopenharmony_ci	/* device has changed, so the abs proportions/dimensions have
461a46c0ec8Sopenharmony_ci	 * changed. */
462a46c0ec8Sopenharmony_ci	if (w->evdev.device != w->evdev.last_device) {
463a46c0ec8Sopenharmony_ci		struct evdev_device *d;
464a46c0ec8Sopenharmony_ci
465a46c0ec8Sopenharmony_ci		ax = NULL;
466a46c0ec8Sopenharmony_ci		ay = NULL;
467a46c0ec8Sopenharmony_ci
468a46c0ec8Sopenharmony_ci		list_for_each(d, &w->evdev_devices, node) {
469a46c0ec8Sopenharmony_ci			if ((uintptr_t)d->libinput_device != w->evdev.device)
470a46c0ec8Sopenharmony_ci				continue;
471a46c0ec8Sopenharmony_ci
472a46c0ec8Sopenharmony_ci			ax = libevdev_get_abs_info(d->evdev, ABS_X);
473a46c0ec8Sopenharmony_ci			ay = libevdev_get_abs_info(d->evdev, ABS_Y);
474a46c0ec8Sopenharmony_ci			w->evdev.last_device = w->evdev.device;
475a46c0ec8Sopenharmony_ci		}
476a46c0ec8Sopenharmony_ci
477a46c0ec8Sopenharmony_ci	}
478a46c0ec8Sopenharmony_ci	if (ax == NULL || ay == NULL)
479a46c0ec8Sopenharmony_ci		goto draw_outline;
480a46c0ec8Sopenharmony_ci
481a46c0ec8Sopenharmony_ci	width = ax->maximum - ax->minimum;
482a46c0ec8Sopenharmony_ci	height = ay->maximum - ay->minimum;
483a46c0ec8Sopenharmony_ci	outline_height = 1.0 * height/width * normalized_width;
484a46c0ec8Sopenharmony_ci	outline_width = normalized_width;
485a46c0ec8Sopenharmony_ci
486a46c0ec8Sopenharmony_ci	x = 1.0 * (w->evdev.x - ax->minimum)/width * outline_width;
487a46c0ec8Sopenharmony_ci	y = 1.0 * (w->evdev.y - ay->minimum)/height * outline_height;
488a46c0ec8Sopenharmony_ci	x += center_x - outline_width/2;
489a46c0ec8Sopenharmony_ci	y += center_y - outline_height/2;
490a46c0ec8Sopenharmony_ci	cairo_arc(cr, x, y, 10, 0, 2 * M_PI);
491a46c0ec8Sopenharmony_ci	cairo_fill(cr);
492a46c0ec8Sopenharmony_ci
493a46c0ec8Sopenharmony_ci	for (size_t i = 0; i < ARRAY_LENGTH(w->evdev.slots); i++) {
494a46c0ec8Sopenharmony_ci		if (!w->evdev.slots[i].active)
495a46c0ec8Sopenharmony_ci			continue;
496a46c0ec8Sopenharmony_ci
497a46c0ec8Sopenharmony_ci		cairo_set_source_rgb(cr, .2, .2, .8);
498a46c0ec8Sopenharmony_ci		x = w->evdev.slots[i].x;
499a46c0ec8Sopenharmony_ci		y = w->evdev.slots[i].y;
500a46c0ec8Sopenharmony_ci		x = 1.0 * (x - ax->minimum)/width * outline_width;
501a46c0ec8Sopenharmony_ci		y = 1.0 * (y - ay->minimum)/height * outline_height;
502a46c0ec8Sopenharmony_ci		x += center_x - outline_width/2;
503a46c0ec8Sopenharmony_ci		y += center_y - outline_height/2;
504a46c0ec8Sopenharmony_ci		cairo_arc(cr, x, y, 10, 0, 2 * M_PI);
505a46c0ec8Sopenharmony_ci		cairo_fill(cr);
506a46c0ec8Sopenharmony_ci
507a46c0ec8Sopenharmony_ci		char finger_text[3];
508a46c0ec8Sopenharmony_ci		cairo_text_extents_t finger_text_extents;
509a46c0ec8Sopenharmony_ci		snprintf(finger_text, 3, "%zu", i);
510a46c0ec8Sopenharmony_ci		cairo_set_source_rgb(cr, 1.f, 1.f, 1.f);
511a46c0ec8Sopenharmony_ci		cairo_set_font_size(cr, 12.0);
512a46c0ec8Sopenharmony_ci		cairo_text_extents(cr, finger_text, &finger_text_extents);
513a46c0ec8Sopenharmony_ci		cairo_move_to(cr, x - finger_text_extents.width/2,
514a46c0ec8Sopenharmony_ci				  y + finger_text_extents.height/2);
515a46c0ec8Sopenharmony_ci		cairo_show_text(cr, finger_text);
516a46c0ec8Sopenharmony_ci	}
517a46c0ec8Sopenharmony_ci
518a46c0ec8Sopenharmony_cidraw_outline:
519a46c0ec8Sopenharmony_ci	/* The touchpad outline */
520a46c0ec8Sopenharmony_ci	cairo_set_source_rgb(cr, .2, .2, .8);
521a46c0ec8Sopenharmony_ci	cairo_rectangle(cr,
522a46c0ec8Sopenharmony_ci			center_x - outline_width/2,
523a46c0ec8Sopenharmony_ci			center_y - outline_height/2,
524a46c0ec8Sopenharmony_ci			outline_width,
525a46c0ec8Sopenharmony_ci			outline_height);
526a46c0ec8Sopenharmony_ci	cairo_stroke(cr);
527a46c0ec8Sopenharmony_ci	cairo_restore(cr);
528a46c0ec8Sopenharmony_ci}
529a46c0ec8Sopenharmony_ci
530a46c0ec8Sopenharmony_cistatic inline void
531a46c0ec8Sopenharmony_cidraw_gestures(struct window *w, cairo_t *cr)
532a46c0ec8Sopenharmony_ci{
533a46c0ec8Sopenharmony_ci	int offset;
534a46c0ec8Sopenharmony_ci
535a46c0ec8Sopenharmony_ci	/* swipe */
536a46c0ec8Sopenharmony_ci	cairo_save(cr);
537a46c0ec8Sopenharmony_ci	cairo_translate(cr, w->swipe.x, w->swipe.y);
538a46c0ec8Sopenharmony_ci	for (int i = 0; i < w->swipe.nfingers; i++) {
539a46c0ec8Sopenharmony_ci		cairo_set_source_rgb(cr, .8, .8, .4);
540a46c0ec8Sopenharmony_ci		cairo_arc(cr, (i - 2) * 40, 0, 20, 0, 2 * M_PI);
541a46c0ec8Sopenharmony_ci		cairo_fill(cr);
542a46c0ec8Sopenharmony_ci	}
543a46c0ec8Sopenharmony_ci
544a46c0ec8Sopenharmony_ci	for (int i = 0; i < 4; i++) { /* 4 fg max */
545a46c0ec8Sopenharmony_ci		cairo_set_source_rgb(cr, 0, 0, 0);
546a46c0ec8Sopenharmony_ci		cairo_arc(cr, (i - 2) * 40, 0, 20, 0, 2 * M_PI);
547a46c0ec8Sopenharmony_ci		cairo_stroke(cr);
548a46c0ec8Sopenharmony_ci	}
549a46c0ec8Sopenharmony_ci	cairo_restore(cr);
550a46c0ec8Sopenharmony_ci
551a46c0ec8Sopenharmony_ci	/* pinch */
552a46c0ec8Sopenharmony_ci	cairo_save(cr);
553a46c0ec8Sopenharmony_ci	offset = w->pinch.scale * 100;
554a46c0ec8Sopenharmony_ci	cairo_translate(cr, w->pinch.x, w->pinch.y);
555a46c0ec8Sopenharmony_ci	cairo_rotate(cr, w->pinch.angle * M_PI/180.0);
556a46c0ec8Sopenharmony_ci	if (w->pinch.nfingers > 0) {
557a46c0ec8Sopenharmony_ci		cairo_set_source_rgb(cr, .4, .4, .8);
558a46c0ec8Sopenharmony_ci		cairo_arc(cr, offset, -offset, 20, 0, 2 * M_PI);
559a46c0ec8Sopenharmony_ci		cairo_arc(cr, -offset, offset, 20, 0, 2 * M_PI);
560a46c0ec8Sopenharmony_ci		cairo_fill(cr);
561a46c0ec8Sopenharmony_ci	}
562a46c0ec8Sopenharmony_ci
563a46c0ec8Sopenharmony_ci	cairo_set_source_rgb(cr, 0, 0, 0);
564a46c0ec8Sopenharmony_ci	cairo_arc(cr, offset, -offset, 20, 0, 2 * M_PI);
565a46c0ec8Sopenharmony_ci	cairo_stroke(cr);
566a46c0ec8Sopenharmony_ci	cairo_arc(cr, -offset, offset, 20, 0, 2 * M_PI);
567a46c0ec8Sopenharmony_ci	cairo_stroke(cr);
568a46c0ec8Sopenharmony_ci
569a46c0ec8Sopenharmony_ci	cairo_restore(cr);
570a46c0ec8Sopenharmony_ci
571a46c0ec8Sopenharmony_ci	/* hold */
572a46c0ec8Sopenharmony_ci	cairo_save(cr);
573a46c0ec8Sopenharmony_ci	cairo_translate(cr, w->width/2, w->height/2 + 100);
574a46c0ec8Sopenharmony_ci
575a46c0ec8Sopenharmony_ci	for (int i = 4; i > 0; i--) { /* 4 fg max */
576a46c0ec8Sopenharmony_ci		double r, g, b, hold_alpha;
577a46c0ec8Sopenharmony_ci
578a46c0ec8Sopenharmony_ci		r = .4 + .2 * (i % 2);
579a46c0ec8Sopenharmony_ci		g = .2;
580a46c0ec8Sopenharmony_ci		b = .2;
581a46c0ec8Sopenharmony_ci		hold_alpha = (w->hold.active && i <= w->hold.nfingers) ? 1 : .5;
582a46c0ec8Sopenharmony_ci
583a46c0ec8Sopenharmony_ci		cairo_set_source_rgba(cr, r, g, b, hold_alpha);
584a46c0ec8Sopenharmony_ci		cairo_arc(cr, 0, 0, 20 * i, 0, 2 * M_PI);
585a46c0ec8Sopenharmony_ci		cairo_fill(cr);
586a46c0ec8Sopenharmony_ci
587a46c0ec8Sopenharmony_ci		cairo_set_source_rgba(cr, 0, 0, 0, hold_alpha);
588a46c0ec8Sopenharmony_ci		cairo_arc(cr, 0, 0, 20 * i, 0, 2 * M_PI);
589a46c0ec8Sopenharmony_ci		cairo_stroke(cr);
590a46c0ec8Sopenharmony_ci	}
591a46c0ec8Sopenharmony_ci
592a46c0ec8Sopenharmony_ci	cairo_restore(cr);
593a46c0ec8Sopenharmony_ci}
594a46c0ec8Sopenharmony_ci
595a46c0ec8Sopenharmony_cistatic inline void
596a46c0ec8Sopenharmony_cidraw_scrollbars(struct window *w, cairo_t *cr)
597a46c0ec8Sopenharmony_ci{
598a46c0ec8Sopenharmony_ci
599a46c0ec8Sopenharmony_ci	/* normal scrollbars */
600a46c0ec8Sopenharmony_ci	cairo_save(cr);
601a46c0ec8Sopenharmony_ci	cairo_set_source_rgb(cr, .4, .8, 0);
602a46c0ec8Sopenharmony_ci	cairo_rectangle(cr, w->scroll.vx - 10, w->scroll.vy - 20, 20, 40);
603a46c0ec8Sopenharmony_ci	cairo_rectangle(cr, w->scroll.hx - 20, w->scroll.hy - 10, 40, 20);
604a46c0ec8Sopenharmony_ci	cairo_fill(cr);
605a46c0ec8Sopenharmony_ci
606a46c0ec8Sopenharmony_ci	/* discrete scrollbars */
607a46c0ec8Sopenharmony_ci	cairo_set_source_rgb(cr, .8, .4, 0);
608a46c0ec8Sopenharmony_ci	cairo_rectangle(cr, w->scroll.vx_discrete - 5, w->scroll.vy_discrete - 10, 10, 20);
609a46c0ec8Sopenharmony_ci	cairo_rectangle(cr, w->scroll.hx_discrete - 10, w->scroll.hy_discrete - 5, 20, 10);
610a46c0ec8Sopenharmony_ci	cairo_fill(cr);
611a46c0ec8Sopenharmony_ci
612a46c0ec8Sopenharmony_ci	cairo_restore(cr);
613a46c0ec8Sopenharmony_ci}
614a46c0ec8Sopenharmony_ci
615a46c0ec8Sopenharmony_cistatic inline void
616a46c0ec8Sopenharmony_cidraw_touchpoints(struct window *w, cairo_t *cr)
617a46c0ec8Sopenharmony_ci{
618a46c0ec8Sopenharmony_ci	cairo_save(cr);
619a46c0ec8Sopenharmony_ci	ARRAY_FOR_EACH(w->touches, t) {
620a46c0ec8Sopenharmony_ci		if (t->state == TOUCH_ACTIVE)
621a46c0ec8Sopenharmony_ci			cairo_set_source_rgb(cr, .8, .2, .2);
622a46c0ec8Sopenharmony_ci		else
623a46c0ec8Sopenharmony_ci			cairo_set_source_rgb(cr, .8, .4, .4);
624a46c0ec8Sopenharmony_ci		cairo_arc(cr, t->x, t->y, 10, 0, 2 * M_PI);
625a46c0ec8Sopenharmony_ci		if (t->state == TOUCH_CANCELLED)
626a46c0ec8Sopenharmony_ci			cairo_stroke(cr);
627a46c0ec8Sopenharmony_ci		else
628a46c0ec8Sopenharmony_ci			cairo_fill(cr);
629a46c0ec8Sopenharmony_ci	}
630a46c0ec8Sopenharmony_ci	cairo_restore(cr);
631a46c0ec8Sopenharmony_ci}
632a46c0ec8Sopenharmony_ci
633a46c0ec8Sopenharmony_cistatic inline void
634a46c0ec8Sopenharmony_cidraw_abs_pointer(struct window *w, cairo_t *cr)
635a46c0ec8Sopenharmony_ci{
636a46c0ec8Sopenharmony_ci
637a46c0ec8Sopenharmony_ci	cairo_save(cr);
638a46c0ec8Sopenharmony_ci	cairo_set_source_rgb(cr, .2, .4, .8);
639a46c0ec8Sopenharmony_ci	cairo_arc(cr, w->abs.x, w->abs.y, 10, 0, 2 * M_PI);
640a46c0ec8Sopenharmony_ci	cairo_fill(cr);
641a46c0ec8Sopenharmony_ci	cairo_restore(cr);
642a46c0ec8Sopenharmony_ci}
643a46c0ec8Sopenharmony_ci
644a46c0ec8Sopenharmony_cistatic inline void
645a46c0ec8Sopenharmony_cidraw_text(cairo_t *cr, const char *text, double x, double y)
646a46c0ec8Sopenharmony_ci{
647a46c0ec8Sopenharmony_ci	cairo_text_extents_t te;
648a46c0ec8Sopenharmony_ci	cairo_font_extents_t fe;
649a46c0ec8Sopenharmony_ci
650a46c0ec8Sopenharmony_ci	cairo_text_extents(cr, text, &te);
651a46c0ec8Sopenharmony_ci	cairo_font_extents(cr, &fe);
652a46c0ec8Sopenharmony_ci	/* center of the rectangle */
653a46c0ec8Sopenharmony_ci	cairo_move_to(cr, x, y);
654a46c0ec8Sopenharmony_ci	cairo_rel_move_to(cr, -te.width/2, -fe.descent + te.height/2);
655a46c0ec8Sopenharmony_ci	cairo_show_text(cr, text);
656a46c0ec8Sopenharmony_ci}
657a46c0ec8Sopenharmony_ci
658a46c0ec8Sopenharmony_cistatic inline void
659a46c0ec8Sopenharmony_cidraw_other_button (struct window *w, cairo_t *cr)
660a46c0ec8Sopenharmony_ci{
661a46c0ec8Sopenharmony_ci	const char *name = w->buttons.other_name;
662a46c0ec8Sopenharmony_ci
663a46c0ec8Sopenharmony_ci	cairo_save(cr);
664a46c0ec8Sopenharmony_ci
665a46c0ec8Sopenharmony_ci	if (!w->buttons.other)
666a46c0ec8Sopenharmony_ci		goto outline;
667a46c0ec8Sopenharmony_ci
668a46c0ec8Sopenharmony_ci	if (!name)
669a46c0ec8Sopenharmony_ci		name = "undefined";
670a46c0ec8Sopenharmony_ci
671a46c0ec8Sopenharmony_ci	cairo_set_source_rgb(cr, .2, .8, .8);
672a46c0ec8Sopenharmony_ci	cairo_rectangle(cr, w->width/2 - 40, w->height - 150, 80, 30);
673a46c0ec8Sopenharmony_ci	cairo_fill(cr);
674a46c0ec8Sopenharmony_ci
675a46c0ec8Sopenharmony_ci	cairo_set_source_rgb(cr, 0, 0, 0);
676a46c0ec8Sopenharmony_ci
677a46c0ec8Sopenharmony_ci	draw_text(cr, name, w->width/2, w->height - 150 + 15);
678a46c0ec8Sopenharmony_ci
679a46c0ec8Sopenharmony_cioutline:
680a46c0ec8Sopenharmony_ci	cairo_set_source_rgb(cr, 0, 0, 0);
681a46c0ec8Sopenharmony_ci	cairo_rectangle(cr, w->width/2 - 40, w->height - 150, 80, 30);
682a46c0ec8Sopenharmony_ci	cairo_stroke(cr);
683a46c0ec8Sopenharmony_ci	cairo_restore(cr);
684a46c0ec8Sopenharmony_ci}
685a46c0ec8Sopenharmony_ci
686a46c0ec8Sopenharmony_cistatic inline void
687a46c0ec8Sopenharmony_cidraw_buttons(struct window *w, cairo_t *cr)
688a46c0ec8Sopenharmony_ci{
689a46c0ec8Sopenharmony_ci	cairo_save(cr);
690a46c0ec8Sopenharmony_ci
691a46c0ec8Sopenharmony_ci	if (w->buttons.l || w->buttons.m || w->buttons.r) {
692a46c0ec8Sopenharmony_ci		cairo_set_source_rgb(cr, .2, .8, .8);
693a46c0ec8Sopenharmony_ci		if (w->buttons.l)
694a46c0ec8Sopenharmony_ci			cairo_rectangle(cr, w->width/2 - 100, w->height - 200, 70, 30);
695a46c0ec8Sopenharmony_ci		if (w->buttons.m)
696a46c0ec8Sopenharmony_ci			cairo_rectangle(cr, w->width/2 - 20, w->height - 200, 40, 30);
697a46c0ec8Sopenharmony_ci		if (w->buttons.r)
698a46c0ec8Sopenharmony_ci			cairo_rectangle(cr, w->width/2 + 30, w->height - 200, 70, 30);
699a46c0ec8Sopenharmony_ci		cairo_fill(cr);
700a46c0ec8Sopenharmony_ci	}
701a46c0ec8Sopenharmony_ci
702a46c0ec8Sopenharmony_ci	cairo_set_source_rgb(cr, 0, 0, 0);
703a46c0ec8Sopenharmony_ci	cairo_rectangle(cr, w->width/2 - 100, w->height - 200, 70, 30);
704a46c0ec8Sopenharmony_ci	cairo_rectangle(cr, w->width/2 - 20, w->height - 200, 40, 30);
705a46c0ec8Sopenharmony_ci	cairo_rectangle(cr, w->width/2 + 30, w->height - 200, 70, 30);
706a46c0ec8Sopenharmony_ci	cairo_stroke(cr);
707a46c0ec8Sopenharmony_ci	cairo_restore(cr);
708a46c0ec8Sopenharmony_ci
709a46c0ec8Sopenharmony_ci	draw_other_button(w, cr);
710a46c0ec8Sopenharmony_ci}
711a46c0ec8Sopenharmony_ci
712a46c0ec8Sopenharmony_cistatic inline void
713a46c0ec8Sopenharmony_cidraw_pad(struct window *w, cairo_t *cr)
714a46c0ec8Sopenharmony_ci{
715a46c0ec8Sopenharmony_ci	double rx, ry;
716a46c0ec8Sopenharmony_ci	double pos;
717a46c0ec8Sopenharmony_ci	char number[3];
718a46c0ec8Sopenharmony_ci
719a46c0ec8Sopenharmony_ci	rx = w->width/2 - 200;
720a46c0ec8Sopenharmony_ci	ry = w->height/2 + 100;
721a46c0ec8Sopenharmony_ci
722a46c0ec8Sopenharmony_ci	cairo_save(cr);
723a46c0ec8Sopenharmony_ci	/* outer ring */
724a46c0ec8Sopenharmony_ci	cairo_set_source_rgb(cr, .7, .7, .0);
725a46c0ec8Sopenharmony_ci	cairo_arc(cr, rx, ry, 50, 0, 2 * M_PI);
726a46c0ec8Sopenharmony_ci	cairo_fill(cr);
727a46c0ec8Sopenharmony_ci
728a46c0ec8Sopenharmony_ci	/* inner ring */
729a46c0ec8Sopenharmony_ci	cairo_set_source_rgb(cr, 1., 1., 1.);
730a46c0ec8Sopenharmony_ci	cairo_arc(cr, rx, ry, 30, 0, 2 * M_PI);
731a46c0ec8Sopenharmony_ci	cairo_fill(cr);
732a46c0ec8Sopenharmony_ci
733a46c0ec8Sopenharmony_ci	/* marker */
734a46c0ec8Sopenharmony_ci	/* libinput has degrees and 0 is north, cairo has radians and 0 is
735a46c0ec8Sopenharmony_ci	 * east */
736a46c0ec8Sopenharmony_ci	if (w->pad.ring.position != -1) {
737a46c0ec8Sopenharmony_ci		pos = (w->pad.ring.position + 270) * M_PI/180.0;
738a46c0ec8Sopenharmony_ci		cairo_set_source_rgb(cr, .0, .0, .0);
739a46c0ec8Sopenharmony_ci		cairo_set_line_width(cr, 20);
740a46c0ec8Sopenharmony_ci		cairo_arc(cr, rx, ry, 40, pos - M_PI/8 , pos + M_PI/8);
741a46c0ec8Sopenharmony_ci		cairo_stroke(cr);
742a46c0ec8Sopenharmony_ci
743a46c0ec8Sopenharmony_ci		snprintf(number, sizeof(number), "%d", w->pad.ring.number);
744a46c0ec8Sopenharmony_ci		cairo_set_source_rgb(cr, .0, .0, .0);
745a46c0ec8Sopenharmony_ci		draw_text(cr, number, rx, ry);
746a46c0ec8Sopenharmony_ci
747a46c0ec8Sopenharmony_ci	}
748a46c0ec8Sopenharmony_ci
749a46c0ec8Sopenharmony_ci	cairo_restore(cr);
750a46c0ec8Sopenharmony_ci
751a46c0ec8Sopenharmony_ci	rx = w->width/2 - 300;
752a46c0ec8Sopenharmony_ci	ry = w->height/2 + 50;
753a46c0ec8Sopenharmony_ci
754a46c0ec8Sopenharmony_ci	cairo_save(cr);
755a46c0ec8Sopenharmony_ci	cairo_set_source_rgb(cr, .7, .7, .0);
756a46c0ec8Sopenharmony_ci	cairo_rectangle(cr, rx, ry, 20, 100);
757a46c0ec8Sopenharmony_ci	cairo_fill(cr);
758a46c0ec8Sopenharmony_ci
759a46c0ec8Sopenharmony_ci	if (w->pad.strip.position != -1) {
760a46c0ec8Sopenharmony_ci		pos = w->pad.strip.position * 80;
761a46c0ec8Sopenharmony_ci		cairo_set_source_rgb(cr, .0, .0, .0);
762a46c0ec8Sopenharmony_ci		cairo_rectangle(cr, rx, ry + pos, 20, 20);
763a46c0ec8Sopenharmony_ci		cairo_fill(cr);
764a46c0ec8Sopenharmony_ci
765a46c0ec8Sopenharmony_ci		snprintf(number, sizeof(number), "%d", w->pad.strip.number);
766a46c0ec8Sopenharmony_ci		cairo_set_source_rgb(cr, .0, .0, .0);
767a46c0ec8Sopenharmony_ci		draw_text(cr, number, rx + 10, ry - 10);
768a46c0ec8Sopenharmony_ci	}
769a46c0ec8Sopenharmony_ci
770a46c0ec8Sopenharmony_ci	cairo_restore(cr);
771a46c0ec8Sopenharmony_ci}
772a46c0ec8Sopenharmony_ci
773a46c0ec8Sopenharmony_cistatic inline void
774a46c0ec8Sopenharmony_cidraw_tablet(struct window *w, cairo_t *cr)
775a46c0ec8Sopenharmony_ci{
776a46c0ec8Sopenharmony_ci	double x, y;
777a46c0ec8Sopenharmony_ci	int first, last;
778a46c0ec8Sopenharmony_ci	size_t mask;
779a46c0ec8Sopenharmony_ci	int rx, ry;
780a46c0ec8Sopenharmony_ci
781a46c0ec8Sopenharmony_ci	/* pressure/distance bars */
782a46c0ec8Sopenharmony_ci	rx = w->width/2 + 100;
783a46c0ec8Sopenharmony_ci	ry = w->height/2 + 50;
784a46c0ec8Sopenharmony_ci	cairo_save(cr);
785a46c0ec8Sopenharmony_ci	cairo_set_source_rgb(cr, .2, .6, .6);
786a46c0ec8Sopenharmony_ci	cairo_rectangle(cr, rx, ry, 20, 100);
787a46c0ec8Sopenharmony_ci	cairo_stroke(cr);
788a46c0ec8Sopenharmony_ci
789a46c0ec8Sopenharmony_ci	if (w->tool.distance > 0) {
790a46c0ec8Sopenharmony_ci		double pos = w->tool.distance * 100;
791a46c0ec8Sopenharmony_ci		cairo_rectangle(cr, rx, ry + 100 - pos, 20, 5);
792a46c0ec8Sopenharmony_ci		cairo_fill(cr);
793a46c0ec8Sopenharmony_ci	}
794a46c0ec8Sopenharmony_ci	if (w->tool.pressure > 0) {
795a46c0ec8Sopenharmony_ci		double pos = w->tool.pressure * 100;
796a46c0ec8Sopenharmony_ci		if (w->tool.is_down)
797a46c0ec8Sopenharmony_ci			cairo_rectangle(cr, rx + 25, ry + 95, 5, 5);
798a46c0ec8Sopenharmony_ci		cairo_rectangle(cr, rx, ry + 100 - pos, 20, pos);
799a46c0ec8Sopenharmony_ci		cairo_fill(cr);
800a46c0ec8Sopenharmony_ci	}
801a46c0ec8Sopenharmony_ci	cairo_restore(cr);
802a46c0ec8Sopenharmony_ci
803a46c0ec8Sopenharmony_ci	/* tablet tool, square for prox-in location */
804a46c0ec8Sopenharmony_ci	cairo_save(cr);
805a46c0ec8Sopenharmony_ci	cairo_set_source_rgb(cr, .2, .6, .6);
806a46c0ec8Sopenharmony_ci	if (w->tool.x_in && w->tool.y_in) {
807a46c0ec8Sopenharmony_ci		cairo_rectangle(cr, w->tool.x_in - 15, w->tool.y_in - 15, 30, 30);
808a46c0ec8Sopenharmony_ci		cairo_stroke(cr);
809a46c0ec8Sopenharmony_ci	}
810a46c0ec8Sopenharmony_ci
811a46c0ec8Sopenharmony_ci	if (w->tool.x_down && w->tool.y_down) {
812a46c0ec8Sopenharmony_ci		cairo_rectangle(cr, w->tool.x_down - 10, w->tool.y_down - 10, 20, 20);
813a46c0ec8Sopenharmony_ci		cairo_stroke(cr);
814a46c0ec8Sopenharmony_ci	}
815a46c0ec8Sopenharmony_ci
816a46c0ec8Sopenharmony_ci	if (w->tool.x_up && w->tool.y_up) {
817a46c0ec8Sopenharmony_ci		cairo_rectangle(cr, w->tool.x_up - 10, w->tool.y_up - 10, 20, 20);
818a46c0ec8Sopenharmony_ci		cairo_stroke(cr);
819a46c0ec8Sopenharmony_ci	}
820a46c0ec8Sopenharmony_ci
821a46c0ec8Sopenharmony_ci	if (w->tool.pressure)
822a46c0ec8Sopenharmony_ci		cairo_set_source_rgb(cr, .2, .8, .8);
823a46c0ec8Sopenharmony_ci
824a46c0ec8Sopenharmony_ci	cairo_translate(cr, w->tool.x, w->tool.y);
825a46c0ec8Sopenharmony_ci	/* scale of 2.5 is large enough to make the marker visible around the
826a46c0ec8Sopenharmony_ci	   physical totem */
827a46c0ec8Sopenharmony_ci	cairo_scale(cr,
828a46c0ec8Sopenharmony_ci		    1.0 + w->tool.size_major * 2.5,
829a46c0ec8Sopenharmony_ci		    1.0 + w->tool.size_minor * 2.5);
830a46c0ec8Sopenharmony_ci	cairo_scale(cr, 1.0 + w->tool.tilt_x/30.0, 1.0 + w->tool.tilt_y/30.0);
831a46c0ec8Sopenharmony_ci	if (w->tool.rotation)
832a46c0ec8Sopenharmony_ci		cairo_rotate(cr, w->tool.rotation * M_PI/180.0);
833a46c0ec8Sopenharmony_ci	if (w->tool.pressure)
834a46c0ec8Sopenharmony_ci		cairo_set_source_rgb(cr, .8, .8, .2);
835a46c0ec8Sopenharmony_ci	cairo_arc(cr, 0, 0,
836a46c0ec8Sopenharmony_ci		  1 + 10 * max(w->tool.pressure, w->tool.distance),
837a46c0ec8Sopenharmony_ci		  0, 2 * M_PI);
838a46c0ec8Sopenharmony_ci	cairo_fill(cr);
839a46c0ec8Sopenharmony_ci	cairo_restore(cr);
840a46c0ec8Sopenharmony_ci
841a46c0ec8Sopenharmony_ci	/* The line to indicate the origin */
842a46c0ec8Sopenharmony_ci	if (w->tool.size_major) {
843a46c0ec8Sopenharmony_ci		cairo_save(cr);
844a46c0ec8Sopenharmony_ci		cairo_scale(cr, 1.0, 1.0);
845a46c0ec8Sopenharmony_ci		cairo_translate(cr, w->tool.x, w->tool.y);
846a46c0ec8Sopenharmony_ci		if (w->tool.rotation)
847a46c0ec8Sopenharmony_ci			cairo_rotate(cr, w->tool.rotation * M_PI/180.0);
848a46c0ec8Sopenharmony_ci		cairo_set_source_rgb(cr, .0, .0, .0);
849a46c0ec8Sopenharmony_ci		cairo_move_to(cr, 0, 0);
850a46c0ec8Sopenharmony_ci		cairo_rel_line_to(cr, 0, -w->tool.size_major * 2.5);
851a46c0ec8Sopenharmony_ci		cairo_stroke(cr);
852a46c0ec8Sopenharmony_ci		cairo_restore(cr);
853a46c0ec8Sopenharmony_ci	}
854a46c0ec8Sopenharmony_ci
855a46c0ec8Sopenharmony_ci	/* tablet deltas */
856a46c0ec8Sopenharmony_ci	mask = ARRAY_LENGTH(w->tool.deltas);
857a46c0ec8Sopenharmony_ci	first = max(w->tool.ndeltas + 1, mask) - mask;
858a46c0ec8Sopenharmony_ci	last = w->tool.ndeltas;
859a46c0ec8Sopenharmony_ci
860a46c0ec8Sopenharmony_ci	cairo_save(cr);
861a46c0ec8Sopenharmony_ci	cairo_set_source_rgb(cr, .8, .8, .2);
862a46c0ec8Sopenharmony_ci
863a46c0ec8Sopenharmony_ci	x = w->tool.deltas[first % mask].x;
864a46c0ec8Sopenharmony_ci	y = w->tool.deltas[first % mask].y;
865a46c0ec8Sopenharmony_ci	cairo_move_to(cr, x, y);
866a46c0ec8Sopenharmony_ci
867a46c0ec8Sopenharmony_ci	for (int i = first + 1; i < last; i++) {
868a46c0ec8Sopenharmony_ci		x = w->tool.deltas[i % mask].x;
869a46c0ec8Sopenharmony_ci		y = w->tool.deltas[i % mask].y;
870a46c0ec8Sopenharmony_ci		cairo_line_to(cr, x, y);
871a46c0ec8Sopenharmony_ci	}
872a46c0ec8Sopenharmony_ci
873a46c0ec8Sopenharmony_ci	cairo_stroke(cr);
874a46c0ec8Sopenharmony_ci	cairo_restore(cr);
875a46c0ec8Sopenharmony_ci}
876a46c0ec8Sopenharmony_ci
877a46c0ec8Sopenharmony_cistatic inline void
878a46c0ec8Sopenharmony_cidraw_pointer(struct window *w, cairo_t *cr)
879a46c0ec8Sopenharmony_ci{
880a46c0ec8Sopenharmony_ci	double x, y;
881a46c0ec8Sopenharmony_ci	int first, last;
882a46c0ec8Sopenharmony_ci	size_t mask;
883a46c0ec8Sopenharmony_ci
884a46c0ec8Sopenharmony_ci	/* draw pointer sprite */
885a46c0ec8Sopenharmony_ci	cairo_set_source_rgb(cr, 0, 0, 0);
886a46c0ec8Sopenharmony_ci	cairo_save(cr);
887a46c0ec8Sopenharmony_ci	cairo_move_to(cr, w->pointer.x, w->pointer.y);
888a46c0ec8Sopenharmony_ci	cairo_rel_line_to(cr, 10, 15);
889a46c0ec8Sopenharmony_ci	cairo_rel_line_to(cr, -10, 0);
890a46c0ec8Sopenharmony_ci	cairo_rel_line_to(cr, 0, -15);
891a46c0ec8Sopenharmony_ci	cairo_fill(cr);
892a46c0ec8Sopenharmony_ci
893a46c0ec8Sopenharmony_ci	/* draw unaccelerated sprite */
894a46c0ec8Sopenharmony_ci	cairo_set_source_rgb(cr, 0.7, 0.7, 0.7);
895a46c0ec8Sopenharmony_ci	cairo_save(cr);
896a46c0ec8Sopenharmony_ci	cairo_move_to(cr, w->unaccelerated.x, w->unaccelerated.y);
897a46c0ec8Sopenharmony_ci	cairo_rel_line_to(cr, -5, -10);
898a46c0ec8Sopenharmony_ci	cairo_rel_line_to(cr, 10, 0);
899a46c0ec8Sopenharmony_ci	cairo_rel_line_to(cr, -5, 10);
900a46c0ec8Sopenharmony_ci	cairo_fill(cr);
901a46c0ec8Sopenharmony_ci
902a46c0ec8Sopenharmony_ci	/* pointer deltas */
903a46c0ec8Sopenharmony_ci	mask = ARRAY_LENGTH(w->deltas);
904a46c0ec8Sopenharmony_ci	first = max(w->ndeltas + 1, mask) - mask;
905a46c0ec8Sopenharmony_ci	last = w->ndeltas;
906a46c0ec8Sopenharmony_ci
907a46c0ec8Sopenharmony_ci	cairo_set_source_rgb(cr, .8, .5, .2);
908a46c0ec8Sopenharmony_ci
909a46c0ec8Sopenharmony_ci	x = w->deltas[first % mask].x;
910a46c0ec8Sopenharmony_ci	y = w->deltas[first % mask].y;
911a46c0ec8Sopenharmony_ci	cairo_move_to(cr, x, y);
912a46c0ec8Sopenharmony_ci
913a46c0ec8Sopenharmony_ci	for (int i = first + 1; i < last; i++) {
914a46c0ec8Sopenharmony_ci		x = w->deltas[i % mask].x;
915a46c0ec8Sopenharmony_ci		y = w->deltas[i % mask].y;
916a46c0ec8Sopenharmony_ci		cairo_line_to(cr, x, y);
917a46c0ec8Sopenharmony_ci	}
918a46c0ec8Sopenharmony_ci
919a46c0ec8Sopenharmony_ci	cairo_stroke(cr);
920a46c0ec8Sopenharmony_ci	cairo_restore(cr);
921a46c0ec8Sopenharmony_ci}
922a46c0ec8Sopenharmony_ci
923a46c0ec8Sopenharmony_cistatic inline void
924a46c0ec8Sopenharmony_cidraw_background(struct window *w, cairo_t *cr)
925a46c0ec8Sopenharmony_ci{
926a46c0ec8Sopenharmony_ci	int x1, x2, y1, y2, x3, y3, x4, y4;
927a46c0ec8Sopenharmony_ci	int cols;
928a46c0ec8Sopenharmony_ci
929a46c0ec8Sopenharmony_ci	/* 10px and 5px grids */
930a46c0ec8Sopenharmony_ci	cairo_save(cr);
931a46c0ec8Sopenharmony_ci	cairo_set_source_rgb(cr, 0.8, 0.8, 0.8);
932a46c0ec8Sopenharmony_ci	x1 = w->width/2 - 200;
933a46c0ec8Sopenharmony_ci	y1 = w->height/2 - 200;
934a46c0ec8Sopenharmony_ci	x2 = w->width/2 + 200;
935a46c0ec8Sopenharmony_ci	y2 = w->height/2 - 200;
936a46c0ec8Sopenharmony_ci	for (cols = 1; cols < 10; cols++) {
937a46c0ec8Sopenharmony_ci		cairo_move_to(cr, x1 + 10 * cols, y1);
938a46c0ec8Sopenharmony_ci		cairo_rel_line_to(cr, 0, 100);
939a46c0ec8Sopenharmony_ci		cairo_move_to(cr, x1, y1 + 10 * cols);
940a46c0ec8Sopenharmony_ci		cairo_rel_line_to(cr, 100, 0);
941a46c0ec8Sopenharmony_ci
942a46c0ec8Sopenharmony_ci		cairo_move_to(cr, x2 + 5 * cols, y2);
943a46c0ec8Sopenharmony_ci		cairo_rel_line_to(cr, 0, 50);
944a46c0ec8Sopenharmony_ci		cairo_move_to(cr, x2, y2 + 5 * cols);
945a46c0ec8Sopenharmony_ci		cairo_rel_line_to(cr, 50, 0);
946a46c0ec8Sopenharmony_ci	}
947a46c0ec8Sopenharmony_ci
948a46c0ec8Sopenharmony_ci	/* 3px horiz/vert bar codes */
949a46c0ec8Sopenharmony_ci	x3 = w->width/2 - 200;
950a46c0ec8Sopenharmony_ci	y3 = w->height/2 + 200;
951a46c0ec8Sopenharmony_ci	x4 = w->width/2 + 200;
952a46c0ec8Sopenharmony_ci	y4 = w->height/2 + 100;
953a46c0ec8Sopenharmony_ci	for (cols = 0; cols < 50; cols++) {
954a46c0ec8Sopenharmony_ci		cairo_move_to(cr, x3 + 3 * cols, y3);
955a46c0ec8Sopenharmony_ci		cairo_rel_line_to(cr, 0, 20);
956a46c0ec8Sopenharmony_ci
957a46c0ec8Sopenharmony_ci		cairo_move_to(cr, x4, y4 + 3 * cols);
958a46c0ec8Sopenharmony_ci		cairo_rel_line_to(cr, 20, 0);
959a46c0ec8Sopenharmony_ci	}
960a46c0ec8Sopenharmony_ci	cairo_stroke(cr);
961a46c0ec8Sopenharmony_ci
962a46c0ec8Sopenharmony_ci	/* round targets */
963a46c0ec8Sopenharmony_ci	for (int i = 0; i <= 3; i++) {
964a46c0ec8Sopenharmony_ci		x1 = w->width * i/4.0;
965a46c0ec8Sopenharmony_ci		x2 = w->width * i/4.0;
966a46c0ec8Sopenharmony_ci
967a46c0ec8Sopenharmony_ci		y1 = w->height * 1.0/4.0;
968a46c0ec8Sopenharmony_ci		y2 = w->height * 3.0/4.0;
969a46c0ec8Sopenharmony_ci
970a46c0ec8Sopenharmony_ci		cairo_arc(cr, x1, y1, 10, 0, 2 * M_PI);
971a46c0ec8Sopenharmony_ci		cairo_stroke(cr);
972a46c0ec8Sopenharmony_ci		cairo_arc(cr, x2, y2, 10, 0, 2 * M_PI);
973a46c0ec8Sopenharmony_ci		cairo_stroke(cr);
974a46c0ec8Sopenharmony_ci	}
975a46c0ec8Sopenharmony_ci
976a46c0ec8Sopenharmony_ci	cairo_restore(cr);
977a46c0ec8Sopenharmony_ci}
978a46c0ec8Sopenharmony_ci
979a46c0ec8Sopenharmony_cistatic gboolean
980a46c0ec8Sopenharmony_cidraw(GtkWidget *widget, cairo_t *cr, gpointer data)
981a46c0ec8Sopenharmony_ci{
982a46c0ec8Sopenharmony_ci	struct window *w = data;
983a46c0ec8Sopenharmony_ci
984a46c0ec8Sopenharmony_ci	cairo_set_font_size(cr, 12.0);
985a46c0ec8Sopenharmony_ci	cairo_set_source_rgb(cr, 1, 1, 1);
986a46c0ec8Sopenharmony_ci	cairo_rectangle(cr, 0, 0, w->width, w->height);
987a46c0ec8Sopenharmony_ci	cairo_fill(cr);
988a46c0ec8Sopenharmony_ci
989a46c0ec8Sopenharmony_ci	draw_background(w, cr);
990a46c0ec8Sopenharmony_ci	draw_evdev_rel(w, cr);
991a46c0ec8Sopenharmony_ci	draw_evdev_abs(w, cr);
992a46c0ec8Sopenharmony_ci
993a46c0ec8Sopenharmony_ci	draw_pad(w, cr);
994a46c0ec8Sopenharmony_ci	draw_tablet(w, cr);
995a46c0ec8Sopenharmony_ci	draw_gestures(w, cr);
996a46c0ec8Sopenharmony_ci	draw_scrollbars(w, cr);
997a46c0ec8Sopenharmony_ci	draw_touchpoints(w, cr);
998a46c0ec8Sopenharmony_ci	draw_abs_pointer(w, cr);
999a46c0ec8Sopenharmony_ci	draw_buttons(w, cr);
1000a46c0ec8Sopenharmony_ci	draw_pointer(w, cr);
1001a46c0ec8Sopenharmony_ci
1002a46c0ec8Sopenharmony_ci	return TRUE;
1003a46c0ec8Sopenharmony_ci}
1004a46c0ec8Sopenharmony_ci
1005a46c0ec8Sopenharmony_ci#if HAVE_GTK4
1006a46c0ec8Sopenharmony_cistatic void
1007a46c0ec8Sopenharmony_cidraw_gtk4(GtkDrawingArea *widget,
1008a46c0ec8Sopenharmony_ci	  cairo_t *cr,
1009a46c0ec8Sopenharmony_ci	  int width,
1010a46c0ec8Sopenharmony_ci	  int height,
1011a46c0ec8Sopenharmony_ci	  gpointer data)
1012a46c0ec8Sopenharmony_ci{
1013a46c0ec8Sopenharmony_ci	draw(GTK_WIDGET(widget), cr, data);
1014a46c0ec8Sopenharmony_ci}
1015a46c0ec8Sopenharmony_ci#endif
1016a46c0ec8Sopenharmony_ci
1017a46c0ec8Sopenharmony_cistatic void
1018a46c0ec8Sopenharmony_ciwindow_place_ui_elements(GtkWidget *widget, struct window *w)
1019a46c0ec8Sopenharmony_ci{
1020a46c0ec8Sopenharmony_ci#if HAVE_GTK4
1021a46c0ec8Sopenharmony_ci	w->width = gtk_widget_get_width(w->area);
1022a46c0ec8Sopenharmony_ci	w->height = gtk_widget_get_height(w->area);
1023a46c0ec8Sopenharmony_ci#else
1024a46c0ec8Sopenharmony_ci	gtk_window_get_size(GTK_WINDOW(widget), &w->width, &w->height);
1025a46c0ec8Sopenharmony_ci#endif
1026a46c0ec8Sopenharmony_ci
1027a46c0ec8Sopenharmony_ci	w->pointer.x = w->width/2;
1028a46c0ec8Sopenharmony_ci	w->pointer.y = w->height/2;
1029a46c0ec8Sopenharmony_ci	w->unaccelerated.x = w->width/2;
1030a46c0ec8Sopenharmony_ci	w->unaccelerated.y = w->height/2;
1031a46c0ec8Sopenharmony_ci	w->deltas[0].x = w->pointer.x;
1032a46c0ec8Sopenharmony_ci	w->deltas[0].y = w->pointer.y;
1033a46c0ec8Sopenharmony_ci
1034a46c0ec8Sopenharmony_ci	w->scroll.vx = w->width/2;
1035a46c0ec8Sopenharmony_ci	w->scroll.vy = w->height/2;
1036a46c0ec8Sopenharmony_ci	w->scroll.hx = w->width/2;
1037a46c0ec8Sopenharmony_ci	w->scroll.hy = w->height/2;
1038a46c0ec8Sopenharmony_ci	w->scroll.vx_discrete = w->width/2;
1039a46c0ec8Sopenharmony_ci	w->scroll.vy_discrete = w->height/2;
1040a46c0ec8Sopenharmony_ci	w->scroll.hx_discrete = w->width/2;
1041a46c0ec8Sopenharmony_ci	w->scroll.hy_discrete = w->height/2;
1042a46c0ec8Sopenharmony_ci
1043a46c0ec8Sopenharmony_ci	w->swipe.x = w->width/2;
1044a46c0ec8Sopenharmony_ci	w->swipe.y = w->height/2;
1045a46c0ec8Sopenharmony_ci
1046a46c0ec8Sopenharmony_ci	w->pinch.scale = 1.0;
1047a46c0ec8Sopenharmony_ci	w->pinch.x = w->width/2;
1048a46c0ec8Sopenharmony_ci	w->pinch.y = w->height/2;
1049a46c0ec8Sopenharmony_ci}
1050a46c0ec8Sopenharmony_ci
1051a46c0ec8Sopenharmony_ci#if HAVE_GTK4
1052a46c0ec8Sopenharmony_cistatic void
1053a46c0ec8Sopenharmony_cimap_event_cb(GtkDrawingArea *widget, int width, int height, gpointer data)
1054a46c0ec8Sopenharmony_ci{
1055a46c0ec8Sopenharmony_ci	struct window *w = data;
1056a46c0ec8Sopenharmony_ci
1057a46c0ec8Sopenharmony_ci	window_place_ui_elements(GTK_WIDGET(widget), w);
1058a46c0ec8Sopenharmony_ci
1059a46c0ec8Sopenharmony_ci	gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(w->area),
1060a46c0ec8Sopenharmony_ci				       draw_gtk4,
1061a46c0ec8Sopenharmony_ci				       w,
1062a46c0ec8Sopenharmony_ci				       NULL);
1063a46c0ec8Sopenharmony_ci
1064a46c0ec8Sopenharmony_ci	gtk_widget_set_cursor_from_name(w->win, "none");
1065a46c0ec8Sopenharmony_ci
1066a46c0ec8Sopenharmony_ci	window_lock_pointer(w);
1067a46c0ec8Sopenharmony_ci}
1068a46c0ec8Sopenharmony_ci#else
1069a46c0ec8Sopenharmony_cistatic void
1070a46c0ec8Sopenharmony_cimap_event_cb(GtkWidget *widget, GdkEvent *event, gpointer data)
1071a46c0ec8Sopenharmony_ci{
1072a46c0ec8Sopenharmony_ci	struct window *w = data;
1073a46c0ec8Sopenharmony_ci	GdkDisplay *display;
1074a46c0ec8Sopenharmony_ci	GdkWindow *window;
1075a46c0ec8Sopenharmony_ci
1076a46c0ec8Sopenharmony_ci	window_place_ui_elements(widget, w);
1077a46c0ec8Sopenharmony_ci
1078a46c0ec8Sopenharmony_ci	g_signal_connect(G_OBJECT(w->area), "draw", G_CALLBACK(draw), w);
1079a46c0ec8Sopenharmony_ci
1080a46c0ec8Sopenharmony_ci	window = gdk_event_get_window(event);
1081a46c0ec8Sopenharmony_ci	display = gdk_window_get_display(window);
1082a46c0ec8Sopenharmony_ci
1083a46c0ec8Sopenharmony_ci	gdk_window_set_cursor(gtk_widget_get_window(w->win),
1084a46c0ec8Sopenharmony_ci			      gdk_cursor_new_for_display(display,
1085a46c0ec8Sopenharmony_ci							 GDK_BLANK_CURSOR));
1086a46c0ec8Sopenharmony_ci
1087a46c0ec8Sopenharmony_ci	window_lock_pointer(w);
1088a46c0ec8Sopenharmony_ci}
1089a46c0ec8Sopenharmony_ci#endif
1090a46c0ec8Sopenharmony_ci
1091a46c0ec8Sopenharmony_cistatic void
1092a46c0ec8Sopenharmony_ciwindow_quit(struct window *w)
1093a46c0ec8Sopenharmony_ci{
1094a46c0ec8Sopenharmony_ci	g_main_loop_quit(w->event_loop);
1095a46c0ec8Sopenharmony_ci}
1096a46c0ec8Sopenharmony_ci
1097a46c0ec8Sopenharmony_ci#if HAVE_GTK4
1098a46c0ec8Sopenharmony_cistatic gboolean
1099a46c0ec8Sopenharmony_ciwindow_delete_event_cb(GtkWindow *window, gpointer data)
1100a46c0ec8Sopenharmony_ci{
1101a46c0ec8Sopenharmony_ci	struct window *w = data;
1102a46c0ec8Sopenharmony_ci
1103a46c0ec8Sopenharmony_ci	window_quit(w);
1104a46c0ec8Sopenharmony_ci
1105a46c0ec8Sopenharmony_ci	return TRUE;
1106a46c0ec8Sopenharmony_ci}
1107a46c0ec8Sopenharmony_ci#else
1108a46c0ec8Sopenharmony_cistatic void
1109a46c0ec8Sopenharmony_ciwindow_delete_event_cb(GtkWidget *widget, GdkEvent *event, gpointer data)
1110a46c0ec8Sopenharmony_ci{
1111a46c0ec8Sopenharmony_ci	struct window *w = data;
1112a46c0ec8Sopenharmony_ci
1113a46c0ec8Sopenharmony_ci	window_quit(w);
1114a46c0ec8Sopenharmony_ci}
1115a46c0ec8Sopenharmony_ci#endif
1116a46c0ec8Sopenharmony_ci
1117a46c0ec8Sopenharmony_cistatic void
1118a46c0ec8Sopenharmony_ciwindow_init(struct window *w)
1119a46c0ec8Sopenharmony_ci{
1120a46c0ec8Sopenharmony_ci	list_init(&w->evdev_devices);
1121a46c0ec8Sopenharmony_ci
1122a46c0ec8Sopenharmony_ci#if HAVE_GTK4
1123a46c0ec8Sopenharmony_ci	w->win = gtk_window_new();
1124a46c0ec8Sopenharmony_ci#else
1125a46c0ec8Sopenharmony_ci	w->win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1126a46c0ec8Sopenharmony_ci#endif
1127a46c0ec8Sopenharmony_ci
1128a46c0ec8Sopenharmony_ci	if (getenv("LIBINPUT_RUNNING_TEST_SUITE")) {
1129a46c0ec8Sopenharmony_ci#if HAVE_GTK4
1130a46c0ec8Sopenharmony_ci		gtk_window_minimize(GTK_WINDOW(w->win));
1131a46c0ec8Sopenharmony_ci#else
1132a46c0ec8Sopenharmony_ci		gtk_window_iconify(GTK_WINDOW(w->win));
1133a46c0ec8Sopenharmony_ci#endif
1134a46c0ec8Sopenharmony_ci	}
1135a46c0ec8Sopenharmony_ci
1136a46c0ec8Sopenharmony_ci	gtk_window_set_title(GTK_WINDOW(w->win), "libinput debugging tool");
1137a46c0ec8Sopenharmony_ci	gtk_window_set_default_size(GTK_WINDOW(w->win), 1024, 768);
1138a46c0ec8Sopenharmony_ci	gtk_window_maximize(GTK_WINDOW(w->win));
1139a46c0ec8Sopenharmony_ci	gtk_window_set_resizable(GTK_WINDOW(w->win), TRUE);
1140a46c0ec8Sopenharmony_ci	gtk_widget_realize(w->win);
1141a46c0ec8Sopenharmony_ci
1142a46c0ec8Sopenharmony_ci	w->area = gtk_drawing_area_new();
1143a46c0ec8Sopenharmony_ci
1144a46c0ec8Sopenharmony_ci#if HAVE_GTK4
1145a46c0ec8Sopenharmony_ci	g_signal_connect(G_OBJECT(w->area), "resize", G_CALLBACK(map_event_cb), w);
1146a46c0ec8Sopenharmony_ci	g_signal_connect(G_OBJECT(w->win), "close-request", G_CALLBACK(window_delete_event_cb), w);
1147a46c0ec8Sopenharmony_ci
1148a46c0ec8Sopenharmony_ci	gtk_window_set_child(GTK_WINDOW(w->win), w->area);
1149a46c0ec8Sopenharmony_ci	gtk_widget_set_visible(w->win, TRUE);
1150a46c0ec8Sopenharmony_ci#else
1151a46c0ec8Sopenharmony_ci	g_signal_connect(G_OBJECT(w->win), "map-event", G_CALLBACK(map_event_cb), w);
1152a46c0ec8Sopenharmony_ci	g_signal_connect(G_OBJECT(w->win), "delete-event", G_CALLBACK(window_delete_event_cb), w);
1153a46c0ec8Sopenharmony_ci
1154a46c0ec8Sopenharmony_ci	gtk_widget_set_events(w->win, 0);
1155a46c0ec8Sopenharmony_ci	gtk_widget_set_events(w->area, 0);
1156a46c0ec8Sopenharmony_ci
1157a46c0ec8Sopenharmony_ci	gtk_container_add(GTK_CONTAINER(w->win), w->area);
1158a46c0ec8Sopenharmony_ci	gtk_widget_show_all(w->win);
1159a46c0ec8Sopenharmony_ci#endif
1160a46c0ec8Sopenharmony_ci
1161a46c0ec8Sopenharmony_ci	w->pad.ring.position = -1;
1162a46c0ec8Sopenharmony_ci	w->pad.strip.position = -1;
1163a46c0ec8Sopenharmony_ci}
1164a46c0ec8Sopenharmony_ci
1165a46c0ec8Sopenharmony_cistatic void
1166a46c0ec8Sopenharmony_ciwindow_cleanup(struct window *w)
1167a46c0ec8Sopenharmony_ci{
1168a46c0ec8Sopenharmony_ci	ARRAY_FOR_EACH(w->devices, dev) {
1169a46c0ec8Sopenharmony_ci		if (*dev)
1170a46c0ec8Sopenharmony_ci			libinput_device_unref(*dev);
1171a46c0ec8Sopenharmony_ci	}
1172a46c0ec8Sopenharmony_ci}
1173a46c0ec8Sopenharmony_ci
1174a46c0ec8Sopenharmony_cistatic void
1175a46c0ec8Sopenharmony_cichange_ptraccel(struct window *w, double amount)
1176a46c0ec8Sopenharmony_ci{
1177a46c0ec8Sopenharmony_ci	ARRAY_FOR_EACH(w->devices, dev) {
1178a46c0ec8Sopenharmony_ci		double speed;
1179a46c0ec8Sopenharmony_ci		enum libinput_config_status status;
1180a46c0ec8Sopenharmony_ci
1181a46c0ec8Sopenharmony_ci		if (*dev == NULL)
1182a46c0ec8Sopenharmony_ci			continue;
1183a46c0ec8Sopenharmony_ci
1184a46c0ec8Sopenharmony_ci		if (!libinput_device_config_accel_is_available(*dev))
1185a46c0ec8Sopenharmony_ci			continue;
1186a46c0ec8Sopenharmony_ci
1187a46c0ec8Sopenharmony_ci		speed = libinput_device_config_accel_get_speed(*dev);
1188a46c0ec8Sopenharmony_ci		speed = clip(speed + amount, -1, 1);
1189a46c0ec8Sopenharmony_ci
1190a46c0ec8Sopenharmony_ci		status = libinput_device_config_accel_set_speed(*dev, speed);
1191a46c0ec8Sopenharmony_ci
1192a46c0ec8Sopenharmony_ci		if (status != LIBINPUT_CONFIG_STATUS_SUCCESS) {
1193a46c0ec8Sopenharmony_ci			msg("%s: failed to change accel to %.2f (%s)\n",
1194a46c0ec8Sopenharmony_ci			    libinput_device_get_name(*dev),
1195a46c0ec8Sopenharmony_ci			    speed,
1196a46c0ec8Sopenharmony_ci			    libinput_config_status_to_str(status));
1197a46c0ec8Sopenharmony_ci		} else {
1198a46c0ec8Sopenharmony_ci			printf("%s: speed is %.2f\n",
1199a46c0ec8Sopenharmony_ci			       libinput_device_get_name(*dev),
1200a46c0ec8Sopenharmony_ci			       speed);
1201a46c0ec8Sopenharmony_ci		}
1202a46c0ec8Sopenharmony_ci
1203a46c0ec8Sopenharmony_ci	}
1204a46c0ec8Sopenharmony_ci}
1205a46c0ec8Sopenharmony_ci
1206a46c0ec8Sopenharmony_cistatic int
1207a46c0ec8Sopenharmony_cihandle_event_evdev(GIOChannel *source, GIOCondition condition, gpointer data)
1208a46c0ec8Sopenharmony_ci{
1209a46c0ec8Sopenharmony_ci	struct libinput_device *dev = data;
1210a46c0ec8Sopenharmony_ci	struct libinput *li = libinput_device_get_context(dev);
1211a46c0ec8Sopenharmony_ci	struct window *w = libinput_get_user_data(li);
1212a46c0ec8Sopenharmony_ci	struct evdev_device *d,
1213a46c0ec8Sopenharmony_ci			    *device = NULL;
1214a46c0ec8Sopenharmony_ci	struct input_event e;
1215a46c0ec8Sopenharmony_ci	int rc;
1216a46c0ec8Sopenharmony_ci
1217a46c0ec8Sopenharmony_ci	list_for_each(d, &w->evdev_devices, node) {
1218a46c0ec8Sopenharmony_ci		if (d->libinput_device == dev) {
1219a46c0ec8Sopenharmony_ci			device = d;
1220a46c0ec8Sopenharmony_ci			break;
1221a46c0ec8Sopenharmony_ci		}
1222a46c0ec8Sopenharmony_ci	}
1223a46c0ec8Sopenharmony_ci
1224a46c0ec8Sopenharmony_ci	if (device == NULL) {
1225a46c0ec8Sopenharmony_ci		msg("Unknown device: %s\n", libinput_device_get_name(dev));
1226a46c0ec8Sopenharmony_ci		return FALSE;
1227a46c0ec8Sopenharmony_ci	}
1228a46c0ec8Sopenharmony_ci
1229a46c0ec8Sopenharmony_ci	do {
1230a46c0ec8Sopenharmony_ci		rc = libevdev_next_event(device->evdev,
1231a46c0ec8Sopenharmony_ci					 LIBEVDEV_READ_FLAG_NORMAL,
1232a46c0ec8Sopenharmony_ci					 &e);
1233a46c0ec8Sopenharmony_ci		if (rc == -EAGAIN) {
1234a46c0ec8Sopenharmony_ci			break;
1235a46c0ec8Sopenharmony_ci		} else if (rc == LIBEVDEV_READ_STATUS_SYNC) {
1236a46c0ec8Sopenharmony_ci			msg("SYN_DROPPED received\n");
1237a46c0ec8Sopenharmony_ci			goto out;
1238a46c0ec8Sopenharmony_ci		} else if (rc != LIBEVDEV_READ_STATUS_SUCCESS) {
1239a46c0ec8Sopenharmony_ci			msg("Error reading event: %s\n", strerror(-rc));
1240a46c0ec8Sopenharmony_ci			goto out;
1241a46c0ec8Sopenharmony_ci		}
1242a46c0ec8Sopenharmony_ci
1243a46c0ec8Sopenharmony_ci#define EVENT(t_, c_) (t_ << 16 | c_)
1244a46c0ec8Sopenharmony_ci		switch (EVENT(e.type, e.code)) {
1245a46c0ec8Sopenharmony_ci		case EVENT(EV_REL, REL_X):
1246a46c0ec8Sopenharmony_ci			w->evdev.rel_x = e.value;
1247a46c0ec8Sopenharmony_ci			break;
1248a46c0ec8Sopenharmony_ci		case EVENT(EV_REL, REL_Y):
1249a46c0ec8Sopenharmony_ci			w->evdev.rel_y = e.value;
1250a46c0ec8Sopenharmony_ci			break;
1251a46c0ec8Sopenharmony_ci		case EVENT(EV_ABS, ABS_MT_SLOT):
1252a46c0ec8Sopenharmony_ci			w->evdev.slot = min((unsigned int)e.value,
1253a46c0ec8Sopenharmony_ci					  ARRAY_LENGTH(w->evdev.slots) - 1);
1254a46c0ec8Sopenharmony_ci			w->evdev.device = (uintptr_t)dev;
1255a46c0ec8Sopenharmony_ci			break;
1256a46c0ec8Sopenharmony_ci		case EVENT(EV_ABS, ABS_MT_TRACKING_ID):
1257a46c0ec8Sopenharmony_ci			w->evdev.slots[w->evdev.slot].active = (e.value != -1);
1258a46c0ec8Sopenharmony_ci			w->evdev.device = (uintptr_t)dev;
1259a46c0ec8Sopenharmony_ci			break;
1260a46c0ec8Sopenharmony_ci		case EVENT(EV_ABS, ABS_X):
1261a46c0ec8Sopenharmony_ci			w->evdev.x = e.value;
1262a46c0ec8Sopenharmony_ci			w->evdev.device = (uintptr_t)dev;
1263a46c0ec8Sopenharmony_ci			break;
1264a46c0ec8Sopenharmony_ci		case EVENT(EV_ABS, ABS_Y):
1265a46c0ec8Sopenharmony_ci			w->evdev.y = e.value;
1266a46c0ec8Sopenharmony_ci			w->evdev.device = (uintptr_t)dev;
1267a46c0ec8Sopenharmony_ci			break;
1268a46c0ec8Sopenharmony_ci		case EVENT(EV_ABS, ABS_MT_POSITION_X):
1269a46c0ec8Sopenharmony_ci			w->evdev.slots[w->evdev.slot].x = e.value;
1270a46c0ec8Sopenharmony_ci			w->evdev.device = (uintptr_t)dev;
1271a46c0ec8Sopenharmony_ci			break;
1272a46c0ec8Sopenharmony_ci		case EVENT(EV_ABS, ABS_MT_POSITION_Y):
1273a46c0ec8Sopenharmony_ci			w->evdev.slots[w->evdev.slot].y = e.value;
1274a46c0ec8Sopenharmony_ci			w->evdev.device = (uintptr_t)dev;
1275a46c0ec8Sopenharmony_ci			break;
1276a46c0ec8Sopenharmony_ci		}
1277a46c0ec8Sopenharmony_ci	} while (rc == LIBEVDEV_READ_STATUS_SUCCESS);
1278a46c0ec8Sopenharmony_ci
1279a46c0ec8Sopenharmony_ci	gtk_widget_queue_draw(w->area);
1280a46c0ec8Sopenharmony_ciout:
1281a46c0ec8Sopenharmony_ci	return TRUE;
1282a46c0ec8Sopenharmony_ci}
1283a46c0ec8Sopenharmony_ci
1284a46c0ec8Sopenharmony_cistatic void
1285a46c0ec8Sopenharmony_ciregister_evdev_device(struct window *w, struct libinput_device *dev)
1286a46c0ec8Sopenharmony_ci{
1287a46c0ec8Sopenharmony_ci	GIOChannel *c;
1288a46c0ec8Sopenharmony_ci	struct udev_device *ud;
1289a46c0ec8Sopenharmony_ci	struct libevdev *evdev;
1290a46c0ec8Sopenharmony_ci	const char *device_node;
1291a46c0ec8Sopenharmony_ci	int fd;
1292a46c0ec8Sopenharmony_ci	struct evdev_device *d;
1293a46c0ec8Sopenharmony_ci
1294a46c0ec8Sopenharmony_ci	ud = libinput_device_get_udev_device(dev);
1295a46c0ec8Sopenharmony_ci	device_node = udev_device_get_devnode(ud);
1296a46c0ec8Sopenharmony_ci
1297a46c0ec8Sopenharmony_ci	fd = open(device_node, O_RDONLY|O_NONBLOCK);
1298a46c0ec8Sopenharmony_ci	if (fd == -1) {
1299a46c0ec8Sopenharmony_ci		msg("failed to open %s, evdev events unavailable\n", device_node);
1300a46c0ec8Sopenharmony_ci		goto out;
1301a46c0ec8Sopenharmony_ci	}
1302a46c0ec8Sopenharmony_ci
1303a46c0ec8Sopenharmony_ci	if (libevdev_new_from_fd(fd, &evdev) != 0) {
1304a46c0ec8Sopenharmony_ci		msg("failed to create context for %s, evdev events unavailable\n",
1305a46c0ec8Sopenharmony_ci		    device_node);
1306a46c0ec8Sopenharmony_ci		goto out;
1307a46c0ec8Sopenharmony_ci	}
1308a46c0ec8Sopenharmony_ci
1309a46c0ec8Sopenharmony_ci	d = zalloc(sizeof *d);
1310a46c0ec8Sopenharmony_ci	list_append(&w->evdev_devices, &d->node);
1311a46c0ec8Sopenharmony_ci	d->fd = fd;
1312a46c0ec8Sopenharmony_ci	d->evdev = evdev;
1313a46c0ec8Sopenharmony_ci	d->libinput_device =libinput_device_ref(dev);
1314a46c0ec8Sopenharmony_ci
1315a46c0ec8Sopenharmony_ci	c = g_io_channel_unix_new(fd);
1316a46c0ec8Sopenharmony_ci	g_io_channel_set_encoding(c, NULL, NULL);
1317a46c0ec8Sopenharmony_ci	d->source_id = g_io_add_watch(c, G_IO_IN,
1318a46c0ec8Sopenharmony_ci				      handle_event_evdev,
1319a46c0ec8Sopenharmony_ci				      d->libinput_device);
1320a46c0ec8Sopenharmony_ci	fd = -1;
1321a46c0ec8Sopenharmony_ciout:
1322a46c0ec8Sopenharmony_ci	close(fd);
1323a46c0ec8Sopenharmony_ci	udev_device_unref(ud);
1324a46c0ec8Sopenharmony_ci}
1325a46c0ec8Sopenharmony_ci
1326a46c0ec8Sopenharmony_cistatic void
1327a46c0ec8Sopenharmony_ciunregister_evdev_device(struct window *w, struct libinput_device *dev)
1328a46c0ec8Sopenharmony_ci{
1329a46c0ec8Sopenharmony_ci	struct evdev_device *d;
1330a46c0ec8Sopenharmony_ci
1331a46c0ec8Sopenharmony_ci	list_for_each_safe(d, &w->evdev_devices, node) {
1332a46c0ec8Sopenharmony_ci		if (d->libinput_device != dev)
1333a46c0ec8Sopenharmony_ci			continue;
1334a46c0ec8Sopenharmony_ci
1335a46c0ec8Sopenharmony_ci		list_remove(&d->node);
1336a46c0ec8Sopenharmony_ci		g_source_remove(d->source_id);
1337a46c0ec8Sopenharmony_ci		free(libinput_device_get_user_data(d->libinput_device));
1338a46c0ec8Sopenharmony_ci		libinput_device_unref(d->libinput_device);
1339a46c0ec8Sopenharmony_ci		libevdev_free(d->evdev);
1340a46c0ec8Sopenharmony_ci		close(d->fd);
1341a46c0ec8Sopenharmony_ci		free(d);
1342a46c0ec8Sopenharmony_ci		w->evdev.last_device = 0;
1343a46c0ec8Sopenharmony_ci		break;
1344a46c0ec8Sopenharmony_ci	}
1345a46c0ec8Sopenharmony_ci}
1346a46c0ec8Sopenharmony_ci
1347a46c0ec8Sopenharmony_cistatic void
1348a46c0ec8Sopenharmony_cihandle_event_device_notify(struct libinput_event *ev)
1349a46c0ec8Sopenharmony_ci{
1350a46c0ec8Sopenharmony_ci	struct libinput_device *dev = libinput_event_get_device(ev);
1351a46c0ec8Sopenharmony_ci	struct libinput *li;
1352a46c0ec8Sopenharmony_ci	struct window *w;
1353a46c0ec8Sopenharmony_ci	const char *type;
1354a46c0ec8Sopenharmony_ci
1355a46c0ec8Sopenharmony_ci	li = libinput_event_get_context(ev);
1356a46c0ec8Sopenharmony_ci	w = libinput_get_user_data(li);
1357a46c0ec8Sopenharmony_ci
1358a46c0ec8Sopenharmony_ci	if (libinput_event_get_type(ev) == LIBINPUT_EVENT_DEVICE_ADDED) {
1359a46c0ec8Sopenharmony_ci		type = "added";
1360a46c0ec8Sopenharmony_ci		register_evdev_device(w, dev);
1361a46c0ec8Sopenharmony_ci		tools_device_apply_config(libinput_event_get_device(ev),
1362a46c0ec8Sopenharmony_ci					  &w->options);
1363a46c0ec8Sopenharmony_ci	} else {
1364a46c0ec8Sopenharmony_ci		type = "removed";
1365a46c0ec8Sopenharmony_ci		unregister_evdev_device(w, dev);
1366a46c0ec8Sopenharmony_ci	}
1367a46c0ec8Sopenharmony_ci
1368a46c0ec8Sopenharmony_ci	msg("%s %-30s %s\n",
1369a46c0ec8Sopenharmony_ci	    libinput_device_get_sysname(dev),
1370a46c0ec8Sopenharmony_ci	    libinput_device_get_name(dev),
1371a46c0ec8Sopenharmony_ci	    type);
1372a46c0ec8Sopenharmony_ci
1373a46c0ec8Sopenharmony_ci	if (libinput_event_get_type(ev) == LIBINPUT_EVENT_DEVICE_ADDED) {
1374a46c0ec8Sopenharmony_ci		ARRAY_FOR_EACH(w->devices, device) {
1375a46c0ec8Sopenharmony_ci			if (*device == NULL) {
1376a46c0ec8Sopenharmony_ci				*device = libinput_device_ref(dev);
1377a46c0ec8Sopenharmony_ci				break;
1378a46c0ec8Sopenharmony_ci			}
1379a46c0ec8Sopenharmony_ci		}
1380a46c0ec8Sopenharmony_ci	} else  {
1381a46c0ec8Sopenharmony_ci		ARRAY_FOR_EACH(w->devices, device) {
1382a46c0ec8Sopenharmony_ci			if (*device == dev) {
1383a46c0ec8Sopenharmony_ci				libinput_device_unref(*device);
1384a46c0ec8Sopenharmony_ci				*device = NULL;
1385a46c0ec8Sopenharmony_ci				break;
1386a46c0ec8Sopenharmony_ci			}
1387a46c0ec8Sopenharmony_ci		}
1388a46c0ec8Sopenharmony_ci	}
1389a46c0ec8Sopenharmony_ci}
1390a46c0ec8Sopenharmony_ci
1391a46c0ec8Sopenharmony_cistatic void
1392a46c0ec8Sopenharmony_cihandle_event_motion(struct libinput_event *ev, struct window *w)
1393a46c0ec8Sopenharmony_ci{
1394a46c0ec8Sopenharmony_ci	struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev);
1395a46c0ec8Sopenharmony_ci	double dx = libinput_event_pointer_get_dx(p),
1396a46c0ec8Sopenharmony_ci	       dy = libinput_event_pointer_get_dy(p);
1397a46c0ec8Sopenharmony_ci	double dx_unaccel = libinput_event_pointer_get_dx_unaccelerated(p),
1398a46c0ec8Sopenharmony_ci	       dy_unaccel = libinput_event_pointer_get_dy_unaccelerated(p);
1399a46c0ec8Sopenharmony_ci	struct point point;
1400a46c0ec8Sopenharmony_ci	const int mask = ARRAY_LENGTH(w->deltas);
1401a46c0ec8Sopenharmony_ci	size_t idx;
1402a46c0ec8Sopenharmony_ci
1403a46c0ec8Sopenharmony_ci	w->pointer.x = clip(w->pointer.x + dx, 0.0, w->width);
1404a46c0ec8Sopenharmony_ci	w->pointer.y = clip(w->pointer.y + dy, 0.0, w->height);
1405a46c0ec8Sopenharmony_ci	w->unaccelerated.x = clip(w->unaccelerated.x + dx_unaccel, 0.0, w->width);
1406a46c0ec8Sopenharmony_ci	w->unaccelerated.y = clip(w->unaccelerated.y + dy_unaccel, 0.0, w->height);
1407a46c0ec8Sopenharmony_ci
1408a46c0ec8Sopenharmony_ci	idx = w->ndeltas % mask;
1409a46c0ec8Sopenharmony_ci	point = w->deltas[idx];
1410a46c0ec8Sopenharmony_ci	idx = (w->ndeltas + 1) % mask;
1411a46c0ec8Sopenharmony_ci	point.x += dx_unaccel;
1412a46c0ec8Sopenharmony_ci	point.y += dy_unaccel;
1413a46c0ec8Sopenharmony_ci	w->deltas[idx] = point;
1414a46c0ec8Sopenharmony_ci	w->ndeltas++;
1415a46c0ec8Sopenharmony_ci}
1416a46c0ec8Sopenharmony_ci
1417a46c0ec8Sopenharmony_cistatic void
1418a46c0ec8Sopenharmony_cihandle_event_absmotion(struct libinput_event *ev, struct window *w)
1419a46c0ec8Sopenharmony_ci{
1420a46c0ec8Sopenharmony_ci	struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev);
1421a46c0ec8Sopenharmony_ci	double x = libinput_event_pointer_get_absolute_x_transformed(p, w->width),
1422a46c0ec8Sopenharmony_ci	       y = libinput_event_pointer_get_absolute_y_transformed(p, w->height);
1423a46c0ec8Sopenharmony_ci
1424a46c0ec8Sopenharmony_ci	w->abs.x = x;
1425a46c0ec8Sopenharmony_ci	w->abs.y = y;
1426a46c0ec8Sopenharmony_ci}
1427a46c0ec8Sopenharmony_ci
1428a46c0ec8Sopenharmony_cistatic void
1429a46c0ec8Sopenharmony_cihandle_event_touch(struct libinput_event *ev, struct window *w)
1430a46c0ec8Sopenharmony_ci{
1431a46c0ec8Sopenharmony_ci	struct libinput_event_touch *t = libinput_event_get_touch_event(ev);
1432a46c0ec8Sopenharmony_ci	int slot = libinput_event_touch_get_seat_slot(t);
1433a46c0ec8Sopenharmony_ci	struct touch *touch;
1434a46c0ec8Sopenharmony_ci	double x, y;
1435a46c0ec8Sopenharmony_ci
1436a46c0ec8Sopenharmony_ci	if (slot == -1 || slot >= (int) ARRAY_LENGTH(w->touches))
1437a46c0ec8Sopenharmony_ci		return;
1438a46c0ec8Sopenharmony_ci
1439a46c0ec8Sopenharmony_ci	touch = &w->touches[slot];
1440a46c0ec8Sopenharmony_ci
1441a46c0ec8Sopenharmony_ci	switch (libinput_event_get_type(ev)) {
1442a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_TOUCH_UP:
1443a46c0ec8Sopenharmony_ci		touch->state = TOUCH_ENDED;
1444a46c0ec8Sopenharmony_ci		return;
1445a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_TOUCH_CANCEL:
1446a46c0ec8Sopenharmony_ci		touch->state = TOUCH_CANCELLED;
1447a46c0ec8Sopenharmony_ci		return;
1448a46c0ec8Sopenharmony_ci	default:
1449a46c0ec8Sopenharmony_ci		break;
1450a46c0ec8Sopenharmony_ci	}
1451a46c0ec8Sopenharmony_ci
1452a46c0ec8Sopenharmony_ci	x = libinput_event_touch_get_x_transformed(t, w->width),
1453a46c0ec8Sopenharmony_ci	y = libinput_event_touch_get_y_transformed(t, w->height);
1454a46c0ec8Sopenharmony_ci
1455a46c0ec8Sopenharmony_ci	touch->state = TOUCH_ACTIVE;
1456a46c0ec8Sopenharmony_ci	touch->x = (int)x;
1457a46c0ec8Sopenharmony_ci	touch->y = (int)y;
1458a46c0ec8Sopenharmony_ci}
1459a46c0ec8Sopenharmony_ci
1460a46c0ec8Sopenharmony_cistatic void
1461a46c0ec8Sopenharmony_cihandle_event_axis(struct libinput_event *ev, struct window *w)
1462a46c0ec8Sopenharmony_ci{
1463a46c0ec8Sopenharmony_ci	struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev);
1464a46c0ec8Sopenharmony_ci	double value;
1465a46c0ec8Sopenharmony_ci	enum libinput_pointer_axis axis;
1466a46c0ec8Sopenharmony_ci	enum libinput_event_type type;
1467a46c0ec8Sopenharmony_ci
1468a46c0ec8Sopenharmony_ci	type = libinput_event_get_type(ev);
1469a46c0ec8Sopenharmony_ci
1470a46c0ec8Sopenharmony_ci	axis = LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL;
1471a46c0ec8Sopenharmony_ci	if (libinput_event_pointer_has_axis(p, axis)) {
1472a46c0ec8Sopenharmony_ci		value = libinput_event_pointer_get_scroll_value(p, axis);
1473a46c0ec8Sopenharmony_ci		w->scroll.vy += value;
1474a46c0ec8Sopenharmony_ci		w->scroll.vy = clip(w->scroll.vy, 0, w->height);
1475a46c0ec8Sopenharmony_ci
1476a46c0ec8Sopenharmony_ci		if (type == LIBINPUT_EVENT_POINTER_SCROLL_WHEEL) {
1477a46c0ec8Sopenharmony_ci			w->scroll.vy_discrete += value;
1478a46c0ec8Sopenharmony_ci			w->scroll.vy_discrete = clip(w->scroll.vy_discrete, 0, w->height);
1479a46c0ec8Sopenharmony_ci		}
1480a46c0ec8Sopenharmony_ci	}
1481a46c0ec8Sopenharmony_ci
1482a46c0ec8Sopenharmony_ci	axis = LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL;
1483a46c0ec8Sopenharmony_ci	if (libinput_event_pointer_has_axis(p, axis)) {
1484a46c0ec8Sopenharmony_ci		value = libinput_event_pointer_get_scroll_value(p, axis);
1485a46c0ec8Sopenharmony_ci		w->scroll.hx += value;
1486a46c0ec8Sopenharmony_ci		w->scroll.hx = clip(w->scroll.hx, 0, w->width);
1487a46c0ec8Sopenharmony_ci
1488a46c0ec8Sopenharmony_ci		if (type == LIBINPUT_EVENT_POINTER_SCROLL_WHEEL) {
1489a46c0ec8Sopenharmony_ci			w->scroll.hx_discrete += value;
1490a46c0ec8Sopenharmony_ci			w->scroll.hx_discrete = clip(w->scroll.hx_discrete, 0, w->width);
1491a46c0ec8Sopenharmony_ci		}
1492a46c0ec8Sopenharmony_ci	}
1493a46c0ec8Sopenharmony_ci}
1494a46c0ec8Sopenharmony_ci
1495a46c0ec8Sopenharmony_cistatic int
1496a46c0ec8Sopenharmony_cihandle_event_keyboard(struct libinput_event *ev, struct window *w)
1497a46c0ec8Sopenharmony_ci{
1498a46c0ec8Sopenharmony_ci	struct libinput_event_keyboard *k = libinput_event_get_keyboard_event(ev);
1499a46c0ec8Sopenharmony_ci	unsigned int key = libinput_event_keyboard_get_key(k);
1500a46c0ec8Sopenharmony_ci
1501a46c0ec8Sopenharmony_ci	if (libinput_event_keyboard_get_key_state(k) ==
1502a46c0ec8Sopenharmony_ci	    LIBINPUT_KEY_STATE_RELEASED)
1503a46c0ec8Sopenharmony_ci		return 0;
1504a46c0ec8Sopenharmony_ci
1505a46c0ec8Sopenharmony_ci	switch(key) {
1506a46c0ec8Sopenharmony_ci	case KEY_ESC:
1507a46c0ec8Sopenharmony_ci		return 1;
1508a46c0ec8Sopenharmony_ci	case KEY_UP:
1509a46c0ec8Sopenharmony_ci		change_ptraccel(w, 0.1);
1510a46c0ec8Sopenharmony_ci		break;
1511a46c0ec8Sopenharmony_ci	case KEY_DOWN:
1512a46c0ec8Sopenharmony_ci		change_ptraccel(w, -0.1);
1513a46c0ec8Sopenharmony_ci		break;
1514a46c0ec8Sopenharmony_ci	default:
1515a46c0ec8Sopenharmony_ci		break;
1516a46c0ec8Sopenharmony_ci	}
1517a46c0ec8Sopenharmony_ci
1518a46c0ec8Sopenharmony_ci	return 0;
1519a46c0ec8Sopenharmony_ci}
1520a46c0ec8Sopenharmony_ci
1521a46c0ec8Sopenharmony_cistatic void
1522a46c0ec8Sopenharmony_cihandle_event_button(struct libinput_event *ev, struct window *w)
1523a46c0ec8Sopenharmony_ci{
1524a46c0ec8Sopenharmony_ci	struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev);
1525a46c0ec8Sopenharmony_ci	unsigned int button = libinput_event_pointer_get_button(p);
1526a46c0ec8Sopenharmony_ci	bool is_press;
1527a46c0ec8Sopenharmony_ci
1528a46c0ec8Sopenharmony_ci	is_press = libinput_event_pointer_get_button_state(p) == LIBINPUT_BUTTON_STATE_PRESSED;
1529a46c0ec8Sopenharmony_ci
1530a46c0ec8Sopenharmony_ci	switch (button) {
1531a46c0ec8Sopenharmony_ci	case BTN_LEFT:
1532a46c0ec8Sopenharmony_ci		w->buttons.l = is_press;
1533a46c0ec8Sopenharmony_ci		break;
1534a46c0ec8Sopenharmony_ci	case BTN_RIGHT:
1535a46c0ec8Sopenharmony_ci		w->buttons.r = is_press;
1536a46c0ec8Sopenharmony_ci		break;
1537a46c0ec8Sopenharmony_ci	case BTN_MIDDLE:
1538a46c0ec8Sopenharmony_ci		w->buttons.m = is_press;
1539a46c0ec8Sopenharmony_ci		break;
1540a46c0ec8Sopenharmony_ci	default:
1541a46c0ec8Sopenharmony_ci		w->buttons.other = is_press;
1542a46c0ec8Sopenharmony_ci		w->buttons.other_name = libevdev_event_code_get_name(EV_KEY,
1543a46c0ec8Sopenharmony_ci								     button);
1544a46c0ec8Sopenharmony_ci	}
1545a46c0ec8Sopenharmony_ci
1546a46c0ec8Sopenharmony_ci}
1547a46c0ec8Sopenharmony_ci
1548a46c0ec8Sopenharmony_cistatic void
1549a46c0ec8Sopenharmony_cihandle_event_swipe(struct libinput_event *ev, struct window *w)
1550a46c0ec8Sopenharmony_ci{
1551a46c0ec8Sopenharmony_ci	struct libinput_event_gesture *g = libinput_event_get_gesture_event(ev);
1552a46c0ec8Sopenharmony_ci	int nfingers;
1553a46c0ec8Sopenharmony_ci	double dx, dy;
1554a46c0ec8Sopenharmony_ci
1555a46c0ec8Sopenharmony_ci	nfingers = libinput_event_gesture_get_finger_count(g);
1556a46c0ec8Sopenharmony_ci
1557a46c0ec8Sopenharmony_ci	switch (libinput_event_get_type(ev)) {
1558a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN:
1559a46c0ec8Sopenharmony_ci		w->swipe.nfingers = nfingers;
1560a46c0ec8Sopenharmony_ci		w->swipe.x = w->width/2;
1561a46c0ec8Sopenharmony_ci		w->swipe.y = w->height/2;
1562a46c0ec8Sopenharmony_ci		break;
1563a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE:
1564a46c0ec8Sopenharmony_ci		dx = libinput_event_gesture_get_dx(g);
1565a46c0ec8Sopenharmony_ci		dy = libinput_event_gesture_get_dy(g);
1566a46c0ec8Sopenharmony_ci		w->swipe.x += dx;
1567a46c0ec8Sopenharmony_ci		w->swipe.y += dy;
1568a46c0ec8Sopenharmony_ci		break;
1569a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_GESTURE_SWIPE_END:
1570a46c0ec8Sopenharmony_ci		w->swipe.nfingers = 0;
1571a46c0ec8Sopenharmony_ci		w->swipe.x = w->width/2;
1572a46c0ec8Sopenharmony_ci		w->swipe.y = w->height/2;
1573a46c0ec8Sopenharmony_ci		break;
1574a46c0ec8Sopenharmony_ci	default:
1575a46c0ec8Sopenharmony_ci		abort();
1576a46c0ec8Sopenharmony_ci	}
1577a46c0ec8Sopenharmony_ci}
1578a46c0ec8Sopenharmony_ci
1579a46c0ec8Sopenharmony_cistatic void
1580a46c0ec8Sopenharmony_cihandle_event_pinch(struct libinput_event *ev, struct window *w)
1581a46c0ec8Sopenharmony_ci{
1582a46c0ec8Sopenharmony_ci	struct libinput_event_gesture *g = libinput_event_get_gesture_event(ev);
1583a46c0ec8Sopenharmony_ci	int nfingers;
1584a46c0ec8Sopenharmony_ci	double dx, dy;
1585a46c0ec8Sopenharmony_ci
1586a46c0ec8Sopenharmony_ci	nfingers = libinput_event_gesture_get_finger_count(g);
1587a46c0ec8Sopenharmony_ci
1588a46c0ec8Sopenharmony_ci	switch (libinput_event_get_type(ev)) {
1589a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN:
1590a46c0ec8Sopenharmony_ci		w->pinch.nfingers = nfingers;
1591a46c0ec8Sopenharmony_ci		w->pinch.x = w->width/2;
1592a46c0ec8Sopenharmony_ci		w->pinch.y = w->height/2;
1593a46c0ec8Sopenharmony_ci		break;
1594a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE:
1595a46c0ec8Sopenharmony_ci		dx = libinput_event_gesture_get_dx(g);
1596a46c0ec8Sopenharmony_ci		dy = libinput_event_gesture_get_dy(g);
1597a46c0ec8Sopenharmony_ci		w->pinch.x += dx;
1598a46c0ec8Sopenharmony_ci		w->pinch.y += dy;
1599a46c0ec8Sopenharmony_ci		w->pinch.scale = libinput_event_gesture_get_scale(g);
1600a46c0ec8Sopenharmony_ci		w->pinch.angle += libinput_event_gesture_get_angle_delta(g);
1601a46c0ec8Sopenharmony_ci		break;
1602a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_GESTURE_PINCH_END:
1603a46c0ec8Sopenharmony_ci		w->pinch.nfingers = 0;
1604a46c0ec8Sopenharmony_ci		w->pinch.x = w->width/2;
1605a46c0ec8Sopenharmony_ci		w->pinch.y = w->height/2;
1606a46c0ec8Sopenharmony_ci		w->pinch.angle = 0.0;
1607a46c0ec8Sopenharmony_ci		w->pinch.scale = 1.0;
1608a46c0ec8Sopenharmony_ci		break;
1609a46c0ec8Sopenharmony_ci	default:
1610a46c0ec8Sopenharmony_ci		abort();
1611a46c0ec8Sopenharmony_ci	}
1612a46c0ec8Sopenharmony_ci}
1613a46c0ec8Sopenharmony_ci
1614a46c0ec8Sopenharmony_cistatic void
1615a46c0ec8Sopenharmony_cihandle_event_hold(struct libinput_event *ev, struct window *w)
1616a46c0ec8Sopenharmony_ci{
1617a46c0ec8Sopenharmony_ci	struct libinput_event_gesture *g = libinput_event_get_gesture_event(ev);
1618a46c0ec8Sopenharmony_ci	int nfingers;
1619a46c0ec8Sopenharmony_ci
1620a46c0ec8Sopenharmony_ci	nfingers = libinput_event_gesture_get_finger_count(g);
1621a46c0ec8Sopenharmony_ci
1622a46c0ec8Sopenharmony_ci	switch (libinput_event_get_type(ev)) {
1623a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_GESTURE_HOLD_BEGIN:
1624a46c0ec8Sopenharmony_ci		w->hold.nfingers = nfingers;
1625a46c0ec8Sopenharmony_ci		w->hold.active = true;
1626a46c0ec8Sopenharmony_ci		break;
1627a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_GESTURE_HOLD_END:
1628a46c0ec8Sopenharmony_ci		w->hold.nfingers = nfingers;
1629a46c0ec8Sopenharmony_ci		w->hold.active = false;
1630a46c0ec8Sopenharmony_ci		break;
1631a46c0ec8Sopenharmony_ci	default:
1632a46c0ec8Sopenharmony_ci		abort();
1633a46c0ec8Sopenharmony_ci	}
1634a46c0ec8Sopenharmony_ci}
1635a46c0ec8Sopenharmony_ci
1636a46c0ec8Sopenharmony_cistatic void
1637a46c0ec8Sopenharmony_cihandle_event_tablet(struct libinput_event *ev, struct window *w)
1638a46c0ec8Sopenharmony_ci{
1639a46c0ec8Sopenharmony_ci	struct libinput_event_tablet_tool *t = libinput_event_get_tablet_tool_event(ev);
1640a46c0ec8Sopenharmony_ci	double x, y;
1641a46c0ec8Sopenharmony_ci	struct point point;
1642a46c0ec8Sopenharmony_ci	int idx;
1643a46c0ec8Sopenharmony_ci	const int mask = ARRAY_LENGTH(w->tool.deltas);
1644a46c0ec8Sopenharmony_ci	bool is_press;
1645a46c0ec8Sopenharmony_ci	unsigned int button;
1646a46c0ec8Sopenharmony_ci
1647a46c0ec8Sopenharmony_ci	x = libinput_event_tablet_tool_get_x_transformed(t, w->width);
1648a46c0ec8Sopenharmony_ci	y = libinput_event_tablet_tool_get_y_transformed(t, w->height);
1649a46c0ec8Sopenharmony_ci
1650a46c0ec8Sopenharmony_ci	switch (libinput_event_get_type(ev)) {
1651a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY:
1652a46c0ec8Sopenharmony_ci		if (libinput_event_tablet_tool_get_proximity_state(t) ==
1653a46c0ec8Sopenharmony_ci		    LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT) {
1654a46c0ec8Sopenharmony_ci			w->tool.x_in = 0;
1655a46c0ec8Sopenharmony_ci			w->tool.y_in = 0;
1656a46c0ec8Sopenharmony_ci			w->tool.x_down = 0;
1657a46c0ec8Sopenharmony_ci			w->tool.y_down = 0;
1658a46c0ec8Sopenharmony_ci			w->tool.x_up = 0;
1659a46c0ec8Sopenharmony_ci			w->tool.y_up = 0;
1660a46c0ec8Sopenharmony_ci		} else {
1661a46c0ec8Sopenharmony_ci			w->tool.x_in = x;
1662a46c0ec8Sopenharmony_ci			w->tool.y_in = y;
1663a46c0ec8Sopenharmony_ci			w->tool.ndeltas = 0;
1664a46c0ec8Sopenharmony_ci			w->tool.deltas[0].x = w->width/2;
1665a46c0ec8Sopenharmony_ci			w->tool.deltas[0].y = w->height/2;
1666a46c0ec8Sopenharmony_ci		}
1667a46c0ec8Sopenharmony_ci		break;
1668a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_TABLET_TOOL_TIP:
1669a46c0ec8Sopenharmony_ci		w->tool.pressure = libinput_event_tablet_tool_get_pressure(t);
1670a46c0ec8Sopenharmony_ci		w->tool.distance = libinput_event_tablet_tool_get_distance(t);
1671a46c0ec8Sopenharmony_ci		w->tool.tilt_x = libinput_event_tablet_tool_get_tilt_x(t);
1672a46c0ec8Sopenharmony_ci		w->tool.tilt_y = libinput_event_tablet_tool_get_tilt_y(t);
1673a46c0ec8Sopenharmony_ci		if (libinput_event_tablet_tool_get_tip_state(t) ==
1674a46c0ec8Sopenharmony_ci		    LIBINPUT_TABLET_TOOL_TIP_DOWN) {
1675a46c0ec8Sopenharmony_ci			w->tool.x_down = x;
1676a46c0ec8Sopenharmony_ci			w->tool.y_down = y;
1677a46c0ec8Sopenharmony_ci			w->tool.is_down = true;
1678a46c0ec8Sopenharmony_ci		} else {
1679a46c0ec8Sopenharmony_ci			w->tool.x_up = x;
1680a46c0ec8Sopenharmony_ci			w->tool.y_up = y;
1681a46c0ec8Sopenharmony_ci			w->tool.is_down = false;
1682a46c0ec8Sopenharmony_ci		}
1683a46c0ec8Sopenharmony_ci		_fallthrough_;
1684a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
1685a46c0ec8Sopenharmony_ci		w->tool.x = x;
1686a46c0ec8Sopenharmony_ci		w->tool.y = y;
1687a46c0ec8Sopenharmony_ci		w->tool.pressure = libinput_event_tablet_tool_get_pressure(t);
1688a46c0ec8Sopenharmony_ci		w->tool.distance = libinput_event_tablet_tool_get_distance(t);
1689a46c0ec8Sopenharmony_ci		w->tool.tilt_x = libinput_event_tablet_tool_get_tilt_x(t);
1690a46c0ec8Sopenharmony_ci		w->tool.tilt_y = libinput_event_tablet_tool_get_tilt_y(t);
1691a46c0ec8Sopenharmony_ci		w->tool.rotation = libinput_event_tablet_tool_get_rotation(t);
1692a46c0ec8Sopenharmony_ci		w->tool.size_major = libinput_event_tablet_tool_get_size_major(t);
1693a46c0ec8Sopenharmony_ci		w->tool.size_minor = libinput_event_tablet_tool_get_size_minor(t);
1694a46c0ec8Sopenharmony_ci
1695a46c0ec8Sopenharmony_ci		/* Add the delta to the last position and store them as abs
1696a46c0ec8Sopenharmony_ci		 * coordinates */
1697a46c0ec8Sopenharmony_ci		idx = w->tool.ndeltas % mask;
1698a46c0ec8Sopenharmony_ci		point = w->tool.deltas[idx];
1699a46c0ec8Sopenharmony_ci
1700a46c0ec8Sopenharmony_ci		idx = (w->tool.ndeltas + 1) % mask;
1701a46c0ec8Sopenharmony_ci		point.x += libinput_event_tablet_tool_get_dx(t);
1702a46c0ec8Sopenharmony_ci		point.y += libinput_event_tablet_tool_get_dy(t);
1703a46c0ec8Sopenharmony_ci		w->tool.deltas[idx] = point;
1704a46c0ec8Sopenharmony_ci		w->tool.ndeltas++;
1705a46c0ec8Sopenharmony_ci		break;
1706a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_TABLET_TOOL_BUTTON:
1707a46c0ec8Sopenharmony_ci		is_press = libinput_event_tablet_tool_get_button_state(t) == LIBINPUT_BUTTON_STATE_PRESSED;
1708a46c0ec8Sopenharmony_ci		button = libinput_event_tablet_tool_get_button(t);
1709a46c0ec8Sopenharmony_ci
1710a46c0ec8Sopenharmony_ci		w->buttons.other = is_press;
1711a46c0ec8Sopenharmony_ci		w->buttons.other_name = libevdev_event_code_get_name(EV_KEY,
1712a46c0ec8Sopenharmony_ci								     button);
1713a46c0ec8Sopenharmony_ci		break;
1714a46c0ec8Sopenharmony_ci	default:
1715a46c0ec8Sopenharmony_ci		abort();
1716a46c0ec8Sopenharmony_ci	}
1717a46c0ec8Sopenharmony_ci}
1718a46c0ec8Sopenharmony_ci
1719a46c0ec8Sopenharmony_cistatic void
1720a46c0ec8Sopenharmony_cihandle_event_tablet_pad(struct libinput_event *ev, struct window *w)
1721a46c0ec8Sopenharmony_ci{
1722a46c0ec8Sopenharmony_ci	struct libinput_event_tablet_pad *p = libinput_event_get_tablet_pad_event(ev);
1723a46c0ec8Sopenharmony_ci	bool is_press;
1724a46c0ec8Sopenharmony_ci	unsigned int button;
1725a46c0ec8Sopenharmony_ci	static const char *pad_buttons[] = {
1726a46c0ec8Sopenharmony_ci		"Pad 0", "Pad 1", "Pad 2", "Pad 3", "Pad 4", "Pad 5",
1727a46c0ec8Sopenharmony_ci		"Pad 6", "Pad 7", "Pad 8", "Pad 9", "Pad >= 10"
1728a46c0ec8Sopenharmony_ci	};
1729a46c0ec8Sopenharmony_ci	double position;
1730a46c0ec8Sopenharmony_ci	double number;
1731a46c0ec8Sopenharmony_ci
1732a46c0ec8Sopenharmony_ci	switch (libinput_event_get_type(ev)) {
1733a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_TABLET_PAD_BUTTON:
1734a46c0ec8Sopenharmony_ci		is_press = libinput_event_tablet_pad_get_button_state(p) == LIBINPUT_BUTTON_STATE_PRESSED;
1735a46c0ec8Sopenharmony_ci		button = libinput_event_tablet_pad_get_button_number(p);
1736a46c0ec8Sopenharmony_ci		w->buttons.other = is_press;
1737a46c0ec8Sopenharmony_ci		w->buttons.other_name = pad_buttons[min(button, 10)];
1738a46c0ec8Sopenharmony_ci		break;
1739a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_TABLET_PAD_RING:
1740a46c0ec8Sopenharmony_ci		position = libinput_event_tablet_pad_get_ring_position(p);
1741a46c0ec8Sopenharmony_ci		number = libinput_event_tablet_pad_get_ring_number(p);
1742a46c0ec8Sopenharmony_ci		w->pad.ring.number = number;
1743a46c0ec8Sopenharmony_ci		w->pad.ring.position = position;
1744a46c0ec8Sopenharmony_ci		break;
1745a46c0ec8Sopenharmony_ci	case LIBINPUT_EVENT_TABLET_PAD_STRIP:
1746a46c0ec8Sopenharmony_ci		position = libinput_event_tablet_pad_get_strip_position(p);
1747a46c0ec8Sopenharmony_ci		number = libinput_event_tablet_pad_get_strip_number(p);
1748a46c0ec8Sopenharmony_ci		w->pad.strip.number = number;
1749a46c0ec8Sopenharmony_ci		w->pad.strip.position = position;
1750a46c0ec8Sopenharmony_ci		break;
1751a46c0ec8Sopenharmony_ci	default:
1752a46c0ec8Sopenharmony_ci		abort();
1753a46c0ec8Sopenharmony_ci	}
1754a46c0ec8Sopenharmony_ci}
1755a46c0ec8Sopenharmony_ci
1756a46c0ec8Sopenharmony_cistatic gboolean
1757a46c0ec8Sopenharmony_cihandle_event_libinput(GIOChannel *source, GIOCondition condition, gpointer data)
1758a46c0ec8Sopenharmony_ci{
1759a46c0ec8Sopenharmony_ci	struct libinput *li = data;
1760a46c0ec8Sopenharmony_ci	struct window *w = libinput_get_user_data(li);
1761a46c0ec8Sopenharmony_ci	struct libinput_event *ev;
1762a46c0ec8Sopenharmony_ci
1763a46c0ec8Sopenharmony_ci	tools_dispatch(li);
1764a46c0ec8Sopenharmony_ci
1765a46c0ec8Sopenharmony_ci	while ((ev = libinput_get_event(li))) {
1766a46c0ec8Sopenharmony_ci		switch (libinput_event_get_type(ev)) {
1767a46c0ec8Sopenharmony_ci		case LIBINPUT_EVENT_NONE:
1768a46c0ec8Sopenharmony_ci			abort();
1769a46c0ec8Sopenharmony_ci		case LIBINPUT_EVENT_DEVICE_ADDED:
1770a46c0ec8Sopenharmony_ci		case LIBINPUT_EVENT_DEVICE_REMOVED:
1771a46c0ec8Sopenharmony_ci			handle_event_device_notify(ev);
1772a46c0ec8Sopenharmony_ci			break;
1773a46c0ec8Sopenharmony_ci		case LIBINPUT_EVENT_POINTER_MOTION:
1774a46c0ec8Sopenharmony_ci			handle_event_motion(ev, w);
1775a46c0ec8Sopenharmony_ci			break;
1776a46c0ec8Sopenharmony_ci		case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
1777a46c0ec8Sopenharmony_ci			handle_event_absmotion(ev, w);
1778a46c0ec8Sopenharmony_ci			break;
1779a46c0ec8Sopenharmony_ci		case LIBINPUT_EVENT_TOUCH_DOWN:
1780a46c0ec8Sopenharmony_ci		case LIBINPUT_EVENT_TOUCH_MOTION:
1781a46c0ec8Sopenharmony_ci		case LIBINPUT_EVENT_TOUCH_UP:
1782a46c0ec8Sopenharmony_ci		case LIBINPUT_EVENT_TOUCH_CANCEL:
1783a46c0ec8Sopenharmony_ci			handle_event_touch(ev, w);
1784a46c0ec8Sopenharmony_ci			break;
1785a46c0ec8Sopenharmony_ci		case LIBINPUT_EVENT_TOUCH_FRAME:
1786a46c0ec8Sopenharmony_ci			break;
1787a46c0ec8Sopenharmony_ci		case LIBINPUT_EVENT_POINTER_AXIS:
1788a46c0ec8Sopenharmony_ci			/* ignore */
1789a46c0ec8Sopenharmony_ci			break;
1790a46c0ec8Sopenharmony_ci		case LIBINPUT_EVENT_POINTER_SCROLL_WHEEL:
1791a46c0ec8Sopenharmony_ci		case LIBINPUT_EVENT_POINTER_SCROLL_FINGER:
1792a46c0ec8Sopenharmony_ci		case LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS:
1793a46c0ec8Sopenharmony_ci			handle_event_axis(ev, w);
1794a46c0ec8Sopenharmony_ci			break;
1795a46c0ec8Sopenharmony_ci		case LIBINPUT_EVENT_POINTER_BUTTON:
1796a46c0ec8Sopenharmony_ci			handle_event_button(ev, w);
1797a46c0ec8Sopenharmony_ci			break;
1798a46c0ec8Sopenharmony_ci		case LIBINPUT_EVENT_KEYBOARD_KEY:
1799a46c0ec8Sopenharmony_ci			if (handle_event_keyboard(ev, w)) {
1800a46c0ec8Sopenharmony_ci				libinput_event_destroy(ev);
1801a46c0ec8Sopenharmony_ci				window_quit(w);
1802a46c0ec8Sopenharmony_ci				return FALSE;
1803a46c0ec8Sopenharmony_ci			}
1804a46c0ec8Sopenharmony_ci			break;
1805a46c0ec8Sopenharmony_ci		case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN:
1806a46c0ec8Sopenharmony_ci		case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE:
1807a46c0ec8Sopenharmony_ci		case LIBINPUT_EVENT_GESTURE_SWIPE_END:
1808a46c0ec8Sopenharmony_ci			handle_event_swipe(ev, w);
1809a46c0ec8Sopenharmony_ci			break;
1810a46c0ec8Sopenharmony_ci		case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN:
1811a46c0ec8Sopenharmony_ci		case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE:
1812a46c0ec8Sopenharmony_ci		case LIBINPUT_EVENT_GESTURE_PINCH_END:
1813a46c0ec8Sopenharmony_ci			handle_event_pinch(ev, w);
1814a46c0ec8Sopenharmony_ci			break;
1815a46c0ec8Sopenharmony_ci		case LIBINPUT_EVENT_GESTURE_HOLD_BEGIN:
1816a46c0ec8Sopenharmony_ci		case LIBINPUT_EVENT_GESTURE_HOLD_END:
1817a46c0ec8Sopenharmony_ci			handle_event_hold(ev, w);
1818a46c0ec8Sopenharmony_ci			break;
1819a46c0ec8Sopenharmony_ci		case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
1820a46c0ec8Sopenharmony_ci		case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY:
1821a46c0ec8Sopenharmony_ci		case LIBINPUT_EVENT_TABLET_TOOL_TIP:
1822a46c0ec8Sopenharmony_ci		case LIBINPUT_EVENT_TABLET_TOOL_BUTTON:
1823a46c0ec8Sopenharmony_ci			handle_event_tablet(ev, w);
1824a46c0ec8Sopenharmony_ci			break;
1825a46c0ec8Sopenharmony_ci		case LIBINPUT_EVENT_TABLET_PAD_BUTTON:
1826a46c0ec8Sopenharmony_ci		case LIBINPUT_EVENT_TABLET_PAD_RING:
1827a46c0ec8Sopenharmony_ci		case LIBINPUT_EVENT_TABLET_PAD_STRIP:
1828a46c0ec8Sopenharmony_ci			handle_event_tablet_pad(ev, w);
1829a46c0ec8Sopenharmony_ci			break;
1830a46c0ec8Sopenharmony_ci		case LIBINPUT_EVENT_TABLET_PAD_KEY:
1831a46c0ec8Sopenharmony_ci			break;
1832a46c0ec8Sopenharmony_ci		case LIBINPUT_EVENT_SWITCH_TOGGLE:
1833a46c0ec8Sopenharmony_ci			break;
1834a46c0ec8Sopenharmony_ci		}
1835a46c0ec8Sopenharmony_ci
1836a46c0ec8Sopenharmony_ci		libinput_event_destroy(ev);
1837a46c0ec8Sopenharmony_ci	}
1838a46c0ec8Sopenharmony_ci	gtk_widget_queue_draw(w->area);
1839a46c0ec8Sopenharmony_ci
1840a46c0ec8Sopenharmony_ci	return TRUE;
1841a46c0ec8Sopenharmony_ci}
1842a46c0ec8Sopenharmony_ci
1843a46c0ec8Sopenharmony_cistatic void
1844a46c0ec8Sopenharmony_cisockets_init(struct libinput *li)
1845a46c0ec8Sopenharmony_ci{
1846a46c0ec8Sopenharmony_ci	GIOChannel *c = g_io_channel_unix_new(libinput_get_fd(li));
1847a46c0ec8Sopenharmony_ci
1848a46c0ec8Sopenharmony_ci	g_io_channel_set_encoding(c, NULL, NULL);
1849a46c0ec8Sopenharmony_ci	g_io_add_watch(c, G_IO_IN, handle_event_libinput, li);
1850a46c0ec8Sopenharmony_ci}
1851a46c0ec8Sopenharmony_ci
1852a46c0ec8Sopenharmony_cistatic void
1853a46c0ec8Sopenharmony_ciusage(void) {
1854a46c0ec8Sopenharmony_ci	printf("Usage: libinput debug-gui [options] [--udev <seat>|[--device] /dev/input/event0]\n");
1855a46c0ec8Sopenharmony_ci}
1856a46c0ec8Sopenharmony_ci
1857a46c0ec8Sopenharmony_cistatic gboolean
1858a46c0ec8Sopenharmony_cisignal_handler(void *data)
1859a46c0ec8Sopenharmony_ci{
1860a46c0ec8Sopenharmony_ci	struct libinput *li = data;
1861a46c0ec8Sopenharmony_ci	struct window *w = libinput_get_user_data(li);
1862a46c0ec8Sopenharmony_ci
1863a46c0ec8Sopenharmony_ci	window_quit(w);
1864a46c0ec8Sopenharmony_ci
1865a46c0ec8Sopenharmony_ci	return FALSE;
1866a46c0ec8Sopenharmony_ci}
1867a46c0ec8Sopenharmony_ci
1868a46c0ec8Sopenharmony_ciint
1869a46c0ec8Sopenharmony_cimain(int argc, char **argv)
1870a46c0ec8Sopenharmony_ci{
1871a46c0ec8Sopenharmony_ci	struct window w = {0};
1872a46c0ec8Sopenharmony_ci	struct tools_options options;
1873a46c0ec8Sopenharmony_ci	struct libinput *li;
1874a46c0ec8Sopenharmony_ci	enum tools_backend backend = BACKEND_NONE;
1875a46c0ec8Sopenharmony_ci	const char *seat_or_device[2] = {"seat0", NULL};
1876a46c0ec8Sopenharmony_ci	bool verbose = false;
1877a46c0ec8Sopenharmony_ci	bool gtk_init = false;
1878a46c0ec8Sopenharmony_ci
1879a46c0ec8Sopenharmony_ci#if HAVE_GTK4
1880a46c0ec8Sopenharmony_ci	gtk_init = gtk_init_check();
1881a46c0ec8Sopenharmony_ci#else
1882a46c0ec8Sopenharmony_ci	gtk_init = gtk_init_check(&argc, &argv);
1883a46c0ec8Sopenharmony_ci#endif
1884a46c0ec8Sopenharmony_ci
1885a46c0ec8Sopenharmony_ci	if (!gtk_init)
1886a46c0ec8Sopenharmony_ci		return 77;
1887a46c0ec8Sopenharmony_ci
1888a46c0ec8Sopenharmony_ci	tools_init_options(&options);
1889a46c0ec8Sopenharmony_ci
1890a46c0ec8Sopenharmony_ci	while (1) {
1891a46c0ec8Sopenharmony_ci		int c;
1892a46c0ec8Sopenharmony_ci		int option_index = 0;
1893a46c0ec8Sopenharmony_ci		enum {
1894a46c0ec8Sopenharmony_ci			OPT_DEVICE = 1,
1895a46c0ec8Sopenharmony_ci			OPT_UDEV,
1896a46c0ec8Sopenharmony_ci			OPT_GRAB,
1897a46c0ec8Sopenharmony_ci			OPT_VERBOSE,
1898a46c0ec8Sopenharmony_ci		};
1899a46c0ec8Sopenharmony_ci		static struct option opts[] = {
1900a46c0ec8Sopenharmony_ci			CONFIGURATION_OPTIONS,
1901a46c0ec8Sopenharmony_ci			{ "help",                      no_argument,       0, 'h' },
1902a46c0ec8Sopenharmony_ci			{ "device",                    required_argument, 0, OPT_DEVICE },
1903a46c0ec8Sopenharmony_ci			{ "udev",                      required_argument, 0, OPT_UDEV },
1904a46c0ec8Sopenharmony_ci			{ "grab",                      no_argument,       0, OPT_GRAB },
1905a46c0ec8Sopenharmony_ci			{ "verbose",                   no_argument,       0, OPT_VERBOSE },
1906a46c0ec8Sopenharmony_ci			{ 0, 0, 0, 0}
1907a46c0ec8Sopenharmony_ci		};
1908a46c0ec8Sopenharmony_ci
1909a46c0ec8Sopenharmony_ci		c = getopt_long(argc, argv, "h", opts, &option_index);
1910a46c0ec8Sopenharmony_ci		if (c == -1)
1911a46c0ec8Sopenharmony_ci			break;
1912a46c0ec8Sopenharmony_ci
1913a46c0ec8Sopenharmony_ci		switch(c) {
1914a46c0ec8Sopenharmony_ci		case '?':
1915a46c0ec8Sopenharmony_ci			exit(EXIT_INVALID_USAGE);
1916a46c0ec8Sopenharmony_ci			break;
1917a46c0ec8Sopenharmony_ci		case 'h':
1918a46c0ec8Sopenharmony_ci			usage();
1919a46c0ec8Sopenharmony_ci			exit(0);
1920a46c0ec8Sopenharmony_ci			break;
1921a46c0ec8Sopenharmony_ci		case OPT_DEVICE:
1922a46c0ec8Sopenharmony_ci			backend = BACKEND_DEVICE;
1923a46c0ec8Sopenharmony_ci			seat_or_device[0] = optarg;
1924a46c0ec8Sopenharmony_ci			break;
1925a46c0ec8Sopenharmony_ci		case OPT_UDEV:
1926a46c0ec8Sopenharmony_ci			backend = BACKEND_UDEV;
1927a46c0ec8Sopenharmony_ci			seat_or_device[0] = optarg;
1928a46c0ec8Sopenharmony_ci			break;
1929a46c0ec8Sopenharmony_ci		case OPT_GRAB:
1930a46c0ec8Sopenharmony_ci			w.grab = true;
1931a46c0ec8Sopenharmony_ci			break;
1932a46c0ec8Sopenharmony_ci		case OPT_VERBOSE:
1933a46c0ec8Sopenharmony_ci			verbose = true;
1934a46c0ec8Sopenharmony_ci			break;
1935a46c0ec8Sopenharmony_ci		default:
1936a46c0ec8Sopenharmony_ci			if (tools_parse_option(c, optarg, &options) != 0) {
1937a46c0ec8Sopenharmony_ci				usage();
1938a46c0ec8Sopenharmony_ci				return EXIT_INVALID_USAGE;
1939a46c0ec8Sopenharmony_ci			}
1940a46c0ec8Sopenharmony_ci			break;
1941a46c0ec8Sopenharmony_ci		}
1942a46c0ec8Sopenharmony_ci
1943a46c0ec8Sopenharmony_ci	}
1944a46c0ec8Sopenharmony_ci
1945a46c0ec8Sopenharmony_ci	if (optind < argc) {
1946a46c0ec8Sopenharmony_ci		if (optind < argc - 1 || backend != BACKEND_NONE) {
1947a46c0ec8Sopenharmony_ci			usage();
1948a46c0ec8Sopenharmony_ci			return EXIT_INVALID_USAGE;
1949a46c0ec8Sopenharmony_ci		}
1950a46c0ec8Sopenharmony_ci		backend = BACKEND_DEVICE;
1951a46c0ec8Sopenharmony_ci		seat_or_device[0] = argv[optind];
1952a46c0ec8Sopenharmony_ci	} else if (backend == BACKEND_NONE) {
1953a46c0ec8Sopenharmony_ci		backend = BACKEND_UDEV;
1954a46c0ec8Sopenharmony_ci	}
1955a46c0ec8Sopenharmony_ci
1956a46c0ec8Sopenharmony_ci	li = tools_open_backend(backend, seat_or_device, verbose, &w.grab);
1957a46c0ec8Sopenharmony_ci	if (!li)
1958a46c0ec8Sopenharmony_ci		return EXIT_FAILURE;
1959a46c0ec8Sopenharmony_ci
1960a46c0ec8Sopenharmony_ci	libinput_set_user_data(li, &w);
1961a46c0ec8Sopenharmony_ci
1962a46c0ec8Sopenharmony_ci	g_unix_signal_add(SIGINT, signal_handler, li);
1963a46c0ec8Sopenharmony_ci
1964a46c0ec8Sopenharmony_ci	window_init(&w);
1965a46c0ec8Sopenharmony_ci	w.options = options;
1966a46c0ec8Sopenharmony_ci	sockets_init(li);
1967a46c0ec8Sopenharmony_ci	handle_event_libinput(NULL, 0, li);
1968a46c0ec8Sopenharmony_ci
1969a46c0ec8Sopenharmony_ci	w.event_loop = g_main_loop_new(NULL, FALSE);
1970a46c0ec8Sopenharmony_ci	g_main_loop_run(w.event_loop);
1971a46c0ec8Sopenharmony_ci
1972a46c0ec8Sopenharmony_ci	window_unlock_pointer(&w);
1973a46c0ec8Sopenharmony_ci	window_cleanup(&w);
1974a46c0ec8Sopenharmony_ci	libinput_unref(li);
1975a46c0ec8Sopenharmony_ci
1976a46c0ec8Sopenharmony_ci	return EXIT_SUCCESS;
1977a46c0ec8Sopenharmony_ci}
1978