GCC Code Coverage Report


Directory: ./
File: panels/wacom/calibrator/main.c
Date: 2024-05-04 07:58:27
Exec Total Coverage
Lines: 0 205 0.0%
Functions: 0 8 0.0%
Branches: 0 122 0.0%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2009 Tias Guns
3 * Copyright (c) 2009 Soren Hauberg
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the 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 THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 * THE SOFTWARE.
22 */
23
24 #include "config.h"
25
26 #include <stdlib.h>
27 #include <ctype.h>
28 #include <string.h>
29 #include <dirent.h>
30 #include <glib/gi18n.h>
31
32 #include <X11/extensions/XInput.h>
33
34 #include "calibrator-gui.h"
35 #include "calibrator.h"
36
37 static GMainLoop *mainloop = NULL;
38
39 /**
40 * find a calibratable touchscreen device (using XInput)
41 *
42 * if pre_device is NULL, the last calibratable device is selected.
43 * retuns number of devices found,
44 * the data of the device is returned in the last 3 function parameters
45 */
46 static int find_device(const char* pre_device, gboolean verbose, gboolean list_devices,
47 XID* device_id, const char** device_name, XYinfo* device_axis)
48 {
49 gboolean pre_device_is_id = TRUE;
50 int found = 0;
51
52 Display* display = XOpenDisplay(NULL);
53 if (display == NULL) {
54 fprintf(stderr, "Unable to connect to X server\n");
55 exit(1);
56 }
57
58 int xi_opcode, event, error;
59 if (!XQueryExtension(display, "XInputExtension", &xi_opcode, &event, &error)) {
60 fprintf(stderr, "X Input extension not available.\n");
61 exit(1);
62 }
63
64 /* verbose, get Xi version */
65 if (verbose) {
66 XExtensionVersion *version = XGetExtensionVersion(display, INAME);
67
68 if (version && (version != (XExtensionVersion*) NoSuchExtension)) {
69 printf("DEBUG: %s version is %i.%i\n",
70 INAME, version->major_version, version->minor_version);
71 XFree(version);
72 }
73 }
74
75 if (pre_device != NULL) {
76 /* check whether the pre_device is an ID (only digits) */
77 int len = strlen(pre_device);
78 int loop;
79 for (loop=0; loop<len; loop++) {
80 if (!isdigit(pre_device[loop])) {
81 pre_device_is_id = FALSE;
82 break;
83 }
84 }
85 }
86
87
88 if (verbose)
89 printf("DEBUG: Skipping virtual master devices and devices without axis valuators.\n");
90 int ndevices;
91 XDeviceInfoPtr list, slist;
92 slist=list=(XDeviceInfoPtr) XListInputDevices (display, &ndevices);
93 int i;
94 for (i=0; i<ndevices; i++, list++)
95 {
96 if (list->use == IsXKeyboard || list->use == IsXPointer) /* virtual master device */
97 continue;
98
99 /* if we are looking for a specific device */
100 if (pre_device != NULL) {
101 if ((pre_device_is_id && list->id == (XID) atoi(pre_device)) ||
102 (!pre_device_is_id && strcmp(list->name, pre_device) == 0)) {
103 /* OK, fall through */
104 } else {
105 /* skip, not this device */
106 continue;
107 }
108 }
109
110 XAnyClassPtr any = (XAnyClassPtr) (list->inputclassinfo);
111 int j;
112 for (j=0; j<list->num_classes; j++)
113 {
114
115 if (any->class == ValuatorClass)
116 {
117 XValuatorInfoPtr V = (XValuatorInfoPtr) any;
118 XAxisInfoPtr ax = (XAxisInfoPtr) V->axes;
119
120 if (V->mode != Absolute) {
121 if (verbose)
122 printf("DEBUG: Skipping device '%s' id=%i, does not report Absolute events.\n",
123 list->name, (int)list->id);
124 } else if (V->num_axes < 2 ||
125 (ax[0].min_value == -1 && ax[0].max_value == -1) ||
126 (ax[1].min_value == -1 && ax[1].max_value == -1)) {
127 if (verbose)
128 printf("DEBUG: Skipping device '%s' id=%i, does not have two calibratable axes.\n",
129 list->name, (int)list->id);
130 } else {
131 /* a calibratable device (has 2 axis valuators) */
132 found++;
133 *device_id = list->id;
134 *device_name = g_strdup(list->name);
135 device_axis->x_min = ax[0].min_value;
136 device_axis->x_max = ax[0].max_value;
137 device_axis->y_min = ax[1].min_value;
138 device_axis->y_max = ax[1].max_value;
139
140 if (list_devices)
141 printf("Device \"%s\" id=%i\n", *device_name, (int)*device_id);
142 }
143
144 }
145
146 /*
147 * Increment 'any' to point to the next item in the linked
148 * list. The length is in bytes, so 'any' must be cast to
149 * a character pointer before being incremented.
150 */
151 any = (XAnyClassPtr) ((char *) any + any->length);
152 }
153
154 }
155 XFreeDeviceList(slist);
156 XCloseDisplay(display);
157
158 return found;
159 }
160
161 static void usage(char* cmd, unsigned thr_misclick)
162 {
163 fprintf(stderr, "Usage: %s [-h|--help] [-v|--verbose] [--list] [--device <device name or id>] [--precalib <minx> <maxx> <miny> <maxy>] [--misclick <nr of pixels>] [--output-type <auto|xorg.conf.d|hal|xinput>] [--fake]\n", cmd);
164 fprintf(stderr, "\t-h, --help: print this help message\n");
165 fprintf(stderr, "\t-v, --verbose: print debug messages during the process\n");
166 fprintf(stderr, "\t--list: list calibratable input devices and quit\n");
167 fprintf(stderr, "\t--device <device name or id>: select a specific device to calibrate\n");
168 fprintf(stderr, "\t--precalib: manually provide the current calibration setting (eg. the values in xorg.conf)\n");
169 fprintf(stderr, "\t--misclick: set the misclick threshold (0=off, default: %i pixels)\n",
170 thr_misclick);
171 fprintf(stderr, "\t--fake: emulate a fake device (for testing purposes)\n");
172 }
173
174 static struct Calib* CalibratorXorgPrint(const char* const device_name0, const XYinfo *axis0, const gboolean verbose0, const int thr_misclick, const int thr_doubleclick)
175 {
176 struct Calib* c = (struct Calib*)calloc(1, sizeof(struct Calib));
177 c->threshold_misclick = thr_misclick;
178 c->threshold_doubleclick = thr_doubleclick;
179
180 printf("Calibrating standard Xorg driver \"%s\"\n", device_name0);
181 printf("\tcurrent calibration values: min_x=%lf, max_x=%lf and min_y=%lf, max_y=%lf\n",
182 axis0->x_min, axis0->x_max, axis0->y_min, axis0->y_max);
183 printf("\tIf these values are estimated wrong, either supply it manually with the --precalib option, or run the 'get_precalib.sh' script to automatically get it (through HAL).\n");
184
185 return c;
186 }
187
188 static struct Calib* main_common(int argc, char** argv)
189 {
190 gboolean verbose = FALSE;
191 gboolean list_devices = FALSE;
192 gboolean fake = FALSE;
193 gboolean precalib = FALSE;
194 XYinfo pre_axis = {-1, -1, -1, -1};
195 const char* pre_device = NULL;
196 unsigned thr_misclick = 15;
197 unsigned thr_doubleclick = 7;
198
199 /* parse input */
200 if (argc > 1) {
201 int i;
202 for (i=1; i!=argc; i++) {
203 /* Display help ? */
204 if (strcmp("-h", argv[i]) == 0 ||
205 strcmp("--help", argv[i]) == 0) {
206 fprintf(stderr, "xinput_calibrator, v%s\n\n", "0.0.0");
207 usage(argv[0], thr_misclick);
208 exit(0);
209 } else
210
211 /* Verbose output ? */
212 if (strcmp("-v", argv[i]) == 0 ||
213 strcmp("--verbose", argv[i]) == 0) {
214 verbose = TRUE;
215 } else
216
217 /* Just list devices ? */
218 if (strcmp("--list", argv[i]) == 0) {
219 list_devices = TRUE;
220 } else
221
222 /* Select specific device ? */
223 if (strcmp("--device", argv[i]) == 0) {
224 if (argc > i+1)
225 pre_device = argv[++i];
226 else {
227 fprintf(stderr, "Error: --device needs a device name or id as argument; use --list to list the calibratable input devices.\n\n");
228 usage(argv[0], thr_misclick);
229 exit(1);
230 }
231 } else
232
233 /* Get pre-calibration ? */
234 if (strcmp("--precalib", argv[i]) == 0) {
235 precalib = TRUE;
236 if (argc > i+1)
237 pre_axis.x_min = atoi(argv[++i]);
238 if (argc > i+1)
239 pre_axis.x_max = atoi(argv[++i]);
240 if (argc > i+1)
241 pre_axis.y_min = atoi(argv[++i]);
242 if (argc > i+1)
243 pre_axis.y_max = atoi(argv[++i]);
244 } else
245
246 /* Get mis-click threshold ? */
247 if (strcmp("--misclick", argv[i]) == 0) {
248 if (argc > i+1)
249 thr_misclick = atoi(argv[++i]);
250 else {
251 fprintf(stderr, "Error: --misclick needs a number (the pixel threshold) as argument. Set to 0 to disable mis-click detection.\n\n");
252 usage(argv[0], thr_misclick);
253 exit(1);
254 }
255 } else
256
257 /* Fake calibratable device ? */
258 if (strcmp("--fake", argv[i]) == 0) {
259 fake = TRUE;
260 }
261
262 /* unknown option */
263 else {
264 fprintf(stderr, "Unknown option: %s\n\n", argv[i]);
265 usage(argv[0], thr_misclick);
266 exit(0);
267 }
268 }
269 }
270
271
272 /* Choose the device to calibrate */
273 XID device_id = (XID) -1;
274 const char* device_name = NULL;
275 XYinfo device_axis = {-1, -1, -1, -1};
276 if (fake) {
277 /* Fake a calibratable device */
278 device_name = "Fake_device";
279 device_axis.x_min=0;
280 device_axis.x_max=1000;
281 device_axis.y_min=0;
282 device_axis.y_max=1000;
283
284 if (verbose) {
285 printf("DEBUG: Faking device: %s\n", device_name);
286 }
287 } else {
288 /* Find the right device */
289 int nr_found = find_device(pre_device, verbose, list_devices, &device_id, &device_name, &device_axis);
290
291 if (list_devices) {
292 /* printed the list in find_device */
293 if (nr_found == 0)
294 printf("No calibratable devices found.\n");
295 exit(0);
296 }
297
298 if (nr_found == 0) {
299 if (pre_device == NULL)
300 fprintf (stderr, "Error: No calibratable devices found.\n");
301 else
302 fprintf (stderr, "Error: Device \"%s\" not found; use --list to list the calibratable input devices.\n", pre_device);
303 exit(1);
304
305 } else if (nr_found > 1) {
306 printf ("Warning: multiple calibratable devices found, calibrating last one (%s)\n\tuse --device to select another one.\n", device_name);
307 }
308
309 if (verbose) {
310 printf("DEBUG: Selected device: %s\n", device_name);
311 }
312 }
313
314 /* override min/max XY from command line ? */
315 if (precalib) {
316 if (pre_axis.x_min != -1)
317 device_axis.x_min = pre_axis.x_min;
318 if (pre_axis.x_max != -1)
319 device_axis.x_max = pre_axis.x_max;
320 if (pre_axis.y_min != -1)
321 device_axis.y_min = pre_axis.y_min;
322 if (pre_axis.y_max != -1)
323 device_axis.y_max = pre_axis.y_max;
324
325 if (verbose) {
326 printf("DEBUG: Setting precalibration: %lf, %lf, %lf, %lf\n",
327 device_axis.x_min, device_axis.x_max,
328 device_axis.y_min, device_axis.y_max);
329 }
330 }
331
332 /* lastly, presume a standard Xorg driver (evtouch, mutouch, ...) */
333 return CalibratorXorgPrint(device_name, &device_axis,
334 verbose, thr_misclick, thr_doubleclick);
335 }
336
337 static gboolean output_xorgconfd(const XYinfo new_axis, int swap_xy, int new_swap_xy)
338 {
339 const char* sysfs_name = "!!Name_Of_TouchScreen!!";
340
341 /* xorg.conf.d snippet */
342 printf(" copy the snippet below into '/etc/X11/xorg.conf.d/99-calibration.conf'\n");
343 printf("Section \"InputClass\"\n");
344 printf(" Identifier \"calibration\"\n");
345 printf(" MatchProduct \"%s\"\n", sysfs_name);
346 printf(" Option \"MinX\" \"%lf\"\n", new_axis.x_min);
347 printf(" Option \"MaxX\" \"%lf\"\n", new_axis.x_max);
348 printf(" Option \"MinY\" \"%lf\"\n", new_axis.y_min);
349 printf(" Option \"MaxY\" \"%lf\"\n", new_axis.y_max);
350 if (swap_xy != 0)
351 printf(" Option \"SwapXY\" \"%d\" # unless it was already set to 1\n", new_swap_xy);
352 printf("EndSection\n");
353
354 return TRUE;
355 }
356
357 static gboolean finish_data(const XYinfo new_axis, int swap_xy)
358 {
359 gboolean success = TRUE;
360
361 /* we suppose the previous 'swap_xy' value was 0 */
362 /* (unfortunately there is no way to verify this (yet)) */
363 int new_swap_xy = swap_xy;
364
365 printf("\n\n--> Making the calibration permanent <--\n");
366 success &= output_xorgconfd(new_axis, swap_xy, new_swap_xy);
367
368 return success;
369 }
370
371 static void
372 calibration_finished_cb (CcCalibArea *area,
373 gpointer user_data)
374 {
375 gboolean success;
376 XYinfo axis;
377 gboolean swap_xy;
378
379 success = cc_calib_area_finish (area);
380 if (success)
381 {
382 cc_calib_area_get_axis (area, &axis, &swap_xy);
383 success = finish_data (axis, swap_xy);
384 }
385 else
386 fprintf(stderr, "Error: unable to apply or save configuration values\n");
387
388 g_main_loop_quit (mainloop);
389 }
390
391 int main(int argc, char** argv)
392 {
393
394 struct Calib* calibrator = main_common(argc, argv);
395 CcCalibArea *calib_area;
396
397 bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
398 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
399 textdomain (GETTEXT_PACKAGE);
400
401 gtk_init ();
402
403 g_setenv ("G_MESSAGES_DEBUG", "all", TRUE);
404
405 calib_area = cc_calib_area_new (NULL,
406 NULL, /* monitor */
407 NULL, /* NULL to accept input from any device */
408 calibration_finished_cb,
409 NULL,
410 calibrator->threshold_doubleclick,
411 calibrator->threshold_misclick);
412
413 mainloop = g_main_loop_new (NULL, FALSE);
414 g_main_loop_run (mainloop);
415
416 cc_calib_area_free (calib_area);
417
418 free(calibrator);
419
420 return 0;
421 }
422