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