• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2012 Intel Corporation
3  * Copyright 2017-2018 Collabora, Ltd.
4  * Copyright 2017-2018 General Electric Company
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the next
14  * paragraph) shall be included in all copies or substantial portions of the
15  * Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23  * DEALINGS IN THE SOFTWARE.
24  */
25 
26 #include "config.h"
27 
28 #include <stdint.h>
29 #include <stdbool.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <cairo.h>
34 #include <math.h>
35 #include <assert.h>
36 #include <getopt.h>
37 #include <errno.h>
38 
39 #include <wayland-client.h>
40 
41 #include "clients/window.h"
42 #include "shared/helpers.h"
43 #include <libweston/matrix.h>
44 
45 #include "weston-touch-calibration-client-protocol.h"
46 
47 enum exit_code {
48 	CAL_EXIT_SUCCESS = 0,
49 	CAL_EXIT_ERROR = 1,
50 	CAL_EXIT_CANCELLED = 2,
51 };
52 
53 static int debug_;
54 static int verbose_;
55 
56 #define pr_ver(...) do { \
57 	if (verbose_) \
58 		printf(__VA_ARGS__); \
59 } while (0)
60 
61 #define pr_dbg(...) do { \
62 	if (debug_) \
63 		fprintf(stderr, __VA_ARGS__); \
64 } while (0)
65 
66 static void
67 pr_err(const char *fmt, ...) WL_PRINTF(1, 2);
68 
69 /* Our points for the calibration must be not be on a line */
70 static const struct {
71 	float x_ratio, y_ratio;
72 } test_ratios[] =  {
73 	{ 0.15, 0.10 }, /* three points for calibration */
74 	{ 0.85, 0.13 },
75 	{ 0.20, 0.80 },
76 	{ 0.70, 0.75 }  /* and one for verification */
77 };
78 
79 #define NR_SAMPLES ((int)ARRAY_LENGTH(test_ratios))
80 
81 struct point {
82 	double x;
83 	double y;
84 };
85 
86 struct sample {
87 	int ind;
88 	struct point drawn;	/**< drawn point, pixels */
89 	struct weston_touch_coordinate *pending;
90 	struct point drawn_cal;	/**< drawn point, converted */
91 	bool conv_done;
92 	struct point touched;	/**< touch point, normalized */
93 	bool touch_done;
94 };
95 
96 struct poly {
97 	struct color {
98 		double r, g, b, a;
99 	} color;
100 	int n_verts;
101 	const struct point *verts;
102 };
103 
104 /** Touch event handling state machine
105  *
106  * Only a complete down->up->frame sequence should be accepted with user
107  * feedback "right", and anything that deviates from that (invalid_touch,
108  * cancel, multiple touch-downs) needs to undo the current sample and
109  * possibly show user feedback "wrong".
110  *
111  * \<STATE\>
112  * - \<triggers\>: \<actions\>
113  *
114  * IDLE
115  * - touch down: sample, -> DOWN
116  * - touch up: no-op
117  * - frame: no-op
118  * - invalid_touch: (undo), wrong, -> WAIT
119  * - cancel: no-op
120  * DOWN (first touch down)
121  * - touch down: undo, wrong, -> WAIT
122  * - touch up: -> UP
123  * - frame: no-op
124  * - invalid_touch: undo, wrong, -> WAIT
125  * - cancel: undo, -> IDLE
126  * UP (first touch was down and up)
127  * - touch down: undo, wrong, -> WAIT
128  * - touch up: no-op
129  * - frame: right, touch finish, -> WAIT
130  * - invalid_touch: undo, wrong, -> WAIT
131  * - cancel: undo, -> IDLE
132  * WAIT (show user feedback)
133  * - touch down: no-op
134  * - touch up: no-op
135  * - frame, cancel, timer: if num_tp == 0 && timer_done -> IDLE
136  * - invalid_touch: no-op
137  */
138 enum touch_state {
139 	STATE_IDLE,
140 	STATE_DOWN,
141 	STATE_UP,
142 	STATE_WAIT
143 };
144 
145 struct calibrator {
146 	struct sample samples[NR_SAMPLES];
147 	int current_sample;
148 
149 	struct display *display;
150 	struct weston_touch_calibration *calibration;
151 	struct weston_touch_calibrator *calibrator;
152 	struct window *window;
153 	struct widget *widget;
154 
155 	int n_devices_listed;
156 	char *match_name;
157 	char *device_name;
158 
159 	int width;
160 	int height;
161 
162 	bool cancelled;
163 
164 	const struct poly *current_poly;
165 	bool exiting;
166 
167 	struct toytimer wait_timer;
168 	bool timer_pending;
169 	enum touch_state state;
170 
171 	int num_tp;		/* touch points down count */
172 };
173 
174 static struct sample *
current_sample(struct calibrator * cal)175 current_sample(struct calibrator *cal)
176 {
177 	return &cal->samples[cal->current_sample];
178 }
179 
180 static void
sample_start(struct calibrator * cal,int i)181 sample_start(struct calibrator *cal, int i)
182 {
183 	struct sample *s = &cal->samples[i];
184 
185 	assert(i >= 0 && i < NR_SAMPLES);
186 
187 	s->ind = i;
188 	s->drawn.x = round(test_ratios[i].x_ratio * cal->width);
189 	s->drawn.y = round(test_ratios[i].y_ratio * cal->height);
190 	s->pending = NULL;
191 	s->conv_done = false;
192 	s->touch_done = false;
193 
194 	cal->current_sample = i;
195 }
196 
197 static struct point
wire_to_point(uint32_t xu,uint32_t yu)198 wire_to_point(uint32_t xu, uint32_t yu)
199 {
200 	struct point p = {
201 		.x = (double)xu / 0xffffffff,
202 		.y = (double)yu / 0xffffffff
203 	};
204 
205 	return p;
206 }
207 
208 static void
sample_touch_down(struct calibrator * cal,uint32_t xu,uint32_t yu)209 sample_touch_down(struct calibrator *cal, uint32_t xu, uint32_t yu)
210 {
211 	struct sample *s = current_sample(cal);
212 
213 	s->touched = wire_to_point(xu, yu);
214 	s->touch_done = true;
215 
216 	pr_dbg("Down[%d] (%f, %f)\n", s->ind, s->touched.x, s->touched.y);
217 }
218 
219 static void
coordinate_result_handler(void * data,struct weston_touch_coordinate * interface,uint32_t xu,uint32_t yu)220 coordinate_result_handler(void *data, struct weston_touch_coordinate *interface,
221 			  uint32_t xu, uint32_t yu)
222 {
223 	struct sample *s = data;
224 
225 	weston_touch_coordinate_destroy(s->pending);
226 	s->pending = NULL;
227 
228 	s->drawn_cal = wire_to_point(xu, yu);
229 	s->conv_done = true;
230 
231 	pr_dbg("Conv[%d] (%f, %f)\n", s->ind, s->drawn_cal.x, s->drawn_cal.y);
232 }
233 
234 struct weston_touch_coordinate_listener coordinate_listener = {
235 	coordinate_result_handler
236 };
237 
238 static void
sample_undo(struct calibrator * cal)239 sample_undo(struct calibrator *cal)
240 {
241 	struct sample *s = current_sample(cal);
242 
243 	pr_dbg("Undo[%d]\n", s->ind);
244 
245 	s->touch_done = false;
246 	s->conv_done = false;
247 	if (s->pending) {
248 		weston_touch_coordinate_destroy(s->pending);
249 		s->pending = NULL;
250 	}
251 }
252 
253 static void
sample_finish(struct calibrator * cal)254 sample_finish(struct calibrator *cal)
255 {
256 	struct sample *s = current_sample(cal);
257 
258 	pr_dbg("Finish[%d]\n", s->ind);
259 
260 	assert(!s->pending && !s->conv_done);
261 
262 	s->pending = weston_touch_calibrator_convert(cal->calibrator,
263 						     (int32_t)s->drawn.x,
264 						     (int32_t)s->drawn.y);
265 	weston_touch_coordinate_add_listener(s->pending,
266 					     &coordinate_listener, s);
267 
268 	if (cal->current_sample + 1 < NR_SAMPLES) {
269 		sample_start(cal, cal->current_sample + 1);
270 	} else {
271 		pr_dbg("got all touches\n");
272 		cal->exiting = true;
273 	}
274 }
275 
276 /*
277  * Calibration algorithm:
278  *
279  * The equation we want to apply at event time where x' and y' are the
280  * calibrated co-ordinates.
281  *
282  * x' = Ax + By + C
283  * y' = Dx + Ey + F
284  *
285  * For example "zero calibration" would be A=1.0 B=0.0 C=0.0, D=0.0, E=1.0,
286  * and F=0.0.
287  *
288  * With 6 unknowns we need 6 equations to find the constants:
289  *
290  * x1' = Ax1 + By1 + C
291  * y1' = Dx1 + Ey1 + F
292  * ...
293  * x3' = Ax3 + By3 + C
294  * y3' = Dx3 + Ey3 + F
295  *
296  * In matrix form:
297  *
298  * x1'   x1 y1 1      A
299  * x2' = x2 y2 1  x   B
300  * x3'   x3 y3 1      C
301  *
302  * So making the matrix M we can find the constants with:
303  *
304  * A            x1'
305  * B = M^-1  x  x2'
306  * C            x3'
307  *
308  * (and similarly for D, E and F)
309  *
310  * For the calibration the desired values x, y are the same values at which
311  * we've drawn at.
312  *
313  */
314 static int
compute_calibration(struct calibrator * cal,float * result)315 compute_calibration(struct calibrator *cal, float *result)
316 {
317 	struct weston_matrix m;
318 	struct weston_matrix inverse;
319 	struct weston_vector x_calib;
320 	struct weston_vector y_calib;
321 	int i;
322 
323 	assert(NR_SAMPLES >= 3);
324 
325 	/*
326 	 * x1 y1  1  0
327 	 * x2 y2  1  0
328 	 * x3 y3  1  0
329 	 *  0  0  0  1
330 	 */
331 	weston_matrix_init(&m);
332 	for (i = 0; i < 3; i++) {
333 		m.d[i + 0] = cal->samples[i].touched.x;
334 		m.d[i + 4] = cal->samples[i].touched.y;
335 		m.d[i + 8] = 1.0f;
336 	}
337 	m.type = WESTON_MATRIX_TRANSFORM_OTHER;
338 
339 	if (weston_matrix_invert(&inverse, &m) < 0) {
340 		pr_err("non-invertible matrix during computation\n");
341 		return -1;
342 	}
343 
344 	for (i = 0; i < 3; i++) {
345 		x_calib.f[i] = cal->samples[i].drawn_cal.x;
346 		y_calib.f[i] = cal->samples[i].drawn_cal.y;
347 	}
348 	x_calib.f[3] = 0.0f;
349 	y_calib.f[3] = 0.0f;
350 
351 	/* Multiples into the vector */
352 	weston_matrix_transform(&inverse, &x_calib);
353 	weston_matrix_transform(&inverse, &y_calib);
354 
355 	for (i = 0; i < 3; i++)
356 		result[i] = x_calib.f[i];
357 	for (i = 0; i < 3; i++)
358 		result[i + 3] = y_calib.f[i];
359 
360 	return 0;
361 }
362 
363 static int
verify_calibration(struct calibrator * cal,const float * r)364 verify_calibration(struct calibrator *cal, const float *r)
365 {
366 	double thr = 0.1; /* accepted error radius */
367 	struct point e; /* expected value; error */
368 	const struct sample *s = &cal->samples[3];
369 
370 	/* transform raw touches through the matrix */
371 	e.x = r[0] * s->touched.x + r[1] * s->touched.y + r[2];
372 	e.y = r[3] * s->touched.x + r[4] * s->touched.y + r[5];
373 
374 	/* compute error */
375 	e.x -= s->drawn_cal.x;
376 	e.y -= s->drawn_cal.y;
377 
378 	pr_dbg("calibration test error: %f, %f\n", e.x, e.y);
379 
380 	if (e.x * e.x + e.y * e.y < thr * thr)
381 		return 0;
382 
383 	pr_err("Calibration verification failed, too large error.\n");
384 	return -1;
385 }
386 
387 static void
send_calibration(struct calibrator * cal,float * values)388 send_calibration(struct calibrator *cal, float *values)
389 {
390 	struct wl_array matrix;
391 	float *f;
392 	int i;
393 
394 	wl_array_init(&matrix);
395 	for (i = 0; i < 6; i++) {
396 		f = wl_array_add(&matrix, sizeof *f);
397 		*f = values[i];
398 	}
399 	weston_touch_calibration_save(cal->calibration,
400 				      cal->device_name, &matrix);
401 	wl_array_release(&matrix);
402 }
403 
404 static const struct point cross_verts[] = {
405 	{ 0.1, 0.2 },
406 	{ 0.2, 0.1 },
407 	{ 0.5, 0.4 },
408 	{ 0.8, 0.1 },
409 	{ 0.9, 0.2 },
410 	{ 0.6, 0.5 },
411 	{ 0.9, 0.8 },
412 	{ 0.8, 0.9 },
413 	{ 0.5, 0.6 },
414 	{ 0.2, 0.9 },
415 	{ 0.1, 0.8 },
416 	{ 0.4, 0.5 },
417 };
418 
419 /* a red cross, for "wrong" */
420 static const struct poly cross = {
421 	.color = { 0.7, 0.0, 0.0, 1.0 },
422 	.n_verts = ARRAY_LENGTH(cross_verts),
423 	.verts = cross_verts
424 };
425 
426 static const struct point check_verts[] = {
427 	{ 0.5, 0.7 },
428 	{ 0.8, 0.1 },
429 	{ 0.9, 0.1 },
430 	{ 0.55, 0.8 },
431 	{ 0.45, 0.8 },
432 	{ 0.3, 0.5 },
433 	{ 0.4, 0.5 }
434 };
435 
436 /* a green check mark, for "right" */
437 static const struct poly check = {
438 	.color = { 0.0, 0.7, 0.0, 1.0 },
439 	.n_verts = ARRAY_LENGTH(check_verts),
440 	.verts = check_verts
441 };
442 
443 static void
draw_poly(cairo_t * cr,const struct poly * poly)444 draw_poly(cairo_t *cr, const struct poly *poly)
445 {
446 	int i;
447 
448 	cairo_set_source_rgba(cr, poly->color.r, poly->color.g,
449 			      poly->color.b, poly->color.a);
450 	cairo_move_to(cr, poly->verts[0].x, poly->verts[0].y);
451 	for (i = 1; i < poly->n_verts; i++)
452 		cairo_line_to(cr, poly->verts[i].x, poly->verts[i].y);
453 	cairo_close_path(cr);
454 	cairo_fill(cr);
455 }
456 
457 static void
feedback_show(struct calibrator * cal,const struct poly * what)458 feedback_show(struct calibrator *cal, const struct poly *what)
459 {
460 	cal->current_poly = what;
461 	widget_schedule_redraw(cal->widget);
462 
463 	toytimer_arm_once_usec(&cal->wait_timer, 1000 * 1000);
464 	cal->timer_pending = true;
465 }
466 
467 static void
feedback_hide(struct calibrator * cal)468 feedback_hide(struct calibrator *cal)
469 {
470 	cal->current_poly = NULL;
471 	widget_schedule_redraw(cal->widget);
472 }
473 
474 static void
try_enter_state_idle(struct calibrator * cal)475 try_enter_state_idle(struct calibrator *cal)
476 {
477 	if (cal->num_tp != 0)
478 		return;
479 
480 	if (cal->timer_pending)
481 		return;
482 
483 	cal->state = STATE_IDLE;
484 
485 	feedback_hide(cal);
486 
487 	if (cal->exiting)
488 		display_exit(cal->display);
489 }
490 
491 static void
enter_state_wait(struct calibrator * cal)492 enter_state_wait(struct calibrator *cal)
493 {
494 	assert(cal->timer_pending);
495 	cal->state = STATE_WAIT;
496 }
497 
498 static void
wait_timer_done(struct toytimer * tt)499 wait_timer_done(struct toytimer *tt)
500 {
501 	struct calibrator *cal = container_of(tt, struct calibrator, wait_timer);
502 
503 	assert(cal->state == STATE_WAIT);
504 	cal->timer_pending = false;
505 	try_enter_state_idle(cal);
506 }
507 
508 static void
redraw_handler(struct widget * widget,void * data)509 redraw_handler(struct widget *widget, void *data)
510 {
511 	struct calibrator *cal = data;
512 	struct sample *s = current_sample(cal);
513 	struct rectangle allocation;
514 	cairo_surface_t *surface;
515 	cairo_t *cr;
516 
517 	widget_get_allocation(cal->widget, &allocation);
518 	assert(allocation.width == cal->width);
519 	assert(allocation.height == cal->height);
520 
521 	surface = window_get_surface(cal->window);
522 	cr = cairo_create(surface);
523 	cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
524 	cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
525 	cairo_paint(cr);
526 
527 	if (!cal->current_poly) {
528 		cairo_translate(cr, s->drawn.x, s->drawn.y);
529 		cairo_set_line_width(cr, 2.0);
530 		cairo_set_source_rgb(cr, 0.7, 0.0, 0.0);
531 		cairo_move_to(cr, 0, -10.0);
532 		cairo_line_to(cr, 0, 10.0);
533 		cairo_stroke(cr);
534 		cairo_move_to(cr, -10.0, 0);
535 		cairo_line_to(cr, 10.0, 0.0);
536 		cairo_stroke(cr);
537 	} else {
538 		cairo_scale(cr, allocation.width, allocation.height);
539 		draw_poly(cr, cal->current_poly);
540 	}
541 
542 	cairo_destroy(cr);
543 	cairo_surface_destroy(surface);
544 }
545 
546 static struct calibrator *
calibrator_create(struct display * display,const char * match_name)547 calibrator_create(struct display *display, const char *match_name)
548 {
549 	struct calibrator *cal;
550 
551 	cal = zalloc(sizeof *cal);
552 	if (!cal)
553 		abort();
554 
555 	cal->match_name = match_name ? strdup(match_name) : NULL;
556 	cal->window = window_create_custom(display);
557 	cal->widget = window_add_widget(cal->window, cal);
558 	window_inhibit_redraw(cal->window);
559 	window_set_title(cal->window, "Touchscreen calibrator");
560 	cal->display = display;
561 
562 	widget_set_redraw_handler(cal->widget, redraw_handler);
563 
564 	toytimer_init(&cal->wait_timer, CLOCK_MONOTONIC,
565 		      display, wait_timer_done);
566 
567 	cal->state = STATE_IDLE;
568 	cal->num_tp = 0;
569 
570 	return cal;
571 }
572 
573 static void
configure_handler(void * data,struct weston_touch_calibrator * interface,int32_t width,int32_t height)574 configure_handler(void *data, struct weston_touch_calibrator *interface,
575 		  int32_t width, int32_t height)
576 {
577 	struct calibrator *cal = data;
578 
579 	pr_dbg("Configure calibrator window to size %ix%i\n", width, height);
580 	cal->width = width;
581 	cal->height = height;
582 	window_schedule_resize(cal->window, width, height);
583 	window_uninhibit_redraw(cal->window);
584 
585 	sample_start(cal, 0);
586 	widget_schedule_redraw(cal->widget);
587 }
588 
589 static void
cancel_calibration_handler(void * data,struct weston_touch_calibrator * interface)590 cancel_calibration_handler(void *data, struct weston_touch_calibrator *interface)
591 {
592 	struct calibrator *cal = data;
593 
594 	pr_dbg("calibration cancelled by the display server, quitting.\n");
595 	cal->cancelled = true;
596 	display_exit(cal->display);
597 }
598 
599 static void
invalid_touch_handler(void * data,struct weston_touch_calibrator * interface)600 invalid_touch_handler(void *data, struct weston_touch_calibrator *interface)
601 {
602 	struct calibrator *cal = data;
603 
604 	pr_dbg("invalid touch\n");
605 
606 	switch (cal->state) {
607 	case STATE_IDLE:
608 	case STATE_DOWN:
609 	case STATE_UP:
610 		sample_undo(cal);
611 		feedback_show(cal, &cross);
612 		enter_state_wait(cal);
613 		break;
614 	case STATE_WAIT:
615 		/* no-op */
616 		break;
617 	}
618 }
619 
620 static void
down_handler(void * data,struct weston_touch_calibrator * interface,uint32_t time,int32_t id,uint32_t xu,uint32_t yu)621 down_handler(void *data, struct weston_touch_calibrator *interface,
622 	     uint32_t time, int32_t id, uint32_t xu, uint32_t yu)
623 {
624 	struct calibrator *cal = data;
625 
626 	cal->num_tp++;
627 
628 	switch (cal->state) {
629 	case STATE_IDLE:
630 		sample_touch_down(cal, xu, yu);
631 		cal->state = STATE_DOWN;
632 		break;
633 	case STATE_DOWN:
634 	case STATE_UP:
635 		sample_undo(cal);
636 		feedback_show(cal, &cross);
637 		enter_state_wait(cal);
638 		break;
639 	case STATE_WAIT:
640 		/* no-op */
641 		break;
642 	}
643 
644 	if (cal->current_poly)
645 		return;
646 }
647 
648 static void
up_handler(void * data,struct weston_touch_calibrator * interface,uint32_t time,int32_t id)649 up_handler(void *data, struct weston_touch_calibrator *interface,
650 	   uint32_t time, int32_t id)
651 {
652 	struct calibrator *cal = data;
653 
654 	cal->num_tp--;
655 	if (cal->num_tp < 0) {
656 		pr_dbg("Unmatched touch up.\n");
657 		cal->num_tp = 0;
658 	}
659 
660 	switch (cal->state) {
661 	case STATE_DOWN:
662 		cal->state = STATE_UP;
663 		break;
664 	case STATE_IDLE:
665 	case STATE_UP:
666 	case STATE_WAIT:
667 		/* no-op */
668 		break;
669 	}
670 }
671 
672 static void
motion_handler(void * data,struct weston_touch_calibrator * interface,uint32_t time,int32_t id,uint32_t xu,uint32_t yu)673 motion_handler(void *data, struct weston_touch_calibrator *interface,
674 	       uint32_t time, int32_t id, uint32_t xu, uint32_t yu)
675 {
676 	/* motion is ignored */
677 }
678 
679 static void
frame_handler(void * data,struct weston_touch_calibrator * interface)680 frame_handler(void *data, struct weston_touch_calibrator *interface)
681 {
682 	struct calibrator *cal = data;
683 
684 	switch (cal->state) {
685 	case STATE_IDLE:
686 	case STATE_DOWN:
687 		/* no-op */
688 		break;
689 	case STATE_UP:
690 		feedback_show(cal, &check);
691 		sample_finish(cal);
692 		enter_state_wait(cal);
693 		break;
694 	case STATE_WAIT:
695 		try_enter_state_idle(cal);
696 		break;
697 	}
698 }
699 
700 static void
cancel_handler(void * data,struct weston_touch_calibrator * interface)701 cancel_handler(void *data, struct weston_touch_calibrator *interface)
702 {
703 	struct calibrator *cal = data;
704 
705 	cal->num_tp = 0;
706 
707 	switch (cal->state) {
708 	case STATE_IDLE:
709 		/* no-op */
710 		break;
711 	case STATE_DOWN:
712 	case STATE_UP:
713 		sample_undo(cal);
714 		try_enter_state_idle(cal);
715 		break;
716 	case STATE_WAIT:
717 		try_enter_state_idle(cal);
718 		break;
719 	}
720 }
721 
722 struct weston_touch_calibrator_listener calibrator_listener = {
723 	configure_handler,
724 	cancel_calibration_handler,
725 	invalid_touch_handler,
726 	down_handler,
727 	up_handler,
728 	motion_handler,
729 	frame_handler,
730 	cancel_handler
731 };
732 
733 static void
calibrator_show(struct calibrator * cal)734 calibrator_show(struct calibrator *cal)
735 {
736 	struct wl_surface *surface = window_get_wl_surface(cal->window);
737 
738 	cal->calibrator =
739 		weston_touch_calibration_create_calibrator(cal->calibration,
740 							   surface,
741 							   cal->device_name);
742 	weston_touch_calibrator_add_listener(cal->calibrator,
743 					     &calibrator_listener, cal);
744 }
745 
746 static void
calibrator_destroy(struct calibrator * cal)747 calibrator_destroy(struct calibrator *cal)
748 {
749 	toytimer_fini(&cal->wait_timer);
750 	if (cal->calibrator)
751 		weston_touch_calibrator_destroy(cal->calibrator);
752 	if (cal->calibration)
753 		weston_touch_calibration_destroy(cal->calibration);
754 	if (cal->widget)
755 		widget_destroy(cal->widget);
756 	if (cal->window)
757 		window_destroy(cal->window);
758 	free(cal->match_name);
759 	free(cal->device_name);
760 	free(cal);
761 }
762 
763 static void
touch_device_handler(void * data,struct weston_touch_calibration * c,const char * device,const char * head)764 touch_device_handler(void *data, struct weston_touch_calibration *c,
765 		     const char *device, const char *head)
766 {
767 	struct calibrator *cal = data;
768 
769 	cal->n_devices_listed++;
770 
771 	if (!cal->match_name) {
772 		printf("device \"%s\" - head \"%s\"\n", device, head);
773 		return;
774 	}
775 
776 	if (cal->device_name)
777 		return;
778 
779 	if (strcmp(cal->match_name, device) == 0 ||
780 	    strcmp(cal->match_name, head) == 0)
781 		cal->device_name = strdup(device);
782 }
783 
784 struct weston_touch_calibration_listener touch_calibration_listener = {
785 	touch_device_handler
786 };
787 
788 static void
global_handler(struct display * display,uint32_t name,const char * interface,uint32_t version,void * data)789 global_handler(struct display *display, uint32_t name,
790 	       const char *interface, uint32_t version, void *data)
791 {
792 	struct calibrator *cal = data;
793 
794 	if (strcmp(interface, "weston_touch_calibration") == 0) {
795 		cal->calibration = display_bind(display, name,
796 						&weston_touch_calibration_interface, 1);
797 		weston_touch_calibration_add_listener(cal->calibration,
798 						      &touch_calibration_listener,
799 						      cal);
800 	}
801 }
802 
803 static int
calibrator_run(struct calibrator * cal)804 calibrator_run(struct calibrator *cal)
805 {
806 	struct wl_display *dpy;
807 	struct sample *s;
808 	bool wait;
809 	int i;
810 	int ret;
811 	float result[6];
812 
813 	calibrator_show(cal);
814 	display_run(cal->display);
815 
816 	if (cal->cancelled)
817 		return CAL_EXIT_CANCELLED;
818 
819 	/* remove the window, no more input events */
820 	widget_destroy(cal->widget);
821 	cal->widget = NULL;
822 	window_destroy(cal->window);
823 	cal->window = NULL;
824 
825 	/* wait for all conversions to return */
826 	dpy = display_get_display(cal->display);
827 	do {
828 		wait = false;
829 
830 		for (i = 0; i < NR_SAMPLES; i++)
831 			if (cal->samples[i].pending)
832 				wait = true;
833 
834 		if (wait) {
835 			ret = wl_display_roundtrip(dpy);
836 			if (ret < 0)
837 				return CAL_EXIT_ERROR;
838 		}
839 	} while (wait);
840 
841 	for (i = 0; i < NR_SAMPLES; i++) {
842 		s = &cal->samples[i];
843 		if (!s->conv_done || !s->touch_done)
844 			return CAL_EXIT_ERROR;
845 	}
846 
847 	if (compute_calibration(cal, result) < 0)
848 		return CAL_EXIT_ERROR;
849 
850 	if (verify_calibration(cal, result) < 0)
851 		return CAL_EXIT_ERROR;
852 
853 	pr_ver("Calibration values:");
854 	for (i = 0; i < 6; i++)
855 		pr_ver(" %f", result[i]);
856 	pr_ver("\n");
857 
858 	send_calibration(cal, result);
859 	ret = wl_display_roundtrip(dpy);
860 	if (ret < 0)
861 		return CAL_EXIT_ERROR;
862 
863 	return CAL_EXIT_SUCCESS;
864 }
865 
866 static void
pr_err(const char * fmt,...)867 pr_err(const char *fmt, ...)
868 {
869 	va_list argp;
870 
871 	va_start(argp, fmt);
872 	fprintf(stderr, "%s error: ", program_invocation_short_name);
873 	vfprintf(stderr, fmt, argp);
874 	va_end(argp);
875 }
876 
877 static void
help(void)878 help(void)
879 {
880 	fprintf(stderr, "Compute a touchscreen calibration matrix for "
881 		"a Wayland compositor by\n"
882 		"having the user touch points on the screen.\n\n");
883 	fprintf(stderr, "Usage: %s [options...] name\n\n",
884 		program_invocation_short_name);
885 	fprintf(stderr,
886 		"Where 'name' can be a touch device sys path or a head name.\n"
887 		"If 'name' is not given, all devices available for "
888 		"calibration will be listed.\n"
889 		"If 'name' is given, it must be exactly as listed.\n"
890 		"Options:\n"
891 		"  --debug         Print messages to help debugging.\n"
892 		"  -h, --help      Display this help message\n"
893 		"  -v, --verbose   Print list header and calibration result.\n");
894 }
895 
896 int
main(int argc,char * argv[])897 main(int argc, char *argv[])
898 {
899 	struct display *display;
900 	struct calibrator *cal;
901 	int c;
902 	char *match_name = NULL;
903 	int exit_code = CAL_EXIT_SUCCESS;
904 	static const struct option opts[] = {
905 		{ "help",    no_argument,       NULL,      'h' },
906 		{ "debug",   no_argument,       &debug_,   1 },
907 		{ "verbose", no_argument,       &verbose_, 1 },
908 		{ 0,         0,                 NULL,      0  }
909 	};
910 
911 	while ((c = getopt_long(argc, argv, "hv", opts, NULL)) != -1) {
912 		switch (c) {
913 		case 'h':
914 			help();
915 			return CAL_EXIT_SUCCESS;
916 		case 'v':
917 			verbose_ = 1;
918 			break;
919 		case 0:
920 			break;
921 		default:
922 			return CAL_EXIT_ERROR;
923 		}
924 	}
925 
926 	if (optind < argc)
927 		match_name = argv[optind++];
928 
929 	if (optind < argc) {
930 		pr_err("extra arguments given.\n\n");
931 		help();
932 		return CAL_EXIT_ERROR;
933 	}
934 
935 	display = display_create(&argc, argv);
936 	if (!display)
937 		return CAL_EXIT_ERROR;
938 
939 	cal = calibrator_create(display, match_name);
940 	if (!cal)
941 		return CAL_EXIT_ERROR;
942 
943 	display_set_user_data(display, cal);
944 	display_set_global_handler(display, global_handler);
945 
946 	if (!match_name)
947 		pr_ver("Available touch devices:\n");
948 
949 	/* Roundtrip to get list of available touch devices,
950 	 * first globals, then touch_device events */
951 	wl_display_roundtrip(display_get_display(display));
952 	wl_display_roundtrip(display_get_display(display));
953 
954 	if (!cal->calibration) {
955 		exit_code = CAL_EXIT_ERROR;
956 		pr_err("the Wayland server does not expose the calibration interface.\n");
957 	} else if (cal->device_name) {
958 		exit_code = calibrator_run(cal);
959 	} else if (match_name) {
960 		exit_code = CAL_EXIT_ERROR;
961 		pr_err("\"%s\" was not found.\n", match_name);
962 	} else if (cal->n_devices_listed == 0) {
963 		fprintf(stderr, "No devices listed.\n");
964 	}
965 
966 	calibrator_destroy(cal);
967 	display_destroy(display);
968 
969 	return exit_code;
970 }
971