1 /*
2 * Copyright 2017-2018 Collabora, Ltd.
3 * Copyright 2017-2018 General Electric Company
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial
15 * portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * SOFTWARE.
25 */
26
27 #include "config.h"
28
29 #include <string.h>
30 #include <wayland-server.h>
31
32 #include "shared/helpers.h"
33 #include "shared/string-helpers.h"
34 #include <libweston/zalloc.h>
35 #include "shared/timespec-util.h"
36 #include <libweston/libweston.h>
37 #include "libweston-internal.h"
38 #include "backend.h"
39
40 #include "weston-touch-calibration-server-protocol.h"
41
42 struct weston_touch_calibrator {
43 struct wl_resource *resource;
44
45 struct weston_compositor *compositor;
46
47 struct weston_surface *surface;
48 struct wl_listener surface_destroy_listener;
49 struct wl_listener surface_commit_listener;
50
51 struct weston_touch_device *device;
52 struct wl_listener device_destroy_listener;
53
54 struct weston_output *output;
55 struct wl_listener output_destroy_listener;
56
57 struct weston_view *view;
58
59 /** The calibration procedure has been cancelled. */
60 bool calibration_cancelled;
61
62 /** The current touch sequence has been cancelled. */
63 bool touch_cancelled;
64 };
65
66 static struct weston_touch_calibrator *
calibrator_from_device(struct weston_touch_device * device)67 calibrator_from_device(struct weston_touch_device *device)
68 {
69 return device->aggregate->seat->compositor->touch_calibrator;
70 }
71
72 static uint32_t
wire_uint_from_double(double c)73 wire_uint_from_double(double c)
74 {
75 assert(c >= 0.0);
76 assert(c <= 1.0);
77
78 return round(c * 0xffffffff);
79 }
80
81 static bool
normalized_is_valid(const struct weston_point2d_device_normalized * p)82 normalized_is_valid(const struct weston_point2d_device_normalized *p)
83 {
84 return p->x >= 0.0 && p->x <= 1.0 &&
85 p->y >= 0.0 && p->y <= 1.0;
86 }
87
88 WL_EXPORT void
notify_touch_calibrator(struct weston_touch_device * device,const struct timespec * time,int32_t slot,const struct weston_point2d_device_normalized * norm,int touch_type)89 notify_touch_calibrator(struct weston_touch_device *device,
90 const struct timespec *time, int32_t slot,
91 const struct weston_point2d_device_normalized *norm,
92 int touch_type)
93 {
94 struct weston_touch_calibrator *calibrator;
95 struct wl_resource *res;
96 uint32_t msecs;
97 uint32_t x = 0;
98 uint32_t y = 0;
99
100 calibrator = calibrator_from_device(device);
101 if (!calibrator)
102 return;
103
104 res = calibrator->resource;
105
106 /* Ignore any touch events coming from another device */
107 if (device != calibrator->device) {
108 if (touch_type == WL_TOUCH_DOWN)
109 weston_touch_calibrator_send_invalid_touch(res);
110 return;
111 }
112
113 /* Ignore all events if we have sent 'cancel' event until all
114 * touches (on the seat) are up.
115 */
116 if (calibrator->touch_cancelled) {
117 if (calibrator->device->aggregate->num_tp == 0) {
118 assert(touch_type == WL_TOUCH_UP);
119 calibrator->touch_cancelled = false;
120 }
121 return;
122 }
123
124 msecs = timespec_to_msec(time);
125 if (touch_type != WL_TOUCH_UP) {
126 if (normalized_is_valid(norm)) {
127 x = wire_uint_from_double(norm->x);
128 y = wire_uint_from_double(norm->y);
129 } else {
130 /* Coordinates are out of bounds */
131 if (touch_type == WL_TOUCH_MOTION) {
132 weston_touch_calibrator_send_cancel(res);
133 calibrator->touch_cancelled = true;
134 }
135 weston_touch_calibrator_send_invalid_touch(res);
136 return;
137 }
138 }
139
140 switch (touch_type) {
141 case WL_TOUCH_UP:
142 weston_touch_calibrator_send_up(res, msecs, slot);
143 break;
144 case WL_TOUCH_DOWN:
145 weston_touch_calibrator_send_down(res, msecs, slot, x, y);
146 break;
147 case WL_TOUCH_MOTION:
148 weston_touch_calibrator_send_motion(res, msecs, slot, x, y);
149 break;
150 default:
151 return;
152 }
153 }
154
155 WL_EXPORT void
notify_touch_calibrator_frame(struct weston_touch_device * device)156 notify_touch_calibrator_frame(struct weston_touch_device *device)
157 {
158 struct weston_touch_calibrator *calibrator;
159
160 calibrator = calibrator_from_device(device);
161 if (!calibrator)
162 return;
163
164 weston_touch_calibrator_send_frame(calibrator->resource);
165 }
166
167 WL_EXPORT void
notify_touch_calibrator_cancel(struct weston_touch_device * device)168 notify_touch_calibrator_cancel(struct weston_touch_device *device)
169 {
170 struct weston_touch_calibrator *calibrator;
171
172 calibrator = calibrator_from_device(device);
173 if (!calibrator)
174 return;
175
176 weston_touch_calibrator_send_cancel(calibrator->resource);
177 }
178
179 static void
map_calibrator(struct weston_touch_calibrator * calibrator)180 map_calibrator(struct weston_touch_calibrator *calibrator)
181 {
182 struct weston_compositor *c = calibrator->compositor;
183 struct weston_touch_device *device = calibrator->device;
184 static const struct weston_touch_device_matrix identity = {
185 .m = { 1, 0, 0, 0, 1, 0}
186 };
187
188 assert(!calibrator->view);
189 assert(calibrator->output);
190 assert(calibrator->surface);
191 assert(calibrator->surface->resource);
192
193 calibrator->view = weston_view_create(calibrator->surface);
194 if (!calibrator->view) {
195 wl_resource_post_no_memory(calibrator->surface->resource);
196 return;
197 }
198
199 weston_layer_entry_insert(&c->calibrator_layer.view_list,
200 &calibrator->view->layer_link);
201
202 weston_view_set_position(calibrator->view,
203 calibrator->output->x,
204 calibrator->output->y);
205 calibrator->view->output = calibrator->surface->output;
206 calibrator->view->is_mapped = true;
207
208 calibrator->surface->output = calibrator->output;
209 calibrator->surface->is_mapped = true;
210
211 weston_output_schedule_repaint(calibrator->output);
212
213 device->ops->get_calibration(device, &device->saved_calibration);
214 device->ops->set_calibration(device, &identity);
215 }
216
217 static void
unmap_calibrator(struct weston_touch_calibrator * calibrator)218 unmap_calibrator(struct weston_touch_calibrator *calibrator)
219 {
220 struct weston_touch_device *device = calibrator->device;
221
222 wl_list_remove(&calibrator->surface_commit_listener.link);
223 wl_list_init(&calibrator->surface_commit_listener.link);
224
225 if (!calibrator->view)
226 return;
227
228 weston_view_destroy(calibrator->view);
229 calibrator->view = NULL;
230 weston_surface_unmap(calibrator->surface);
231
232 /* Reload saved calibration */
233 if (device)
234 device->ops->set_calibration(device,
235 &device->saved_calibration);
236 }
237
238 void
touch_calibrator_mode_changed(struct weston_compositor * compositor)239 touch_calibrator_mode_changed(struct weston_compositor *compositor)
240 {
241 struct weston_touch_calibrator *calibrator;
242
243 calibrator = compositor->touch_calibrator;
244 if (!calibrator)
245 return;
246
247 if (calibrator->calibration_cancelled)
248 return;
249
250 if (compositor->touch_mode == WESTON_TOUCH_MODE_CALIB)
251 map_calibrator(calibrator);
252 }
253
254 static void
touch_calibrator_surface_committed(struct wl_listener * listener,void * data)255 touch_calibrator_surface_committed(struct wl_listener *listener, void *data)
256 {
257 struct weston_touch_calibrator *calibrator =
258 container_of(listener, struct weston_touch_calibrator,
259 surface_commit_listener);
260 struct weston_surface *surface = calibrator->surface;
261
262 wl_list_remove(&calibrator->surface_commit_listener.link);
263 wl_list_init(&calibrator->surface_commit_listener.link);
264
265 if (surface->width != calibrator->output->width ||
266 surface->height != calibrator->output->height) {
267 wl_resource_post_error(calibrator->resource,
268 WESTON_TOUCH_CALIBRATOR_ERROR_BAD_SIZE,
269 "calibrator surface size does not match");
270 return;
271 }
272
273 weston_compositor_set_touch_mode_calib(calibrator->compositor);
274 /* results in call to touch_calibrator_mode_changed() */
275 }
276
277 static void
touch_calibrator_convert(struct wl_client * client,struct wl_resource * resource,int32_t x,int32_t y,uint32_t coordinate_id)278 touch_calibrator_convert(struct wl_client *client,
279 struct wl_resource *resource,
280 int32_t x,
281 int32_t y,
282 uint32_t coordinate_id)
283 {
284 struct weston_touch_calibrator *calibrator;
285 struct wl_resource *coordinate_resource;
286 struct weston_output *output;
287 struct weston_surface *surface;
288 uint32_t version;
289 struct weston_vector p = { { 0.0, 0.0, 0.0, 1.0 } };
290 struct weston_point2d_device_normalized norm;
291
292 version = wl_resource_get_version(resource);
293 calibrator = wl_resource_get_user_data(resource);
294 surface = calibrator->surface;
295 output = calibrator->output;
296
297 coordinate_resource =
298 wl_resource_create(client, &weston_touch_coordinate_interface,
299 version, coordinate_id);
300 if (!coordinate_resource) {
301 wl_client_post_no_memory(client);
302 return;
303 }
304
305 if (calibrator->calibration_cancelled) {
306 weston_touch_coordinate_send_result(coordinate_resource, 0, 0);
307 wl_resource_destroy(coordinate_resource);
308 return;
309 }
310
311 if (!surface || !surface->is_mapped) {
312 wl_resource_post_error(resource,
313 WESTON_TOUCH_CALIBRATOR_ERROR_NOT_MAPPED,
314 "calibrator surface is not mapped");
315 return;
316 }
317 assert(calibrator->view);
318 assert(output);
319
320 if (x < 0 || y < 0 || x >= surface->width || y >= surface->height) {
321 wl_resource_post_error(resource,
322 WESTON_TOUCH_CALIBRATOR_ERROR_BAD_COORDINATES,
323 "convert(%d, %d) input is out of bounds",
324 x, y);
325 return;
326 }
327
328 /* Convert from surface-local coordinates into global, from global
329 * into output-raw, do perspective division and normalize.
330 */
331 weston_view_to_global_float(calibrator->view, x, y, &p.f[0], &p.f[1]);
332 weston_matrix_transform(&output->matrix, &p);
333 norm.x = p.f[0] / (p.f[3] * output->current_mode->width);
334 norm.y = p.f[1] / (p.f[3] * output->current_mode->height);
335
336 if (!normalized_is_valid(&norm)) {
337 wl_resource_post_error(resource,
338 WESTON_TOUCH_CALIBRATOR_ERROR_BAD_COORDINATES,
339 "convert(%d, %d) output is out of bounds",
340 x, y);
341 return;
342 }
343
344 weston_touch_coordinate_send_result(coordinate_resource,
345 wire_uint_from_double(norm.x),
346 wire_uint_from_double(norm.y));
347 wl_resource_destroy(coordinate_resource);
348 }
349
350 static void
destroy_touch_calibrator(struct wl_resource * resource)351 destroy_touch_calibrator(struct wl_resource *resource)
352 {
353 struct weston_touch_calibrator *calibrator;
354
355 calibrator = wl_resource_get_user_data(resource);
356
357 calibrator->compositor->touch_calibrator = NULL;
358
359 weston_compositor_set_touch_mode_normal(calibrator->compositor);
360
361 if (calibrator->surface) {
362 unmap_calibrator(calibrator);
363 wl_list_remove(&calibrator->surface_destroy_listener.link);
364 wl_list_remove(&calibrator->surface_commit_listener.link);
365 }
366
367 if (calibrator->device)
368 wl_list_remove(&calibrator->device_destroy_listener.link);
369
370 if (calibrator->output)
371 wl_list_remove(&calibrator->output_destroy_listener.link);
372
373 free(calibrator);
374 }
375
376 static void
touch_calibrator_destroy(struct wl_client * client,struct wl_resource * resource)377 touch_calibrator_destroy(struct wl_client *client,
378 struct wl_resource *resource)
379 {
380 wl_resource_destroy(resource);
381 }
382
383 static const struct weston_touch_calibrator_interface
384 touch_calibrator_implementation = {
385 touch_calibrator_destroy,
386 touch_calibrator_convert
387 };
388
389 static void
touch_calibrator_cancel_calibration(struct weston_touch_calibrator * calibrator)390 touch_calibrator_cancel_calibration(struct weston_touch_calibrator *calibrator)
391 {
392 weston_touch_calibrator_send_cancel_calibration(calibrator->resource);
393 calibrator->calibration_cancelled = true;
394
395 if (calibrator->surface)
396 unmap_calibrator(calibrator);
397 }
398
399 static void
touch_calibrator_output_destroyed(struct wl_listener * listener,void * data)400 touch_calibrator_output_destroyed(struct wl_listener *listener, void *data)
401 {
402 struct weston_touch_calibrator *calibrator =
403 container_of(listener, struct weston_touch_calibrator,
404 output_destroy_listener);
405
406 assert(calibrator->output == data);
407 calibrator->output = NULL;
408
409 touch_calibrator_cancel_calibration(calibrator);
410 }
411
412 static void
touch_calibrator_device_destroyed(struct wl_listener * listener,void * data)413 touch_calibrator_device_destroyed(struct wl_listener *listener, void *data)
414 {
415 struct weston_touch_calibrator *calibrator =
416 container_of(listener, struct weston_touch_calibrator,
417 device_destroy_listener);
418
419 assert(calibrator->device == data);
420 calibrator->device = NULL;
421
422 touch_calibrator_cancel_calibration(calibrator);
423 }
424
425 static void
touch_calibrator_surface_destroyed(struct wl_listener * listener,void * data)426 touch_calibrator_surface_destroyed(struct wl_listener *listener, void *data)
427 {
428 struct weston_touch_calibrator *calibrator =
429 container_of(listener, struct weston_touch_calibrator,
430 surface_destroy_listener);
431
432 assert(calibrator->surface->resource == data);
433
434 unmap_calibrator(calibrator);
435 calibrator->surface = NULL;
436 }
437
438 static void
touch_calibration_destroy(struct wl_client * client,struct wl_resource * resource)439 touch_calibration_destroy(struct wl_client *client,
440 struct wl_resource *resource)
441 {
442 wl_resource_destroy(resource);
443 }
444
445 static struct weston_touch_device *
weston_compositor_find_touch_device_by_syspath(struct weston_compositor * compositor,const char * syspath)446 weston_compositor_find_touch_device_by_syspath(
447 struct weston_compositor *compositor,
448 const char *syspath)
449 {
450 struct weston_seat *seat;
451 struct weston_touch *touch;
452 struct weston_touch_device *device;
453
454 if (!syspath)
455 return NULL;
456
457 wl_list_for_each(seat, &compositor->seat_list, link) {
458 touch = weston_seat_get_touch(seat);
459 if (!touch)
460 continue;
461
462 wl_list_for_each(device, &touch->device_list, link) {
463 if (strcmp(device->syspath, syspath) == 0)
464 return device;
465 }
466 }
467
468 return NULL;
469 }
470
471 static void
touch_calibration_create_calibrator(struct wl_client * client,struct wl_resource * touch_calibration_resource,struct wl_resource * surface_resource,const char * syspath,uint32_t calibrator_id)472 touch_calibration_create_calibrator(
473 struct wl_client *client,
474 struct wl_resource *touch_calibration_resource,
475 struct wl_resource *surface_resource,
476 const char *syspath,
477 uint32_t calibrator_id)
478 {
479 struct weston_compositor *compositor;
480 struct weston_touch_calibrator *calibrator;
481 struct weston_touch_device *device;
482 struct weston_output *output = NULL;
483 struct weston_surface *surface;
484 uint32_t version;
485 int ret;
486
487 version = wl_resource_get_version(touch_calibration_resource);
488 compositor = wl_resource_get_user_data(touch_calibration_resource);
489
490 if (compositor->touch_calibrator != NULL) {
491 wl_resource_post_error(touch_calibration_resource,
492 WESTON_TOUCH_CALIBRATION_ERROR_ALREADY_EXISTS,
493 "a calibrator has already been created");
494 return;
495 }
496
497 calibrator = zalloc(sizeof *calibrator);
498 if (!calibrator) {
499 wl_client_post_no_memory(client);
500 return;
501 }
502
503 calibrator->compositor = compositor;
504 calibrator->resource = wl_resource_create(client,
505 &weston_touch_calibrator_interface,
506 version, calibrator_id);
507 if (!calibrator->resource) {
508 wl_client_post_no_memory(client);
509 goto err_dealloc;
510 }
511
512 surface = wl_resource_get_user_data(surface_resource);
513 assert(surface);
514 ret = weston_surface_set_role(surface, "weston_touch_calibrator",
515 touch_calibration_resource,
516 WESTON_TOUCH_CALIBRATION_ERROR_INVALID_SURFACE);
517 if (ret < 0)
518 goto err_destroy_resource;
519
520 calibrator->surface_destroy_listener.notify =
521 touch_calibrator_surface_destroyed;
522 wl_resource_add_destroy_listener(surface->resource,
523 &calibrator->surface_destroy_listener);
524 calibrator->surface = surface;
525
526 calibrator->surface_commit_listener.notify =
527 touch_calibrator_surface_committed;
528 wl_signal_add(&surface->commit_signal,
529 &calibrator->surface_commit_listener);
530
531 device = weston_compositor_find_touch_device_by_syspath(compositor,
532 syspath);
533 if (device) {
534 output = device->ops->get_output(device);
535 if (weston_touch_device_can_calibrate(device) && output)
536 calibrator->device = device;
537 }
538
539 if (!calibrator->device) {
540 wl_resource_post_error(touch_calibration_resource,
541 WESTON_TOUCH_CALIBRATION_ERROR_INVALID_DEVICE,
542 "the given touch device '%s' is not valid",
543 syspath ?: "");
544 goto err_unlink_surface;
545 }
546
547 calibrator->device_destroy_listener.notify =
548 touch_calibrator_device_destroyed;
549 wl_signal_add(&calibrator->device->destroy_signal,
550 &calibrator->device_destroy_listener);
551
552 wl_resource_set_implementation(calibrator->resource,
553 &touch_calibrator_implementation,
554 calibrator, destroy_touch_calibrator);
555
556 assert(output);
557 calibrator->output_destroy_listener.notify =
558 touch_calibrator_output_destroyed;
559 wl_signal_add(&output->destroy_signal,
560 &calibrator->output_destroy_listener);
561 calibrator->output = output;
562
563 weston_touch_calibrator_send_configure(calibrator->resource,
564 output->width,
565 output->height);
566
567 compositor->touch_calibrator = calibrator;
568
569 return;
570
571 err_unlink_surface:
572 wl_list_remove(&calibrator->surface_commit_listener.link);
573 wl_list_remove(&calibrator->surface_destroy_listener.link);
574
575 err_destroy_resource:
576 wl_resource_destroy(calibrator->resource);
577
578 err_dealloc:
579 free(calibrator);
580 }
581
582 static void
touch_calibration_save(struct wl_client * client,struct wl_resource * touch_calibration_resource,const char * device_name,struct wl_array * matrix_data)583 touch_calibration_save(struct wl_client *client,
584 struct wl_resource *touch_calibration_resource,
585 const char *device_name,
586 struct wl_array *matrix_data)
587 {
588 struct weston_touch_device *device;
589 struct weston_compositor *compositor;
590 struct weston_touch_device_matrix calibration;
591 struct weston_touch_calibrator *calibrator;
592 int i = 0;
593 float *c;
594
595 compositor = wl_resource_get_user_data(touch_calibration_resource);
596
597 device = weston_compositor_find_touch_device_by_syspath(compositor,
598 device_name);
599 if (!device || !weston_touch_device_can_calibrate(device)) {
600 wl_resource_post_error(touch_calibration_resource,
601 WESTON_TOUCH_CALIBRATION_ERROR_INVALID_DEVICE,
602 "the given device is not valid");
603 return;
604 }
605
606 wl_array_for_each(c, matrix_data) {
607 calibration.m[i++] = *c;
608 }
609
610 /* If calibration can't be saved, don't set it as current */
611 if (compositor->touch_calibration_save &&
612 compositor->touch_calibration_save(compositor, device,
613 &calibration) < 0)
614 return;
615
616 /* If calibrator is still mapped, the compositor will use
617 * saved_calibration when going back to normal touch handling.
618 * Continuing calibrating after save request is undefined. */
619 calibrator = compositor->touch_calibrator;
620 if (calibrator &&
621 calibrator->surface &&
622 weston_surface_is_mapped(calibrator->surface))
623 device->saved_calibration = calibration;
624 else
625 device->ops->set_calibration(device, &calibration);
626 }
627
628 static const struct weston_touch_calibration_interface
629 touch_calibration_implementation = {
630 touch_calibration_destroy,
631 touch_calibration_create_calibrator,
632 touch_calibration_save
633 };
634
635 static void
bind_touch_calibration(struct wl_client * client,void * data,uint32_t version,uint32_t id)636 bind_touch_calibration(struct wl_client *client,
637 void *data, uint32_t version, uint32_t id)
638 {
639 struct weston_compositor *compositor = data;
640 struct wl_resource *resource;
641 struct weston_touch_device *device;
642 struct weston_seat *seat;
643 struct weston_touch *touch;
644 const char *name;
645
646 resource = wl_resource_create(client,
647 &weston_touch_calibration_interface,
648 version, id);
649 if (resource == NULL) {
650 wl_client_post_no_memory(client);
651 return;
652 }
653
654 wl_resource_set_implementation(resource,
655 &touch_calibration_implementation,
656 compositor, NULL);
657
658 wl_list_for_each(seat, &compositor->seat_list, link) {
659 touch = weston_seat_get_touch(seat);
660 if (!touch)
661 continue;
662
663 wl_list_for_each(device, &touch->device_list, link) {
664 if (!weston_touch_device_can_calibrate(device))
665 continue;
666
667 name = device->ops->get_calibration_head_name(device);
668 if (!name)
669 continue;
670
671 weston_touch_calibration_send_touch_device(resource,
672 device->syspath, name);
673 }
674 }
675 }
676
677 /** Advertise touch_calibration support
678 *
679 * \param compositor The compositor to init for.
680 * \param save The callback function for saving a new calibration, or NULL.
681 * \return Zero on success, -1 on failure or if already enabled.
682 *
683 * Calling this initializes the weston_touch_calibration protocol support,
684 * so that the interface will be advertised to clients. It is recommended
685 * to use some mechanism, e.g. wl_display_set_global_filter(), to restrict
686 * access to the interface.
687 *
688 * There is no way to disable this once enabled.
689 *
690 * If the save callback is NULL, a new calibration provided by a client will
691 * always be accepted. If the save callback is not NULL, it must return
692 * success for the new calibration to be accepted.
693 */
694 WL_EXPORT int
weston_compositor_enable_touch_calibrator(struct weston_compositor * compositor,weston_touch_calibration_save_func save)695 weston_compositor_enable_touch_calibrator(struct weston_compositor *compositor,
696 weston_touch_calibration_save_func save)
697 {
698 if (compositor->touch_calibration)
699 return -1;
700
701 compositor->touch_calibration = wl_global_create(compositor->wl_display,
702 &weston_touch_calibration_interface, 1,
703 compositor, bind_touch_calibration);
704 if (!compositor->touch_calibration)
705 return -1;
706
707 compositor->touch_calibration_save = save;
708 weston_layer_init(&compositor->calibrator_layer, compositor);
709
710 /* needs to be stacked above everything except lock screen and cursor,
711 * otherwise the position value is arbitrary */
712 weston_layer_set_position(&compositor->calibrator_layer,
713 WESTON_LAYER_POSITION_TOP_UI + 120);
714
715 return 0;
716 }
717