summaryrefslogtreecommitdiffstats
path: root/panels/wacom/calibrator/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'panels/wacom/calibrator/main.c')
-rw-r--r--panels/wacom/calibrator/main.c421
1 files changed, 421 insertions, 0 deletions
diff --git a/panels/wacom/calibrator/main.c b/panels/wacom/calibrator/main.c
new file mode 100644
index 0000000..71421c7
--- /dev/null
+++ b/panels/wacom/calibrator/main.c
@@ -0,0 +1,421 @@
+/*
+ * Copyright (c) 2009 Tias Guns
+ * Copyright (c) 2009 Soren Hauberg
+ *
+ * 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 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 <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <dirent.h>
+#include <glib/gi18n.h>
+
+#include <X11/extensions/XInput.h>
+
+#include "calibrator-gui.h"
+#include "calibrator.h"
+
+static GMainLoop *mainloop = NULL;
+
+/**
+ * find a calibratable touchscreen device (using XInput)
+ *
+ * if pre_device is NULL, the last calibratable device is selected.
+ * retuns number of devices found,
+ * the data of the device is returned in the last 3 function parameters
+ */
+static int find_device(const char* pre_device, gboolean verbose, gboolean list_devices,
+ XID* device_id, const char** device_name, XYinfo* device_axis)
+{
+ gboolean pre_device_is_id = TRUE;
+ int found = 0;
+
+ Display* display = XOpenDisplay(NULL);
+ if (display == NULL) {
+ fprintf(stderr, "Unable to connect to X server\n");
+ exit(1);
+ }
+
+ int xi_opcode, event, error;
+ if (!XQueryExtension(display, "XInputExtension", &xi_opcode, &event, &error)) {
+ fprintf(stderr, "X Input extension not available.\n");
+ exit(1);
+ }
+
+ /* verbose, get Xi version */
+ if (verbose) {
+ XExtensionVersion *version = XGetExtensionVersion(display, INAME);
+
+ if (version && (version != (XExtensionVersion*) NoSuchExtension)) {
+ printf("DEBUG: %s version is %i.%i\n",
+ INAME, version->major_version, version->minor_version);
+ XFree(version);
+ }
+ }
+
+ if (pre_device != NULL) {
+ /* check whether the pre_device is an ID (only digits) */
+ int len = strlen(pre_device);
+ int loop;
+ for (loop=0; loop<len; loop++) {
+ if (!isdigit(pre_device[loop])) {
+ pre_device_is_id = FALSE;
+ break;
+ }
+ }
+ }
+
+
+ if (verbose)
+ printf("DEBUG: Skipping virtual master devices and devices without axis valuators.\n");
+ int ndevices;
+ XDeviceInfoPtr list, slist;
+ slist=list=(XDeviceInfoPtr) XListInputDevices (display, &ndevices);
+ int i;
+ for (i=0; i<ndevices; i++, list++)
+ {
+ if (list->use == IsXKeyboard || list->use == IsXPointer) /* virtual master device */
+ continue;
+
+ /* if we are looking for a specific device */
+ if (pre_device != NULL) {
+ if ((pre_device_is_id && list->id == (XID) atoi(pre_device)) ||
+ (!pre_device_is_id && strcmp(list->name, pre_device) == 0)) {
+ /* OK, fall through */
+ } else {
+ /* skip, not this device */
+ continue;
+ }
+ }
+
+ XAnyClassPtr any = (XAnyClassPtr) (list->inputclassinfo);
+ int j;
+ for (j=0; j<list->num_classes; j++)
+ {
+
+ if (any->class == ValuatorClass)
+ {
+ XValuatorInfoPtr V = (XValuatorInfoPtr) any;
+ XAxisInfoPtr ax = (XAxisInfoPtr) V->axes;
+
+ if (V->mode != Absolute) {
+ if (verbose)
+ printf("DEBUG: Skipping device '%s' id=%i, does not report Absolute events.\n",
+ list->name, (int)list->id);
+ } else if (V->num_axes < 2 ||
+ (ax[0].min_value == -1 && ax[0].max_value == -1) ||
+ (ax[1].min_value == -1 && ax[1].max_value == -1)) {
+ if (verbose)
+ printf("DEBUG: Skipping device '%s' id=%i, does not have two calibratable axes.\n",
+ list->name, (int)list->id);
+ } else {
+ /* a calibratable device (has 2 axis valuators) */
+ found++;
+ *device_id = list->id;
+ *device_name = g_strdup(list->name);
+ device_axis->x_min = ax[0].min_value;
+ device_axis->x_max = ax[0].max_value;
+ device_axis->y_min = ax[1].min_value;
+ device_axis->y_max = ax[1].max_value;
+
+ if (list_devices)
+ printf("Device \"%s\" id=%i\n", *device_name, (int)*device_id);
+ }
+
+ }
+
+ /*
+ * Increment 'any' to point to the next item in the linked
+ * list. The length is in bytes, so 'any' must be cast to
+ * a character pointer before being incremented.
+ */
+ any = (XAnyClassPtr) ((char *) any + any->length);
+ }
+
+ }
+ XFreeDeviceList(slist);
+ XCloseDisplay(display);
+
+ return found;
+}
+
+static void usage(char* cmd, unsigned thr_misclick)
+{
+ 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);
+ fprintf(stderr, "\t-h, --help: print this help message\n");
+ fprintf(stderr, "\t-v, --verbose: print debug messages during the process\n");
+ fprintf(stderr, "\t--list: list calibratable input devices and quit\n");
+ fprintf(stderr, "\t--device <device name or id>: select a specific device to calibrate\n");
+ fprintf(stderr, "\t--precalib: manually provide the current calibration setting (eg. the values in xorg.conf)\n");
+ fprintf(stderr, "\t--misclick: set the misclick threshold (0=off, default: %i pixels)\n",
+ thr_misclick);
+ fprintf(stderr, "\t--fake: emulate a fake device (for testing purposes)\n");
+}
+
+static struct Calib* CalibratorXorgPrint(const char* const device_name0, const XYinfo *axis0, const gboolean verbose0, const int thr_misclick, const int thr_doubleclick)
+{
+ struct Calib* c = (struct Calib*)calloc(1, sizeof(struct Calib));
+ c->threshold_misclick = thr_misclick;
+ c->threshold_doubleclick = thr_doubleclick;
+
+ printf("Calibrating standard Xorg driver \"%s\"\n", device_name0);
+ printf("\tcurrent calibration values: min_x=%lf, max_x=%lf and min_y=%lf, max_y=%lf\n",
+ axis0->x_min, axis0->x_max, axis0->y_min, axis0->y_max);
+ 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");
+
+ return c;
+}
+
+static struct Calib* main_common(int argc, char** argv)
+{
+ gboolean verbose = FALSE;
+ gboolean list_devices = FALSE;
+ gboolean fake = FALSE;
+ gboolean precalib = FALSE;
+ XYinfo pre_axis = {-1, -1, -1, -1};
+ const char* pre_device = NULL;
+ unsigned thr_misclick = 15;
+ unsigned thr_doubleclick = 7;
+
+ /* parse input */
+ if (argc > 1) {
+ int i;
+ for (i=1; i!=argc; i++) {
+ /* Display help ? */
+ if (strcmp("-h", argv[i]) == 0 ||
+ strcmp("--help", argv[i]) == 0) {
+ fprintf(stderr, "xinput_calibrator, v%s\n\n", "0.0.0");
+ usage(argv[0], thr_misclick);
+ exit(0);
+ } else
+
+ /* Verbose output ? */
+ if (strcmp("-v", argv[i]) == 0 ||
+ strcmp("--verbose", argv[i]) == 0) {
+ verbose = TRUE;
+ } else
+
+ /* Just list devices ? */
+ if (strcmp("--list", argv[i]) == 0) {
+ list_devices = TRUE;
+ } else
+
+ /* Select specific device ? */
+ if (strcmp("--device", argv[i]) == 0) {
+ if (argc > i+1)
+ pre_device = argv[++i];
+ else {
+ fprintf(stderr, "Error: --device needs a device name or id as argument; use --list to list the calibratable input devices.\n\n");
+ usage(argv[0], thr_misclick);
+ exit(1);
+ }
+ } else
+
+ /* Get pre-calibration ? */
+ if (strcmp("--precalib", argv[i]) == 0) {
+ precalib = TRUE;
+ if (argc > i+1)
+ pre_axis.x_min = atoi(argv[++i]);
+ if (argc > i+1)
+ pre_axis.x_max = atoi(argv[++i]);
+ if (argc > i+1)
+ pre_axis.y_min = atoi(argv[++i]);
+ if (argc > i+1)
+ pre_axis.y_max = atoi(argv[++i]);
+ } else
+
+ /* Get mis-click threshold ? */
+ if (strcmp("--misclick", argv[i]) == 0) {
+ if (argc > i+1)
+ thr_misclick = atoi(argv[++i]);
+ else {
+ fprintf(stderr, "Error: --misclick needs a number (the pixel threshold) as argument. Set to 0 to disable mis-click detection.\n\n");
+ usage(argv[0], thr_misclick);
+ exit(1);
+ }
+ } else
+
+ /* Fake calibratable device ? */
+ if (strcmp("--fake", argv[i]) == 0) {
+ fake = TRUE;
+ }
+
+ /* unknown option */
+ else {
+ fprintf(stderr, "Unknown option: %s\n\n", argv[i]);
+ usage(argv[0], thr_misclick);
+ exit(0);
+ }
+ }
+ }
+
+
+ /* Choose the device to calibrate */
+ XID device_id = (XID) -1;
+ const char* device_name = NULL;
+ XYinfo device_axis = {-1, -1, -1, -1};
+ if (fake) {
+ /* Fake a calibratable device */
+ device_name = "Fake_device";
+ device_axis.x_min=0;
+ device_axis.x_max=1000;
+ device_axis.y_min=0;
+ device_axis.y_max=1000;
+
+ if (verbose) {
+ printf("DEBUG: Faking device: %s\n", device_name);
+ }
+ } else {
+ /* Find the right device */
+ int nr_found = find_device(pre_device, verbose, list_devices, &device_id, &device_name, &device_axis);
+
+ if (list_devices) {
+ /* printed the list in find_device */
+ if (nr_found == 0)
+ printf("No calibratable devices found.\n");
+ exit(0);
+ }
+
+ if (nr_found == 0) {
+ if (pre_device == NULL)
+ fprintf (stderr, "Error: No calibratable devices found.\n");
+ else
+ fprintf (stderr, "Error: Device \"%s\" not found; use --list to list the calibratable input devices.\n", pre_device);
+ exit(1);
+
+ } else if (nr_found > 1) {
+ printf ("Warning: multiple calibratable devices found, calibrating last one (%s)\n\tuse --device to select another one.\n", device_name);
+ }
+
+ if (verbose) {
+ printf("DEBUG: Selected device: %s\n", device_name);
+ }
+ }
+
+ /* override min/max XY from command line ? */
+ if (precalib) {
+ if (pre_axis.x_min != -1)
+ device_axis.x_min = pre_axis.x_min;
+ if (pre_axis.x_max != -1)
+ device_axis.x_max = pre_axis.x_max;
+ if (pre_axis.y_min != -1)
+ device_axis.y_min = pre_axis.y_min;
+ if (pre_axis.y_max != -1)
+ device_axis.y_max = pre_axis.y_max;
+
+ if (verbose) {
+ printf("DEBUG: Setting precalibration: %lf, %lf, %lf, %lf\n",
+ device_axis.x_min, device_axis.x_max,
+ device_axis.y_min, device_axis.y_max);
+ }
+ }
+
+ /* lastly, presume a standard Xorg driver (evtouch, mutouch, ...) */
+ return CalibratorXorgPrint(device_name, &device_axis,
+ verbose, thr_misclick, thr_doubleclick);
+}
+
+static gboolean output_xorgconfd(const XYinfo new_axis, int swap_xy, int new_swap_xy)
+{
+ const char* sysfs_name = "!!Name_Of_TouchScreen!!";
+
+ /* xorg.conf.d snippet */
+ printf(" copy the snippet below into '/etc/X11/xorg.conf.d/99-calibration.conf'\n");
+ printf("Section \"InputClass\"\n");
+ printf(" Identifier \"calibration\"\n");
+ printf(" MatchProduct \"%s\"\n", sysfs_name);
+ printf(" Option \"MinX\" \"%lf\"\n", new_axis.x_min);
+ printf(" Option \"MaxX\" \"%lf\"\n", new_axis.x_max);
+ printf(" Option \"MinY\" \"%lf\"\n", new_axis.y_min);
+ printf(" Option \"MaxY\" \"%lf\"\n", new_axis.y_max);
+ if (swap_xy != 0)
+ printf(" Option \"SwapXY\" \"%d\" # unless it was already set to 1\n", new_swap_xy);
+ printf("EndSection\n");
+
+ return TRUE;
+}
+
+static gboolean finish_data(const XYinfo new_axis, int swap_xy)
+{
+ gboolean success = TRUE;
+
+ /* we suppose the previous 'swap_xy' value was 0 */
+ /* (unfortunately there is no way to verify this (yet)) */
+ int new_swap_xy = swap_xy;
+
+ printf("\n\n--> Making the calibration permanent <--\n");
+ success &= output_xorgconfd(new_axis, swap_xy, new_swap_xy);
+
+ return success;
+}
+
+static void
+calibration_finished_cb (CcCalibArea *area,
+ gpointer user_data)
+{
+ gboolean success;
+ XYinfo axis;
+ gboolean swap_xy;
+
+ success = cc_calib_area_finish (area);
+ if (success)
+ {
+ cc_calib_area_get_axis (area, &axis, &swap_xy);
+ success = finish_data (axis, swap_xy);
+ }
+ else
+ fprintf(stderr, "Error: unable to apply or save configuration values\n");
+
+ g_main_loop_quit (mainloop);
+}
+
+int main(int argc, char** argv)
+{
+
+ struct Calib* calibrator = main_common(argc, argv);
+ CcCalibArea *calib_area;
+
+ bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+
+ gtk_init ();
+
+ g_setenv ("G_MESSAGES_DEBUG", "all", TRUE);
+
+ calib_area = cc_calib_area_new (NULL,
+ NULL, /* monitor */
+ NULL, /* NULL to accept input from any device */
+ calibration_finished_cb,
+ NULL,
+ calibrator->threshold_doubleclick,
+ calibrator->threshold_misclick);
+
+ mainloop = g_main_loop_new (NULL, FALSE);
+ g_main_loop_run (mainloop);
+
+ cc_calib_area_free (calib_area);
+
+ free(calibrator);
+
+ return 0;
+}