[PATCH weston 24/25] clients: add a new touchscreen calibrator
Pekka Paalanen
ppaalanen at gmail.com
Fri Mar 23 12:01:04 UTC 2018
From: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
The new calibrator uses weston_touch_calibration protocol extension and
provides the following features:
- chooses the physical touch device to be calibrated by DEVPATH or by
the output/head name; device enumeration provided
- the compositor ensures the calibrator window is shown in the correct
position and size
- no matter how wrong the old calibration is, the touch events will
always arrive in the application
- the calibration is complete, not incremental; the received touch
events are guaranteed to be unmodified
- computes a libinput style calibration matrix directly, not the
WL_CALIBRATION format
- supports multiple touch devices: calibrate one device at a time, and
show user feedback on touching a wrong device instead of recording bad
data
- uses four touch point samples: three to compute the calibration, and
one to verify the calibration is roughly correct
- consistent exit codes
- upload the new calibration into the server after successful
and verified calibration
Due to using special touchscreen calibration protocol extension, this
application cannot be tested without touch input from the compositor.
Practically all of the above mentioned are unlike how the old
calibrator client worked.
Co-developed by Louis-Francis and Pekka.
Signed-off-by: Louis-Francis Ratté-Boulianne <lfrb at collabora.com>
Signed-off-by: Pekka Paalanen <pekka.paalanen at collabora.co.uk>
---
.gitignore | 1 +
Makefile.am | 14 +
clients/touch-calibrator.c | 774 +++++++++++++++++++++++++++++++++++++++++++++
clients/window.c | 4 +-
clients/window.h | 4 +
5 files changed, 795 insertions(+), 2 deletions(-)
create mode 100644 clients/touch-calibrator.c
diff --git a/.gitignore b/.gitignore
index ac76fd9f..b6226927 100644
--- a/.gitignore
+++ b/.gitignore
@@ -76,6 +76,7 @@ weston-simple-damage
weston-smoke
weston-stacking
weston-subsurfaces
+weston-touch-calibrator
weston-transformed
weston-view
diff --git a/Makefile.am b/Makefile.am
index ca878824..dad7e8ac 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -543,6 +543,7 @@ demo_clients = \
weston-fullscreen \
weston-stacking \
weston-calibrator \
+ weston-touch-calibrator \
weston-scaler
if INSTALL_DEMO_CLIENTS
@@ -778,6 +779,17 @@ weston_calibrator_SOURCES = \
weston_calibrator_LDADD = libtoytoolkit.la
weston_calibrator_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
+weston_touch_calibrator_SOURCES = \
+ clients/touch-calibrator.c \
+ shared/helpers.h \
+ shared/matrix.c \
+ shared/matrix.h
+nodist_weston_touch_calibrator_SOURCES = \
+ protocol/weston-touch-calibration-protocol.c \
+ protocol/weston-touch-calibration-client-protocol.h
+weston_touch_calibrator_LDADD = libtoytoolkit.la
+weston_touch_calibrator_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
+
if BUILD_SUBSURFACES_CLIENT
demo_clients += weston-subsurfaces
weston_subsurfaces_SOURCES = \
@@ -863,6 +875,8 @@ endif
BUILT_SOURCES += \
protocol/weston-screenshooter-protocol.c \
protocol/weston-screenshooter-client-protocol.h \
+ protocol/weston-touch-calibration-protocol.c \
+ protocol/weston-touch-calibration-client-protocol.h \
protocol/text-cursor-position-client-protocol.h \
protocol/text-cursor-position-protocol.c \
protocol/text-input-unstable-v1-protocol.c \
diff --git a/clients/touch-calibrator.c b/clients/touch-calibrator.c
new file mode 100644
index 00000000..aa399822
--- /dev/null
+++ b/clients/touch-calibrator.c
@@ -0,0 +1,774 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ * Copyright (c) 2017, 2018 Collabora, Ltd.
+ * Copyright (c) 2017, 2018 General Electric Company
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <cairo.h>
+#include <math.h>
+#include <assert.h>
+#include <getopt.h>
+#include <errno.h>
+
+#include <wayland-client.h>
+
+#include "clients/window.h"
+#include "shared/helpers.h"
+#include "shared/matrix.h"
+
+#include "weston-touch-calibration-client-protocol.h"
+
+enum exit_code {
+ CAL_EXIT_SUCCESS = 0,
+ CAL_EXIT_ERROR = 1,
+ CAL_EXIT_CANCELLED = 2,
+};
+
+static int debug_;
+static int verbose_;
+
+#define pr_ver(...) do { \
+ if (verbose_) \
+ printf(__VA_ARGS__); \
+} while (0)
+
+#define pr_dbg(...) do { \
+ if (debug_) \
+ fprintf(stderr, __VA_ARGS__); \
+} while (0)
+
+static void
+pr_err(const char *fmt, ...) WL_PRINTF(1, 2);
+
+/* Our points for the calibration must be not be on a line */
+static const struct {
+ float x_ratio, y_ratio;
+} test_ratios[] = {
+ { 0.15, 0.10 }, /* three points for calibration */
+ { 0.85, 0.13 },
+ { 0.20, 0.80 },
+ { 0.70, 0.75 } /* and one for verification */
+};
+
+#define NR_SAMPLES ((int)ARRAY_LENGTH(test_ratios))
+
+struct point {
+ double x;
+ double y;
+};
+
+struct sample {
+ struct point drawn; /**< drawn point, pixels */
+ struct weston_touch_coordinate *pending;
+ struct point drawn_cal; /**< drawn point, converted */
+ bool conv_done;
+ struct point touched; /**< touch point, normalized */
+ bool touch_done;
+};
+
+struct poly {
+ struct color {
+ double r, g, b, a;
+ } color;
+ int n_verts;
+ const struct point *verts;
+};
+
+struct calibrator {
+ struct sample samples[NR_SAMPLES];
+ int current_sample;
+
+ struct display *display;
+ struct weston_touch_calibration *calibration;
+ struct weston_touch_calibrator *calibrator;
+ struct window *window;
+ struct widget *widget;
+
+ int n_devices_listed;
+ char *match_name;
+ char *device_name;
+
+ int width;
+ int height;
+
+ bool cancelled;
+
+ struct toytimer feedback;
+ const struct poly *current_poly;
+ bool exiting;
+};
+
+static void
+sample_start(struct calibrator *cal, int i)
+{
+ struct sample *s = &cal->samples[i];
+
+ assert(i >= 0 && i < NR_SAMPLES);
+
+ s->drawn.x = round(test_ratios[i].x_ratio * cal->width);
+ s->drawn.y = round(test_ratios[i].y_ratio * cal->height);
+ s->pending = NULL;
+ s->conv_done = false;
+ s->touch_done = false;
+
+ cal->current_sample = i;
+
+ widget_schedule_redraw(cal->widget);
+}
+
+static double
+calcoord_to_double(uint32_t u)
+{
+ return (double)u / 0xffffffff;
+}
+
+static void
+coordinate_result_handler(void *data, struct weston_touch_coordinate *interface,
+ uint32_t xu, uint32_t yu)
+{
+ struct sample *s = data;
+
+ weston_touch_coordinate_destroy(s->pending);
+ s->pending = NULL;
+
+ s->drawn_cal.x = calcoord_to_double(xu);
+ s->drawn_cal.y = calcoord_to_double(yu);
+ s->conv_done = true;
+
+ pr_dbg("Conv (%f, %f)\n", s->drawn_cal.x, s->drawn_cal.y);
+}
+
+struct weston_touch_coordinate_listener coordinate_listener = {
+ coordinate_result_handler
+};
+
+static void
+sample_convert(struct calibrator *cal, struct sample *s)
+{
+ assert(!s->pending && !s->conv_done);
+
+ s->pending = weston_touch_calibrator_convert(cal->calibrator,
+ (int32_t)s->drawn.x,
+ (int32_t)s->drawn.y);
+ weston_touch_coordinate_add_listener(s->pending,
+ &coordinate_listener, s);
+}
+
+/*
+ * Calibration algorithm:
+ *
+ * The equation we want to apply at event time where x' and y' are the
+ * calibrated co-ordinates.
+ *
+ * x' = Ax + By + C
+ * y' = Dx + Ey + F
+ *
+ * For example "zero calibration" would be A=1.0 B=0.0 C=0.0, D=0.0, E=1.0,
+ * and F=0.0.
+ *
+ * With 6 unknowns we need 6 equations to find the constants:
+ *
+ * x1' = Ax1 + By1 + C
+ * y1' = Dx1 + Ey1 + F
+ * ...
+ * x3' = Ax3 + By3 + C
+ * y3' = Dx3 + Ey3 + F
+ *
+ * In matrix form:
+ *
+ * x1' x1 y1 1 A
+ * x2' = x2 y2 1 x B
+ * x3' x3 y3 1 C
+ *
+ * So making the matrix M we can find the constants with:
+ *
+ * A x1'
+ * B = M^-1 x x2'
+ * C x3'
+ *
+ * (and similarly for D, E and F)
+ *
+ * For the calibration the desired values x, y are the same values at which
+ * we've drawn at.
+ *
+ */
+static int
+compute_calibration(struct calibrator *cal, float *result)
+{
+ struct weston_matrix m;
+ struct weston_matrix inverse;
+ struct weston_vector x_calib;
+ struct weston_vector y_calib;
+ int i;
+
+ assert(NR_SAMPLES >= 3);
+
+ /*
+ * x1 y1 1 0
+ * x2 y2 1 0
+ * x3 y3 1 0
+ * 0 0 0 1
+ */
+ weston_matrix_init(&m);
+ for (i = 0; i < 3; i++) {
+ m.d[i + 0] = cal->samples[i].touched.x;
+ m.d[i + 4] = cal->samples[i].touched.y;
+ m.d[i + 8] = 1.0f;
+ }
+ m.type = WESTON_MATRIX_TRANSFORM_OTHER;
+
+ if (weston_matrix_invert(&inverse, &m) < 0) {
+ pr_err("non-invertible matrix during computation\n");
+ return -1;
+ }
+
+ for (i = 0; i < 3; i++) {
+ x_calib.f[i] = cal->samples[i].drawn_cal.x;
+ y_calib.f[i] = cal->samples[i].drawn_cal.y;
+ }
+ x_calib.f[3] = 0.0f;
+ y_calib.f[3] = 0.0f;
+
+ /* Multiples into the vector */
+ weston_matrix_transform(&inverse, &x_calib);
+ weston_matrix_transform(&inverse, &y_calib);
+
+ for (i = 0; i < 3; i++)
+ result[i] = x_calib.f[i];
+ for (i = 0; i < 3; i++)
+ result[i + 3] = y_calib.f[i];
+
+ return 0;
+}
+
+static int
+verify_calibration(struct calibrator *cal, const float *r)
+{
+ double thr = 0.1; /* accepted error radius */
+ struct point e; /* expected value; error */
+ const struct sample *s = &cal->samples[3];
+
+ /* transform raw touches through the matrix */
+ e.x = r[0] * s->touched.x + r[1] * s->touched.y + r[2];
+ e.y = r[3] * s->touched.x + r[4] * s->touched.y + r[5];
+
+ /* compute error */
+ e.x -= s->drawn_cal.x;
+ e.y -= s->drawn_cal.y;
+
+ pr_dbg("calibration test error: %f, %f\n", e.x, e.y);
+
+ if (e.x * e.x + e.y * e.y < thr * thr)
+ return 0;
+
+ pr_err("Calibration verification failed, too large error.\n");
+ return -1;
+}
+
+static void
+send_calibration(struct calibrator *cal, float *values)
+{
+ struct wl_array matrix;
+ float *f;
+ int i;
+
+ wl_array_init(&matrix);
+ for (i = 0; i < 6; i++) {
+ f = wl_array_add(&matrix, sizeof *f);
+ *f = values[i];
+ }
+ weston_touch_calibration_save(cal->calibration,
+ cal->device_name, &matrix);
+ wl_array_release(&matrix);
+}
+
+static const struct point cross_verts[] = {
+ { 0.1, 0.2 },
+ { 0.2, 0.1 },
+ { 0.5, 0.4 },
+ { 0.8, 0.1 },
+ { 0.9, 0.2 },
+ { 0.6, 0.5 },
+ { 0.9, 0.8 },
+ { 0.8, 0.9 },
+ { 0.5, 0.6 },
+ { 0.2, 0.9 },
+ { 0.1, 0.8 },
+ { 0.4, 0.5 },
+};
+
+/* a red cross, for "wrong" */
+static const struct poly cross = {
+ .color = { 0.7, 0.0, 0.0, 1.0 },
+ .n_verts = ARRAY_LENGTH(cross_verts),
+ .verts = cross_verts
+};
+
+static const struct point check_verts[] = {
+ { 0.5, 0.7 },
+ { 0.8, 0.1 },
+ { 0.9, 0.1 },
+ { 0.55, 0.8 },
+ { 0.45, 0.8 },
+ { 0.3, 0.5 },
+ { 0.4, 0.5 }
+};
+
+/* a green check mark, for "right" */
+static const struct poly check = {
+ .color = { 0.0, 0.7, 0.0, 1.0 },
+ .n_verts = ARRAY_LENGTH(check_verts),
+ .verts = check_verts
+};
+
+static void
+draw_poly(cairo_t *cr, const struct poly *poly)
+{
+ int i;
+
+ cairo_set_source_rgba(cr, poly->color.r, poly->color.g,
+ poly->color.b, poly->color.a);
+ cairo_move_to(cr, poly->verts[0].x, poly->verts[0].y);
+ for (i = 1; i < poly->n_verts; i++)
+ cairo_line_to(cr, poly->verts[i].x, poly->verts[i].y);
+ cairo_close_path(cr);
+ cairo_fill(cr);
+}
+
+static void
+feedback_done(struct toytimer *tt)
+{
+ struct calibrator *cal = container_of(tt, struct calibrator, feedback);
+
+ cal->current_poly = NULL;
+ widget_schedule_redraw(cal->widget);
+
+ if (cal->exiting)
+ display_exit(cal->display);
+}
+
+static void
+feedback_show(struct calibrator *cal, const struct poly *what)
+{
+ cal->current_poly = what;
+ toytimer_arm_once_usec(&cal->feedback, 1000 * 1000);
+ widget_schedule_redraw(cal->widget);
+}
+
+static void
+redraw_handler(struct widget *widget, void *data)
+{
+ struct calibrator *cal = data;
+ struct sample *s = &cal->samples[cal->current_sample];
+ struct rectangle allocation;
+ cairo_surface_t *surface;
+ cairo_t *cr;
+
+ widget_get_allocation(cal->widget, &allocation);
+ assert(allocation.width == cal->width);
+ assert(allocation.height == cal->height);
+
+ surface = window_get_surface(cal->window);
+ cr = cairo_create(surface);
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+ cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
+ cairo_paint(cr);
+
+ if (!cal->current_poly) {
+ cairo_translate(cr, s->drawn.x, s->drawn.y);
+ cairo_set_line_width(cr, 2.0);
+ cairo_set_source_rgb(cr, 0.7, 0.0, 0.0);
+ cairo_move_to(cr, 0, -10.0);
+ cairo_line_to(cr, 0, 10.0);
+ cairo_stroke(cr);
+ cairo_move_to(cr, -10.0, 0);
+ cairo_line_to(cr, 10.0, 0.0);
+ cairo_stroke(cr);
+ } else {
+ cairo_scale(cr, allocation.width, allocation.height);
+ draw_poly(cr, cal->current_poly);
+ }
+
+ cairo_destroy(cr);
+ cairo_surface_destroy(surface);
+}
+
+static struct calibrator *
+calibrator_create(struct display *display, const char *match_name)
+{
+ struct calibrator *cal;
+
+ cal = zalloc(sizeof *cal);
+ if (!cal)
+ abort();
+
+ cal->match_name = match_name ? strdup(match_name) : NULL;
+ cal->window = window_create_custom(display);
+ cal->widget = window_add_widget(cal->window, cal);
+ window_inhibit_redraw(cal->window);
+ window_set_title(cal->window, "Touchscreen calibrator");
+ cal->display = display;
+
+ widget_set_redraw_handler(cal->widget, redraw_handler);
+
+ toytimer_init(&cal->feedback, CLOCK_MONOTONIC, display, feedback_done);
+
+ return cal;
+}
+
+static void
+configure_handler(void *data, struct weston_touch_calibrator *interface,
+ int32_t width, int32_t height)
+{
+ struct calibrator *cal = data;
+
+ pr_dbg("Configure calibrator window to size %ix%i\n", width, height);
+ cal->width = width;
+ cal->height = height;
+ window_schedule_resize(cal->window, width, height);
+ window_uninhibit_redraw(cal->window);
+
+ sample_start(cal, 0);
+}
+
+static void
+cancel_calibration_handler(void *data, struct weston_touch_calibrator *interface)
+{
+ struct calibrator *cal = data;
+
+ pr_dbg("calibration cancelled by the display server, quitting.\n");
+ cal->cancelled = true;
+ display_exit(cal->display);
+}
+
+static void
+wrong_touch_handler(void *data, struct weston_touch_calibrator *interface)
+{
+ struct calibrator *cal = data;
+
+ pr_dbg("wrong touch\n");
+ feedback_show(cal, &cross);
+}
+
+static void
+down_handler(void *data, struct weston_touch_calibrator *interface,
+ uint32_t time, int32_t id, uint32_t xu, uint32_t yu)
+{
+ struct calibrator *cal = data;
+ struct sample *s = &cal->samples[cal->current_sample];
+
+ if (cal->current_poly)
+ return;
+
+ /* XXX: instead, should act on frame event, after touch down and up */
+
+ s->touched.x = calcoord_to_double(xu);
+ s->touched.y = calcoord_to_double(yu);
+ s->touch_done = true;
+
+ pr_dbg("Down (%f, %f)\n", s->touched.x, s->touched.y);
+
+ feedback_show(cal, &check);
+ sample_convert(cal, s);
+
+ if (cal->current_sample + 1 < NR_SAMPLES) {
+ sample_start(cal, cal->current_sample + 1);
+ } else {
+ pr_dbg("got all touches\n");
+ cal->exiting = true;
+ }
+}
+
+static void
+up_handler(void *data, struct weston_touch_calibrator *interface,
+ uint32_t time, int32_t id)
+{
+}
+
+static void
+motion_handler(void *data, struct weston_touch_calibrator *interface,
+ uint32_t time, int32_t id, uint32_t xu, uint32_t yu)
+{
+}
+
+static void
+frame_handler(void *data, struct weston_touch_calibrator *interface)
+{
+}
+
+static void
+cancel_handler(void *data, struct weston_touch_calibrator *interface)
+{
+}
+
+struct weston_touch_calibrator_listener calibrator_listener = {
+ configure_handler,
+ cancel_calibration_handler,
+ wrong_touch_handler,
+ down_handler,
+ up_handler,
+ motion_handler,
+ frame_handler,
+ cancel_handler
+};
+
+static void
+calibrator_show(struct calibrator *cal)
+{
+ struct wl_surface *surface = window_get_wl_surface(cal->window);
+
+ cal->calibrator =
+ weston_touch_calibration_create_calibrator(cal->calibration,
+ surface,
+ cal->device_name);
+ weston_touch_calibrator_add_listener(cal->calibrator,
+ &calibrator_listener, cal);
+}
+
+static void
+calibrator_destroy(struct calibrator *cal)
+{
+ toytimer_fini(&cal->feedback);
+ if (cal->calibrator)
+ weston_touch_calibrator_destroy(cal->calibrator);
+ if (cal->calibration)
+ weston_touch_calibration_destroy(cal->calibration);
+ if (cal->widget)
+ widget_destroy(cal->widget);
+ if (cal->window)
+ window_destroy(cal->window);
+ free(cal->match_name);
+ free(cal->device_name);
+ free(cal);
+}
+
+static void
+touch_device_handler(void *data, struct weston_touch_calibration *c,
+ const char *device, const char *head)
+{
+ struct calibrator *cal = data;
+
+ cal->n_devices_listed++;
+
+ if (!cal->match_name) {
+ printf("device \"%s\" - head \"%s\"\n", device, head);
+ return;
+ }
+
+ if (cal->device_name)
+ return;
+
+ if (strcmp(cal->match_name, device) == 0 ||
+ strcmp(cal->match_name, head) == 0)
+ cal->device_name = strdup(device);
+}
+
+struct weston_touch_calibration_listener touch_calibration_listener = {
+ touch_device_handler
+};
+
+static void
+global_handler(struct display *display, uint32_t name,
+ const char *interface, uint32_t version, void *data)
+{
+ struct calibrator *cal = data;
+
+ if (strcmp(interface, "weston_touch_calibration") == 0) {
+ cal->calibration = display_bind(display, name,
+ &weston_touch_calibration_interface, 1);
+ weston_touch_calibration_add_listener(cal->calibration,
+ &touch_calibration_listener,
+ cal);
+ }
+}
+
+static int
+calibrator_run(struct calibrator *cal)
+{
+ struct wl_display *dpy;
+ struct sample *s;
+ bool wait;
+ int i;
+ int ret;
+ float result[6];
+
+ calibrator_show(cal);
+ display_run(cal->display);
+
+ if (cal->cancelled)
+ return CAL_EXIT_CANCELLED;
+
+ /* remove the window, no more input events */
+ widget_destroy(cal->widget);
+ cal->widget = NULL;
+ window_destroy(cal->window);
+ cal->window = NULL;
+
+ /* wait for all conversions to return */
+ dpy = display_get_display(cal->display);
+ do {
+ wait = false;
+
+ for (i = 0; i < NR_SAMPLES; i++)
+ if (cal->samples[i].pending)
+ wait = true;
+
+ if (wait) {
+ ret = wl_display_roundtrip(dpy);
+ if (ret < 0)
+ return CAL_EXIT_ERROR;
+ }
+ } while (wait);
+
+ for (i = 0; i < NR_SAMPLES; i++) {
+ s = &cal->samples[i];
+ if (!s->conv_done || !s->touch_done)
+ return CAL_EXIT_ERROR;
+ }
+
+ if (compute_calibration(cal, result) < 0)
+ return CAL_EXIT_ERROR;
+
+ if (verify_calibration(cal, result) < 0)
+ return CAL_EXIT_ERROR;
+
+ pr_ver("Calibration values:");
+ for (i = 0; i < 6; i++)
+ pr_ver(" %f", result[i]);
+ pr_ver("\n");
+
+ send_calibration(cal, result);
+ ret = wl_display_roundtrip(dpy);
+ if (ret < 0)
+ return CAL_EXIT_ERROR;
+
+ return CAL_EXIT_SUCCESS;
+}
+
+static void
+pr_err(const char *fmt, ...)
+{
+ va_list argp;
+
+ va_start(argp, fmt);
+ fprintf(stderr, "%s error: ", program_invocation_short_name);
+ vfprintf(stderr, fmt, argp);
+ va_end(argp);
+}
+
+static void
+help(void)
+{
+ fprintf(stderr, "Usage: %s [options...] [name]\n\n",
+ program_invocation_short_name);
+ fprintf(stderr,
+ "Where 'name' can be a touch device DEVPATH or a head name.\n"
+ "If 'name' is not given, all devices available for "
+ "calibration will be listed.\n"
+ "Options:\n"
+ " --debug Print messages to help debugging.\n"
+ " -h, --help Display this help message\n"
+ " -v, --verbose Print list header and calibration result.\n");
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct display *display;
+ struct calibrator *cal;
+ int c;
+ char *match_name = NULL;
+ int exit_code = CAL_EXIT_SUCCESS;
+ static const struct option opts[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "debug", no_argument, &debug_, 1 },
+ { "verbose", no_argument, &verbose_, 1 },
+ { 0, 0, NULL, 0 }
+ };
+
+ while ((c = getopt_long(argc, argv, "hv", opts, NULL)) != -1) {
+ switch (c) {
+ case 'h':
+ help();
+ return CAL_EXIT_SUCCESS;
+ case 'v':
+ verbose_ = 1;
+ break;
+ case 0:
+ break;
+ default:
+ return CAL_EXIT_ERROR;
+ }
+ }
+
+ if (optind < argc)
+ match_name = argv[optind++];
+
+ if (optind < argc) {
+ pr_err("extra arguments given.\n\n");
+ help();
+ return CAL_EXIT_ERROR;
+ }
+
+ display = display_create(&argc, argv);
+ if (!display)
+ return CAL_EXIT_ERROR;
+
+ cal = calibrator_create(display, match_name);
+ if (!cal)
+ return CAL_EXIT_ERROR;
+
+ display_set_user_data(display, cal);
+ display_set_global_handler(display, global_handler);
+
+ if (!match_name)
+ pr_ver("Available touch devices:\n");
+
+ /* Roundtrip to get list of available touch devices,
+ * first globals, then touch_device events */
+ wl_display_roundtrip(display_get_display(display));
+ wl_display_roundtrip(display_get_display(display));
+
+ if (!cal->calibration) {
+ exit_code = CAL_EXIT_ERROR;
+ pr_err("the Wayland server does not expose the calibration interface.\n");
+ } else if (cal->device_name) {
+ exit_code = calibrator_run(cal);
+ } else if (match_name) {
+ exit_code = CAL_EXIT_ERROR;
+ pr_err("\"%s\" was not found.\n", match_name);
+ } else if (cal->n_devices_listed == 0) {
+ fprintf(stderr, "No devices listed.\n");
+ }
+
+ calibrator_destroy(cal);
+ display_destroy(display);
+
+ return exit_code;
+}
diff --git a/clients/window.c b/clients/window.c
index bcf2b017..d0c7581d 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -4219,7 +4219,7 @@ window_get_shadow_margin(struct window *window)
return 0;
}
-static void
+void
window_inhibit_redraw(struct window *window)
{
window->redraw_inhibited = 1;
@@ -4228,7 +4228,7 @@ window_inhibit_redraw(struct window *window)
window->redraw_task_scheduled = 0;
}
-static void
+void
window_uninhibit_redraw(struct window *window)
{
window->redraw_inhibited = 0;
diff --git a/clients/window.h b/clients/window.h
index 3366ab15..fde5c2f0 100644
--- a/clients/window.h
+++ b/clients/window.h
@@ -604,6 +604,10 @@ widget_set_axis_handlers(struct widget *widget,
widget_axis_stop_handler_t axis_stop_handler,
widget_axis_discrete_handler_t axis_discrete_handler);
+void
+window_inhibit_redraw(struct window *window);
+void
+window_uninhibit_redraw(struct window *window);
void
widget_schedule_redraw(struct widget *widget);
void
--
2.16.1
More information about the wayland-devel
mailing list