~ubuntu-branches/ubuntu/trusty/unity-control-center/trusty

« back to all changes in this revision

Viewing changes to panels/wacom/calibrator/main.c

  • Committer: Package Import Robot
  • Author(s): Robert Ancell
  • Date: 2014-01-08 16:29:18 UTC
  • Revision ID: package-import@ubuntu.com-20140108162918-g29dd08tr913y2qh
Tags: upstream-14.04.0
ImportĀ upstreamĀ versionĀ 14.04.0

Show diffs side-by-side

added added

removed removed

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