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 <cairo.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <getopt.h>
31 #include <math.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <stdarg.h>
35 #include <string.h>
36 #include <unistd.h>
37 
38 #include <gtk/gtk.h>
39 #include <glib.h>
40 
41 #include <libinput.h>
42 #include <libinput-util.h>
43 
44 #include "shared.h"
45 
46 #define clip(val_, min_, max_) min((max_), max((min_), (val_)))
47 
48 struct touch {
49 	int active;
50 	int x, y;
51 };
52 
53 struct point {
54 	double x, y;
55 };
56 
57 struct window {
58 	bool grab;
59 	struct tools_options options;
60 
61 	GtkWidget *win;
62 	GtkWidget *area;
63 	int width, height; /* of window */
64 
65 	/* sprite position */
66 	double x, y;
67 
68 	/* these are for the delta coordinates, but they're not
69 	 * deltas, they are converted into abs positions */
70 	size_t ndeltas;
71 	struct point deltas[64];
72 
73 	/* abs position */
74 	int absx, absy;
75 
76 	/* scroll bar positions */
77 	double vx, vy;
78 	double hx, hy;
79 
80 	/* touch positions */
81 	struct touch touches[32];
82 
83 	/* l/m/r mouse buttons */
84 	int l, m, r;
85 
86 	/* touchpad swipe */
87 	struct {
88 		int nfingers;
89 		double x, y;
90 	} swipe;
91 
92 	struct {
93 		int nfingers;
94 		double scale;
95 		double angle;
96 		double x, y;
97 	} pinch;
98 
99 	struct {
100 		double x, y;
101 		double x_in, y_in;
102 		double x_down, y_down;
103 		double x_up, y_up;
104 		double pressure;
105 		double distance;
106 		double tilt_x, tilt_y;
107 
108 		/* these are for the delta coordinates, but they're not
109 		 * deltas, they are converted into abs positions */
110 		size_t ndeltas;
111 		struct point deltas[64];
112 	} tool;
113 
114 	struct libinput_device *devices[50];
115 };
116 
117 LIBINPUT_ATTRIBUTE_PRINTF(1, 2)
118 static inline void
msg(const char * fmt,...)119 msg(const char *fmt, ...)
120 {
121 	va_list args;
122 	printf("info: ");
123 
124 	va_start(args, fmt);
125 	vprintf(fmt, args);
126 	va_end(args);
127 }
128 
129 static inline void
draw_gestures(struct window * w,cairo_t * cr)130 draw_gestures(struct window *w, cairo_t *cr)
131 {
132 	int i;
133 	int offset;
134 
135 	/* swipe */
136 	cairo_save(cr);
137 	cairo_translate(cr, w->swipe.x, w->swipe.y);
138 	for (i = 0; i < w->swipe.nfingers; i++) {
139 		cairo_set_source_rgb(cr, .8, .8, .4);
140 		cairo_arc(cr, (i - 2) * 40, 0, 20, 0, 2 * M_PI);
141 		cairo_fill(cr);
142 	}
143 
144 	for (i = 0; i < 4; i++) { /* 4 fg max */
145 		cairo_set_source_rgb(cr, 0, 0, 0);
146 		cairo_arc(cr, (i - 2) * 40, 0, 20, 0, 2 * M_PI);
147 		cairo_stroke(cr);
148 	}
149 	cairo_restore(cr);
150 
151 	/* pinch */
152 	cairo_save(cr);
153 	offset = w->pinch.scale * 100;
154 	cairo_translate(cr, w->pinch.x, w->pinch.y);
155 	cairo_rotate(cr, w->pinch.angle * M_PI/180.0);
156 	if (w->pinch.nfingers > 0) {
157 		cairo_set_source_rgb(cr, .4, .4, .8);
158 		cairo_arc(cr, offset, -offset, 20, 0, 2 * M_PI);
159 		cairo_arc(cr, -offset, offset, 20, 0, 2 * M_PI);
160 		cairo_fill(cr);
161 	}
162 
163 	cairo_set_source_rgb(cr, 0, 0, 0);
164 	cairo_arc(cr, offset, -offset, 20, 0, 2 * M_PI);
165 	cairo_stroke(cr);
166 	cairo_arc(cr, -offset, offset, 20, 0, 2 * M_PI);
167 	cairo_stroke(cr);
168 
169 	cairo_restore(cr);
170 
171 }
172 
173 static inline void
draw_scrollbars(struct window * w,cairo_t * cr)174 draw_scrollbars(struct window *w, cairo_t *cr)
175 {
176 	cairo_set_source_rgb(cr, .4, .8, 0);
177 
178 	cairo_save(cr);
179 	cairo_rectangle(cr, w->vx - 10, w->vy - 20, 20, 40);
180 	cairo_rectangle(cr, w->hx - 20, w->hy - 10, 40, 20);
181 	cairo_fill(cr);
182 	cairo_restore(cr);
183 }
184 
185 static inline void
draw_touchpoints(struct window * w,cairo_t * cr)186 draw_touchpoints(struct window *w, cairo_t *cr)
187 {
188 	struct touch *t;
189 
190 	cairo_set_source_rgb(cr, .8, .2, .2);
191 
192 	ARRAY_FOR_EACH(w->touches, t) {
193 		cairo_save(cr);
194 		cairo_arc(cr, t->x, t->y, 10, 0, 2 * M_PI);
195 		cairo_fill(cr);
196 		cairo_restore(cr);
197 	}
198 }
199 
200 static inline void
draw_abs_pointer(struct window * w,cairo_t * cr)201 draw_abs_pointer(struct window *w, cairo_t *cr)
202 {
203 	cairo_set_source_rgb(cr, .2, .4, .8);
204 
205 	cairo_save(cr);
206 	cairo_arc(cr, w->absx, w->absy, 10, 0, 2 * M_PI);
207 	cairo_fill(cr);
208 	cairo_restore(cr);
209 }
210 
211 static inline void
draw_buttons(struct window * w,cairo_t * cr)212 draw_buttons(struct window *w, cairo_t *cr)
213 {
214 	cairo_save(cr);
215 	if (w->l || w->m || w->r) {
216 		cairo_set_source_rgb(cr, .2, .8, .8);
217 		if (w->l)
218 			cairo_rectangle(cr, w->width/2 - 100, w->height - 200, 70, 30);
219 		if (w->m)
220 			cairo_rectangle(cr, w->width/2 - 20, w->height - 200, 40, 30);
221 		if (w->r)
222 			cairo_rectangle(cr, w->width/2 + 30, w->height - 200, 70, 30);
223 		cairo_fill(cr);
224 	}
225 
226 	cairo_set_source_rgb(cr, 0, 0, 0);
227 	cairo_rectangle(cr, w->width/2 - 100, w->height - 200, 70, 30);
228 	cairo_rectangle(cr, w->width/2 - 20, w->height - 200, 40, 30);
229 	cairo_rectangle(cr, w->width/2 + 30, w->height - 200, 70, 30);
230 	cairo_stroke(cr);
231 	cairo_restore(cr);
232 }
233 
234 static inline void
draw_tablet(struct window * w,cairo_t * cr)235 draw_tablet(struct window *w, cairo_t *cr)
236 {
237 	double x, y;
238 	int first, last;
239 	size_t mask;
240 	int i;
241 
242 	/* tablet tool, square for prox-in location */
243 	cairo_save(cr);
244 	cairo_set_source_rgb(cr, .8, .8, .8);
245 	if (w->tool.x_in && w->tool.y_in) {
246 		cairo_rectangle(cr, w->tool.x_in - 15, w->tool.y_in - 15, 30, 30);
247 		cairo_stroke(cr);
248 		cairo_restore(cr);
249 		cairo_save(cr);
250 	}
251 
252 	if (w->tool.x_down && w->tool.y_down) {
253 		cairo_rectangle(cr, w->tool.x_down - 10, w->tool.y_down - 10, 20, 20);
254 		cairo_stroke(cr);
255 		cairo_restore(cr);
256 		cairo_save(cr);
257 	}
258 
259 	if (w->tool.x_up && w->tool.y_up) {
260 		cairo_rectangle(cr, w->tool.x_up - 10, w->tool.y_up - 10, 20, 20);
261 		cairo_stroke(cr);
262 		cairo_restore(cr);
263 		cairo_save(cr);
264 	}
265 
266 	if (w->tool.pressure)
267 		cairo_set_source_rgb(cr, .8, .8, .2);
268 
269 	cairo_translate(cr, w->tool.x, w->tool.y);
270 	cairo_scale(cr, 1.0 + w->tool.tilt_x/30.0, 1.0 + w->tool.tilt_y/30.0);
271 	cairo_arc(cr, 0, 0,
272 		  1 + 10 * max(w->tool.pressure, w->tool.distance),
273 		  0, 2 * M_PI);
274 	cairo_fill(cr);
275 	cairo_restore(cr);
276 
277 	/* pointer deltas */
278 	mask = ARRAY_LENGTH(w->deltas);
279 	first = max(w->ndeltas + 1, mask) - mask;
280 	last = w->ndeltas;
281 
282 	cairo_save(cr);
283 	cairo_set_source_rgb(cr, .8, .5, .2);
284 
285 	x = w->deltas[first % mask].x;
286 	y = w->deltas[first % mask].y;
287 	cairo_move_to(cr, x, y);
288 
289 	for (i = first + 1; i < last; i++) {
290 		x = w->deltas[i % mask].x;
291 		y = w->deltas[i % mask].y;
292 		cairo_line_to(cr, x, y);
293 	}
294 
295 	cairo_stroke(cr);
296 
297 	/* tablet deltas */
298 	mask = ARRAY_LENGTH(w->tool.deltas);
299 	first = max(w->tool.ndeltas + 1, mask) - mask;
300 	last = w->tool.ndeltas;
301 
302 	cairo_save(cr);
303 	cairo_set_source_rgb(cr, .8, .8, .2);
304 
305 	x = w->tool.deltas[first % mask].x;
306 	y = w->tool.deltas[first % mask].y;
307 	cairo_move_to(cr, x, y);
308 
309 	for (i = first + 1; i < last; i++) {
310 		x = w->tool.deltas[i % mask].x;
311 		y = w->tool.deltas[i % mask].y;
312 		cairo_line_to(cr, x, y);
313 	}
314 
315 	cairo_stroke(cr);
316 
317 }
318 
319 static inline void
draw_pointer(struct window * w,cairo_t * cr)320 draw_pointer(struct window *w, cairo_t *cr)
321 {
322 	/* draw pointer sprite */
323 	cairo_set_source_rgb(cr, 0, 0, 0);
324 	cairo_save(cr);
325 	cairo_move_to(cr, w->x, w->y);
326 	cairo_rel_line_to(cr, 10, 15);
327 	cairo_rel_line_to(cr, -10, 0);
328 	cairo_rel_line_to(cr, 0, -15);
329 	cairo_fill(cr);
330 	cairo_restore(cr);
331 }
332 
333 static inline void
draw_background(struct window * w,cairo_t * cr)334 draw_background(struct window *w, cairo_t *cr)
335 {
336 	int x1, x2, y1, y2, x3, y3, x4, y4;
337 	int cols;
338 
339 	/* 10px and 5px grids */
340 	cairo_save(cr);
341 	cairo_set_source_rgb(cr, 0.8, 0.8, 0.8);
342 	x1 = w->width/2 - 200;
343 	y1 = w->height/2 - 200;
344 	x2 = w->width/2 + 200;
345 	y2 = w->height/2 - 200;
346 	for (cols = 1; cols < 10; cols++) {
347 		cairo_move_to(cr, x1 + 10 * cols, y1);
348 		cairo_rel_line_to(cr, 0, 100);
349 		cairo_move_to(cr, x1, y1 + 10 * cols);
350 		cairo_rel_line_to(cr, 100, 0);
351 
352 		cairo_move_to(cr, x2 + 5 * cols, y2);
353 		cairo_rel_line_to(cr, 0, 50);
354 		cairo_move_to(cr, x2, y2 + 5 * cols);
355 		cairo_rel_line_to(cr, 50, 0);
356 	}
357 
358 	/* 3px horiz/vert bar codes */
359 	x3 = w->width/2 - 200;
360 	y3 = w->height/2 + 200;
361 	x4 = w->width/2 + 200;
362 	y4 = w->height/2 + 100;
363 	for (cols = 0; cols < 50; cols++) {
364 		cairo_move_to(cr, x3 + 3 * cols, y3);
365 		cairo_rel_line_to(cr, 0, 20);
366 
367 		cairo_move_to(cr, x4, y4 + 3 * cols);
368 		cairo_rel_line_to(cr, 20, 0);
369 	}
370 	cairo_stroke(cr);
371 
372 	/* round targets */
373 	for (int i = 0; i <= 3; i++) {
374 		x1 = w->width * i/4.0;
375 		x2 = w->width * i/4.0;
376 
377 		y1 = w->height * 1.0/4.0;
378 		y2 = w->height * 3.0/4.0;
379 
380 		cairo_arc(cr, x1, y1, 10, 0, 2 * M_PI);
381 		cairo_stroke(cr);
382 		cairo_arc(cr, x2, y2, 10, 0, 2 * M_PI);
383 		cairo_stroke(cr);
384 	}
385 
386 }
387 
388 static gboolean
draw(GtkWidget * widget,cairo_t * cr,gpointer data)389 draw(GtkWidget *widget, cairo_t *cr, gpointer data)
390 {
391 	struct window *w = data;
392 
393 	cairo_set_source_rgb(cr, 1, 1, 1);
394 	cairo_rectangle(cr, 0, 0, w->width, w->height);
395 	cairo_fill(cr);
396 
397 	draw_background(w, cr);
398 
399 	draw_gestures(w, cr);
400 	draw_scrollbars(w, cr);
401 	draw_touchpoints(w, cr);
402 	draw_abs_pointer(w, cr);
403 	draw_buttons(w, cr);
404 	draw_tablet(w, cr);
405 	draw_pointer(w, cr);
406 
407 	return TRUE;
408 }
409 
410 static void
map_event_cb(GtkWidget * widget,GdkEvent * event,gpointer data)411 map_event_cb(GtkWidget *widget, GdkEvent *event, gpointer data)
412 {
413 	struct window *w = data;
414 	GdkDisplay *display;
415 	GdkSeat *seat;
416 	GdkWindow *window;
417 
418 	gtk_window_get_size(GTK_WINDOW(widget), &w->width, &w->height);
419 
420 	w->x = w->width/2;
421 	w->y = w->height/2;
422 
423 	w->vx = w->width/2;
424 	w->vy = w->height/2;
425 	w->hx = w->width/2;
426 	w->hy = w->height/2;
427 
428 	w->swipe.x = w->width/2;
429 	w->swipe.y = w->height/2;
430 
431 	w->pinch.scale = 1.0;
432 	w->pinch.x = w->width/2;
433 	w->pinch.y = w->height/2;
434 
435 	g_signal_connect(G_OBJECT(w->area), "draw", G_CALLBACK(draw), w);
436 
437 	window = gdk_event_get_window(event);
438 	display = gdk_window_get_display(window);
439 
440 	gdk_window_set_cursor(gtk_widget_get_window(w->win),
441 			      gdk_cursor_new_for_display(display,
442 							 GDK_BLANK_CURSOR));
443 
444 	seat = gdk_display_get_default_seat(display);
445 	gdk_seat_grab(seat,
446 		      window,
447 		      GDK_SEAT_CAPABILITY_ALL_POINTING,
448 		      FALSE, /* owner-events */
449 		      NULL, /* cursor */
450 		      NULL, /* triggering event */
451 		      NULL, /* prepare_func */
452 		      NULL /* prepare_func_data */
453 		     );
454 }
455 
456 static void
window_init(struct window * w)457 window_init(struct window *w)
458 {
459 	w->win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
460 	gtk_widget_set_events(w->win, 0);
461 	gtk_window_set_title(GTK_WINDOW(w->win), "libinput debugging tool");
462 	gtk_window_set_default_size(GTK_WINDOW(w->win), 1024, 768);
463 	gtk_window_maximize(GTK_WINDOW(w->win));
464 	gtk_window_set_resizable(GTK_WINDOW(w->win), TRUE);
465 	gtk_widget_realize(w->win);
466 	g_signal_connect(G_OBJECT(w->win), "map-event", G_CALLBACK(map_event_cb), w);
467 	g_signal_connect(G_OBJECT(w->win), "delete-event", G_CALLBACK(gtk_main_quit), NULL);
468 
469 	w->area = gtk_drawing_area_new();
470 	gtk_widget_set_events(w->area, 0);
471 	gtk_container_add(GTK_CONTAINER(w->win), w->area);
472 	gtk_widget_show_all(w->win);
473 }
474 
475 static void
window_cleanup(struct window * w)476 window_cleanup(struct window *w)
477 {
478 	struct libinput_device **dev;
479 	ARRAY_FOR_EACH(w->devices, dev) {
480 		if (*dev)
481 			libinput_device_unref(*dev);
482 	}
483 }
484 
485 static void
change_ptraccel(struct window * w,double amount)486 change_ptraccel(struct window *w, double amount)
487 {
488 	struct libinput_device **dev;
489 
490 	ARRAY_FOR_EACH(w->devices, dev) {
491 		double speed;
492 		enum libinput_config_status status;
493 
494 		if (*dev == NULL)
495 			continue;
496 
497 		if (!libinput_device_config_accel_is_available(*dev))
498 			continue;
499 
500 		speed = libinput_device_config_accel_get_speed(*dev);
501 		speed = clip(speed + amount, -1, 1);
502 
503 		status = libinput_device_config_accel_set_speed(*dev, speed);
504 
505 		if (status != LIBINPUT_CONFIG_STATUS_SUCCESS) {
506 			msg("%s: failed to change accel to %.2f (%s)\n",
507 			    libinput_device_get_name(*dev),
508 			    speed,
509 			    libinput_config_status_to_str(status));
510 		} else {
511 			printf("%s: speed is %.2f\n",
512 			       libinput_device_get_name(*dev),
513 			       speed);
514 		}
515 
516 	}
517 }
518 
519 static void
handle_event_device_notify(struct libinput_event * ev)520 handle_event_device_notify(struct libinput_event *ev)
521 {
522 	struct libinput_device *dev = libinput_event_get_device(ev);
523 	struct libinput *li;
524 	struct window *w;
525 	const char *type;
526 	size_t i;
527 
528 	if (libinput_event_get_type(ev) == LIBINPUT_EVENT_DEVICE_ADDED)
529 		type = "added";
530 	else
531 		type = "removed";
532 
533 	msg("%s %-30s %s\n",
534 	    libinput_device_get_sysname(dev),
535 	    libinput_device_get_name(dev),
536 	    type);
537 
538 	li = libinput_event_get_context(ev);
539 	w = libinput_get_user_data(li);
540 
541 	tools_device_apply_config(libinput_event_get_device(ev),
542 				  &w->options);
543 
544 	if (libinput_event_get_type(ev) == LIBINPUT_EVENT_DEVICE_ADDED) {
545 		for (i = 0; i < ARRAY_LENGTH(w->devices); i++) {
546 			if (w->devices[i] == NULL) {
547 				w->devices[i] = libinput_device_ref(dev);
548 				break;
549 			}
550 		}
551 	} else  {
552 		for (i = 0; i < ARRAY_LENGTH(w->devices); i++) {
553 			if (w->devices[i] == dev) {
554 				libinput_device_unref(w->devices[i]);
555 				w->devices[i] = NULL;
556 				break;
557 			}
558 		}
559 	}
560 }
561 
562 static void
handle_event_motion(struct libinput_event * ev,struct window * w)563 handle_event_motion(struct libinput_event *ev, struct window *w)
564 {
565 	struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev);
566 	double dx = libinput_event_pointer_get_dx(p),
567 	       dy = libinput_event_pointer_get_dy(p);
568 	struct point point;
569 	const int mask = ARRAY_LENGTH(w->deltas);
570 	size_t idx;
571 
572 	w->x += dx;
573 	w->y += dy;
574 	w->x = clip(w->x, 0.0, w->width);
575 	w->y = clip(w->y, 0.0, w->height);
576 
577 	idx = w->ndeltas % mask;
578 	point = w->deltas[idx];
579 	idx = (w->ndeltas + 1) % mask;
580 	point.x += libinput_event_pointer_get_dx_unaccelerated(p);
581 	point.y += libinput_event_pointer_get_dy_unaccelerated(p);
582 	w->deltas[idx] = point;
583 	w->ndeltas++;
584 }
585 
586 static void
handle_event_absmotion(struct libinput_event * ev,struct window * w)587 handle_event_absmotion(struct libinput_event *ev, struct window *w)
588 {
589 	struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev);
590 	double x = libinput_event_pointer_get_absolute_x_transformed(p, w->width),
591 	       y = libinput_event_pointer_get_absolute_y_transformed(p, w->height);
592 
593 	w->absx = x;
594 	w->absy = y;
595 }
596 
597 static void
handle_event_touch(struct libinput_event * ev,struct window * w)598 handle_event_touch(struct libinput_event *ev, struct window *w)
599 {
600 	struct libinput_event_touch *t = libinput_event_get_touch_event(ev);
601 	int slot = libinput_event_touch_get_seat_slot(t);
602 	struct touch *touch;
603 	double x, y;
604 
605 	if (slot == -1 || slot >= (int) ARRAY_LENGTH(w->touches))
606 		return;
607 
608 	touch = &w->touches[slot];
609 
610 	if (libinput_event_get_type(ev) == LIBINPUT_EVENT_TOUCH_UP) {
611 		touch->active = 0;
612 		return;
613 	}
614 
615 	x = libinput_event_touch_get_x_transformed(t, w->width),
616 	y = libinput_event_touch_get_y_transformed(t, w->height);
617 
618 	touch->active = 1;
619 	touch->x = (int)x;
620 	touch->y = (int)y;
621 }
622 
623 static void
handle_event_axis(struct libinput_event * ev,struct window * w)624 handle_event_axis(struct libinput_event *ev, struct window *w)
625 {
626 	struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev);
627 	double value;
628 
629 	if (libinput_event_pointer_has_axis(p,
630 			LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL)) {
631 		value = libinput_event_pointer_get_axis_value(p,
632 				LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
633 		w->vy += value;
634 		w->vy = clip(w->vy, 0, w->height);
635 	}
636 
637 	if (libinput_event_pointer_has_axis(p,
638 			LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL)) {
639 		value = libinput_event_pointer_get_axis_value(p,
640 				LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
641 		w->hx += value;
642 		w->hx = clip(w->hx, 0, w->width);
643 	}
644 }
645 
646 static int
handle_event_keyboard(struct libinput_event * ev,struct window * w)647 handle_event_keyboard(struct libinput_event *ev, struct window *w)
648 {
649 	struct libinput_event_keyboard *k = libinput_event_get_keyboard_event(ev);
650 	unsigned int key = libinput_event_keyboard_get_key(k);
651 
652 	if (libinput_event_keyboard_get_key_state(k) ==
653 	    LIBINPUT_KEY_STATE_RELEASED)
654 		return 0;
655 
656 	switch(key) {
657 	case KEY_ESC:
658 		return 1;
659 	case KEY_UP:
660 		change_ptraccel(w, 0.1);
661 		break;
662 	case KEY_DOWN:
663 		change_ptraccel(w, -0.1);
664 		break;
665 	default:
666 		break;
667 	}
668 
669 	return 0;
670 }
671 
672 static void
handle_event_button(struct libinput_event * ev,struct window * w)673 handle_event_button(struct libinput_event *ev, struct window *w)
674 {
675 	struct libinput_event_pointer *p = libinput_event_get_pointer_event(ev);
676 	unsigned int button = libinput_event_pointer_get_button(p);
677 	int is_press;
678 
679 	is_press = libinput_event_pointer_get_button_state(p) == LIBINPUT_BUTTON_STATE_PRESSED;
680 
681 	switch (button) {
682 	case BTN_LEFT:
683 		w->l = is_press;
684 		break;
685 	case BTN_RIGHT:
686 		w->r = is_press;
687 		break;
688 	case BTN_MIDDLE:
689 		w->m = is_press;
690 		break;
691 	}
692 
693 }
694 
695 static void
handle_event_swipe(struct libinput_event * ev,struct window * w)696 handle_event_swipe(struct libinput_event *ev, struct window *w)
697 {
698 	struct libinput_event_gesture *g = libinput_event_get_gesture_event(ev);
699 	int nfingers;
700 	double dx, dy;
701 
702 	nfingers = libinput_event_gesture_get_finger_count(g);
703 
704 	switch (libinput_event_get_type(ev)) {
705 	case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN:
706 		w->swipe.nfingers = nfingers;
707 		w->swipe.x = w->width/2;
708 		w->swipe.y = w->height/2;
709 		break;
710 	case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE:
711 		dx = libinput_event_gesture_get_dx(g);
712 		dy = libinput_event_gesture_get_dy(g);
713 		w->swipe.x += dx;
714 		w->swipe.y += dy;
715 		break;
716 	case LIBINPUT_EVENT_GESTURE_SWIPE_END:
717 		w->swipe.nfingers = 0;
718 		w->swipe.x = w->width/2;
719 		w->swipe.y = w->height/2;
720 		break;
721 	default:
722 		abort();
723 	}
724 }
725 
726 static void
handle_event_pinch(struct libinput_event * ev,struct window * w)727 handle_event_pinch(struct libinput_event *ev, struct window *w)
728 {
729 	struct libinput_event_gesture *g = libinput_event_get_gesture_event(ev);
730 	int nfingers;
731 	double dx, dy;
732 
733 	nfingers = libinput_event_gesture_get_finger_count(g);
734 
735 	switch (libinput_event_get_type(ev)) {
736 	case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN:
737 		w->pinch.nfingers = nfingers;
738 		w->pinch.x = w->width/2;
739 		w->pinch.y = w->height/2;
740 		break;
741 	case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE:
742 		dx = libinput_event_gesture_get_dx(g);
743 		dy = libinput_event_gesture_get_dy(g);
744 		w->pinch.x += dx;
745 		w->pinch.y += dy;
746 		w->pinch.scale = libinput_event_gesture_get_scale(g);
747 		w->pinch.angle += libinput_event_gesture_get_angle_delta(g);
748 		break;
749 	case LIBINPUT_EVENT_GESTURE_PINCH_END:
750 		w->pinch.nfingers = 0;
751 		w->pinch.x = w->width/2;
752 		w->pinch.y = w->height/2;
753 		w->pinch.angle = 0.0;
754 		w->pinch.scale = 1.0;
755 		break;
756 	default:
757 		abort();
758 	}
759 }
760 
761 static void
handle_event_tablet(struct libinput_event * ev,struct window * w)762 handle_event_tablet(struct libinput_event *ev, struct window *w)
763 {
764 	struct libinput_event_tablet_tool *t = libinput_event_get_tablet_tool_event(ev);
765 	double x, y;
766 	struct point point;
767 	int idx;
768 	const int mask = ARRAY_LENGTH(w->tool.deltas);
769 
770 	x = libinput_event_tablet_tool_get_x_transformed(t, w->width);
771 	y = libinput_event_tablet_tool_get_y_transformed(t, w->height);
772 
773 	switch (libinput_event_get_type(ev)) {
774 	case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY:
775 		if (libinput_event_tablet_tool_get_proximity_state(t) ==
776 		    LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT) {
777 			w->tool.x_in = 0;
778 			w->tool.y_in = 0;
779 			w->tool.x_down = 0;
780 			w->tool.y_down = 0;
781 			w->tool.x_up = 0;
782 			w->tool.y_up = 0;
783 		} else {
784 			w->tool.x_in = x;
785 			w->tool.y_in = y;
786 			w->tool.ndeltas = 0;
787 			w->tool.deltas[0].x = w->width/2;
788 			w->tool.deltas[0].y = w->height/2;
789 		}
790 		break;
791 	case LIBINPUT_EVENT_TABLET_TOOL_TIP:
792 		w->tool.pressure = libinput_event_tablet_tool_get_pressure(t);
793 		w->tool.distance = libinput_event_tablet_tool_get_distance(t);
794 		w->tool.tilt_x = libinput_event_tablet_tool_get_tilt_x(t);
795 		w->tool.tilt_y = libinput_event_tablet_tool_get_tilt_y(t);
796 		if (libinput_event_tablet_tool_get_tip_state(t) ==
797 		    LIBINPUT_TABLET_TOOL_TIP_DOWN) {
798 			w->tool.x_down = x;
799 			w->tool.y_down = y;
800 		} else {
801 			w->tool.x_up = x;
802 			w->tool.y_up = y;
803 		}
804 		/* fallthrough */
805 	case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
806 		w->tool.x = x;
807 		w->tool.y = y;
808 		w->tool.pressure = libinput_event_tablet_tool_get_pressure(t);
809 		w->tool.distance = libinput_event_tablet_tool_get_distance(t);
810 		w->tool.tilt_x = libinput_event_tablet_tool_get_tilt_x(t);
811 		w->tool.tilt_y = libinput_event_tablet_tool_get_tilt_y(t);
812 
813 		/* Add the delta to the last position and store them as abs
814 		 * coordinates */
815 		idx = w->tool.ndeltas % mask;
816 		point = w->tool.deltas[idx];
817 
818 		idx = (w->tool.ndeltas + 1) % mask;
819 		point.x += libinput_event_tablet_tool_get_dx(t);
820 		point.y += libinput_event_tablet_tool_get_dy(t);
821 		w->tool.deltas[idx] = point;
822 		w->tool.ndeltas++;
823 		break;
824 	case LIBINPUT_EVENT_TABLET_TOOL_BUTTON:
825 		break;
826 	default:
827 		abort();
828 	}
829 }
830 
831 static gboolean
handle_event_libinput(GIOChannel * source,GIOCondition condition,gpointer data)832 handle_event_libinput(GIOChannel *source, GIOCondition condition, gpointer data)
833 {
834 	struct libinput *li = data;
835 	struct window *w = libinput_get_user_data(li);
836 	struct libinput_event *ev;
837 
838 	libinput_dispatch(li);
839 
840 	while ((ev = libinput_get_event(li))) {
841 		switch (libinput_event_get_type(ev)) {
842 		case LIBINPUT_EVENT_NONE:
843 			abort();
844 		case LIBINPUT_EVENT_DEVICE_ADDED:
845 		case LIBINPUT_EVENT_DEVICE_REMOVED:
846 			handle_event_device_notify(ev);
847 			break;
848 		case LIBINPUT_EVENT_POINTER_MOTION:
849 			handle_event_motion(ev, w);
850 			break;
851 		case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
852 			handle_event_absmotion(ev, w);
853 			break;
854 		case LIBINPUT_EVENT_TOUCH_DOWN:
855 		case LIBINPUT_EVENT_TOUCH_MOTION:
856 		case LIBINPUT_EVENT_TOUCH_UP:
857 			handle_event_touch(ev, w);
858 			break;
859 		case LIBINPUT_EVENT_POINTER_AXIS:
860 			handle_event_axis(ev, w);
861 			break;
862 		case LIBINPUT_EVENT_TOUCH_CANCEL:
863 		case LIBINPUT_EVENT_TOUCH_FRAME:
864 			break;
865 		case LIBINPUT_EVENT_POINTER_BUTTON:
866 			handle_event_button(ev, w);
867 			break;
868 		case LIBINPUT_EVENT_KEYBOARD_KEY:
869 			if (handle_event_keyboard(ev, w)) {
870 				libinput_event_destroy(ev);
871 				gtk_main_quit();
872 				return FALSE;
873 			}
874 			break;
875 		case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN:
876 		case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE:
877 		case LIBINPUT_EVENT_GESTURE_SWIPE_END:
878 			handle_event_swipe(ev, w);
879 			break;
880 		case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN:
881 		case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE:
882 		case LIBINPUT_EVENT_GESTURE_PINCH_END:
883 			handle_event_pinch(ev, w);
884 			break;
885 		case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
886 		case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY:
887 		case LIBINPUT_EVENT_TABLET_TOOL_TIP:
888 		case LIBINPUT_EVENT_TABLET_TOOL_BUTTON:
889 			handle_event_tablet(ev, w);
890 			break;
891 		case LIBINPUT_EVENT_TABLET_PAD_BUTTON:
892 		case LIBINPUT_EVENT_TABLET_PAD_RING:
893 		case LIBINPUT_EVENT_TABLET_PAD_STRIP:
894 			break;
895 		case LIBINPUT_EVENT_SWITCH_TOGGLE:
896 			break;
897 		}
898 
899 		libinput_event_destroy(ev);
900 		libinput_dispatch(li);
901 	}
902 	gtk_widget_queue_draw(w->area);
903 
904 	return TRUE;
905 }
906 
907 static void
sockets_init(struct libinput * li)908 sockets_init(struct libinput *li)
909 {
910 	GIOChannel *c = g_io_channel_unix_new(libinput_get_fd(li));
911 
912 	g_io_channel_set_encoding(c, NULL, NULL);
913 	g_io_add_watch(c, G_IO_IN, handle_event_libinput, li);
914 }
915 
916 static void
usage(void)917 usage(void) {
918 	printf("Usage: libinput debug-gui [options] [--udev <seat>|--device /dev/input/event0]\n");
919 }
920 
921 int
main(int argc,char ** argv)922 main(int argc, char **argv)
923 {
924 	struct window w = {0};
925 	struct tools_options options;
926 	struct libinput *li;
927 	enum tools_backend backend = BACKEND_UDEV;
928 	const char *seat_or_device = "seat0";
929 	bool verbose = false;
930 
931 	gtk_init(&argc, &argv);
932 
933 	tools_init_options(&options);
934 
935 	while (1) {
936 		int c;
937 		int option_index = 0;
938 		enum {
939 			OPT_DEVICE = 1,
940 			OPT_UDEV,
941 			OPT_GRAB,
942 			OPT_VERBOSE,
943 		};
944 		static struct option opts[] = {
945 			CONFIGURATION_OPTIONS,
946 			{ "help",                      no_argument,       0, 'h' },
947 			{ "device",                    required_argument, 0, OPT_DEVICE },
948 			{ "udev",                      required_argument, 0, OPT_UDEV },
949 			{ "grab",                      no_argument,       0, OPT_GRAB },
950 			{ "verbose",                   no_argument,       0, OPT_VERBOSE },
951 			{ 0, 0, 0, 0}
952 		};
953 
954 		c = getopt_long(argc, argv, "h", opts, &option_index);
955 		if (c == -1)
956 			break;
957 
958 		switch(c) {
959 		case '?':
960 			exit(1);
961 			break;
962 		case 'h':
963 			usage();
964 			exit(0);
965 			break;
966 		case OPT_DEVICE:
967 			backend = BACKEND_DEVICE;
968 			seat_or_device = optarg;
969 			break;
970 		case OPT_UDEV:
971 			backend = BACKEND_UDEV;
972 			seat_or_device = optarg;
973 			break;
974 		case OPT_GRAB:
975 			w.grab = true;
976 			break;
977 		case OPT_VERBOSE:
978 			verbose = true;
979 			break;
980 		default:
981 			if (tools_parse_option(c, optarg, &options) != 0) {
982 				usage();
983 				return 1;
984 			}
985 			break;
986 		}
987 
988 	}
989 
990 	if (optind < argc) {
991 		usage();
992 		return 1;
993 	}
994 
995 	li = tools_open_backend(backend, seat_or_device, verbose, &w.grab);
996 	if (!li)
997 		return 1;
998 
999 	libinput_set_user_data(li, &w);
1000 
1001 	window_init(&w);
1002 	w.options = options;
1003 	sockets_init(li);
1004 	handle_event_libinput(NULL, 0, li);
1005 
1006 	gtk_main();
1007 
1008 	window_cleanup(&w);
1009 	libinput_unref(li);
1010 
1011 	return 0;
1012 }
1013