Initial commit 22/1822/1 1.0 1.0_branch accepted/trunk/20120924.201932 submit/trunk/20120924.203713
authorGraydon, Tracy <tracy.graydon@intel.com>
Mon, 24 Sep 2012 20:36:29 +0000 (13:36 -0700)
committerGraydon, Tracy <tracy.graydon@intel.com>
Mon, 24 Sep 2012 20:36:29 +0000 (13:36 -0700)
50 files changed:
.gitignore [new file with mode: 0644]
COPYING [new file with mode: 0644]
Changelog [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
README [new file with mode: 0644]
autogen.sh [new file with mode: 0755]
configure.ac [new file with mode: 0644]
man/Makefile.am [new file with mode: 0644]
man/xinput_calibrator.1 [new file with mode: 0644]
packaging/.osc/_apiurl [new file with mode: 0644]
packaging/.osc/_files [new file with mode: 0644]
packaging/.osc/_meta [new file with mode: 0644]
packaging/.osc/_osclib_version [new file with mode: 0644]
packaging/.osc/_package [new file with mode: 0644]
packaging/.osc/_project [new file with mode: 0644]
packaging/.osc/xinput_calibrator-0.7.5.tar.gz [new file with mode: 0644]
packaging/.osc/xinput_calibrator.changes [new file with mode: 0644]
packaging/.osc/xinput_calibrator.spec [new file with mode: 0644]
packaging/xinput_calibrator.changes [new file with mode: 0644]
packaging/xinput_calibrator.spec [new file with mode: 0644]
scripts/Makefile.am [new file with mode: 0644]
scripts/xinput_calibrator.desktop [new file with mode: 0644]
scripts/xinput_calibrator.svg [new file with mode: 0644]
scripts/xinput_calibrator.xpm [new file with mode: 0644]
scripts/xinput_calibrator_get_hal_calibration.sh [new file with mode: 0755]
scripts/xinput_calibrator_pointercal.sh [new file with mode: 0755]
src/.gitignore [new file with mode: 0644]
src/Makefile.am [new file with mode: 0644]
src/calibrator.cpp [new file with mode: 0644]
src/calibrator.hh [new file with mode: 0644]
src/calibrator/Evdev.cpp [new file with mode: 0644]
src/calibrator/Evdev.hpp [new file with mode: 0644]
src/calibrator/EvdevTester.cpp [new file with mode: 0644]
src/calibrator/EvdevTester.hpp [new file with mode: 0644]
src/calibrator/Makefile.am [new file with mode: 0644]
src/calibrator/Tester.cpp [new file with mode: 0644]
src/calibrator/Tester.hpp [new file with mode: 0644]
src/calibrator/Usbtouchscreen.cpp [new file with mode: 0644]
src/calibrator/Usbtouchscreen.hpp [new file with mode: 0644]
src/calibrator/XorgPrint.cpp [new file with mode: 0644]
src/calibrator/XorgPrint.hpp [new file with mode: 0644]
src/gui/Makefile.am [new file with mode: 0644]
src/gui/gtkmm.cpp [new file with mode: 0644]
src/gui/gtkmm.hpp [new file with mode: 0644]
src/gui/x11.cpp [new file with mode: 0644]
src/gui/x11.hpp [new file with mode: 0644]
src/main_common.cpp [new file with mode: 0644]
src/main_gtkmm.cpp [new file with mode: 0644]
src/main_x11.cpp [new file with mode: 0644]
src/tester.cpp [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..8427b2e
--- /dev/null
@@ -0,0 +1,20 @@
+*.m4
+autom4te.cache
+autoscan.log
+compile
+config.*
+configure
+configure.scan
+depcomp
+.deps/
+install-sh
+libtool
+ltmain.sh
+Makefile
+Makefile.in
+missing
+mkinstalldirs
+*~
+*.o
+*.pc
+tester
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..9ac13cd
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,41 @@
+Copyright (c) 2010 Tias Guns <tias@ulyssis.org> and others
+See the respective files for detailed copyright information.
+
+
+Source code: MIT/X11 License
+------------
+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.
+
+
+Icon xinput_calibrator.svg: CC by-sa
+---------------------------
+(c) Tias Guns <tias@ulyssis.org>
+
+The screen and triangle are from the Tango Desktop Project,
+which is in the Public Domain.
+
+The hand is from Ubuntu's human-icon-theme, which is CC by-sa
+(c) Jeff Waugh <jdub@perkypants.org>
+(c) Daniel Holbach <daniel.holbach@ubuntu.com>
+(c) Martin Pitt <martin.pitt@ubuntu.com>
+Creative Commons Attribution-ShareAlike 3.0 License Agreement
+http://creativecommons.org/licenses/by-sa/3.0/
diff --git a/Changelog b/Changelog
new file mode 100644 (file)
index 0000000..470b20f
--- /dev/null
+++ b/Changelog
@@ -0,0 +1,98 @@
+xinput_calibrator 0.7.5 [2010-09-12]
+Major features:
+* support multi-head setups in the GUIs (Alexey Kuznetsov)
+* now builds and runs on older systems too
+* output xorg.conf.d snippets (Peter Hutterer)
+* simpler and cleaner output, with --output-type to select output type
+
+Enhancements:
+* only link to needed libraries
+* start --fake with sensible non-zero calibration values
+* various spelling fixes (thanks Paul Wise)
+* remove udev configuration (xorg.conf.d instead, Peter Hutterer)
+* remove bogus partial xorg config output, superseded by xorg.conf.d
+* sysfs name detection, when device name is sysfs name
+* dynamically detect xorg.conf.d support
+* updated manpage
+* icon, license is CC-BY-SA 3.0
+* autotools cleanups (thanks Paul Wise)
+
+xinput_calibrator 0.7.0 [2010-08-01]
+Major features:
+* Automatic mis-click detection !
+* Now compiles only one binary (with gtkmm if availabe, otherwise x11)
+* .desktop file for menu entry
+* Made a tango-based calibration icon
+* Manpage information about making calibration permanent
+Bug fixes/enhancements:
+* A COPYING file to explicitise MIT/X11 license
+* Proper make dist (Thierry Reding)
+* Packaging fixes (David Ludlow)
+
+xinput_calibrator 0.6.1 [2010-03-21]
+Bug fixes/enhancements:
+* More robust device detection: non-master device with axis valuators, in
+absolute mode and at least two calibratable axes. (reported by Sam Lin, Eric
+Drechsel)
+* Require libtool in configure.ac
+* fix miny and maxx printing order for UDEV and HAL (Mario Domenech Goulart)
+
+xinput_calibrator 0.6.0 [2010-02-15]
+Major features:
+* switch to autotools based build system (Petr Štetiar)
+* add -v option, prints debug messages
+* add --list option, lists calibratable devices
+* add support for --device option, selects a specific device
+* Add a manpage
+
+Minor features:
+* make it compile with strict flags (Petr Štetiar)
+* Load font fixed when 9x15 fails in GuiCalibratorX11 (Marco Cavallini)
+* add support for specific device id for evdev (necessary when 2 devices have the same name)
+* xorg print: clean up output and added udev rule
+* evdev: print ways to make config permanent (easier when evdev >= 2.3.0)
+* scripts/xinput_calibrator.desktop a sample .desktop file
+* scripts/xinput_calibrator_pointercal.sh script to make the changes permanent
+(xinput is called with every Xorg start)
+
+Bug fixes/enhancements:
+* fix double free in evdev calibrator (reported by Marco Cavallini)
+* Check that XInput >= 1.5 in evdev calibrator (reported by Marcin Juszkiewicz)
+* check that the device is a XI_TOUCHSCREEN
+* set evdev calibration to default when none is apparently set (fixes sleep/resume quirk)
+* swap_xy in dynamic evdev: unswap if already swapped
+
+For the complete changeset, see the git log
+
+xinput_calibrator 0.5.0 [2010-01-11]
+Major features:
+* Rewrite: split the one-huge-file into clean components
+* New X11 based gui: like the gtkmm one, but in pure X11
+
+Minor features:
+* Add --fake option (for development/testing)
+* make the touch points more visuals: draw a cross through them
+* press any key to quit
+* help text of 4 lines
+
+Bug fixes:
+* Use strdup() due to pointer scope autofree [Thanks Sam Lin]
+* clarify that the license is the pure MIT/X11 license
+
+xinput_calibrator 0.4.1 [2009-12-1]
+Other:
+* Add README and Changelog file
+
+xinput_calibrator 0.4.0 [2009-12-1]
+New features/improvements:
+* Add example FDI policy file for generic touchscreen, next to example xorg.conf values
+* Add support for providing the current calibration on the command line (with --precalib), add help information (-h or --help). Included a script that reads the current calibration data from lshal, and runs the calibration program with the right --precalib data
+* Add support for dynamic evdev re-calibration
+
+
+xinput_calibrator 0.2.0 [2009-09-10]
+New features/improvements:
+* Add generic xinput methods for reading the current data and writing example xorg.conf files.
+* put usbtouchscreen specific stuff in a new subclass
+* Initial code from
+http://lists.x.org/archives/xorg/2008-September/039064.html
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..45008a4
--- /dev/null
@@ -0,0 +1,30 @@
+#
+# Copyright (c) 2010 Petr Stetiar <ynezz@true.cz>
+# Copyright (c) 2010 Tias Guns <tias@ulyssis.org>
+#
+# 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.
+#
+
+AUTOMAKE_OPTIONS = foreign
+SUBDIRS = src man scripts
+
+EXTRA_DIST = autogen.sh Changelog
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..9ebe5d6
--- /dev/null
+++ b/README
@@ -0,0 +1,44 @@
+xinput calibrator: A generic touchscreen calibration program for X.Org
+
+Version: 0.7.5
+Website: http://www.freedesktop.org/wiki/Software/xinput_calibrator
+Source:  http://github.com/tias/xinput_calibrator
+Bugs:    http://github.com/tias/xinput_calibrator/issues
+
+
+Build instructions:
+-------------------
+./autogen.sh
+    Sets up build environment, run ./autogen.sh --help to see the build options
+    Notable build options:
+    --with-gui=gtkmm        Use gtkmm GUI
+    --with-gui=x11          Use native x11 GUI
+make
+    Builds the software with the configured GUI
+
+Usage:
+------
+Simply run:
+    xinput_calibrator
+
+For more information, run with --help or check the manpage.
+The scripts/ directory constains scripts to get calibration from hal or use a pointercal file to reapply xinput commands across reboots
+
+
+More about the project:
+-----------------------
+Because all existing calibrators were driver dependent and hard to use, xinput_calibrator was created. The goal of xinput_calibrator is to: 
+* work for any Xorg driver (use Xinput to get axis valuators), 
+* output the calibration as Xorg.conf, HAL policy and udev rule, 
+* support advanced driver options, such as Evdev's dynamic calibration, 
+* have a very intuitive GUI (normal X client). 
+
+Xinput_calibrator is based on a simple calibrator that was proposed on the Xorg mailinglist. The first release(v0.2.0) improved upon it by reading axis valuators from Xinput, hence making it generic for all touchscreen drivers. The announcement was done on the Xorg mailinglist, and the code is on Tias' webpage. 
+
+Starting from v0.4.0, it writes Xorg.conf and (HAL) FDI policy file values, and contains a wrapper script to get axis valuator information for the evtouch driver (evtouch does not export the current calibration through its axis valuators). It is also the first program to support dynamic evdev calibration, by using its advanced Xinput functionality.
+
+The v0.5.0 version is written entirely in the X window system, needing no external dependencies. Because of its modular structure, other frontends can be easily created too.
+
+Version v0.6.0 has a proper build system and gained a lot of features thanks to the feedback of different users.
+
+Version 0.7.0 has mis-click detection and proper packaging support: proper make dist, one binary, has manpage, menu entry and icon. DEB and RPM package meta-data in their respective VCS branches.
diff --git a/autogen.sh b/autogen.sh
new file mode 100755 (executable)
index 0000000..904cd67
--- /dev/null
@@ -0,0 +1,12 @@
+#! /bin/sh
+
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+
+ORIGDIR=`pwd`
+cd $srcdir
+
+autoreconf -v --install || exit 1
+cd $ORIGDIR || exit $?
+
+$srcdir/configure --enable-maintainer-mode "$@"
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..9997354
--- /dev/null
@@ -0,0 +1,87 @@
+#
+# Copyright (c) 2010 Petr Stetiar <ynezz@true.cz>
+# Copyright (c) 2010 Tias Guns <tias@ulyssis.org>
+#
+# 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.
+#
+
+AC_PREREQ([2.57])
+AC_INIT(xinput_calibrator,[0.7.5], [http://github.com/tias/xinput_calibrator/issues],, [http://www.freedesktop.org/wiki/Software/xinput_calibrator])
+AM_INIT_AUTOMAKE([foreign dist-bzip2])
+AM_MAINTAINER_MODE
+
+AC_PROG_CC
+AC_PROG_CXX
+AC_PROG_LIBTOOL
+AC_PROG_INSTALL
+
+AC_PATH_X
+AC_CHECK_HEADERS([stdlib.h string.h])
+AC_HEADER_STDBOOL
+AC_FUNC_STRTOD
+
+PKG_CHECK_MODULES(XINPUT, x11 xext xi inputproto)
+AC_SUBST(XINPUT_CFLAGS)
+AC_SUBST(XINPUT_LIBS)
+
+PKG_CHECK_MODULES(XI_PROP, [xi >= 1.2] [inputproto >= 1.5],
+                       AC_DEFINE(HAVE_XI_PROP, 1, [Xinput properties available]), foo="bar")
+
+
+AC_ARG_WITH([gui], AS_HELP_STRING([--with-gui=default], [Use gtkmm GUI if available, x11 GUI otherwise (default)]),,[with_gui=default])
+AC_ARG_WITH([gui], AS_HELP_STRING([--with-gui=gtkmm], [Use gtkmm GUI]))
+AC_ARG_WITH([gui], AS_HELP_STRING([--with-gui=x11], [Use native x11 GUI]))
+AC_MSG_CHECKING([gui])
+AC_MSG_RESULT($with_gui)
+
+AS_IF([test "x$with_gui" = xdefault || test "x$with_gui" = xgtkmm], [
+       PKG_CHECK_MODULES(GTKMM, [gtkmm-2.4], with_gui="gtkmm",
+        [if test "x$with_gui" = xgtkmm; then
+            AC_MSG_ERROR([GTKMM GUI requested, but gtkmm-2.4 not found])
+         fi])
+    AC_SUBST(GTKMM_CFLAGS)
+       AC_SUBST(GTKMM_LIBS)
+])
+AM_CONDITIONAL([BUILD_GTKMM], [test "x$with_gui" = xgtkmm])
+
+AS_IF([test "x$with_gui" = xdefault || test "x$with_gui" = xx11], [
+       PKG_CHECK_MODULES(X11, [x11], with_gui="x11", with_gui="no")
+    AC_SUBST(X11_CFLAGS)
+    AC_SUBST(X11_LIBS)
+
+    # check for xrandr too
+    PKG_CHECK_MODULES(XRANDR, [xrandr], AC_DEFINE(HAVE_X11_XRANDR, 1), foo="bar")
+    AC_SUBST(XRANDR_CFLAGS)
+    AC_SUBST(XRANDR_LIBS)
+])
+AM_CONDITIONAL([BUILD_X11], [test "x$with_gui" = xx11])
+
+
+
+AC_SUBST(VERSION)
+
+AC_OUTPUT([Makefile
+           scripts/Makefile
+           src/Makefile
+           src/calibrator/Makefile
+           src/gui/Makefile
+           man/Makefile])
diff --git a/man/Makefile.am b/man/Makefile.am
new file mode 100644 (file)
index 0000000..66900f7
--- /dev/null
@@ -0,0 +1,26 @@
+#
+# Copyright (c) 2010 Tias Guns <tias@ulyssis.org>
+#
+# 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.
+#
+
+dist_man_MANS = xinput_calibrator.1
diff --git a/man/xinput_calibrator.1 b/man/xinput_calibrator.1
new file mode 100644 (file)
index 0000000..5a2f16f
--- /dev/null
@@ -0,0 +1,116 @@
+.\" 
+.TH "xinput_calibrator" "1" "" "Tias Guns" ""
+.SH "NAME"
+xinput_calibrator \- A generic touchscreen calibration program for X.Org
+
+.SH "SYNOPSIS"
+.B xinput_calibrator [OPTIONS]
+.SH "DESCRIPTION"
+xinput_calibrator is a program for calibrating your touchscreen, when using the X Window System.
+.PP 
+It currently features:
+.br 
+\- works for any standard Xorg touchscreen driver (uses XInput protocol)
+.br 
+\- mis\-click detection (prevents bogus calibration)
+.br 
+\- dynamically recalibrates the evdev driver
+.br 
+\- outputs the calibration as xorg.conf.d snippet or HAL policy file
+.br 
+\- and more
+.PP 
+see http://www.freedesktop.org/wiki/Software/xinput_calibrator
+
+.SH "OPTIONS"
+.TP 8
+.B \-h, \-\-help
+Print a help message listing the version and available options.
+.PP 
+.TP 8
+.B \-v, \-\-verbose
+Print debug messages during the process.
+.PP 
+.TP 8
+.B \-\-list
+List the calibratable input devices.
+.PP 
+.TP 8
+.B \-\-device \fIdevice_name_or_id\fP
+Select a specific device to calibrate;
+use \-\-list to list the calibratable input devices.
+.PP 
+.TP 8
+.B \-\-precalib \fImin_x\fP \fImax_x\fP \fImin_y\fP \fImax_y\fP
+Manually provide the current calibration setting.
+.br 
+This is useful if the calibration values are stored in your xorg.conf, but the driver does not export them through XInput (eg. the calibrator can not know these values)
+.PP 
+.TP 8
+.B \-\-misclick \fInr_of_pixels\fP
+set the misclick threshold (0=off, default: 15 pixels)
+.PP 
+.TP 8
+.B \-\-output\-type \fIauto|xorg.conf.d|hal|xinput\fP
+type of config to ouput (auto=automatically detect, default: auto)
+.PP 
+.TP 8
+.B \-\-fake
+Emulate a fake driver (for testing purposes)
+.br 
+Useful to test the calibrator without applying the values, and possibly even without having a touchscreen.
+.PP 
+.TP 8
+.B \-\-geometry \fIwidth\fPx\fIheight\fP
+Manually provide the geometry (width and height) for the calibration window.
+.SH "USAGE"
+Run xinput_calibrator in a terminal, as it prints out the calibration values and instructions on standard output.
+.PP 
+
+After clicking the 4 calibration points, xinput_calibrator will calculate the new calibration values. Depending on the Xorg touchscreen driver you use, the new values can be made permanent in different ways:
+.TP 4
+.B Evdev:
+Automatically recalibrates the driver for this session,
+.br 
+Supports following \-\-output\-types: auto, xorg.conf.d, hal, xinput
+
+.TP 4
+.B Usbtouchscreen:
+Automatically recalibrates the *kernel module*, saved in /etc/modprobe.conf.local
+.br 
+Supports following \-\-output\-types: auto
+
+.TP 4
+.B Other Xorg touchscreen drivers:
+No automatic calibration possible,
+.br 
+Supports following \-\-output\-types: auto, xorg.conf.d, hal
+.SH "EXAMPLES"
+To run the calibrator, type in your terminal:
+.LP 
+    xinput_calibrator
+.PP 
+If something goes wrong, or not as expected, turn on verbose messages:
+.LP 
+    xinput_calibrator \-v
+.PP 
+If you have to manually provide the current calibration values (when using EVDEV, you can use this to reset the calibration first):
+.LP 
+    xinput_calibrator \-\-precalib 0 1000 0 1000
+.SH "TROUBLESHOOTING"
+.B In general,
+run the calibrator with the \fI\-v\fP option, it will tell you what happens and what goes wrong.
+
+.B Mis\-click detection,
+the calibrator can automatically detect clicks with unreasonable values. This prevents you from ending up with a bogus calibration.
+.LP 
+If you keep getting the message 'Mis\-click detected, restarting...', one of the following is happening:
+  1. you are bad at clicking on crosses, use a stylus or increase the \-\-misclick threshold
+  2. your device is not properly supported by the kernel, it interprets the clicks wrong
+  3. your screen has a non\-linear deformation, 4\-point calibration can not help you
+.SH "SEE ALSO"
+xinput(1)
+.SH "AUTHORS"
+.nf 
+Tias Guns <tias@ulyssis.org>
+.fi 
diff --git a/packaging/.osc/_apiurl b/packaging/.osc/_apiurl
new file mode 100644 (file)
index 0000000..b46a8a4
--- /dev/null
@@ -0,0 +1 @@
+https://api.tizen.org
diff --git a/packaging/.osc/_files b/packaging/.osc/_files
new file mode 100644 (file)
index 0000000..557c430
--- /dev/null
@@ -0,0 +1,5 @@
+<directory name="xinput_calibrator" rev="1" srcmd5="bf7ce153806ed10e0614718e1ca64001" vrev="1">
+  <entry md5="efee1c65deb0213fd148e2aa57f77a6c" mtime="1348097960" name="xinput_calibrator-0.7.5.tar.gz" size="44213" />
+  <entry md5="6623e459791afec81f983150168aa5a4" mtime="1348083271" name="xinput_calibrator.changes" size="118" />
+  <entry md5="e9ce189b3740c76bee8dd3c7fb5d4400" mtime="1348097960" name="xinput_calibrator.spec" size="1230" />
+</directory>
diff --git a/packaging/.osc/_meta b/packaging/.osc/_meta
new file mode 100644 (file)
index 0000000..ae4238b
--- /dev/null
@@ -0,0 +1,5 @@
+<package project="home:tgraydon" name="xinput_calibrator">
+  <title></title>
+  <description></description>
+</package>
+
diff --git a/packaging/.osc/_osclib_version b/packaging/.osc/_osclib_version
new file mode 100644 (file)
index 0000000..d3827e7
--- /dev/null
@@ -0,0 +1 @@
+1.0
diff --git a/packaging/.osc/_package b/packaging/.osc/_package
new file mode 100644 (file)
index 0000000..06edf55
--- /dev/null
@@ -0,0 +1 @@
+xinput_calibrator
diff --git a/packaging/.osc/_project b/packaging/.osc/_project
new file mode 100644 (file)
index 0000000..30d06ef
--- /dev/null
@@ -0,0 +1 @@
+home:tgraydon
diff --git a/packaging/.osc/xinput_calibrator-0.7.5.tar.gz b/packaging/.osc/xinput_calibrator-0.7.5.tar.gz
new file mode 100644 (file)
index 0000000..84ebcf9
Binary files /dev/null and b/packaging/.osc/xinput_calibrator-0.7.5.tar.gz differ
diff --git a/packaging/.osc/xinput_calibrator.changes b/packaging/.osc/xinput_calibrator.changes
new file mode 100644 (file)
index 0000000..7be4014
--- /dev/null
@@ -0,0 +1,3 @@
+* Wed Sep 19 2012 Geoffroy Van Cutsem <geoffroy.vancutsem@intel.com> v0.7.5
+- Initial packaging for Tizen (X11 only)
+
diff --git a/packaging/.osc/xinput_calibrator.spec b/packaging/.osc/xinput_calibrator.spec
new file mode 100644 (file)
index 0000000..b44ce2c
--- /dev/null
@@ -0,0 +1,45 @@
+Name:       xinput_calibrator
+Summary:    Xinput calibrator A generic touchscreen calibration program for X
+Version:    0.7.5
+Release:    1
+Group:      System/X11
+License:    MIT
+URL:        http://www.freedesktop.org/wiki/Software/xinput_calibrator
+Source0:    http://github.com/downloads/tias/xinput_calibrator/xinput_calibrator-%{version}.tar.gz
+BuildRequires:  pkgconfig(inputproto) >= 1.5
+BuildRequires:  pkgconfig(x11)
+BuildRequires:  pkgconfig(xext)
+BuildRequires:  pkgconfig(xi) >= 1.2
+BuildRequires:  pkgconfig(xrandr)
+BuildRequires:  desktop-file-utils
+
+
+%description
+xinput calibrator: A generic touchscreen calibration program for X.Org
+
+%prep
+%setup -q -n %{name}-%{version}
+
+%build
+%autogen --disable-static \
+       --with-gui=x11
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+%make_install
+
+desktop-file-install --delete-original       \
+  --dir %{buildroot}%{_datadir}/applications             \
+   %{buildroot}%{_datadir}/applications/*.desktop
+
+%files
+%defattr(-,root,root,-)
+%doc COPYING
+%{_bindir}/xinput_calibrator
+%{_bindir}/tester
+%{_datadir}/applications/xinput_calibrator.desktop
+%{_mandir}/man1/xinput_calibrator.1.gz
+%{_datadir}/pixmaps/xinput_calibrator.svg
+%{_datadir}/pixmaps/xinput_calibrator.xpm
+
diff --git a/packaging/xinput_calibrator.changes b/packaging/xinput_calibrator.changes
new file mode 100644 (file)
index 0000000..7be4014
--- /dev/null
@@ -0,0 +1,3 @@
+* Wed Sep 19 2012 Geoffroy Van Cutsem <geoffroy.vancutsem@intel.com> v0.7.5
+- Initial packaging for Tizen (X11 only)
+
diff --git a/packaging/xinput_calibrator.spec b/packaging/xinput_calibrator.spec
new file mode 100644 (file)
index 0000000..b44ce2c
--- /dev/null
@@ -0,0 +1,45 @@
+Name:       xinput_calibrator
+Summary:    Xinput calibrator A generic touchscreen calibration program for X
+Version:    0.7.5
+Release:    1
+Group:      System/X11
+License:    MIT
+URL:        http://www.freedesktop.org/wiki/Software/xinput_calibrator
+Source0:    http://github.com/downloads/tias/xinput_calibrator/xinput_calibrator-%{version}.tar.gz
+BuildRequires:  pkgconfig(inputproto) >= 1.5
+BuildRequires:  pkgconfig(x11)
+BuildRequires:  pkgconfig(xext)
+BuildRequires:  pkgconfig(xi) >= 1.2
+BuildRequires:  pkgconfig(xrandr)
+BuildRequires:  desktop-file-utils
+
+
+%description
+xinput calibrator: A generic touchscreen calibration program for X.Org
+
+%prep
+%setup -q -n %{name}-%{version}
+
+%build
+%autogen --disable-static \
+       --with-gui=x11
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+%make_install
+
+desktop-file-install --delete-original       \
+  --dir %{buildroot}%{_datadir}/applications             \
+   %{buildroot}%{_datadir}/applications/*.desktop
+
+%files
+%defattr(-,root,root,-)
+%doc COPYING
+%{_bindir}/xinput_calibrator
+%{_bindir}/tester
+%{_datadir}/applications/xinput_calibrator.desktop
+%{_mandir}/man1/xinput_calibrator.1.gz
+%{_datadir}/pixmaps/xinput_calibrator.svg
+%{_datadir}/pixmaps/xinput_calibrator.xpm
+
diff --git a/scripts/Makefile.am b/scripts/Makefile.am
new file mode 100644 (file)
index 0000000..a05579f
--- /dev/null
@@ -0,0 +1,12 @@
+EXTRA_DIST = \
+    xinput_calibrator.desktop \
+    xinput_calibrator_get_hal_calibration.sh \
+    xinput_calibrator_pointercal.sh \
+    xinput_calibrator.svg \
+    xinput_calibrator.xpm
+
+icon_DATA = xinput_calibrator.svg xinput_calibrator.xpm
+icondir = $(datadir)/pixmaps
+
+util_DATA = xinput_calibrator.desktop
+utildir = $(datadir)/applications
diff --git a/scripts/xinput_calibrator.desktop b/scripts/xinput_calibrator.desktop
new file mode 100644 (file)
index 0000000..d888899
--- /dev/null
@@ -0,0 +1,11 @@
+[Desktop Entry]
+Name=Calibrate Touchscreen
+Name[de]=Touchscreen Kalibrieren
+Name[nl]=Touchscreen Kalibreren
+Comment=Run the calibration tool for touchscreens
+Exec=/bin/sh -c "xinput_calibrator; cat"
+Terminal=true
+Type=Application
+Icon=xinput_calibrator
+StartupNotify=true
+Categories=System;Settings;
diff --git a/scripts/xinput_calibrator.svg b/scripts/xinput_calibrator.svg
new file mode 100644 (file)
index 0000000..7d4b3ad
--- /dev/null
@@ -0,0 +1,1373 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   version="1.1"
+   width="48"
+   height="48"
+   id="svg2327">
+  <defs
+     id="defs3">
+    <linearGradient
+       id="linearGradient2329">
+      <stop
+         id="stop2331"
+         style="stop-color:#ffffff;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop2333"
+         style="stop-color:#ffffff;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2321">
+      <stop
+         id="stop2323"
+         style="stop-color:#7b7f7a;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop2325"
+         style="stop-color:#7b7f7a;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2711">
+      <stop
+         id="stop2713"
+         style="stop-color:#909090;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop2715"
+         style="stop-color:#bebebe;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2701">
+      <stop
+         id="stop2703"
+         style="stop-color:#585956;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop2705"
+         style="stop-color:#bbbeb8;stop-opacity:1"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2683">
+      <stop
+         id="stop2685"
+         style="stop-color:#000000;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop2687"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2675">
+      <stop
+         id="stop2677"
+         style="stop-color:#5b5b97;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop2679"
+         style="stop-color:#1b1b43;stop-opacity:1"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2667">
+      <stop
+         id="stop2669"
+         style="stop-color:#ffffff;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop2671"
+         style="stop-color:#fcfcff;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2454">
+      <stop
+         id="stop2456"
+         style="stop-color:#000000;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop2458"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2415">
+      <stop
+         id="stop2417"
+         style="stop-color:#ffffff;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop2419"
+         style="stop-color:#ffffff;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2253">
+      <stop
+         id="stop2255"
+         style="stop-color:#8f8f8f;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop2257"
+         style="stop-color:#494949;stop-opacity:1"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2245">
+      <stop
+         id="stop2247"
+         style="stop-color:#dde1d9;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop2249"
+         style="stop-color:#cacdc6;stop-opacity:1"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       x1="8.6116238"
+       y1="7.2293582"
+       x2="34.784473"
+       y2="33.339787"
+       id="linearGradient2251"
+       xlink:href="#linearGradient2245"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.129863,0,0,0.885063,2.875,1.570628)" />
+    <linearGradient
+       x1="17.698339"
+       y1="13.004725"
+       x2="34.974548"
+       y2="55.200756"
+       id="linearGradient2421"
+       xlink:href="#linearGradient2415"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.108069,0,0,0.902471,5.5,3.875)" />
+    <radialGradient
+       cx="12.57571"
+       cy="67.501709"
+       r="8.7662792"
+       fx="12.57571"
+       fy="67.501709"
+       id="radialGradient2460"
+       xlink:href="#linearGradient2454"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="scale(1.925808,0.519262)" />
+    <linearGradient
+       x1="11.492236"
+       y1="1.6537577"
+       x2="17.199417"
+       y2="26.729263"
+       id="linearGradient2673"
+       xlink:href="#linearGradient2667"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.238977,0,0,0.895955,5.090553,1.543476)" />
+    <linearGradient
+       x1="19.150396"
+       y1="32.622238"
+       x2="16.315819"
+       y2="8.8666229"
+       id="linearGradient2681"
+       xlink:href="#linearGradient2675"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.174139,0,0,0.945431,5.221825,1.543476)" />
+    <linearGradient
+       x1="3.7069976"
+       y1="171.29134"
+       x2="3.7069974"
+       y2="162.45061"
+       id="linearGradient2689"
+       xlink:href="#linearGradient2683"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(5.705159,0,0,0.17528,5.5,2.195627)" />
+    <linearGradient
+       x1="12.206709"
+       y1="53.535141"
+       x2="12.127711"
+       y2="64.892525"
+       id="linearGradient2707"
+       xlink:href="#linearGradient2701"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.816345,0,0,1.278927,2.5,-40.24508)" />
+    <linearGradient
+       x1="34.300991"
+       y1="3.9384086"
+       x2="35.520542"
+       y2="3.8451097"
+       id="linearGradient2717"
+       xlink:href="#linearGradient2711"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       x1="34.300991"
+       y1="3.9384086"
+       x2="35.520542"
+       y2="3.8451097"
+       id="linearGradient2721"
+       xlink:href="#linearGradient2711"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       x1="34.300991"
+       y1="3.9384086"
+       x2="35.520542"
+       y2="3.8451097"
+       id="linearGradient2725"
+       xlink:href="#linearGradient2711"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       x1="34.300991"
+       y1="3.9384086"
+       x2="35.520542"
+       y2="3.8451097"
+       id="linearGradient2729"
+       xlink:href="#linearGradient2711"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       x1="34.300991"
+       y1="3.9384086"
+       x2="35.520542"
+       y2="3.8451097"
+       id="linearGradient2733"
+       xlink:href="#linearGradient2711"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       x1="10.390738"
+       y1="5.3817744"
+       x2="32.536823"
+       y2="31.246054"
+       id="linearGradient1561"
+       xlink:href="#linearGradient2253"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.104397,0,0,0.905471,4.5,2.875)" />
+    <linearGradient
+       x1="-35.658386"
+       y1="33.416473"
+       x2="-35.658386"
+       y2="28.205938"
+       id="linearGradient2327"
+       xlink:href="#linearGradient2321"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       x1="-35.122688"
+       y1="34.242237"
+       x2="-35.074745"
+       y2="30.962345"
+       id="linearGradient2337"
+       xlink:href="#linearGradient2329"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       cx="25.1875"
+       cy="41.625"
+       r="18.0625"
+       fx="25.1875"
+       fy="41.625"
+       id="radialGradient3253"
+       xlink:href="#linearGradient2269"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,0.32526,0,28.08607)" />
+    <linearGradient
+       id="linearGradient2269">
+      <stop
+         id="stop2271"
+         style="stop-color:#000000;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop2273"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       x1="42.426411"
+       y1="58.076275"
+       x2="32.350136"
+       y2="16.35697"
+       id="linearGradient3084"
+       xlink:href="#linearGradient3078"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       id="linearGradient3078">
+      <stop
+         id="stop3080"
+         style="stop-color:#c4a000;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop3082"
+         style="stop-color:#fce94f;stop-opacity:1"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       x1="28.835155"
+       y1="11.913623"
+       x2="52.131729"
+       y2="70.073158"
+       id="linearGradient3105"
+       xlink:href="#linearGradient3099"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       id="linearGradient3099">
+      <stop
+         id="stop3101"
+         style="stop-color:#ffffff;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop3103"
+         style="stop-color:#ffffff;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <radialGradient
+       cx="25.1875"
+       cy="41.625"
+       r="18.0625"
+       fx="25.1875"
+       fy="41.625"
+       id="radialGradient2946"
+       xlink:href="#linearGradient2269"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,0.32526,0,28.08607)" />
+    <linearGradient
+       x1="42.426411"
+       y1="58.076275"
+       x2="32.350136"
+       y2="16.35697"
+       id="linearGradient2948"
+       xlink:href="#linearGradient3078"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       x1="28.835155"
+       y1="11.913623"
+       x2="52.131729"
+       y2="70.073158"
+       id="linearGradient2950"
+       xlink:href="#linearGradient3099"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       x1="28.835155"
+       y1="11.913623"
+       x2="52.131729"
+       y2="70.073158"
+       id="linearGradient2961"
+       xlink:href="#linearGradient3099"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0,1,1,0,67.877005,-11.405589)" />
+    <linearGradient
+       x1="42.426411"
+       y1="58.076275"
+       x2="32.350136"
+       y2="16.35697"
+       id="linearGradient2964"
+       xlink:href="#linearGradient3078"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0,1,1,0,67.877005,-11.405589)" />
+    <linearGradient
+       x1="42.426411"
+       y1="58.076275"
+       x2="32.350136"
+       y2="16.35697"
+       id="linearGradient2979"
+       xlink:href="#linearGradient3078"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0,1,1,0,67.877005,-11.405589)" />
+    <linearGradient
+       x1="28.835155"
+       y1="11.913623"
+       x2="52.131729"
+       y2="70.073158"
+       id="linearGradient2981"
+       xlink:href="#linearGradient3099"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0,1,1,0,67.877005,-11.405589)" />
+    <radialGradient
+       cx="25.1875"
+       cy="41.625"
+       r="18.0625"
+       fx="25.1875"
+       fy="41.625"
+       id="radialGradient2983"
+       xlink:href="#linearGradient2269-1"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,0.32526,0,28.08607)" />
+    <linearGradient
+       id="linearGradient2269-1">
+      <stop
+         id="stop2271-2"
+         style="stop-color:#000000;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop2273-8"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <radialGradient
+       cx="25.1875"
+       cy="41.625"
+       r="18.0625"
+       fx="25.1875"
+       fy="41.625"
+       id="radialGradient3021"
+       xlink:href="#linearGradient2269-1"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,0.32526,0,28.08607)" />
+    <linearGradient
+       x1="28.835155"
+       y1="11.913623"
+       x2="52.131729"
+       y2="70.073158"
+       id="linearGradient3812"
+       xlink:href="#linearGradient3099"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0,0.70003969,0.70003969,0,8.443846,-2.5120151)" />
+    <linearGradient
+       x1="42.426411"
+       y1="58.076275"
+       x2="32.350136"
+       y2="16.35697"
+       id="linearGradient3815"
+       xlink:href="#linearGradient3078"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0,0.70003969,0.70003969,0,8.443846,-2.5120151)" />
+    <filter
+       color-interpolation-filters="sRGB"
+       id="filter3812-8">
+      <feGaussianBlur
+         id="feGaussianBlur3814-0"
+         stdDeviation="1.1541666" />
+    </filter>
+    <radialGradient
+       cx="27.180492"
+       cy="77.351418"
+       r="28.000002"
+       fx="27.180492"
+       fy="77.351418"
+       id="radialGradient3747-7"
+       xlink:href="#linearGradient3427-4"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.0575048,-0.1422573,0.2747669,2.8374093,12.669557,-93.201429)" />
+    <linearGradient
+       id="linearGradient3427-4">
+      <stop
+         id="stop3429-9"
+         style="stop-color:#ede3da;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop3431-8"
+         style="stop-color:#d1c19a;stop-opacity:1"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       x1="66.916679"
+       y1="72.207947"
+       x2="60.000015"
+       y2="73.857864"
+       id="linearGradient3742"
+       xlink:href="#linearGradient3435-3"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,1.1841396,-1e-5,-22.844877)" />
+    <linearGradient
+       id="linearGradient3435-3">
+      <stop
+         id="stop3437-8"
+         style="stop-color:#b9a065;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop3439-7"
+         style="stop-color:#ddd1b5;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       x1="53.583317"
+       y1="55.803551"
+       x2="53.583317"
+       y2="85.034912"
+       id="linearGradient3744"
+       xlink:href="#linearGradient3386-5"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,1.1841396,-1e-5,-22.844877)" />
+    <linearGradient
+       id="linearGradient3386-5">
+      <stop
+         id="stop3388-4"
+         style="stop-color:#000000;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop3390-4"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       x1="77.266762"
+       y1="67.88443"
+       x2="69.382645"
+       y2="72.711189"
+       id="linearGradient3737"
+       xlink:href="#linearGradient3435-3"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,1.1841396,-1e-5,-22.844877)" />
+    <linearGradient
+       id="linearGradient3087">
+      <stop
+         id="stop3089"
+         style="stop-color:#b9a065;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop3091"
+         style="stop-color:#ddd1b5;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       x1="69.559471"
+       y1="63.75"
+       x2="69.559471"
+       y2="85.895348"
+       id="linearGradient3739"
+       xlink:href="#linearGradient3386-5"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.125,0,0,1.1841396,-8.33335,-22.844877)" />
+    <linearGradient
+       id="linearGradient3094">
+      <stop
+         id="stop3096"
+         style="stop-color:#000000;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop3098"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       x1="34.09375"
+       y1="32.997398"
+       x2="30.954504"
+       y2="33.704506"
+       id="linearGradient3731-9"
+       xlink:href="#linearGradient3435-3"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(2.6666667,0,0,3.1577056,-1e-5,-22.844877)" />
+    <linearGradient
+       id="linearGradient3101">
+      <stop
+         id="stop3103-5"
+         style="stop-color:#b9a065;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop3105"
+         style="stop-color:#ddd1b5;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       x1="37.712963"
+       y1="29.117413"
+       x2="33.496296"
+       y2="32.388763"
+       id="linearGradient3733"
+       xlink:href="#linearGradient3386-5"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(3,0,0,3.1577056,-22.22224,-22.844877)" />
+    <linearGradient
+       id="linearGradient3108">
+      <stop
+         id="stop3110"
+         style="stop-color:#000000;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop3112"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       x1="53.583332"
+       y1="52.317886"
+       x2="46.66666"
+       y2="53.090298"
+       id="linearGradient3725"
+       xlink:href="#linearGradient3435-3"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,1.1841396,-1e-5,-22.844877)" />
+    <linearGradient
+       id="linearGradient3115">
+      <stop
+         id="stop3117"
+         style="stop-color:#b9a065;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop3119"
+         style="stop-color:#ddd1b5;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       x1="46.66666"
+       y1="80.549843"
+       x2="53.733334"
+       y2="90.652481"
+       id="linearGradient3727"
+       xlink:href="#linearGradient3386-5"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,1.1841396,-1e-5,-22.844877)" />
+    <linearGradient
+       id="linearGradient3122">
+      <stop
+         id="stop3124"
+         style="stop-color:#000000;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop3126"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <radialGradient
+       cx="46.665131"
+       cy="33.30061"
+       r="6.90416"
+       fx="46.665131"
+       fy="33.30061"
+       id="radialGradient3719"
+       xlink:href="#linearGradient3838-3"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,0.7511266,0,7.2936314)" />
+    <linearGradient
+       id="linearGradient3838-3">
+      <stop
+         id="stop3840-8"
+         style="stop-color:#ffffff;stop-opacity:0.60629922"
+         offset="0" />
+      <stop
+         id="stop3842-8"
+         style="stop-color:#ffffff;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       x1="39.760971"
+       y1="29.30661"
+       x2="53.56929"
+       y2="32.30661"
+       id="linearGradient3721"
+       xlink:href="#linearGradient3830-8"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(0,-5.3333333e-6)" />
+    <linearGradient
+       id="linearGradient3830-8">
+      <stop
+         id="stop3832-7"
+         style="stop-color:#000000;stop-opacity:0.50393701"
+         offset="0" />
+      <stop
+         id="stop3834-9"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       x1="46.68898"
+       y1="74.007736"
+       x2="46.68898"
+       y2="81.954689"
+       id="linearGradient2714-1"
+       xlink:href="#linearGradient3776-6"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       id="linearGradient3776-6">
+      <stop
+         id="stop3778-9"
+         style="stop-color:#000000;stop-opacity:0.60629922"
+         offset="0" />
+      <stop
+         id="stop3784-8"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="0.23349234" />
+      <stop
+         id="stop3786-0"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="0.48642099" />
+      <stop
+         id="stop3788-9"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="0.71245962" />
+      <stop
+         id="stop3780-2"
+         style="stop-color:#000000;stop-opacity:0.14173229"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       x1="46.68898"
+       y1="74.007736"
+       x2="46.68898"
+       y2="81.954689"
+       id="linearGradient2716-9"
+       xlink:href="#linearGradient3776-6"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       id="linearGradient3144">
+      <stop
+         id="stop3146"
+         style="stop-color:#000000;stop-opacity:0.60629922"
+         offset="0" />
+      <stop
+         id="stop3148"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="0.23349234" />
+      <stop
+         id="stop3150"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="0.48642099" />
+      <stop
+         id="stop3152"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="0.71245962" />
+      <stop
+         id="stop3154"
+         style="stop-color:#000000;stop-opacity:0.14173229"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       x1="50.587173"
+       y1="81.954689"
+       x2="50.495941"
+       y2="78.397881"
+       id="linearGradient2718-3"
+       xlink:href="#linearGradient3865-9"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       id="linearGradient3865-9">
+      <stop
+         id="stop3867-9"
+         style="stop-color:#ffffff;stop-opacity:0.42519686"
+         offset="0" />
+      <stop
+         id="stop3869-9"
+         style="stop-color:#ffffff;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       x1="46.68898"
+       y1="74.007736"
+       x2="46.68898"
+       y2="81.954689"
+       id="linearGradient2720-7"
+       xlink:href="#linearGradient3776-6"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       id="linearGradient3161">
+      <stop
+         id="stop3163"
+         style="stop-color:#000000;stop-opacity:0.60629922"
+         offset="0" />
+      <stop
+         id="stop3165"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="0.23349234" />
+      <stop
+         id="stop3167"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="0.48642099" />
+      <stop
+         id="stop3169"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="0.71245962" />
+      <stop
+         id="stop3171"
+         style="stop-color:#000000;stop-opacity:0.14173229"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       x1="49.885685"
+       y1="81.954689"
+       x2="49.520824"
+       y2="78.397881"
+       id="linearGradient2722-9"
+       xlink:href="#linearGradient3865-9"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       id="linearGradient3174">
+      <stop
+         id="stop3176"
+         style="stop-color:#ffffff;stop-opacity:0.42519686"
+         offset="0" />
+      <stop
+         id="stop3178"
+         style="stop-color:#ffffff;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       x1="46.68898"
+       y1="74.007736"
+       x2="46.68898"
+       y2="81.954689"
+       id="linearGradient2724-6"
+       xlink:href="#linearGradient3776-6"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       id="linearGradient3181">
+      <stop
+         id="stop3183"
+         style="stop-color:#000000;stop-opacity:0.60629922"
+         offset="0" />
+      <stop
+         id="stop3185"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="0.23349234" />
+      <stop
+         id="stop3187"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="0.48642099" />
+      <stop
+         id="stop3189"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="0.71245962" />
+      <stop
+         id="stop3191"
+         style="stop-color:#000000;stop-opacity:0.14173229"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       x1="43.126053"
+       y1="81.046455"
+       x2="44.218273"
+       y2="78.397881"
+       id="linearGradient2726-3"
+       xlink:href="#linearGradient3865-9"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       id="linearGradient3194">
+      <stop
+         id="stop3196"
+         style="stop-color:#ffffff;stop-opacity:0.42519686"
+         offset="0" />
+      <stop
+         id="stop3198"
+         style="stop-color:#ffffff;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       x1="46.68898"
+       y1="73.841072"
+       x2="46.68898"
+       y2="81.954689"
+       id="linearGradient2728-0"
+       xlink:href="#linearGradient3776-6"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       id="linearGradient3201">
+      <stop
+         id="stop3203"
+         style="stop-color:#000000;stop-opacity:0.60629922"
+         offset="0" />
+      <stop
+         id="stop3205"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="0.23349234" />
+      <stop
+         id="stop3207"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="0.48642099" />
+      <stop
+         id="stop3209"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="0.71245962" />
+      <stop
+         id="stop3211"
+         style="stop-color:#000000;stop-opacity:0.14173229"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       x1="20.960947"
+       y1="38.171875"
+       x2="24.002075"
+       y2="38.171875"
+       id="linearGradient3710-6"
+       xlink:href="#linearGradient3901-6"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(2.6666667,0,0,2.6666667,0,-5.3333333e-6)" />
+    <linearGradient
+       id="linearGradient3901-6">
+      <stop
+         id="stop3903-8"
+         style="stop-color:#ffffff;stop-opacity:0"
+         offset="0" />
+      <stop
+         id="stop3909-3"
+         style="stop-color:#ffffff;stop-opacity:1"
+         offset="0.5" />
+      <stop
+         id="stop3905-3"
+         style="stop-color:#ffffff;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       x1="15.373969"
+       y1="38.919338"
+       x2="19.476271"
+       y2="38.856762"
+       id="linearGradient3707-5"
+       xlink:href="#linearGradient3901-6"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(2.6666667,0,0,2.6666667,0,-5.3333333e-6)" />
+    <linearGradient
+       id="linearGradient3219">
+      <stop
+         id="stop3221"
+         style="stop-color:#ffffff;stop-opacity:0"
+         offset="0" />
+      <stop
+         id="stop3223"
+         style="stop-color:#ffffff;stop-opacity:1"
+         offset="0.5" />
+      <stop
+         id="stop3225"
+         style="stop-color:#ffffff;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       x1="25.80007"
+       y1="38.53125"
+       x2="28.818081"
+       y2="38.53125"
+       id="linearGradient3704-7"
+       xlink:href="#linearGradient3901-6"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(2.6666667,0,0,2.6666667,0,-5.3333333e-6)" />
+    <linearGradient
+       id="linearGradient3228">
+      <stop
+         id="stop3230"
+         style="stop-color:#ffffff;stop-opacity:0"
+         offset="0" />
+      <stop
+         id="stop3232"
+         style="stop-color:#ffffff;stop-opacity:1"
+         offset="0.5" />
+      <stop
+         id="stop3234"
+         style="stop-color:#ffffff;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       x1="28.930264"
+       y1="38.224167"
+       x2="32.976326"
+       y2="38.399643"
+       id="linearGradient3701-2"
+       xlink:href="#linearGradient3901-6"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(2.6666667,0,0,2.6666667,0,-5.3333333e-6)" />
+    <linearGradient
+       id="linearGradient3237">
+      <stop
+         id="stop3239"
+         style="stop-color:#ffffff;stop-opacity:0"
+         offset="0" />
+      <stop
+         id="stop3241"
+         style="stop-color:#ffffff;stop-opacity:1"
+         offset="0.5" />
+      <stop
+         id="stop3243"
+         style="stop-color:#ffffff;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <radialGradient
+       cx="27.180492"
+       cy="77.351418"
+       r="28.000002"
+       fx="27.180492"
+       fy="77.351418"
+       id="radialGradient4138"
+       xlink:href="#linearGradient3427-4"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.0575048,-0.1422573,0.2747669,2.8374093,12.669557,-93.201429)" />
+    <linearGradient
+       id="linearGradient3246">
+      <stop
+         id="stop3248"
+         style="stop-color:#ede3da;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop3250"
+         style="stop-color:#d1c19a;stop-opacity:1"
+         offset="1" />
+    </linearGradient>
+    <radialGradient
+       cx="27.180492"
+       cy="77.351418"
+       r="28.000002"
+       fx="27.180492"
+       fy="77.351418"
+       id="radialGradient4140"
+       xlink:href="#linearGradient3427-4"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.0575048,-0.1422573,0.2747669,2.8374093,12.669557,-93.201429)" />
+    <linearGradient
+       id="linearGradient3253">
+      <stop
+         id="stop3255"
+         style="stop-color:#ede3da;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop3257"
+         style="stop-color:#d1c19a;stop-opacity:1"
+         offset="1" />
+    </linearGradient>
+    <radialGradient
+       cx="27.180492"
+       cy="77.351418"
+       r="28.000002"
+       fx="27.180492"
+       fy="77.351418"
+       id="radialGradient4142"
+       xlink:href="#linearGradient3427-4"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.0575048,-0.1422573,0.2747669,2.8374093,12.669557,-93.201429)" />
+    <linearGradient
+       id="linearGradient3260">
+      <stop
+         id="stop3262"
+         style="stop-color:#ede3da;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop3264"
+         style="stop-color:#d1c19a;stop-opacity:1"
+         offset="1" />
+    </linearGradient>
+    <radialGradient
+       cx="27.180492"
+       cy="77.351418"
+       r="28.000002"
+       fx="27.180492"
+       fy="77.351418"
+       id="radialGradient3754-0"
+       xlink:href="#linearGradient3427-4"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.0575048,-0.1422573,0.2747669,2.8374093,12.669557,-93.201429)" />
+    <linearGradient
+       id="linearGradient3267">
+      <stop
+         id="stop3269"
+         style="stop-color:#ede3da;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop3271"
+         style="stop-color:#d1c19a;stop-opacity:1"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       x1="42.124172"
+       y1="85.225418"
+       x2="36.000011"
+       y2="86.119446"
+       id="linearGradient3771-7"
+       xlink:href="#linearGradient3773-3"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,1.1841396,-9.6666667e-6,-22.844877)" />
+    <linearGradient
+       id="linearGradient3773-3">
+      <stop
+         id="stop3775-8"
+         style="stop-color:#b9a065;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop3777-7"
+         style="stop-color:#ddd1b5;stop-opacity:1"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       x1="36.000011"
+       y1="73.384064"
+       x2="42.419624"
+       y2="101.40114"
+       id="linearGradient3769-2"
+       xlink:href="#linearGradient3386-5"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,1.1841396,-9.6666667e-6,-22.844877)" />
+    <linearGradient
+       id="linearGradient3278">
+      <stop
+         id="stop3280"
+         style="stop-color:#000000;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop3282"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       x1="-81.004936"
+       y1="146.06485"
+       x2="-62.639893"
+       y2="76.868217"
+       id="linearGradient6952"
+       xlink:href="#linearGradient3654-3"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,1.1841396,146.66665,-22.844877)" />
+    <linearGradient
+       id="linearGradient3654-3">
+      <stop
+         id="stop3656-3"
+         style="stop-color:#000000;stop-opacity:0.60629922"
+         offset="0" />
+      <stop
+         id="stop3658-95"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <linearGradient
+       x1="-81.004936"
+       y1="146.06485"
+       x2="-62.639893"
+       y2="76.868217"
+       id="linearGradient3312"
+       xlink:href="#linearGradient3654-3"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,1.1841396,146.66665,-22.844877)" />
+    <radialGradient
+       cx="25.1875"
+       cy="41.625"
+       r="18.0625"
+       fx="25.1875"
+       fy="41.625"
+       id="radialGradient3253-3"
+       xlink:href="#linearGradient2269-18"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,0.32526,0,28.08607)" />
+    <linearGradient
+       id="linearGradient2269-18">
+      <stop
+         id="stop2271-1"
+         style="stop-color:#000000;stop-opacity:1"
+         offset="0" />
+      <stop
+         id="stop2273-3"
+         style="stop-color:#000000;stop-opacity:0"
+         offset="1" />
+    </linearGradient>
+    <radialGradient
+       cx="25.1875"
+       cy="41.625"
+       r="18.0625"
+       fx="25.1875"
+       fy="41.625"
+       id="radialGradient2913"
+       xlink:href="#linearGradient2269-18"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,0.32526,0,28.08607)" />
+  </defs>
+  <g
+     id="layer1">
+    <path
+       d="m 43.25,41.625 a 18.0625,5.875 0 1 1 -36.125,0 18.0625,5.875 0 1 1 36.125,0 z"
+       transform="matrix(0.17228693,0.04787401,-0.25222451,1.1436637,31.606897,-8.7860122)"
+       id="path3251"
+       style="opacity:0.26704544;color:#000000;fill:url(#radialGradient2913);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible" />
+    <g
+       transform="matrix(1.0839889,0,0,1.0839889,-2.342229,-2.4321826)"
+       id="g3789">
+      <path
+         d="m 7.5809024,4.5706221 33.5881946,0 c 0.911342,0 1.624147,0.5834818 1.666752,1.401587 l 1.332044,25.5781139 c 0.05821,1.117735 -0.901056,2.020305 -2.020305,2.020305 l -35.545176,0 c -1.1192491,0 -2.078514,-0.90257 -2.0203052,-2.020305 L 5.9141506,5.9722091 c 0.040284,-0.7735346 0.5475027,-1.401587 1.6667518,-1.401587 z"
+         id="rect2404"
+         style="color:#000000;fill:url(#linearGradient2251);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient1561);stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" />
+      <path
+         d="m 8.910535,7.180827 -1.2421952,22.045317 31.6503892,0 L 37.983712,7.274256 8.910535,7.180827 z"
+         id="path2377"
+         style="fill:url(#linearGradient2681);fill-opacity:1;fill-rule:evenodd;stroke:#000079;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+      <path
+         d="m 6.6774331,31.610789 35.4284769,0"
+         id="path2393"
+         style="fill:none;stroke:url(#linearGradient2689);stroke-width:0.99618119;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.24840764" />
+      <path
+         d="M 7.4145985,5.5813396 41.260101,5.5435383 c 0.283697,-3.169e-4 0.559302,0.2372498 0.582105,0.6525437 l 1.361892,24.803248 c 0.05804,1.057031 -0.539749,1.785871 -1.598371,1.785871 l -34.5239687,0 c -1.0586228,0 -1.5930144,-0.728791 -1.5358714,-1.785871 L 6.8699773,6.505163 C 6.9086732,5.7893326 7.0363626,5.581762 7.4145985,5.5813396 z"
+         id="path2397"
+         style="color:#000000;fill:none;stroke:url(#linearGradient2421);stroke-width:0.99999964;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.70063692;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible" />
+      <path
+         d="M 9.1452447,7.429748 8.1327934,25.491693 C 19.177431,23.091063 24.294509,14.922154 38.027078,12.267603 L 37.741824,7.507088 9.1452447,7.429748 z"
+         id="path2443"
+         style="opacity:0.53142856;fill:url(#linearGradient2673);fill-opacity:1;fill-rule:evenodd;stroke:none" />
+      <g
+         id="g3008">
+        <path
+           d="m 35.620504,3.9384086 a 0.83968931,0.83968931 0 1 1 -1.679378,0 0.83968931,0.83968931 0 1 1 1.679378,0 z"
+           transform="matrix(1.331237,0,0,0.658449,-5.91933,5.728866)"
+           id="path2709"
+           style="color:#000000;fill:url(#linearGradient2717);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.5;marker:none;visibility:visible;display:inline;overflow:visible" />
+        <path
+           d="m 35.620504,3.9384086 a 0.83968931,0.83968931 0 1 1 -1.679378,0 0.83968931,0.83968931 0 1 1 1.679378,0 z"
+           transform="matrix(1.331237,0,0,0.658449,-5.80573,7.83465)"
+           id="path2719"
+           style="color:#000000;fill:url(#linearGradient2721);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.5;marker:none;visibility:visible;display:inline;overflow:visible" />
+        <path
+           d="m 35.620504,3.9384086 a 0.83968931,0.83968931 0 1 1 -1.679378,0 0.83968931,0.83968931 0 1 1 1.679378,0 z"
+           transform="matrix(1.331237,0,0,0.658449,-5.69213,9.83465)"
+           id="path2723"
+           style="color:#000000;fill:url(#linearGradient2725);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.5;marker:none;visibility:visible;display:inline;overflow:visible" />
+        <path
+           d="m 35.620504,3.9384086 a 0.83968931,0.83968931 0 1 1 -1.679378,0 0.83968931,0.83968931 0 1 1 1.679378,0 z"
+           transform="matrix(1.331237,0,0,0.658449,-5.57853,11.83465)"
+           id="path2727"
+           style="color:#000000;fill:url(#linearGradient2729);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.5;marker:none;visibility:visible;display:inline;overflow:visible" />
+        <path
+           d="m 35.620504,3.9384086 a 0.83968931,0.83968931 0 1 1 -1.679378,0 0.83968931,0.83968931 0 1 1 1.679378,0 z"
+           transform="matrix(1.331237,0,0,0.658449,-5.46493,13.83465)"
+           id="path2731"
+           style="color:#000000;fill:url(#linearGradient2733);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.5;marker:none;visibility:visible;display:inline;overflow:visible" />
+      </g>
+      <path
+         d="m 22.5,30.192666 0.281716,0 c 0.08376,1e-6 0.147985,0.01866 0.19266,0.05599 0.04497,0.03703 0.06745,0.08994 0.06745,0.158714 -1e-6,0.06907 -0.02248,0.122268 -0.06745,0.159595 -0.04467,0.03703 -0.108895,0.05555 -0.19266,0.05555 l -0.111981,0 0,0.22837 -0.169735,0 0,-0.658219 m 0.169735,0.123003 0,0.183843 0.0939,0 c 0.03292,0 0.05834,-0.0079 0.07627,-0.02381 0.01793,-0.01617 0.02689,-0.03894 0.02689,-0.06834 0,-0.02939 -0.009,-0.05202 -0.02689,-0.06789 -0.01793,-0.01587 -0.04335,-0.02381 -0.07627,-0.02381 l -0.0939,0 m 0.792244,-0.0119 c -0.05173,1e-6 -0.09185,0.01911 -0.120358,0.05731 -0.02851,0.03821 -0.04276,0.092 -0.04276,0.161359 0,0.06907 0.01425,0.122709 0.04276,0.160918 0.02851,0.03821 0.06863,0.05731 0.120358,0.05731 0.05202,0 0.09229,-0.0191 0.120799,-0.05731 0.02851,-0.03821 0.04276,-0.09185 0.04276,-0.160918 -10e-7,-0.06936 -0.01425,-0.123149 -0.04276,-0.161359 -0.02851,-0.03821 -0.06878,-0.05731 -0.120799,-0.05731 m 0,-0.123003 c 0.105808,1e-6 0.188692,0.03027 0.248651,0.09082 0.05996,0.06055 0.08994,0.144165 0.08994,0.250855 -1e-6,0.106397 -0.02998,0.189868 -0.08994,0.250414 -0.05996,0.06055 -0.142843,0.09082 -0.248651,0.09082 -0.105515,0 -0.188399,-0.03027 -0.248651,-0.09082 -0.05996,-0.06055 -0.08994,-0.144017 -0.08994,-0.250414 0,-0.10669 0.02998,-0.190309 0.08994,-0.250855 0.06025,-0.06055 0.143136,-0.09082 0.248651,-0.09082 m 0.466441,0.0119 0.189574,0 0.239393,0.451451 0,-0.451451 0.160918,0 0,0.658219 -0.189575,0 -0.239392,-0.451451 0,0.451451 -0.160918,0 0,-0.658219 m 0.663069,0 0.185606,0 0.149896,0.234543 0.149896,-0.234543 0.186048,0 -0.250856,0.380912 0,0.277307 -0.169735,0 0,-0.277307 -0.250855,-0.380912"
+         id="text2735"
+         style="font-size:0.9029026px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;writing-mode:lr-tb;text-anchor:start;fill:#4a4a4a;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans" />
+    </g>
+    <path
+       d="m 11.025242,28.617873 27.386633,-19.622067 1.161856,19.622067 -28.548489,0 z m 13.869536,-4.156486 9.800552,0 -0.440371,-6.331656 -9.360181,6.331656 z"
+       id="path1465"
+       style="fill:url(#linearGradient3815);fill-opacity:1;fill-rule:evenodd;stroke:#c4a000;stroke-width:0.71921003px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+    <path
+       d="m 38.895565,27.927007 -25.660823,0.01271 24.541552,-17.613853 1.119271,17.601149 z"
+       id="path3006"
+       style="opacity:0.63874344;fill:none;stroke:url(#linearGradient3812);stroke-width:0.70003968px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+    <path
+       d="m 36.876737,27.943929 0,-0.530932"
+       id="path3022"
+       style="fill:#2e3436;fill-opacity:0.75;fill-rule:evenodd;stroke:#c4a000;stroke-width:0.70003939px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1" />
+    <path
+       d="m 34.076579,27.943929 0,-0.530932"
+       id="path3046"
+       style="fill:#2e3436;fill-opacity:0.75;fill-rule:evenodd;stroke:#c4a000;stroke-width:0.70003939px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1" />
+    <path
+       d="m 31.27642,27.943929 0,-0.530932"
+       id="path3050"
+       style="fill:#2e3436;fill-opacity:0.75;fill-rule:evenodd;stroke:#c4a000;stroke-width:0.70003939px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1" />
+    <path
+       d="m 28.476264,27.943929 0,-0.530932"
+       id="path3054"
+       style="fill:#2e3436;fill-opacity:0.75;fill-rule:evenodd;stroke:#c4a000;stroke-width:0.70003939px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1" />
+    <path
+       d="m 25.676105,27.943929 0,-0.530932"
+       id="path3058"
+       style="fill:#2e3436;fill-opacity:0.75;fill-rule:evenodd;stroke:#c4a000;stroke-width:0.70003939px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1" />
+    <path
+       d="m 22.875948,27.943929 0,-0.530932"
+       id="path3062"
+       style="fill:#2e3436;fill-opacity:0.75;fill-rule:evenodd;stroke:#c4a000;stroke-width:0.70003939px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1" />
+    <path
+       d="m 20.075789,27.943929 0,-0.530932"
+       id="path3066"
+       style="fill:#2e3436;fill-opacity:0.75;fill-rule:evenodd;stroke:#c4a000;stroke-width:0.70003939px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1" />
+    <path
+       d="m 17.27563,27.943929 0,-0.530932"
+       id="path3070"
+       style="fill:#2e3436;fill-opacity:0.75;fill-rule:evenodd;stroke:#c4a000;stroke-width:0.70003939px;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1" />
+    <path
+       d="m 43.25,41.625 a 18.0625,5.875 0 1 1 -36.125,0 18.0625,5.875 0 1 1 36.125,0 z"
+       transform="matrix(0.07223188,0.96475096,-0.37547435,0.0427892,59.243937,-6.3905259)"
+       id="path3251-9"
+       style="opacity:0.26704544;color:#000000;fill:url(#radialGradient3021);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible" />
+    <g
+       transform="matrix(0.3375,0,0,0.36444072,-3.3975036,1.1300095)"
+       id="g3858"
+       style="stroke-width:1.42567217;stroke-miterlimit:4;stroke-dasharray:none;overflow:visible">
+      <path
+         d="m 46.666652,24.520712 c -3.162742,0 -5.817342,1.038548 -6.500002,4.539203 -0.0098,0.02501 0.0091,0.07319 0,0.09868 -0.0059,0.03183 0.0055,0.0667 0,0.09868 -0.08159,0.258777 -0.16667,0.496151 -0.16667,0.789425 l 0,0.789427 0,38.383506 -3.33333,-2.666666 c -1.108,0 -4.666667,22.178114 -4.666667,23.490141 l 9.333337,29.998202 c 0,1.31203 0.892,2.36829 2,2.36828 l 38.666665,0 c 1.108,0 8.666669,-21.58135 8.666666,-22.893371 l 0,-39.716834 c 0,-1.312027 -0.891997,-2.368283 -2,-2.368281 l -8,-1.333333 c -1.108,0 -1.999997,1.056251 -2,2.368281 l 0,-3.157706 c 0,-1.312027 -0.892,-2.368279 -2,-2.368279 l -8,0 c -1.108,0 -2,1.056252 -2,2.368279 l 0,-3.157706 c 0,-1.312027 -0.892,-2.368279 -2,-2.368279 l -9.333332,0 c -1.108,0 -2,1.056252 -2,2.368279 l 0,-21.314513 0,-0.789427 c 0,-0.293274 -0.08508,-0.530648 -0.166667,-0.789425 -0.01106,-0.06395 0.01236,-0.133979 0,-0.197357 -0.682656,-3.500652 -3.337261,-4.539203 -6.5,-4.539203 z"
+         transform="matrix(1,0,0,0.9829739,0,0.417487)"
+         id="path3806-3"
+         style="opacity:0.15;fill:#000000;fill-opacity:0.35840705;fill-rule:nonzero;stroke:#000000;stroke-width:1.43796623;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3812-8);enable-background:accumulate" />
+      <path
+         d="m 46.666652,24.520707 c -3.162742,0 -5.817342,1.038548 -6.500002,4.539203 -0.0098,0.02501 0.0091,0.07319 0,0.09868 -0.0059,0.03183 0.0055,0.0667 0,0.09868 -0.08159,0.258777 -0.16667,0.496151 -0.16667,0.789425 l 0,0.789427 0,38.383506 -3.33333,-2.666666 c -1.108,0 -4.666667,22.178114 -4.666667,23.490141 L 41.33332,120.0413 c 0,1.31203 0.892,2.36829 2,2.36828 l 38.666665,0 c 1.108,0 8.666669,-21.58135 8.666666,-22.893366 L 89.333318,59.799377 c 0,-1.312027 -0.891997,-2.368283 -2,-2.368281 l -6.666667,-1.333333 c -1.108,0 -1.999997,1.056251 -2,2.368281 l 0,-3.157706 c 0,-1.312027 -0.892,-2.368279 -2,-2.368279 l -8,0 c -1.108,0 -2,1.056252 -2,2.368279 l 0,-3.157706 c 0,-1.312027 -0.892,-2.368279 -2,-2.368279 l -9.333332,0 c -1.108,0 -2,1.056252 -2,2.368279 l 0,-21.314513 0,-0.789427 c 0,-0.293274 -0.08508,-0.530648 -0.166667,-0.789425 -0.01106,-0.06395 0.01236,-0.133979 0,-0.197357 -0.682656,-3.500652 -3.337261,-4.539203 -6.5,-4.539203 z"
+         id="rect3375-2"
+         style="fill:url(#radialGradient3747-7);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.42567217;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+      <rect
+         width="13.333333"
+         height="63.154121"
+         rx="2"
+         ry="1.9999999"
+         x="53.333328"
+         y="49.782352"
+         id="rect3356-4"
+         style="fill:url(#linearGradient3742);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient3744);stroke-width:1.42567217;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+      <path
+         d="m 68.916662,52.940057 7.5,0 c 1.2465,0 2.25,1.056253 2.25,2.36828 l 0,55.259843 c 0,1.31203 -1.0035,2.36828 -2.25,2.36828 l -7.5,0 c -1.2465,0 -2.25,-1.05625 -2.25,-2.36828 l 0,-55.259843 c 0,-1.312027 1.0035,-2.36828 2.25,-2.36828 z"
+         id="rect3396-8"
+         style="fill:url(#linearGradient3737);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient3739);stroke-width:1.42567217;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+      <path
+         d="m 80.666652,56.097765 c -0.529102,0 -0.976355,0.296192 -1.333334,0.690747 -0.203344,0.214032 -0.386445,0.505899 -0.5,0.789427 -0.113554,0.283527 -0.166666,0.560098 -0.166666,0.888105 l 0,55.259836 c 0,1.31203 1.003498,2.36828 2.25,2.36828 l 3.083333,0 c 2.602555,-5.32447 6.666669,-15.60968 6.666667,-16.577949 L 89.333319,59.799377 c 0,-0.328007 -0.05311,-0.604578 -0.166667,-0.888105 -0.113555,-0.283528 -0.296656,-0.575395 -0.5,-0.789427 -0.185067,-0.194795 -0.342696,-0.375946 -0.583333,-0.493392 -0.02535,-0.01266 -0.05745,0.01144 -0.08333,0 -0.198253,-0.08797 -0.443821,-0.172344 -0.666666,-0.197355 l -6.666667,-1.333333 z"
+         id="path3401-3"
+         style="fill:url(#linearGradient3731-9);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient3733);stroke-width:1.42567217;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+      <path
+         d="m 46.666653,24.520707 c -3.126473,0 -5.697413,1.000374 -6.416673,4.440525 -0.01869,0.04259 -0.06696,0.0546 -0.08333,0.09868 -0.01236,0.06338 0.01106,0.133404 0,0.197357 -0.0641,0.222955 -0.16667,0.442874 -0.16667,0.690747 l 0,0.888105 0,39.273964 0,37.004355 c 0,1.25788 0.892,2.2696 2,2.2696 l 9.333343,0 c 1.108,0 2,-1.01172 2,-2.2696 l 0,-55.950589 0,-20.32773 0,-0.888105 c 0,-0.247873 -0.10257,-0.467792 -0.16667,-0.690747 -0.01807,-0.104455 -0.06182,-0.193126 -0.08333,-0.296035 -0.71926,-3.440151 -3.2902,-4.440525 -6.41667,-4.440525 z"
+         id="path3413-5"
+         style="fill:url(#linearGradient3725);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient3727);stroke-width:1.42567217;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+      <path
+         d="m 46.666652,24.520707 c -3.126472,0 -5.697412,1.000374 -6.416672,4.440525 -0.01869,0.04259 -0.06696,0.0546 -0.08333,0.09868 0.01744,0.06185 -0.01906,0.136223 0,0.197357 0.87678,2.812068 3.46119,4.835239 6.500002,4.835236 3.045632,0 5.628902,-2.013378 6.5,-4.835236 0.009,-0.02918 -0.0086,-0.06933 0,-0.09868 -0.02042,-0.06838 -0.06827,-0.125319 -0.08333,-0.197355 -0.719253,-3.440151 -3.290192,-4.440525 -6.416667,-4.440525 z"
+         id="path3530-9"
+         style="fill:url(#radialGradient3719);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient3721);stroke-width:1.42567217;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+      <path
+         d="m 52.593995,78.397881 a 5.9050145,3.306808 0 1 1 -11.810029,0 5.9050145,3.306808 0 1 1 11.810029,0 z"
+         transform="translate(0,1.333328)"
+         id="path3774"
+         style="fill:none;stroke:url(#linearGradient2714-1);stroke-width:1.42567217;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+      <path
+         d="m 52.593995,78.397881 a 5.9050145,3.306808 0 1 1 -11.810029,0 5.9050145,3.306808 0 1 1 11.810029,0 z"
+         transform="translate(0,-22.66667)"
+         id="path3790"
+         style="fill:none;stroke:url(#linearGradient2716-9);stroke-width:1.42567217;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+      <path
+         d="m 52.593995,78.397881 a 5.9050145,3.306808 0 1 1 -11.810029,0 5.9050145,3.306808 0 1 1 11.810029,0 z"
+         transform="translate(13.333333,-5.3e-6)"
+         id="path3794"
+         style="fill:url(#linearGradient2718-3);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient2720-7);stroke-width:1.42567217;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+      <path
+         d="m 52.593995,78.397881 a 5.9050145,3.306808 0 1 1 -11.810029,0 5.9050145,3.306808 0 1 1 11.810029,0 z"
+         transform="matrix(0.9153262,0,0,1,29.786666,2.6666614)"
+         id="path3798"
+         style="fill:url(#linearGradient2722-9);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient2724-6);stroke-width:1.49015594;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+      <path
+         d="m 52.593995,78.397881 a 5.9050145,3.306808 0 1 1 -11.810029,0 5.9050145,3.306808 0 1 1 11.810029,0 z"
+         transform="matrix(0.9012138,0,0,1,42.528886,5.333328)"
+         id="path3802"
+         style="fill:url(#linearGradient2726-3);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient2728-0);stroke-width:1.50177801;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+      <path
+         d="m 46.666682,24.499995 c -3.126472,1e-6 -5.743719,0.995538 -6.462977,4.435689 -0.01869,0.04259 -0.02066,0.103561 -0.03703,0.147641 0.01744,0.06185 -0.01906,0.105534 0,0.166667 0.0642,0.205915 0.65409,0.129121 0.736111,0.326089 0.441529,-3.269203 2.631598,-4.385442 5.761112,-4.364428 3.43051,0.02287 5.107906,1.136573 5.827203,4.405779 0.08166,-0.197488 0.611788,-0.160811 0.675574,-0.36744 0.009,-0.02918 -0.0086,-0.05398 0,-0.08333 -0.02042,-0.06838 -0.02197,-0.09463 -0.03703,-0.166667 -0.719253,-3.440151 -3.336488,-4.5 -6.462963,-4.5 z"
+         id="path3846-2"
+         style="fill:#ffffff;fill-opacity:0.51327431;fill-rule:nonzero;stroke:none;stroke-width:1.42567217;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+      <path
+         d="m 63.333334,81.166662 c -0.942496,0.35667 -2.110995,0.5 -3.333333,0.5 -1.054566,0 -1.976118,-0.145058 -2.833334,-0.416666 l -1.416666,0.25 c -1.086822,0.174221 -1.919171,1.230472 -1.833334,2.333333 L 56.833334,121.25 c 0.03741,0.48064 0.268435,0.86992 0.583333,1.16666 l 4.833334,0 2.75,-0.41666 c 1.086821,-0.17422 1.919173,-1.23048 1.833333,-2.33334 L 63.916667,82.249996 c -0.03459,-0.44439 -0.316869,-0.791371 -0.583333,-1.083334 z"
+         id="rect3899"
+         style="opacity:0.18000004;fill:url(#linearGradient3710-6);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.42567217;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+      <path
+         d="m 41.500001,81.333329 c -0.990598,0.255371 -1.747499,1.211472 -1.666667,2.25 l 2.916667,38.666671 0,0.0833 c 0.191312,0.0716 0.371509,0.0833 0.583333,0.0833 l 8.75,0 c 0.433629,-0.42129 0.716152,-1.0309 0.666667,-1.66666 L 49.916667,82.499996 c -0.927637,0.339752 -2.059618,0.5 -3.25,0.5 -2.240952,2e-6 -4.16633,-0.635878 -5.166666,-1.666667 z"
+         id="rect3911"
+         style="opacity:0.20564515;fill:url(#linearGradient3707-5);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.42567217;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+      <path
+         d="m 76.833334,83.083329 c -0.98709,0.797757 -2.573029,1.25 -4.333333,1.25 -1.461947,0 -2.776731,-0.339104 -3.75,-0.916667 -0.111952,0.228795 -0.236339,0.556854 -0.25,0.833334 l -1.833333,37.583334 c -0.01067,0.21579 0.02863,0.38455 0.08333,0.58333 l 9.916667,0 1.833333,-37.166664 c 0.05146,-1.041406 -0.661939,-1.968283 -1.666667,-2.166667 z"
+         id="rect3915"
+         style="opacity:0.20564515;fill:url(#linearGradient3704-7);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.42567217;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+      <path
+         d="m 79.416668,84.416662 -3.666667,37.249998 c -0.02434,0.24774 0.0241,0.51239 0.08333,0.75 l 6.166667,0 c 0.571749,1e-5 2.834533,-5.75723 4.916667,-11.5 l 2.416666,-24.499998 c 0.03315,-0.337325 -0.05006,-0.693248 -0.166666,-1 -0.927307,0.971454 -2.635035,1.583334 -4.583334,1.583334 -2.57037,-3e-6 -4.67017,-1.076928 -5.166666,-2.583334 z"
+         id="rect3919"
+         style="opacity:0.20564515;fill:url(#linearGradient3701-2);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.42567217;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+      <path
+         d="m 41.666667,26.083334 c -0.464496,0.440387 -0.798981,0.989674 -1.083333,1.666666 0.290483,-0.713173 0.685229,-1.213483 1.166667,-1.666666 -0.01661,0.01528 -0.06693,-0.01556 -0.08333,0 z"
+         id="path3767-6"
+         style="fill:url(#radialGradient4138);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.42567217;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+      <path
+         d="m 40.583334,27.75 c -0.164624,0.391942 -0.3228,0.851992 -0.416667,1.333334 0.01637,-0.04408 0.06464,-0.04074 0.08333,-0.08333 0.08991,-0.430018 0.188093,-0.893413 0.333333,-1.25 z"
+         id="path3765-7"
+         style="fill:url(#radialGradient4140);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.42567217;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+      <path
+         d="m 51.583334,26.083334 c 0.481437,0.453183 0.876184,0.953493 1.166667,1.666666 -0.294395,-0.700904 -0.679918,-1.218654 -1.166667,-1.666666 z"
+         id="path3763-5"
+         style="fill:url(#radialGradient4142);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.42567217;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+      <path
+         d="m 52.750001,27.75 c 0.14524,0.356587 0.243426,0.819982 0.333333,1.25 0.0086,0.04116 0.07068,0.04481 0.08333,0.08333 -0.09386,-0.481335 -0.252039,-0.941388 -0.416663,-1.33333 z"
+         id="path3761-6"
+         style="fill:url(#radialGradient3754-0);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.42567217;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+      <path
+         d="m 36.666667,66.583334 c -1.108,0 -4.666667,22.187974 -4.666667,23.5 L 40,115.75 40,70.083334 40,69.250001 36.666667,66.583334 z"
+         id="path3752-3"
+         style="fill:url(#linearGradient3771-7);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient3769-2);stroke-width:1.42567217;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+      <path
+         d="m 46.666652,24.520707 c -3.162742,0 -5.817342,1.038548 -6.500002,4.539203 -0.0098,0.02501 0.0091,0.07319 0,0.09868 -0.0059,0.03183 0.0055,0.0667 0,0.09868 -0.08159,0.258777 -0.16667,0.496151 -0.16667,0.789425 l 0,0.789427 0,38.383506 -3.33333,-2.666666 c -1.108,0 -4.666667,22.178114 -4.666667,23.490141 L 41.33332,120.0413 c 0,1.31203 0.892,2.36829 2,2.36828 l 38.666665,0 c 1.108,0 8.666669,-21.58135 8.666666,-22.893366 L 89.333318,59.799377 c 0,-1.312027 -0.891997,-2.368283 -2,-2.368281 l -6.666667,-1.333333 c -1.108,0 -1.999997,1.056251 -2,2.368281 l 0,-3.157706 c 0,-1.312027 -0.892,-2.368279 -2,-2.368279 l -8,0 c -1.108,0 -2,1.056252 -2,2.368279 l 0,-3.157706 c 0,-1.312027 -0.892,-2.368279 -2,-2.368279 l -9.333332,0 c -1.108,0 -2,1.056252 -2,2.368279 l 0,-21.314513 0,-0.789427 c 0,-0.293274 -0.08508,-0.530648 -0.166667,-0.789425 -0.01106,-0.06395 0.01236,-0.133979 0,-0.197357 -0.682656,-3.500652 -3.337261,-4.539203 -6.5,-4.539203 z"
+         id="path3768-1"
+         style="fill:none;stroke:url(#linearGradient3312);stroke-width:1.42567217;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+    </g>
+  </g>
+</svg>
diff --git a/scripts/xinput_calibrator.xpm b/scripts/xinput_calibrator.xpm
new file mode 100644 (file)
index 0000000..f0c7c5c
--- /dev/null
@@ -0,0 +1,267 @@
+/* XPM */
+static char *xinput_calibrator[] = {
+/* columns rows colors chars-per-pixel */
+"32 32 229 2",
+"   c #303030",
+".  c #393939",
+"X  c #3D3A4A",
+"o  c #353462",
+"O  c #3C3C68",
+"+  c #3C3C7F",
+"@  c #434343",
+"#  c #4D4B4B",
+"$  c #564E48",
+"%  c #5F5743",
+"&  c #51514F",
+"*  c #474453",
+"=  c #494754",
+"-  c #4D4A54",
+";  c #44435D",
+":  c #48465B",
+">  c #504D56",
+",  c #504D5C",
+"<  c #515151",
+"1  c #685D40",
+"2  c #6A5F4D",
+"3  c #605858",
+"4  c #5F605F",
+"5  c #6D6340",
+"6  c #6D624C",
+"7  c #7C6D46",
+"8  c #7A6D4E",
+"9  c #706754",
+"0  c #776E57",
+"q  c #7B6E53",
+"w  c #746C5A",
+"e  c #7C7052",
+"r  c #7B705A",
+"t  c #424060",
+"y  c #45446E",
+"u  c #565564",
+"i  c #585564",
+"p  c #52506A",
+"a  c #444475",
+"s  c #444478",
+"d  c #525277",
+"f  c #55557D",
+"g  c #5B5B7E",
+"h  c #605D62",
+"j  c #635E6C",
+"k  c #666168",
+"l  c #6C666E",
+"z  c #7F7462",
+"x  c #6D6677",
+"c  c #65657D",
+"v  c #777073",
+"b  c #787672",
+"n  c #75707E",
+"m  c #7D7D7C",
+"M  c #8B7A37",
+"N  c #807346",
+"B  c #82714A",
+"V  c #8C7D4A",
+"C  c #867757",
+"Z  c #8C7E5F",
+"A  c #837761",
+"S  c #837862",
+"D  c #8B7F60",
+"F  c #877E68",
+"G  c #B39615",
+"H  c #958537",
+"J  c #A18A2D",
+"K  c #AD9623",
+"L  c #BA9F21",
+"P  c #A08A30",
+"I  c #A08A3A",
+"U  c #B59F3B",
+"Y  c #BCA123",
+"T  c #BCA129",
+"R  c #BAA339",
+"E  c #CEB21E",
+"W  c #D8BB1F",
+"Q  c #D3B623",
+"!  c #DBBF21",
+"~  c #D7BB2C",
+"^  c #C2AE3C",
+"/  c #CFBA30",
+"(  c #DEC225",
+")  c #DBC037",
+"_  c #DEC43B",
+"`  c #E1C629",
+"'  c #E4CA2D",
+"]  c #E7CD31",
+"[  c #E8CF34",
+"{  c #E7CF3B",
+"}  c #E9D034",
+"|  c #EDD53A",
+" . c #F0DA3F",
+".. c #948040",
+"X. c #988540",
+"o. c #9F8C41",
+"O. c #938257",
+"+. c #B09F4C",
+"@. c #908364",
+"#. c #948768",
+"$. c #87807B",
+"%. c #968E79",
+"&. c #9E9173",
+"*. c #9D927B",
+"=. c #A18F66",
+"-. c #A29576",
+";. c #AD9C73",
+":. c #A1967C",
+">. c #B9A87F",
+",. c #C3AC43",
+"<. c #C9B243",
+"1. c #CFB843",
+"2. c #CCB649",
+"3. c #D5BC41",
+"4. c #C3AF7D",
+"5. c #DDC440",
+"6. c #DAC65E",
+"7. c #E1C944",
+"8. c #EFD843",
+"9. c #E6D14A",
+"0. c #E3CD52",
+"q. c #E0CC5B",
+"w. c #EEDA50",
+"e. c #ECD85D",
+"r. c #EEDC6B",
+"t. c #F4E365",
+"y. c #3D3D80",
+"u. c #424283",
+"i. c #4B4C89",
+"p. c #525280",
+"a. c #5D5D80",
+"s. c #53558D",
+"d. c #535496",
+"f. c #575890",
+"g. c #5C5D92",
+"h. c #636382",
+"j. c #6A6A85",
+"k. c #6E6E88",
+"l. c #73738C",
+"z. c #626496",
+"x. c #676898",
+"c. c #696B99",
+"v. c #7B7B93",
+"b. c #757498",
+"n. c #6E70A0",
+"m. c #7879A4",
+"M. c #838483",
+"N. c #8C8C8B",
+"B. c #949493",
+"V. c #989997",
+"C. c #999A99",
+"Z. c #A39A87",
+"A. c #A59C8D",
+"S. c #A79E95",
+"D. c #ADA081",
+"F. c #A9A08B",
+"G. c #B3A685",
+"H. c #B3A78F",
+"J. c #BAAD8E",
+"K. c #AAA296",
+"L. c #A0A19C",
+"P. c #A9A199",
+"I. c #B6AC93",
+"U. c #BAAD91",
+"Y. c #BDB299",
+"T. c #8789AB",
+"R. c #9B9EB6",
+"E. c #A3A3A1",
+"W. c #A7A8A7",
+"Q. c #AEA8A2",
+"!. c #ABACAB",
+"~. c #AEB0AC",
+"^. c #B2B2B2",
+"/. c #B7B9B5",
+"(. c #B9BCB6",
+"). c #BBBEB9",
+"_. c #C1AF88",
+"`. c #C0B18D",
+"'. c #CCBA8E",
+"]. c #C2B492",
+"[. c #CCBB95",
+"{. c #CDBE9A",
+"}. c #D0BF98",
+"|. c #C4BAA3",
+" X c #C9BEA3",
+".X c #BEC1BC",
+"XX c #CFC09F",
+"oX c #D2C29C",
+"OX c #CEC2A8",
+"+X c #D5C6A4",
+"@X c #D6C8A7",
+"#X c #D7C9A9",
+"$X c #D9CBAD",
+"%X c #D6CAB3",
+"&X c #DBCEB3",
+"*X c #DDD1B6",
+"=X c #DDD2BA",
+"-X c #E0D5BD",
+";X c #ACAFC0",
+":X c #AFB1C0",
+">X c #BBBEC5",
+",X c #BBBEC8",
+"<X c #BEC2C8",
+"1X c #C4C5C3",
+"2X c #C5C8C2",
+"3X c #CACDC7",
+"4X c #C7CBCC",
+"5X c #CCCEC8",
+"6X c #CED1CA",
+"7X c #DED4C2",
+"8X c #D1D4CD",
+"9X c #D4D6D2",
+"0X c #D5D8D2",
+"qX c #D9DCD7",
+"wX c #DBDDD9",
+"eX c #E3D7C2",
+"rX c #E4D9C6",
+"tX c #E7DBCB",
+"yX c #E8DDCD",
+"uX c #E9DFD1",
+"iX c #DEE1DC",
+"pX c #EBE1D4",
+"aX c #E1E3DE",
+"sX c #EEE4DA",
+"dX c #E4E6E1",
+"fX c #E6E9E4",
+"gX c #E9EBE7",
+"hX c #ECEEEA",
+"jX c None",
+/* pixels */
+"jXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjX",
+"jXjXjXV.V.V.V.V.C.C.C.C.V.V.V.V.B.B.B.N.N.N.N.N.N.M.M.M.M.jXjXjX",
+"jXjXV.dXhXhXhXhXhXhXhXhXhXhXhXhXhXgXgXhXhXgXgXgXgXgXgXgXaXm jXjX",
+"jXjXV.hX:Xc.c.c.c.c.c.x.c.c.c.c.c.c.c.c.c.c.c.c.x.x.6X0XgXm jXjX",
+"jXjXL.hXm.v.m.N.v.v.v.v.v.l.l.l.l.l.k.l.k.j.j.j.j.a.>X.XfXm jXjX",
+"jXjXE.hXn.v.l.b.v.l.l.l.l.l.k.k.k.j.j.j.h.j.j.h.h.j :X2XdXM.jXjX",
+"jXjXW.gXc.l.l.u i c k.j.j.j.j.j.j.h.h.h.h.h.c c o.T R.3XaXM.jXjX",
+"jXjX!.gXc.k.u Z.+Xw j.j.j.h.h.h.h.h.c h.h.g l R 0.,.T.(.iXM.jXjX",
+"jXjX^.gXx.j.- Y.=Xq h.h.h.h.h.h.c a.a.g g B 2.9.` ,.m.OXwXM.jXjX",
+"jXjX^.gXz.h.> }.{.q a.h.g g g g g g d t P q.{ ` ` <.b.3XwXN.jXjX",
+"jXjX(.dXz.h.- oXoXq a.g g g g f f O $ ,.e.[ ' ` ( 3.l.(.qXB.jXjX",
+"jXjX<XdXg.g - }.oXr f g g f f y o M 6.w.} ] ` ` ( 3.k.8X9XC.jXjX",
+"jXjX1XaXf.a.- oXoXr : , p a O : U r.8.| [ Q G ` ( 5.v 8X9XL.jXjX",
+"jXjX3XiXs.p.= J.].6 XX}.q $ 1 +.t. .| ] Y 2 6 ! ! 5.z 6X8XW.jXjX",
+"jXjX8XiXs.f * OX+X0 @XoX1 XX4.5 V H ~ J y s < ! ! 5.C 6X6X^.  jX",
+"jXjX9XqXi.f * {.oXr #X@Xq +X'.8 '.N 6 s s s i E ( 5.V 6X6X/.. jX",
+"jXjXqXqXu.a X oX@XA $X$X@.@XoXD [.N K Y Y Y Y W ! _ V 6X6X>XX jX",
+"jXjXwX4Xy.; 1 +X#XF $X$X-.@X@X&.oXO./ ] ' ' ` ( ! ) H 8X6X%X@ jX",
+"jXM.wX,Xy.k Z @X$X*.&XOXJ.#X@XG.oX=.^ 7.) 7.~ 5.Q 5.H 5X6X3X# jX",
+"jXM.iX<Xd.F #.@X$XH.&X&X+XY.I.[.oX;.9 S A A A A A A x 5X3X9X# jX",
+"jX$.iX0X0XF.-.@X&X X=X7X&X&X$X@X+X>.~.6X6X6X6X6X6X6X3X3X3X9X& jX",
+"jXv.0X6X.XI.Z.-X-X&XeXeX*X&X%X$X$X_.L..X)..X(.(.(.(.(.(..X3X< jX",
+"jXjXM.C.N.OXU.&XeX=XeXeX-X-X-X$X&X'.b M.M.M.M.M.m m m m b 4 jXjX",
+"jXjXjXjXjXY.{.=XeX-XeXtX-X-X-X$X-X}.jXjXjXjXjXjXjXjXjXjXjXjXjXjX",
+"jXjXjXjXjXI.$X*XeX-XrXyXeXeX-X&X=XoXjXjXjXjXjXjXjXjXjXjXjXjXjXjX",
+"jXjXjXjXjXjX*X=XrXeXtXyXtXrXeX*X=X].jXjXjXjXjXjXjXjXjXjXjXjXjXjX",
+"jXjXjXjXjXjXOX*XrXeXtXuXtXrXeX*X*X:.jXjXjXjXjXjXjXjXjXjXjXjXjXjX",
+"jXjXjXjXjXjXH.*XtXeXtXpXtXtXrX=X*XjXjXjXjXjXjXjXjXjXjXjXjXjXjXjX",
+"jXjXjXjXjXjX%.*XrXeXuXsXuXtXrX-X|.jXjXjXjXjXjXjXjXjXjXjXjXjXjXjX",
+"jXjXjXjXjXjXjX%XrXeXuXsXuXyXrX-XZ.jXjXjXjXjXjXjXjXjXjXjXjXjXjXjX",
+"jXjXjXjXjXjXjXjXA.A.S.Q.P.K.K.A.jXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjX",
+"jXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjXjX"
+};
diff --git a/scripts/xinput_calibrator_get_hal_calibration.sh b/scripts/xinput_calibrator_get_hal_calibration.sh
new file mode 100755 (executable)
index 0000000..648b65b
--- /dev/null
@@ -0,0 +1,74 @@
+#!/bin/sh
+# Get running calibration data from lshal
+# (needed to recalibrate it, most easily fetchable from lshal)
+
+export PATH=".:$PATH"
+#FIND="hal-find-by-property"
+CAPAB="hal-find-by-capability"
+GET="hal-get-property"
+BINARY="xinput_calibrator"
+
+if [ "$(which $CAPAB)" = "" ]; then
+    echo "Error: Can not find executable $CAPAB"
+    exit 1
+fi
+if [ "$(which $GET)" = "" ]; then
+    echo "Error: Can not find executable $GET"
+    exit 1
+fi
+
+
+#udis=$($FIND --key input.x11_driver --string evtouch)
+udis=$($CAPAB --capability input)
+
+if [ "$udis" = "" ]; then
+    echo "HAL Error: No input devices found (tested: info.capabilities 'input'))"
+    exit 1
+fi
+
+
+echo "Trying all available input devices:"
+# possibly multiple screens, iterate over each possibility
+count=0
+cmd=""
+for udi in $udis; do
+    name=$($GET --udi $udi --key info.product)
+    minx=$($GET --udi $udi --key input.x11_options.minx 2> /dev/null)
+    maxx=$($GET --udi $udi --key input.x11_options.maxx 2> /dev/null)
+    miny=$($GET --udi $udi --key input.x11_options.miny 2> /dev/null)
+    maxy=$($GET --udi $udi --key input.x11_options.maxy 2> /dev/null)
+
+    # missing values ?
+    if [ "$minx" = "" ] || [ "$maxx" = "" ] ||
+        [ "$miny" = "" ] || [ "$maxy" = "" ]; then
+        if [ "$minx" = "" ] && [ "$maxx" = "" ] &&
+            [ "$miny" = "" ] && [ "$maxy" = "" ]; then
+            # no calibration data available
+            echo "\t'$name': no calibration data available"
+        else
+            # partial calibration data available ???
+            echo "Error: '$name', only partial calibration data available (MinX='$minx' MaxX='$maxx' MinY='$miny' MaxY='$maxy'). All 4 current calibration values are need to recalibrate the device !"
+        fi
+    else
+        count=$((count += 1))
+        cmd="$BINARY --precalib $minx $maxx $miny $maxy"
+        echo "\t'$name': values found, calibrate by running:"
+        echo "$cmd"
+    fi
+done
+
+if [ $count -gt 1 ]; then
+    echo "Found multiple calibratable touchscreen devices, select one from above and execute the calibration program with the given parameters."
+else
+    if [ $count -eq 0 ]; then
+        echo "Warning: No existing calibration data found, no parameters used."
+        cmd="$BINARY"
+    fi
+
+    if [ "$(which $BINARY)" = "" ]; then
+        echo "Error: can not find calibration program ($BINARY), please run it with the above parameters yourself."
+    else
+        echo "\nRunning calibration program..."
+        $cmd
+    fi
+fi
diff --git a/scripts/xinput_calibrator_pointercal.sh b/scripts/xinput_calibrator_pointercal.sh
new file mode 100755 (executable)
index 0000000..fccb197
--- /dev/null
@@ -0,0 +1,31 @@
+#!/bin/sh
+# script to make the changes permanent (xinput is called with every Xorg start)
+#
+# can be used from Xsession.d
+# script needs tee and sed (busybox variants are enough)
+#
+# original script: Martin Jansa <Martin.Jansa@gmail.com>, 2010-01-31
+# updated by Tias Guns <tias@ulyssis.org>, 2010-02-15
+# updated by Koen Kooi <koen@dominion.thruhere.net>, 2012-02-28
+
+PATH="/usr/bin:$PATH"
+
+BINARY="xinput_calibrator"
+CALFILE="/etc/pointercal.xinput"
+LOGFILE="/var/log/xinput_calibrator.pointercal.log"
+
+if [ -e $CALFILE ] ; then
+  if grep replace $CALFILE ; then
+    echo "Empty calibration file found, removing it"
+    rm $CALFILE
+  else
+    echo "Using calibration data stored in $CALFILE"
+    . $CALFILE && exit 0
+  fi
+fi
+
+CALDATA=`$BINARY --output-type xinput -v | tee $LOGFILE | grep '    xinput set' | sed 's/^    //g; s/$/;/g'`
+if [ ! -z "$CALDATA" ] ; then
+  echo $CALDATA > $CALFILE
+  echo "Calibration data stored in $CALFILE (log in $LOGFILE)"
+fi
diff --git a/src/.gitignore b/src/.gitignore
new file mode 100644 (file)
index 0000000..d186860
--- /dev/null
@@ -0,0 +1,3 @@
+xinput_calibrator_x11
+xinput_calibrator_gtkmm
+xinput_calibrator
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644 (file)
index 0000000..2184389
--- /dev/null
@@ -0,0 +1,61 @@
+#
+# Copyright (c) 2010 Petr Stetiar <ynezz@true.cz>
+# Copyright (c) 2010 Tias Guns <tias@ulyssis.org>
+#
+# 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.
+#
+
+SUBDIRS = \
+       calibrator \
+       gui
+
+AM_CXXFLAGS = -Wall -ansi -pedantic
+
+bin_PROGRAMS = xinput_calibrator tester
+
+COMMON_SRCS=calibrator.cpp calibrator/XorgPrint.cpp calibrator/Evdev.cpp calibrator/Usbtouchscreen.cpp main_common.cpp
+
+# only one of the BUILD_ flags should be set
+if BUILD_X11
+xinput_calibrator_SOURCES = gui/x11.cpp main_x11.cpp $(COMMON_SRCS)
+xinput_calibrator_LDADD = $(XINPUT_LIBS) $(XRANDR_LIBS) $(X11_LIBS)
+xinput_calibrator_CXXFLAGS = $(XINPUT_CFLAGS) $(X11_CFLAGS) $(XRANDR_CFLAGS) $(AM_CXXFLAGS)
+endif
+
+if BUILD_GTKMM
+xinput_calibrator_SOURCES = gui/gtkmm.cpp main_gtkmm.cpp $(COMMON_SRCS)
+xinput_calibrator_LDADD = $(XINPUT_LIBS) $(GTKMM_LIBS)
+xinput_calibrator_CXXFLAGS = $(XINPUT_CFLAGS) $(GTKMM_CFLAGS) $(AM_CXXFLAGS)
+
+# only include the needed gtkmm stuff
+# lets hope this has no side-effects
+xinput_calibrator_LDFLAGS = -Wl,--as-needed
+endif
+
+tester_SOURCES = tester.cpp calibrator.cpp calibrator/Tester.cpp calibrator/Evdev.cpp calibrator/EvdevTester.cpp
+tester_LDADD = $(XINPUT_LIBS) $(XRANDR_LIBS) $(X11_LIBS)
+tester_CXXFLAGS = $(XINPUT_CFLAGS) $(X11_CFLAGS) $(XRANDR_CFLAGS) $(AM_CXXFLAGS)
+
+EXTRA_DIST = \
+       calibrator.cpp \
+       calibrator.hh \
+       main_common.cpp
diff --git a/src/calibrator.cpp b/src/calibrator.cpp
new file mode 100644 (file)
index 0000000..c60a1f6
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2009 Tias Guns
+ * Copyright (c) 2009 Soren Hauberg
+ * Copyright (c) 2011 Antoine Hue
+ *
+ * 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 <algorithm>
+#include <sys/types.h>
+#include <dirent.h>
+#include <iostream>
+#include <fstream>
+#include <cstring>
+#include <cmath>
+
+#include "calibrator.hh"
+
+// static instance
+bool Calibrator::verbose = false;
+
+Calibrator::Calibrator(const char* const device_name0, const XYinfo& axys0,
+    const int thr_misclick, const int thr_doubleclick, const OutputType output_type0, const char* geometry0)
+: device_name(device_name0),
+    threshold_doubleclick(thr_doubleclick), threshold_misclick(thr_misclick),
+    output_type(output_type0), geometry(geometry0)
+{
+    old_axys = axys0;
+
+    clicked.num = 0;
+    //clicked.x(NUM_POINTS);
+    //clicked.y(NUM_POINTS);
+}
+
+bool Calibrator::add_click(int x, int y)
+{
+    // Double-click detection
+    if (threshold_doubleclick > 0 && clicked.num > 0) {
+        int i = clicked.num - 1;
+        while (i >= 0) {
+            if (abs(x - clicked.x[i]) <= threshold_doubleclick
+                && abs(y - clicked.y[i]) <= threshold_doubleclick) {
+                if (verbose) {
+                    printf("DEBUG: Not adding click %i (X=%i, Y=%i): within %i pixels of previous click\n",
+                         clicked.num, x, y, threshold_doubleclick);
+                }
+                return false;
+            }
+            i--;
+        }
+    }
+
+    // Mis-click detection
+    if (threshold_misclick > 0 && clicked.num > 0) {
+        bool misclick = true;
+
+        switch (clicked.num) {
+            case 1:
+                // check that along one axis of first point
+                if (along_axis(x,clicked.x[UL],clicked.y[UL]) ||
+                        along_axis(y,clicked.x[UL],clicked.y[UL]))
+                {
+                    misclick = false;
+                } else if (verbose) {
+                    printf("DEBUG: Mis-click detected, click %i (X=%i, Y=%i) not aligned with click 0 (X=%i, Y=%i) (threshold=%i)\n",
+                            clicked.num, x, y, clicked.x[UL], clicked.y[UL], threshold_misclick);
+                }
+                break;
+
+            case 2:
+                // check that along other axis of first point than second point
+                if ((along_axis( y, clicked.x[UL], clicked.y[UL])
+                            && along_axis( clicked.x[UR], clicked.x[UL], clicked.y[UL]))
+                        || (along_axis( x, clicked.x[UL], clicked.y[UL])
+                            && along_axis( clicked.y[UR], clicked.x[UL], clicked.y[UL])))
+                {
+                    misclick = false;
+                } else if (verbose) {
+                    printf("DEBUG: Mis-click detected, click %i (X=%i, Y=%i) not aligned with click 0 (X=%i, Y=%i) or click 1 (X=%i, Y=%i) (threshold=%i)\n",
+                            clicked.num, x, y, clicked.x[UL], clicked.y[UL], clicked.x[UR], clicked.y[UR], threshold_misclick);
+                }
+                break;
+
+            case 3:
+                // check that along both axis of second and third point
+                if ( ( along_axis( x, clicked.x[UR], clicked.y[UR])
+                            &&   along_axis( y, clicked.x[LL], clicked.y[LL]) )
+                        ||( along_axis( y, clicked.x[UR], clicked.y[UR])
+                            &&  along_axis( x, clicked.x[LL], clicked.y[LL]) ) )
+                {
+                    misclick = false;
+                } else if (verbose) {
+                    printf("DEBUG: Mis-click detected, click %i (X=%i, Y=%i) not aligned with click 1 (X=%i, Y=%i) or click 2 (X=%i, Y=%i) (threshold=%i)\n",
+                            clicked.num, x, y, clicked.x[UR], clicked.y[UR], clicked.x[LL], clicked.y[LL], threshold_misclick);
+                }
+        }
+
+        if (misclick) {
+            reset();
+            return false;
+        }
+    }
+
+    clicked.x.push_back(x);
+    clicked.y.push_back(y);
+    clicked.num++;
+
+    if (verbose)
+        printf("DEBUG: Adding click %i (X=%i, Y=%i)\n", clicked.num-1, x, y);
+
+    return true;
+}
+
+inline bool Calibrator::along_axis(int xy, int x0, int y0)
+{
+    return ((abs(xy - x0) <= threshold_misclick) ||
+            (abs(xy - y0) <= threshold_misclick));
+}
+
+bool Calibrator::finish(int width, int height)
+{
+    if (get_numclicks() != NUM_POINTS) {
+        return false;
+    }
+
+    // new axis origin and scaling
+    // based on old_axys: inversion/swapping is relative to the old axis
+    XYinfo new_axis(old_axys);
+
+
+    // calculate average of clicks
+    float x_min = (clicked.x[UL] + clicked.x[LL])/2.0;
+    float x_max = (clicked.x[UR] + clicked.x[LR])/2.0;
+    float y_min = (clicked.y[UL] + clicked.y[UR])/2.0;
+    float y_max = (clicked.y[LL] + clicked.y[LR])/2.0;
+
+    // Should x and y be swapped?
+    if (abs(clicked.x[UL] - clicked.x[UR]) < abs(clicked.y[UL] - clicked.y[UR])) {
+        new_axis.swap_xy = !new_axis.swap_xy;
+        std::swap(x_min, y_min);
+        std::swap(x_max, y_max);
+    }
+
+    // the screen was divided in num_blocks blocks, and the touch points were at
+    // one block away from the true edges of the screen.
+    const float block_x = width/(float)num_blocks;
+    const float block_y = height/(float)num_blocks;
+    // rescale these blocks from the range of the drawn touchpoints to the range of the 
+    // actually clicked coordinates, and substract/add from the clicked coordinates
+    // to obtain the coordinates corresponding to the edges of the screen.
+    float scale_x = (x_max - x_min)/(width - 2*block_x);
+    x_min -= block_x * scale_x;
+    x_max += block_x * scale_x;
+    float scale_y = (y_max - y_min)/(height - 2*block_y);
+    y_min -= block_y * scale_y;
+    y_max += block_y * scale_y;
+    
+    // now, undo the transformations done by the X server, to obtain the true 'raw' value in X.
+    // The raw value was scaled from old_axis to the device min/max, and from the device min/max
+    // to the screen min/max
+    // hence, the reverse transformation is from screen to old_axis
+    x_min = scaleAxis(x_min, old_axys.x.max, old_axys.x.min, width, 0);
+    x_max = scaleAxis(x_max, old_axys.x.max, old_axys.x.min, width, 0);
+    y_min = scaleAxis(y_min, old_axys.y.max, old_axys.y.min, height, 0);
+    y_max = scaleAxis(y_max, old_axys.y.max, old_axys.y.min, height, 0);
+
+
+    // round and put in new_axis struct
+    new_axis.x.min = round(x_min); new_axis.x.max = round(x_max);
+    new_axis.y.min = round(y_min); new_axis.y.max = round(y_max);
+
+    // finish the data, driver/calibrator specific
+    return finish_data(new_axis);
+}
+
+const char* Calibrator::get_sysfs_name()
+{
+    if (is_sysfs_name(device_name))
+        return device_name;
+
+    // TODO: more mechanisms
+
+    return NULL;
+}
+
+bool Calibrator::is_sysfs_name(const char* name) {
+    const char* SYSFS_INPUT="/sys/class/input";
+    const char* SYSFS_DEVNAME="device/name";
+
+    DIR* dp = opendir(SYSFS_INPUT);
+    if (dp == NULL)
+        return false;
+
+    while (dirent* ep = readdir(dp)) {
+        if (strncmp(ep->d_name, "event", strlen("event")) == 0) {
+            // got event name, get its sysfs device name
+            char filename[40]; // actually 35, but hey...
+            (void) sprintf(filename, "%s/%s/%s", SYSFS_INPUT, ep->d_name, SYSFS_DEVNAME);
+
+            std::ifstream ifile(filename);
+            if (ifile.is_open()) {
+                if (!ifile.eof()) {
+                    std::string devname;
+                    std::getline(ifile, devname);
+                    if (devname == name) {
+                        if (verbose)
+                            printf("DEBUG: Found that '%s' is a sysfs name.\n", name);
+                        return true;
+                    }
+                }
+                ifile.close();
+            }
+        }
+    }
+    (void) closedir(dp);
+
+    if (verbose)
+        printf("DEBUG: Name '%s' does not match any in '%s/event*/%s'\n",
+                    name, SYSFS_INPUT, SYSFS_DEVNAME);
+    return false;
+}
+
+bool Calibrator::has_xorgconfd_support(Display* dpy) {
+    bool has_support = false;
+
+    Display* display = dpy;
+    if (dpy == NULL) // no connection to reuse
+        display = XOpenDisplay(NULL);
+
+    if (display == NULL) {
+        fprintf(stderr, "Unable to connect to X server\n");
+        exit(1);
+    }
+
+    if (strstr(ServerVendor(display), "X.Org") &&
+        VendorRelease(display) >= 10800000) {
+        has_support = true;
+    }
+
+    if (dpy == NULL) // no connection to reuse
+        XCloseDisplay(display);
+
+    return has_support;
+}
+
+/*
+ * FROM xf86Xinput.c
+ *
+ * Cx     - raw data from touch screen
+ * to_max - scaled highest dimension
+ *          (remember, this is of rows - 1 because of 0 origin)
+ * to_min  - scaled lowest dimension
+ * from_max - highest raw value from touch screen calibration
+ * from_min  - lowest raw value from touch screen calibration
+ *
+ * This function is the same for X or Y coordinates.
+ * You may have to reverse the high and low values to compensate for
+ * different orgins on the touch screen vs X.
+ *
+ * e.g. to scale from device coordinates into screen coordinates, call
+ * xf86ScaleAxis(x, 0, screen_width, dev_min, dev_max);
+ */
+int
+xf86ScaleAxis(int Cx, int to_max, int to_min, int from_max, int from_min)
+{
+    int X;
+    int64_t to_width = to_max - to_min;
+    int64_t from_width = from_max - from_min;
+
+    if (from_width) {
+        X = (int) (((to_width * (Cx - from_min)) / from_width) + to_min);
+    }
+    else {
+        X = 0;
+        printf("Divide by Zero in xf86ScaleAxis\n");
+        exit(1);
+    }
+
+    if (X > to_max)
+        X = to_max;
+    if (X < to_min)
+        X = to_min;
+
+    return X;
+}
+
+// same but without rounding to min/max
+float
+scaleAxis(float Cx, int to_max, int to_min, int from_max, int from_min)
+{
+    float X;
+    int64_t to_width = to_max - to_min;
+    int64_t from_width = from_max - from_min;
+
+    if (from_width) {
+        X = (((to_width * (Cx - from_min)) / from_width) + to_min);
+    }
+    else {
+        X = 0;
+        printf("Divide by Zero in scaleAxis\n");
+        exit(1);
+    }
+
+    /* no rounding to max/min
+    if (X > to_max)
+        X = to_max;
+    if (X < to_min)
+        X = to_min;
+    */
+
+    return X;
+}
diff --git a/src/calibrator.hh b/src/calibrator.hh
new file mode 100644 (file)
index 0000000..6e696e4
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2009 Tias Guns
+ * Copyright (c) 2009 Soren Hauberg
+ * Copyright (c) 2011 Antoine Hue
+ *
+ * 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.
+ */
+
+#ifndef _calibrator_hh
+#define _calibrator_hh
+
+#include <stdexcept>
+#include <X11/Xlib.h>
+#include <stdio.h>
+#include <vector>
+
+int xf86ScaleAxis(int Cx, int to_max, int to_min, int from_max, int from_min);
+float scaleAxis(float Cx, int to_max, int to_min, int from_max, int from_min);
+
+/*
+ * Number of blocks. We partition the screen into 'num_blocks' x 'num_blocks'
+ * rectangles of equal size. We then ask the user to press points that are
+ * located at the corner closes to the center of the four blocks in the corners
+ * of the screen. The following ascii art illustrates the situation. We partition
+ * the screen into 8 blocks in each direction. We then let the user press the
+ * points marked with 'O'.
+ *
+ *   +--+--+--+--+--+--+--+--+
+ *   |  |  |  |  |  |  |  |  |
+ *   +--O--+--+--+--+--+--O--+
+ *   |  |  |  |  |  |  |  |  |
+ *   +--+--+--+--+--+--+--+--+
+ *   |  |  |  |  |  |  |  |  |
+ *   +--+--+--+--+--+--+--+--+
+ *   |  |  |  |  |  |  |  |  |
+ *   +--+--+--+--+--+--+--+--+
+ *   |  |  |  |  |  |  |  |  |
+ *   +--+--+--+--+--+--+--+--+
+ *   |  |  |  |  |  |  |  |  |
+ *   +--+--+--+--+--+--+--+--+
+ *   |  |  |  |  |  |  |  |  |
+ *   +--O--+--+--+--+--+--O--+
+ *   |  |  |  |  |  |  |  |  |
+ *   +--+--+--+--+--+--+--+--+
+ */
+const int num_blocks = 8;
+
+struct AxisInfo {
+    int min, max;
+    bool invert;
+
+    AxisInfo() : min(-1), max(-1), invert(false) { }
+    AxisInfo(int mi, int ma, bool inv = false) :
+        min(mi), max(ma), invert(inv) { }
+    AxisInfo(const AxisInfo& old) :
+        min(old.min), max(old.max), invert(old.invert) { }
+
+    void do_invert() {
+        invert = !invert;
+    }
+};
+
+/// struct to hold min/max info of the X and Y axis
+struct XYinfo {
+    /// Axis swapped
+    bool swap_xy;
+    /// X, Y axis
+    AxisInfo x, y;
+
+    XYinfo() : swap_xy(false) {}
+
+    XYinfo(int xmi, int xma, int ymi, int yma, bool swap_xy_ = false,
+        bool inv_x = false, bool inv_y = false) :
+        swap_xy(swap_xy_), x(xmi, xma, inv_x), y(ymi, yma, inv_y) {}
+
+    XYinfo(const XYinfo& old) :
+        swap_xy(old.swap_xy), x(old.x), y(old.y) {}
+
+    void do_xf86ScaleAxis(const XYinfo& to, const XYinfo& from) {
+        x.min = xf86ScaleAxis(x.min, to.x.max, to.x.min, from.x.max, from.x.min);
+        x.max = xf86ScaleAxis(x.max, to.x.max, to.x.min, from.x.max, from.x.min);
+        y.min = xf86ScaleAxis(y.min, to.y.max, to.y.min, from.y.max, from.y.min);
+        y.max = xf86ScaleAxis(y.max, to.y.max, to.y.min, from.y.max, from.y.min);
+    }
+
+    void print(const char* xtra="\n") {
+        printf("XYinfo: x.min=%i, x.max=%i, y.min=%i, y.max=%i, swap_xy=%i, invert_x=%i, invert_y=%i%s",
+               x.min, x.max, y.min, y.max, swap_xy, x.invert, y.invert, xtra);
+    }
+};
+
+/// Names of the points
+enum {
+    UL = 0, // Upper-left
+    UR = 1, // Upper-right
+    LL = 2, // Lower-left
+    LR = 3,  // Lower-right
+    NUM_POINTS
+};
+
+/// Output types
+enum OutputType {
+    OUTYPE_AUTO,
+    OUTYPE_XORGCONFD,
+    OUTYPE_HAL,
+    OUTYPE_XINPUT
+};
+
+class WrongCalibratorException : public std::invalid_argument {
+    public:
+        WrongCalibratorException(const std::string& msg = "") :
+            std::invalid_argument(msg) {}
+};
+
+/// Base class for calculating new calibration parameters
+class Calibrator
+{
+public:
+    /// Parse arguments and create calibrator
+    static Calibrator* make_calibrator(int argc, char** argv);
+
+    /// Constructor
+    ///
+    /// The constructor will throw an exception,
+    /// if the touchscreen is not of the type it supports
+    Calibrator(const char* const device_name,
+               const XYinfo& axys,
+               const int thr_misclick=0,
+               const int thr_doubleclick=0,
+               const OutputType output_type=OUTYPE_AUTO,
+               const char* geometry=0);
+
+    ~Calibrator() {}
+
+    /// set the doubleclick treshold
+    void set_threshold_doubleclick(int t)
+    { threshold_doubleclick = t; }
+
+    /// set the misclick treshold
+    void set_threshold_misclick(int t)
+    { threshold_misclick = t; }
+
+    /// get the number of clicks already registered
+    int get_numclicks() const
+    { return clicked.num; }
+
+    /// return geometry string or NULL
+    const char* get_geometry() const
+    { return geometry; }
+
+    /// reset clicks
+    void reset()
+    {  clicked.num = 0; clicked.x.clear(); clicked.y.clear();}
+
+    /// add a click with the given coordinates
+    bool add_click(int x, int y);
+    /// calculate and apply the calibration
+    virtual bool finish(int width, int height);
+    /// get the sysfs name of the device,
+    /// returns NULL if it can not be found
+    const char* get_sysfs_name();
+
+protected:
+    /// check whether the coordinates are along the respective axis
+    bool along_axis(int xy, int x0, int y0);
+
+    /// Apply new calibration, implementation dependent
+    virtual bool finish_data(const XYinfo new_axys) =0;
+
+    /// Check whether the given name is a sysfs device name
+    bool is_sysfs_name(const char* name);
+
+    /// Check whether the X server has xorg.conf.d support
+    bool has_xorgconfd_support(Display* display=NULL);
+
+    static int find_device(const char* pre_device, bool list_devices,
+            XID& device_id, const char*& device_name, XYinfo& device_axys);
+
+protected:
+    /// Name of the device (driver)
+    const char* const device_name;
+
+    /// Original values
+    XYinfo old_axys;
+
+    /// Be verbose or not
+    static bool verbose;
+
+    /// Clicked values (screen coordinates)
+    struct {
+        /// actual number of clicks registered
+        int num;
+        /// click coordinates
+        std::vector<int> x, y;
+    } clicked;
+
+    // Threshold to keep the same point from being clicked twice.
+    // Set to zero if you don't want this check
+    int threshold_doubleclick;
+
+    // Threshold to detect mis-clicks (clicks not along axes)
+    // A lower value forces more precise calibration
+    // Set to zero if you don't want this check
+    int threshold_misclick;
+
+    // Type of output
+    OutputType output_type;
+
+    // manually specified geometry string
+    const char* geometry;
+};
+
+// Interfance for a CalibratorTester
+class CalibratorTesterInterface
+{
+public:
+    // emulate the driver processing the coordinates in 'raw'
+    virtual XYinfo emulate_driver(const XYinfo& raw, bool useNewAxis, const XYinfo& screen, const XYinfo& device) = 0;
+
+    virtual void new_axis_print() = 0;
+
+    //* From Calibrator
+    /// add a click with the given coordinates
+    virtual bool add_click(int x, int y) = 0;
+    /// calculate and apply the calibration
+    virtual bool finish(int width, int height) = 0;
+};
+
+#endif
diff --git a/src/calibrator/Evdev.cpp b/src/calibrator/Evdev.cpp
new file mode 100644 (file)
index 0000000..8a849b1
--- /dev/null
@@ -0,0 +1,561 @@
+/*
+ * Copyright (c) 2009 Tias Guns
+ * Copyright 2007 Peter Hutterer (xinput_ methods from xinput)
+ * Copyright (c) 2011 Antoine Hue (invertX/Y)
+ *
+ * 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 "calibrator/Evdev.hpp"
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <ctype.h>
+#include <cstdio>
+#include <cstring>
+#include <cstdlib>
+#include <cmath>
+
+#ifndef EXIT_SUCCESS
+#define EXIT_SUCCESS 1
+#endif
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE 0
+#endif
+
+// Constructor
+CalibratorEvdev::CalibratorEvdev(const char* const device_name0,
+                                 const XYinfo& axys0,
+                                 XID device_id,
+                                 const int thr_misclick,
+                                 const int thr_doubleclick,
+                                 const OutputType output_type,
+                                 const char* geometry)
+  : Calibrator(device_name0, axys0, thr_misclick, thr_doubleclick, output_type, geometry)
+{
+    // init
+    display = XOpenDisplay(NULL);
+    if (display == NULL) {
+        throw WrongCalibratorException("Evdev: Unable to connect to X server");
+    }
+
+    // normaly, we already have the device id
+    if (device_id == (XID)-1) {
+        devInfo = xinput_find_device_info(display, device_name, False);
+        if (!devInfo) {
+            XCloseDisplay(display);
+            throw WrongCalibratorException("Evdev: Unable to find device");
+        }
+        device_id = devInfo->id;
+    }
+
+    dev = XOpenDevice(display, device_id);
+    if (!dev) {
+        XCloseDisplay(display);
+        throw WrongCalibratorException("Evdev: Unable to open device");
+    }
+
+#ifndef HAVE_XI_PROP
+    throw WrongCalibratorException("Evdev: you need at least libXi 1.2 and inputproto 1.5 for dynamic recalibration of evdev.");
+#else
+
+    // XGetDeviceProperty vars
+    Atom            property;
+    Atom            act_type;
+    int             act_format;
+    unsigned long   nitems, bytes_after;
+    unsigned char   *data, *ptr;
+
+    // get "Evdev Axis Calibration" property
+    property = xinput_parse_atom(display, "Evdev Axis Calibration");
+    if (XGetDeviceProperty(display, dev, property, 0, 1000, False,
+                           AnyPropertyType, &act_type, &act_format,
+                           &nitems, &bytes_after, &data) != Success)
+    {
+        XCloseDevice(display, dev);
+        XCloseDisplay(display);
+        throw WrongCalibratorException("Evdev: \"Evdev Axis Calibration\" property missing, not a (valid) evdev device");
+
+    } else {
+        if (act_format != 32 || act_type != XA_INTEGER) {
+            XCloseDevice(display, dev);
+            XCloseDisplay(display);
+            throw WrongCalibratorException("Evdev: invalid \"Evdev Axis Calibration\" property format");
+
+        } else if (nitems == 0) {
+            if (verbose)
+                printf("DEBUG: Evdev Axis Calibration not set, setting to axis valuators to be sure.\n");
+
+            // No axis calibration set, set it to the default one
+            // QUIRK: when my machine resumes from a sleep,
+            // the calibration property is no longer exported through xinput, but still active
+            // not setting the values here would result in a wrong first calibration
+            (void) set_calibration(old_axys);
+
+        } else if (nitems > 0) {
+            ptr = data;
+
+            old_axys.x.min = *((long*)ptr);
+            ptr += sizeof(long);
+            old_axys.x.max = *((long*)ptr);
+            ptr += sizeof(long);
+            old_axys.y.min = *((long*)ptr);
+            ptr += sizeof(long);
+            old_axys.y.max = *((long*)ptr);
+            ptr += sizeof(long);
+        }
+
+        XFree(data);
+    }
+
+    // get "Evdev Axes Swap" property
+    property = xinput_parse_atom(display, "Evdev Axes Swap");
+    if (XGetDeviceProperty(display, dev, property, 0, 1000, False,
+                           AnyPropertyType, &act_type, &act_format,
+                           &nitems, &bytes_after, &data) == Success)
+    {
+        if (act_format == 8 && act_type == XA_INTEGER && nitems == 1) {
+            old_axys.swap_xy = *((char*)data);
+
+            if (verbose)
+                printf("DEBUG: Read axes swap value of %i.\n", old_axys.swap_xy);
+        }
+    }
+
+    // get "Evdev Axes Inversion" property
+    property = xinput_parse_atom(display, "Evdev Axis Inversion");
+    if (XGetDeviceProperty(display, dev, property, 0, 1000, False,
+                AnyPropertyType, &act_type, &act_format,
+                &nitems, &bytes_after, &data) == Success) {
+        if (act_format == 8 && act_type == XA_INTEGER && nitems == 2) {
+            old_axys.x.invert = *((char*)data++);
+            old_axys.y.invert = *((char*)data);
+
+            if (verbose)
+                printf("DEBUG: Read InvertX=%i, InvertY=%i.\n", old_axys.x.invert, old_axys.y.invert);
+        }
+    }
+
+    printf("Calibrating EVDEV driver for \"%s\" id=%i\n", device_name, (int)device_id);
+    printf("\tcurrent calibration values (from XInput): min_x=%d, max_x=%d and min_y=%d, max_y=%d\n",
+                old_axys.x.min, old_axys.x.max, old_axys.y.min, old_axys.y.max);
+#endif // HAVE_XI_PROP
+
+}
+// protected pass-through constructor for subclasses
+CalibratorEvdev::CalibratorEvdev(const char* const device_name0,
+                                 const XYinfo& axys0,
+                                 const int thr_misclick,
+                                 const int thr_doubleclick,
+                                 const OutputType output_type,
+                                 const char* geometry)
+  : Calibrator(device_name0, axys0, thr_misclick, thr_doubleclick, output_type, geometry) { }
+
+// Destructor
+CalibratorEvdev::~CalibratorEvdev () {
+    XCloseDevice(display, dev);
+    XCloseDisplay(display);
+}
+
+// From Calibrator but with evdev specific invertion option
+// KEEP IN SYNC with Calibrator::finish() !!
+bool CalibratorEvdev::finish(int width, int height)
+{
+    if (get_numclicks() != NUM_POINTS) {
+        return false;
+    }
+
+    // new axis origin and scaling
+    // based on old_axys: inversion/swapping is relative to the old axis
+    XYinfo new_axis(old_axys);
+
+
+    // calculate average of clicks
+    float x_min = (clicked.x[UL] + clicked.x[LL])/2.0;
+    float x_max = (clicked.x[UR] + clicked.x[LR])/2.0;
+    float y_min = (clicked.y[UL] + clicked.y[UR])/2.0;
+    float y_max = (clicked.y[LL] + clicked.y[LR])/2.0;
+
+
+    // When evdev detects an invert_X/Y option,
+    // it performs the following *crazy* code just before returning
+    // val = (pEvdev->absinfo[i].maximum - val + pEvdev->absinfo[i].minimum);
+    // undo this crazy step before doing the regular calibration routine
+    if (old_axys.x.invert) {
+        x_min = width - x_min;
+        x_max = width - x_max;
+        // avoid invert_x property from here on,
+        // the calibration code can handle this dynamically!
+        new_axis.x.invert = false;
+    }
+    if (old_axys.y.invert) {
+        y_min = height - y_min;
+        y_max = height - y_max;
+        // avoid invert_y property from here on,
+        // the calibration code can handle this dynamically!
+        new_axis.y.invert = false;
+    }
+    // end of evdev inversion crazyness
+
+
+    // Should x and y be swapped?
+    if (abs(clicked.x[UL] - clicked.x[UR]) < abs(clicked.y[UL] - clicked.y[UR])) {
+        new_axis.swap_xy = !new_axis.swap_xy;
+        std::swap(x_min, y_min);
+        std::swap(x_max, y_max);
+    }
+
+    // the screen was divided in num_blocks blocks, and the touch points were at
+    // one block away from the true edges of the screen.
+    const float block_x = width/(float)num_blocks;
+    const float block_y = height/(float)num_blocks;
+    // rescale these blocks from the range of the drawn touchpoints to the range of the 
+    // actually clicked coordinates, and substract/add from the clicked coordinates
+    // to obtain the coordinates corresponding to the edges of the screen.
+    float scale_x = (x_max - x_min)/(width - 2*block_x);
+    x_min -= block_x * scale_x;
+    x_max += block_x * scale_x;
+    float scale_y = (y_max - y_min)/(height - 2*block_y);
+    y_min -= block_y * scale_y;
+    y_max += block_y * scale_y;
+    
+    // now, undo the transformations done by the X server, to obtain the true 'raw' value in X.
+    // The raw value was scaled from old_axis to the device min/max, and from the device min/max
+    // to the screen min/max
+    // hence, the reverse transformation is from screen to old_axis
+    x_min = scaleAxis(x_min, old_axys.x.max, old_axys.x.min, width, 0);
+    x_max = scaleAxis(x_max, old_axys.x.max, old_axys.x.min, width, 0);
+    y_min = scaleAxis(y_min, old_axys.y.max, old_axys.y.min, height, 0);
+    y_max = scaleAxis(y_max, old_axys.y.max, old_axys.y.min, height, 0);
+
+
+    // round and put in new_axis struct
+    new_axis.x.min = round(x_min); new_axis.x.max = round(x_max);
+    new_axis.y.min = round(y_min); new_axis.y.max = round(y_max);
+
+    // finish the data, driver/calibrator specific
+    return finish_data(new_axis);
+}
+
+// Activate calibrated data and output it
+bool CalibratorEvdev::finish_data(const XYinfo new_axys)
+{
+    bool success = true;
+
+    printf("\nDoing dynamic recalibration:\n");
+    // Evdev Axes Swap
+    if (old_axys.swap_xy != new_axys.swap_xy) {
+        success &= set_swapxy(new_axys.swap_xy);
+    }
+
+   // Evdev Axis Inversion
+   if (old_axys.x.invert != new_axys.x.invert ||
+       old_axys.y.invert != new_axys.y.invert) {
+        success &= set_invert_xy(new_axys.x.invert, new_axys.y.invert);
+    }
+
+    // Evdev Axis Calibration
+    success &= set_calibration(new_axys);
+
+    // close
+    XSync(display, False);
+
+    printf("\t--> Making the calibration permanent <--\n");
+    switch (output_type) {
+        case OUTYPE_AUTO:
+            // xorg.conf.d or alternatively xinput commands
+            if (has_xorgconfd_support()) {
+                success &= output_xorgconfd(new_axys);
+            } else {
+                success &= output_xinput(new_axys);
+            }
+            break;
+        case OUTYPE_XORGCONFD:
+            success &= output_xorgconfd(new_axys);
+            break;
+        case OUTYPE_HAL:
+            success &= output_hal(new_axys);
+            break;
+        case OUTYPE_XINPUT:
+            success &= output_xinput(new_axys);
+            break;
+        default:
+            fprintf(stderr, "ERROR: Evdev Calibrator does not support the supplied --output-type\n");
+            success = false;
+    }
+
+    return success;
+}
+
+bool CalibratorEvdev::set_swapxy(const int swap_xy)
+{
+    printf("\tSwapping X and Y axis...\n");
+
+    // xinput set-int-prop "divername" "Evdev Axes Swap" 8 0
+    int arr_cmd[1];
+    arr_cmd[0] = swap_xy;
+
+    bool ret = xinput_do_set_int_prop("Evdev Axes Swap", display, 8, 1, arr_cmd);
+
+    if (verbose) {
+        if (ret == true)
+            printf("DEBUG: Successfully set swapped X and Y axes = %d.\n", swap_xy);
+        else
+            printf("DEBUG: Failed to set swap X and Y axes.\n");
+    }
+
+    return ret;
+}
+
+bool CalibratorEvdev::set_invert_xy(const int invert_x, const int invert_y)
+{
+    printf("\tInverting X and/or Y axis...\n");
+
+    // xinput set-int-prop "divername" "Evdev Axis Inversion" 8 0 0
+    int arr_cmd[2];
+    arr_cmd[0] = invert_x;
+    arr_cmd[1] = invert_y;
+
+    int ret = xinput_do_set_int_prop("Evdev Axis Inversion", display, 8, 2, arr_cmd);
+
+    if (verbose) {
+        if (ret == true)
+            printf("DEBUG: Successfully set invert axis X=%d, Y=%d.\n", invert_x, invert_y);
+        else
+            printf("DEBUG: Failed to set axis inversion.\n");
+    }
+
+    return ret;
+}
+
+bool CalibratorEvdev::set_calibration(const XYinfo new_axys)
+{
+    printf("\tSetting calibration data: %d, %d, %d, %d\n", new_axys.x.min, new_axys.x.max, new_axys.y.min, new_axys.y.max);
+
+    // xinput set-int-prop 4 223 32 5 500 8 300
+    int arr_cmd[4];
+    arr_cmd[0] = new_axys.x.min;
+    arr_cmd[1] = new_axys.x.max;
+    arr_cmd[2] = new_axys.y.min;
+    arr_cmd[3] = new_axys.y.max;
+
+    int ret = xinput_do_set_int_prop("Evdev Axis Calibration", display, 32, 4, arr_cmd);
+
+    if (verbose) {
+        if (ret == true)
+            printf("DEBUG: Successfully applied axis calibration.\n");
+        else
+            printf("DEBUG: Failed to apply axis calibration.\n");
+    }
+
+    return ret;
+}
+
+Atom CalibratorEvdev::xinput_parse_atom(Display *display, const char *name)
+{
+    Bool is_atom = True;
+    int i;
+
+    for (i = 0; name[i] != '\0'; i++) {
+        if (!isdigit(name[i])) {
+            is_atom = False;
+            break;
+        }
+    }
+
+    if (is_atom)
+        return atoi(name);
+    else
+        return XInternAtom(display, name, False);
+}
+
+XDeviceInfo* CalibratorEvdev::xinput_find_device_info(
+Display *display, const char *name, Bool only_extended)
+{
+    XDeviceInfo        *devices;
+    XDeviceInfo *found = NULL;
+    int                loop;
+    int                num_devices;
+    int                len = strlen(name);
+    Bool       is_id = True;
+    XID                id = (XID)-1;
+
+    for (loop=0; loop<len; loop++) {
+        if (!isdigit(name[loop])) {
+            is_id = False;
+            break;
+        }
+    }
+
+    if (is_id) {
+        id = atoi(name);
+    }
+
+    devices = XListInputDevices(display, &num_devices);
+
+    for (loop=0; loop<num_devices; loop++) {
+        if ((!only_extended || (devices[loop].use >= IsXExtensionDevice)) &&
+            ((!is_id && strcmp(devices[loop].name, name) == 0) ||
+             (is_id && devices[loop].id == id))) {
+            if (found) {
+                fprintf(stderr,
+                        "Warning: There are multiple devices named \"%s\".\n"
+                        "To ensure the correct one is selected, please use "
+                        "the device ID instead.\n\n", name);
+                return NULL;
+            } else {
+                found = &devices[loop];
+            }
+        }
+    }
+
+    return found;
+}
+
+// Set Integer property on  X
+bool CalibratorEvdev::xinput_do_set_int_prop( const char * name,
+                                         Display *display,
+                                         int format,
+                                         int argc,
+                                         const int *argv )
+{
+#ifndef HAVE_XI_PROP
+    return false;
+#else
+
+    Atom          prop;
+    Atom          old_type;
+    int           i;
+    int           old_format;
+    unsigned long act_nitems, bytes_after;
+
+    union {
+        unsigned char *c;
+        short *s;
+        long *l;
+        Atom *a;
+    } data;
+
+    if (argc < 1)
+    {
+        fprintf(stderr, "Wrong usage of xinput_do_set_prop, need at least 1 arguments\n");
+        return false;
+    }
+
+    prop = xinput_parse_atom(display, name);
+
+    if (prop == None) {
+        fprintf(stderr, "invalid property %s\n", name);
+        return false;
+    }
+
+    if ( format == 0) {
+        if (XGetDeviceProperty(display, dev, prop, 0, 0, False, AnyPropertyType,
+                               &old_type, &old_format, &act_nitems,
+                               &bytes_after, &data.c) != Success) {
+            fprintf(stderr, "failed to get property type and format for %s\n",
+                    name);
+            return false;
+        } else {
+            format = old_format;
+        }
+
+        XFree(data.c);
+    }
+
+    data.c = (unsigned char*)calloc(argc, sizeof(long));
+
+    for (i = 0; i < argc; i++) {
+      switch (format) {
+        case 8:
+            data.c[i] = argv[i];
+        case 16:
+            data.s[i] = argv[i];
+            break;
+        case 32:
+            data.l[i] = argv[i];
+            break;
+
+        default:
+            fprintf(stderr, "unexpected size for property %s\n", name);
+            return false;
+      }
+    }
+
+    XChangeDeviceProperty(display, dev, prop, XA_INTEGER, format, PropModeReplace,
+                      data.c, argc);
+    free(data.c);
+    return true;
+#endif // HAVE_XI_PROP
+
+}
+
+bool CalibratorEvdev::output_xorgconfd(const XYinfo new_axys)
+{
+    const char* sysfs_name = get_sysfs_name();
+    bool not_sysfs_name = (sysfs_name == NULL);
+    if (not_sysfs_name)
+        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  \"Calibration\" \"%d %d %d %d\"\n",
+                new_axys.x.min, new_axys.x.max, new_axys.y.min, new_axys.y.max);
+    printf("   Option  \"SwapAxes\"    \"%d\"\n", new_axys.swap_xy);
+    printf("EndSection\n");
+
+    if (not_sysfs_name)
+        printf("\nChange '%s' to your device's name in the snippet above.\n", sysfs_name);
+
+    return true;
+}
+
+bool CalibratorEvdev::output_hal(const XYinfo new_axys)
+{
+    const char* sysfs_name = get_sysfs_name();
+    bool not_sysfs_name = (sysfs_name == NULL);
+    if (not_sysfs_name)
+        sysfs_name = "!!Name_Of_TouchScreen!!";
+
+    // HAL policy output
+    printf("  copy the policy below into '/etc/hal/fdi/policy/touchscreen.fdi'\n\
+<match key=\"info.product\" contains=\"%s\">\n\
+  <merge key=\"input.x11_options.calibration\" type=\"string\">%d %d %d %d</merge>\n"
+     , sysfs_name, new_axys.x.min, new_axys.x.max, new_axys.y.min, new_axys.y.max);
+    printf("  <merge key=\"input.x11_options.swapaxes\" type=\"string\">%d</merge>\n", new_axys.swap_xy);
+    printf("</match>\n");
+
+    if (not_sysfs_name)
+        printf("\nChange '%s' to your device's name in the config above.\n", sysfs_name);
+
+    return true;
+}
+
+bool CalibratorEvdev::output_xinput(const XYinfo new_axys)
+{
+    // create startup script
+    printf("  Install the 'xinput' tool and copy the command(s) below in a script that starts with your X session\n");
+    printf("    xinput set-int-prop \"%s\" \"Evdev Axis Calibration\" 32 %d %d %d %d\n", device_name, new_axys.x.min, new_axys.x.max, new_axys.y.min, new_axys.y.max);
+    printf("    xinput set-int-prop \"%s\" \"Evdev Axes Swap\" 8 %d\n", device_name, new_axys.swap_xy);
+
+    return true;
+}
diff --git a/src/calibrator/Evdev.hpp b/src/calibrator/Evdev.hpp
new file mode 100644 (file)
index 0000000..066b0c8
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2009 Tias Guns
+ * Copyright 2007 Peter Hutterer (xinput_ methods from xinput)
+ *
+ * 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.
+ */
+
+#ifndef CALIBRATOR_EVDEV_HPP
+#define CALIBRATOR_EVDEV_HPP
+
+#include "calibrator.hh"
+#include <X11/extensions/XInput.h>
+
+/***************************************
+ * Class for dynamic evdev calibration
+ * uses xinput "Evdev Axis Calibration"
+ ***************************************/
+class CalibratorEvdev: public Calibrator
+{
+private:
+    Display     *display;
+    XDeviceInfo *devInfo;
+    XDevice     *dev;
+
+protected:
+    // protected constructor: should only be used by subclasses!
+    // (pass-through to Calibrator)
+    CalibratorEvdev(const char* const device_name,
+                    const XYinfo& axys,
+                    const int thr_misclick=0,
+                    const int thr_doubleclick=0,
+                    const OutputType output_type=OUTYPE_AUTO,
+                    const char* geometry=0);
+
+public:
+    CalibratorEvdev(const char* const device_name,
+                    const XYinfo& axys,
+                    XID device_id=(XID)-1,
+                    const int thr_misclick=0,
+                    const int thr_doubleclick=0,
+                    const OutputType output_type=OUTYPE_AUTO,
+                    const char* geometry=0);
+    ~CalibratorEvdev();
+
+    /// calculate and apply the calibration
+    virtual bool finish(int width, int height);
+    virtual bool finish_data(const XYinfo new_axys);
+
+    bool set_swapxy(const int swap_xy);
+    bool set_invert_xy(const int invert_x, const int invert_y);
+    bool set_calibration(const XYinfo new_axys);
+
+    // xinput_ functions (from the xinput project)
+    Atom xinput_parse_atom(Display *display, const char* name);
+    XDeviceInfo* xinput_find_device_info(Display *display, const char* name, Bool only_extended);
+    bool xinput_do_set_int_prop( const char * name,
+                                 Display *display,
+                                 int format,
+                                 int argc,
+                                 const int* argv);
+protected:
+    bool output_xorgconfd(const XYinfo new_axys);
+    bool output_hal(const XYinfo new_axys);
+    bool output_xinput(const XYinfo new_axys);
+};
+
+#endif
diff --git a/src/calibrator/EvdevTester.cpp b/src/calibrator/EvdevTester.cpp
new file mode 100644 (file)
index 0000000..5022946
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2009 Tias Guns
+ *
+ * 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 "calibrator/Evdev.hpp"
+#include "calibrator/EvdevTester.hpp"
+
+#include <cstdio>
+
+CalibratorEvdevTester::CalibratorEvdevTester(const char* const device_name0, const XYinfo& axys0, const int thr_misclick, const int thr_doubleclick, const OutputType output_type, const char* geometry)
+  : CalibratorEvdev(device_name0, axys0, thr_misclick, thr_doubleclick, output_type, geometry)
+{
+    //printf("Starting test driver\n");
+}
+
+bool CalibratorEvdevTester::finish_data(const XYinfo axis)
+{
+    new_axis = axis;
+
+    return true;
+}
+
+XYinfo CalibratorEvdevTester::emulate_driver(const XYinfo& raw, bool useNewAxis, const XYinfo& screen, const XYinfo& device) {
+    XYinfo calibAxis;
+    if (useNewAxis)
+        calibAxis = new_axis;
+    else
+        calibAxis = old_axys;
+
+    // call evdev's code (minimally modified to fit us)
+    int mins[2] = {raw.x.min, raw.y.min};
+    evdev_270_processvaluator(device, calibAxis, mins);
+    int maxs[2] = {raw.x.max, raw.y.max};
+    evdev_270_processvaluator(device, calibAxis, maxs);
+
+    XYinfo result(mins[0], maxs[0], mins[1], maxs[1]);
+
+
+    // the last step is usually done by the X server,
+    // or transparently somewhere on the way
+    result.do_xf86ScaleAxis(screen, device);
+    return result;
+}
+
+// return in 'vals'
+void CalibratorEvdevTester::evdev_270_processvaluator(const XYinfo& devAxis, const XYinfo& axis, int* vals)
+{
+        //int vals[2] = {valX, valY};
+        int absinfo_min[2] = {devAxis.x.min, devAxis.y.min};
+        int absinfo_max[2] = {devAxis.x.max, devAxis.y.max};
+
+        /*
+         * Code from xf86-input-evdev: src/evdev.c
+         * function: static void EvdevProcessValuators(InputInfoPtr pInfo)
+         * last change: 2011-12-14 'Fix absolute events with swapped axes'
+         * last change id: 8d6dfd13b0c4177305555294218e366a6cddc83f
+         *
+         * All valuator_mask_isset() test can be skipped here:
+         * its a requirement to have both X and Y coordinates
+         */
+        int i;
+
+        // if (pEvdev->swap_axes) {
+        if (axis.swap_xy) {
+            int swapped_isset[2] = {0, 0};
+            int swapped_values[2];
+
+            for(i = 0; i <= 1; i++) {
+                //if (valuator_mask_isset(pEvdev->vals, i)) {
+                    swapped_isset[1 - i] = 1;
+
+                    /* in all sensible cases, the absinfo is the same for the
+                     * X and Y axis. In that case, the below simplifies to:
+                     * wapped_values[1 - i] = vals[i]
+                     * However, the code below accounts for the oddball
+                     * device for which this would not be the case.
+                     */
+                    swapped_values[1 - i] =
+                        //xf86ScaleAxis(valuator_mask_get(pEvdev->vals, i),
+                        //              pEvdev->absinfo[1 - i].maximum,
+                        //              pEvdev->absinfo[1 - i].minimum,
+                        //              pEvdev->absinfo[i].maximum,
+                        //              pEvdev->absinfo[i].minimum);
+                        xf86ScaleAxis(vals[i],
+                                      absinfo_max[1 - i],
+                                      absinfo_min[1 - i],
+                                      absinfo_max[i],
+                                      absinfo_min[i]);
+                //}
+            }
+
+            for (i = 0; i <= 1; i++) {
+                if (swapped_isset[i])
+                    //valuator_mask_set(pEvdev->vals, i, swapped_values[i]);
+                    vals[i] = swapped_values[i];
+                //else
+                //    valuator_mask_unset(pEvdev->vals, i);
+            }
+        }
+
+        for (i = 0; i <= 1; i++) {
+            int val;
+            int calib_min;
+            int calib_max;
+
+            //if (!valuator_mask_isset(pEvdev->vals, i))
+            //    continue;
+
+            //val = valuator_mask_get(pEvdev->vals, i);
+            val = vals[i];
+
+            if (i == 0) {
+                //calib_min = pEvdev->calibration.min_x;
+                calib_min = axis.x.min;
+                //calib_max = pEvdev->calibration.max_x;
+                calib_max = axis.x.max;
+            } else {
+                //calib_min = pEvdev->calibration.min_y;
+                calib_min = axis.y.min;
+                //calib_max = pEvdev->calibration.max_y;
+                calib_max = axis.y.max;
+            }
+
+            //if (pEvdev->flags & EVDEV_CALIBRATED)
+            if (true)
+                //val = xf86ScaleAxis(val, pEvdev->absinfo[i].maximum,
+                //                    pEvdev->absinfo[i].minimum, calib_max,
+                //                    calib_min);
+                val = xf86ScaleAxis(val, absinfo_max[i],
+                                    absinfo_min[i], calib_max,
+                                    calib_min);
+
+            //if ((i == 0 && pEvdev->invert_x) || (i == 1 && pEvdev->invert_y))
+            if ((i == 0 && axis.x.invert) || (i == 1 && axis.y.invert))
+                //val = (pEvdev->absinfo[i].maximum - val +
+                //       pEvdev->absinfo[i].minimum);
+                val = (absinfo_max[i] - val +
+                       absinfo_min[i]);
+
+            //valuator_mask_set(pEvdev->vals, i, val);
+            vals[i] = val;
+        }
+
+        //return vals;
+}
diff --git a/src/calibrator/EvdevTester.hpp b/src/calibrator/EvdevTester.hpp
new file mode 100644 (file)
index 0000000..e75f282
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2009 Tias Guns
+ *
+ * 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.
+ */
+
+#ifndef CALIBRATOR_EVDEV_TESTER_HPP
+#define CALIBRATOR_EVDEV_TESTER_HPP
+
+#include "calibrator.hh"
+#include "calibrator/Evdev.hpp"
+
+/***************************************
+ * Class for testing the evdev
+ * calibration routine
+ ***************************************/
+class CalibratorEvdevTester: public CalibratorTesterInterface, public CalibratorEvdev
+{
+protected:
+    // store the new axis for use in driver emulation
+    XYinfo new_axis;
+
+public:
+    CalibratorEvdevTester(const char* const device_name, const XYinfo& axys,
+        const int thr_misclick=0, const int thr_doubleclick=0,
+        const OutputType output_type=OUTYPE_AUTO, const char* geometry=0);
+
+    virtual bool finish_data(const XYinfo new_axis);
+
+    // emulate the driver processing the coordinates in 'raw'
+    virtual XYinfo emulate_driver(const XYinfo& raw, bool useNewAxis, const XYinfo& screen, const XYinfo& device);
+
+    virtual void new_axis_print() {
+        new_axis.print();
+    }
+
+    //* From CalibratorEvdev
+    virtual bool add_click(int x, int y) {
+        return CalibratorEvdev::add_click(x, y);
+    }
+    virtual bool finish(int width, int height) {
+        return CalibratorEvdev::finish(width, height);
+    }
+    
+    // evdev 2.7.0 EvdevProcessValuators code, modified to fit us
+    void evdev_270_processvaluator(const XYinfo& devAxis, const XYinfo& axis, int* vals);
+};
+
+#endif
diff --git a/src/calibrator/Makefile.am b/src/calibrator/Makefile.am
new file mode 100644 (file)
index 0000000..ac62ea6
--- /dev/null
@@ -0,0 +1,6 @@
+EXTRA_DIST = \
+       Evdev.cpp \
+       Usbtouchscreen.cpp \
+       XorgPrint.cpp \
+       Tester.cpp \
+       EvdevTester.cpp
diff --git a/src/calibrator/Tester.cpp b/src/calibrator/Tester.cpp
new file mode 100644 (file)
index 0000000..4b1d9cd
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2009 Tias Guns
+ *
+ * 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 "calibrator/Tester.hpp"
+
+#include <cstdio>
+
+CalibratorTester::CalibratorTester(const char* const device_name0, const XYinfo& axys0, const int thr_misclick, const int thr_doubleclick, const OutputType output_type, const char* geometry)
+  : Calibrator(device_name0, axys0, thr_misclick, thr_doubleclick, output_type, geometry)
+{
+    //printf("Starting test driver\n");
+}
+
+bool CalibratorTester::finish_data(const XYinfo axis)
+{
+    new_axis = axis;
+
+    return true;
+}
+
+XYinfo CalibratorTester::emulate_driver(const XYinfo& raw, bool useNewAxis, const XYinfo& screen, const XYinfo& device) {
+    XYinfo calibAxis;
+    if (useNewAxis)
+        calibAxis = new_axis;
+    else
+        calibAxis = old_axys;
+
+    /**
+     * The most simple and intuitive calibration implementation
+     * if only all drivers sticked to this...
+     * Note that axis inversion is automatically supported
+     * by the ScaleAxis implementation (swapping max/min on
+     * one axis will result in the inversion being calculated)
+     */
+
+    // placeholder for the new coordinates
+    XYinfo result(raw);
+
+    // swap coordinates if asked
+    if (calibAxis.swap_xy) {
+        result.x.min = raw.y.min;
+        result.x.max = raw.y.max;
+        result.y.min = raw.x.min;
+        result.y.max = raw.x.max;
+    }
+
+    result.do_xf86ScaleAxis(device, calibAxis);
+
+    // the last step is usually done by the X server,
+    // or transparently somewhere on the way
+    result.do_xf86ScaleAxis(screen, device);
+    return result;
+}
diff --git a/src/calibrator/Tester.hpp b/src/calibrator/Tester.hpp
new file mode 100644 (file)
index 0000000..2bcad34
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2009 Tias Guns
+ *
+ * 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.
+ */
+
+#ifndef CALIBRATOR_TESTER_HPP
+#define CALIBRATOR_TESTER_HPP
+
+#include "calibrator.hh"
+
+/***************************************
+ * Class for testing the generic
+ * calibration routine
+ ***************************************/
+class CalibratorTester: public CalibratorTesterInterface, public Calibrator
+{
+protected:
+    // store the new axis for use in driver emulation
+    XYinfo new_axis;
+
+public:
+    CalibratorTester(const char* const device_name, const XYinfo& axys,
+        const int thr_misclick=0, const int thr_doubleclick=0,
+        const OutputType output_type=OUTYPE_AUTO, const char* geometry=0);
+
+    virtual bool finish_data(const XYinfo new_axis);
+
+    // emulate the driver processing the coordinates in 'raw'
+    virtual XYinfo emulate_driver(const XYinfo& raw,
+                                  bool useNewAxis,
+                                  const XYinfo& screen,
+                                  const XYinfo& device);
+
+    virtual void new_axis_print() {
+        new_axis.print();
+    }
+
+    //* From Calibrator
+    virtual bool add_click(int x, int y) {
+        return Calibrator::add_click(x, y);
+    }
+    virtual bool finish(int width, int height) {
+        return Calibrator::finish(width, height);
+    }
+};
+
+#endif
diff --git a/src/calibrator/Usbtouchscreen.cpp b/src/calibrator/Usbtouchscreen.cpp
new file mode 100644 (file)
index 0000000..f50b954
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * 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 "calibrator/Usbtouchscreen.hpp"
+
+#include <cstdlib>
+#include <cstdio>
+#include <cstring>
+
+/*************************
+ * Variables for usbtouchscreen specifically
+ *************************/
+// The file to which the calibration parameters are saved.
+// (XXX: is this distribution dependend?)
+static const char *modprobe_conf_local = "/etc/modprobe.conf.local";
+
+// Prefix to the kernel path where we can set the parameters
+static const char *module_prefix = "/sys/module/usbtouchscreen/parameters";
+
+// Names of kernel parameters
+static const char *p_range_x = "range_x";
+static const char *p_range_y = "range_y";
+static const char *p_min_x = "min_x";
+static const char *p_min_y = "min_y";
+static const char *p_max_x = "max_x";
+static const char *p_max_y = "max_y";
+static const char *p_transform_xy = "transform_xy";
+static const char *p_flip_x = "flip_x";
+static const char *p_flip_y = "flip_y";
+static const char *p_swap_xy = "swap_xy";
+
+CalibratorUsbtouchscreen::CalibratorUsbtouchscreen(const char* const device_name0, const XYinfo& axys0, const int thr_misclick, const int thr_doubleclick, const OutputType output_type, const char* geometry)
+  : Calibrator(device_name0, axys0, thr_misclick, thr_doubleclick, output_type, geometry)
+{
+    if (strcmp(device_name, "Usbtouchscreen") != 0)
+        throw WrongCalibratorException("Not a usbtouchscreen device");
+
+    // Reset the currently running kernel
+    read_bool_parameter(p_transform_xy, val_transform_xy);
+    read_bool_parameter(p_flip_x, val_flip_x);
+    read_bool_parameter(p_flip_y, val_flip_y);
+    read_bool_parameter(p_swap_xy, val_swap_xy);
+
+    write_bool_parameter(p_transform_xy, false);
+    write_bool_parameter(p_flip_x, false);
+    write_bool_parameter(p_flip_y, false);
+    write_bool_parameter(p_swap_xy, false);
+
+    printf("Calibrating Usbtouchscreen, through the kernel module\n");
+}
+
+CalibratorUsbtouchscreen::~CalibratorUsbtouchscreen()
+{
+    // Dirty exit, so we restore the parameters of the running kernel
+    write_bool_parameter (p_transform_xy, val_transform_xy);
+    write_bool_parameter (p_flip_x, val_flip_x);
+    write_bool_parameter (p_flip_y, val_flip_y);
+    write_bool_parameter (p_swap_xy, val_swap_xy);
+}
+
+bool CalibratorUsbtouchscreen::finish_data(const XYinfo new_axys)
+{
+    if (output_type != OUTYPE_AUTO) {
+        fprintf(stderr, "ERROR: Usbtouchscreen Calibrator does not support the supplied --output-type\n");
+        return false;
+    }
+
+    // New ranges
+    const int range_x = (new_axys.x.max - new_axys.x.min);
+    const int range_y = (new_axys.y.max - new_axys.y.min);
+    // Should x and y be flipped ?
+    const bool flip_x = (new_axys.x.min > new_axys.x.max);
+    const bool flip_y = (new_axys.y.min > new_axys.y.max);
+
+    // Send the estimated parameters to the currently running kernel
+    write_int_parameter(p_range_x, range_x);
+    write_int_parameter(p_range_y, range_y);
+    write_int_parameter(p_min_x, new_axys.x.min);
+    write_int_parameter(p_max_x, new_axys.x.max);
+    write_int_parameter(p_min_y, new_axys.y.min);
+    write_int_parameter(p_max_y, new_axys.y.max);
+    write_bool_parameter(p_transform_xy, true);
+    write_bool_parameter(p_flip_x, flip_x);
+    write_bool_parameter(p_flip_y, flip_y);
+    write_bool_parameter(p_swap_xy, new_axys.swap_xy);
+
+    // Read, then write calibration parameters to modprobe_conf_local,
+    // to keep the for the next boot
+    FILE *fid = fopen(modprobe_conf_local, "r");
+    if (fid == NULL) {
+        fprintf(stderr, "Error: Can't open '%s' for reading. Make sure you have the necessary rights\n", modprobe_conf_local);
+        fprintf(stderr, "New calibration data NOT saved\n");
+        return false;
+    }
+
+    std::string new_contents;
+    const int len = 1024; // XXX: we currently don't handle lines that are longer than this
+    char line[len];
+    const char *opt = "options usbtouchscreen";
+    const int opt_len = strlen(opt);
+    while (fgets(line, len, fid)) {
+        if (strncmp(line, opt, opt_len) == 0) {
+            // This is the line we want to remove
+            continue;
+        }
+        new_contents += line;
+    }
+    fclose(fid);
+
+    char *new_opt = new char[opt_len];
+    sprintf(new_opt, "%s %s=%d %s=%d %s=%d %s=%d %s=%d %s=%d %s=%c %s=%c %s=%c %s=%c\n",
+         opt, p_range_x, range_x, p_range_y, range_y,
+         p_min_x, new_axys.x.min, p_min_y, new_axys.y.min,
+         p_max_x, new_axys.x.max, p_max_y, new_axys.y.max,
+         p_transform_xy, yesno(true), p_flip_x, yesno(flip_x),
+         p_flip_y, yesno(flip_y), p_swap_xy, yesno(new_axys.swap_xy));
+    new_contents += new_opt;
+
+    fid = fopen(modprobe_conf_local, "w");
+    if (fid == NULL) {
+        fprintf(stderr, "Error: Can't open '%s' for writing. Make sure you have the necessary rights\n", modprobe_conf_local);
+        fprintf(stderr, "New calibration data NOT saved\n");
+        return false;
+    }
+    fprintf(fid, "%s", new_contents.c_str ());
+    fclose(fid);
+
+    return true;
+}
+
+void CalibratorUsbtouchscreen::read_int_parameter(const char *param, int &value)
+{
+    int dummy;
+    char filename[100];
+    sprintf(filename, "%s/%s", module_prefix, param);
+    FILE *fid = fopen(filename, "r");
+    if (fid == NULL) {
+        fprintf(stderr, "Could not read parameter '%s'\n", param);
+        return;
+    }
+
+    dummy = fscanf(fid, "%d", &value);
+    fclose(fid);
+}
+
+void CalibratorUsbtouchscreen::read_bool_parameter(const char *param, bool &value)
+{
+    char *dummy;
+    char filename[100];
+    sprintf(filename, "%s/%s", module_prefix, param);
+    FILE *fid = fopen(filename, "r");
+    if (fid == NULL) {
+        fprintf(stderr, "Could not read parameter '%s'\n", param);
+        return;
+    }
+
+    char val[3];
+    dummy = fgets(val, 2, fid);
+    fclose(fid);
+        value = (val[0] == yesno(true));
+}
+
+void CalibratorUsbtouchscreen::write_int_parameter(const char *param, const int value)
+{
+    char filename[100];
+    sprintf(filename, "%s/%s", module_prefix, param);
+    FILE *fid = fopen(filename, "w");
+    if (fid == NULL) {
+        fprintf(stderr, "Could not save parameter '%s'\n", param);
+        return;
+    }
+
+    fprintf(fid, "%d", value);
+    fclose(fid);
+}
+
+void CalibratorUsbtouchscreen::write_bool_parameter(const char *param, const bool value)
+{
+    char filename[100];
+    sprintf(filename, "%s/%s", module_prefix, param);
+    FILE *fid = fopen(filename, "w");
+    if (fid == NULL) {
+        fprintf(stderr, "Could not save parameter '%s'\n", param);
+        return;
+    }
+
+    fprintf(fid, "%c", yesno (value));
+    fclose(fid);
+}
diff --git a/src/calibrator/Usbtouchscreen.hpp b/src/calibrator/Usbtouchscreen.hpp
new file mode 100644 (file)
index 0000000..95a13ce
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+#ifndef CALIBRATOR_USBTOUCHSCREEN_HPP
+#define CALIBRATOR_USBTOUCHSCREEN_HPP
+
+#include "calibrator.hh"
+
+/**********************************
+ * Class for usbtouchscreen driver,
+ * writes output parameters to running kernel and to modprobe.conf
+ **********************************/
+class CalibratorUsbtouchscreen: public Calibrator
+{
+public:
+    CalibratorUsbtouchscreen(const char* const device_name, const XYinfo& axys,
+         const int thr_misclick=0, const int thr_doubleclick=0,
+        const OutputType output_type=OUTYPE_AUTO, const char* geometry=0);
+    ~CalibratorUsbtouchscreen();
+
+    virtual bool finish_data(const XYinfo new_axys);
+
+protected:
+    // Globals for kernel parameters from startup.
+    // We revert to these if the program aborts
+    bool val_transform_xy, val_flip_x, val_flip_y, val_swap_xy;
+
+    // Helper functions
+    char yesno(const bool value)
+    {
+        if (value)
+            return 'Y';
+        else
+            return 'N';
+    }
+
+    void read_int_parameter(const char *param, int &value);
+
+    void read_bool_parameter(const char *param, bool &value);
+
+    void write_int_parameter(const char *param, const int value);
+
+    void write_bool_parameter(const char *param, const bool value);
+};
+
+#endif
diff --git a/src/calibrator/XorgPrint.cpp b/src/calibrator/XorgPrint.cpp
new file mode 100644 (file)
index 0000000..49decff
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2009 Tias Guns
+ *
+ * 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 "calibrator/XorgPrint.hpp"
+
+#include <cstdio>
+
+CalibratorXorgPrint::CalibratorXorgPrint(const char* const device_name0, const XYinfo& axys0, const int thr_misclick, const int thr_doubleclick, const OutputType output_type, const char* geometry)
+  : Calibrator(device_name0, axys0, thr_misclick, thr_doubleclick, output_type, geometry)
+{
+    printf("Calibrating standard Xorg driver \"%s\"\n", device_name);
+    printf("\tcurrent calibration values: min_x=%d, max_x=%d and min_y=%d, max_y=%d\n",
+                old_axys.x.min, old_axys.x.max, old_axys.y.min, old_axys.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");
+}
+
+bool CalibratorXorgPrint::finish_data(const XYinfo new_axys)
+{
+    bool success = true;
+
+
+    printf("\t--> Making the calibration permanent <--\n");
+    switch (output_type) {
+        case OUTYPE_AUTO:
+            // xorg.conf.d or alternatively hal config
+            if (has_xorgconfd_support()) {
+                success &= output_xorgconfd(new_axys);
+            } else {
+                success &= output_hal(new_axys);
+            }
+            break;
+        case OUTYPE_XORGCONFD:
+            success &= output_xorgconfd(new_axys);
+            break;
+        case OUTYPE_HAL:
+            success &= output_hal(new_axys);
+            break;
+        default:
+            fprintf(stderr, "ERROR: XorgPrint Calibrator does not support the supplied --output-type\n");
+            success = false;
+    }
+
+    return success;
+}
+
+bool CalibratorXorgPrint::output_xorgconfd(const XYinfo new_axys)
+{
+    const char* sysfs_name = get_sysfs_name();
+    bool not_sysfs_name = (sysfs_name == NULL);
+    if (not_sysfs_name)
+        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\"        \"%d\"\n", new_axys.x.min);
+    printf("   Option  \"MaxX\"        \"%d\"\n", new_axys.x.max);
+    printf("   Option  \"MinY\"        \"%d\"\n", new_axys.y.min);
+    printf("   Option  \"MaxY\"        \"%d\"\n", new_axys.y.max);
+    printf("   Option  \"SwapXY\"      \"%d\" # unless it was already set to 1\n", new_axys.swap_xy);
+    printf("   Option  \"InvertX\"     \"%d\"  # unless it was already set\n", new_axys.x.invert);
+    printf("   Option  \"InvertY\"     \"%d\"  # unless it was already set\n", new_axys.y.invert);
+    printf("EndSection\n");
+
+    if (not_sysfs_name)
+        printf("\nChange '%s' to your device's name in the config above.\n", sysfs_name);
+
+    return true;
+}
+
+bool CalibratorXorgPrint::output_hal(const XYinfo new_axys)
+{
+    const char* sysfs_name = get_sysfs_name();
+    bool not_sysfs_name = (sysfs_name == NULL);
+    if (not_sysfs_name)
+        sysfs_name = "!!Name_Of_TouchScreen!!";
+
+    // HAL policy output
+    printf("  copy the policy below into '/etc/hal/fdi/policy/touchscreen.fdi'\n\
+<match key=\"info.product\" contains=\"%s\">\n\
+  <merge key=\"input.x11_options.minx\" type=\"string\">%d</merge>\n\
+  <merge key=\"input.x11_options.maxx\" type=\"string\">%d</merge>\n\
+  <merge key=\"input.x11_options.miny\" type=\"string\">%d</merge>\n\
+  <merge key=\"input.x11_options.maxy\" type=\"string\">%d</merge>\n"
+     , sysfs_name, new_axys.x.min, new_axys.x.max, new_axys.y.min, new_axys.y.max);
+    printf("  <merge key=\"input.x11_options.swapxy\" type=\"string\">%d</merge>\n", new_axys.swap_xy);
+    printf("  <merge key=\"input.x11_options.invertx\" type=\"string\">%d</merge>\n", new_axys.x.invert);
+    printf("  <merge key=\"input.x11_options.inverty\" type=\"string\">%d</merge>\n", new_axys.y.invert);
+    printf("</match>\n");
+
+    if (not_sysfs_name)
+        printf("\nChange '%s' to your device's name in the config above.\n", sysfs_name);
+
+    return true;
+}
diff --git a/src/calibrator/XorgPrint.hpp b/src/calibrator/XorgPrint.hpp
new file mode 100644 (file)
index 0000000..6d9975c
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2009 Tias Guns
+ *
+ * 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.
+ */
+
+#ifndef CALIBRATOR_XORGPRINT_HPP
+#define CALIBRATOR_XORGPRINT_HPP
+
+#include "calibrator.hh"
+
+/***************************************
+ * Class for generic Xorg driver,
+ * outputs new Xorg.conf and FDI policy, on stdout
+ ***************************************/
+class CalibratorXorgPrint: public Calibrator
+{
+public:
+    CalibratorXorgPrint(const char* const device_name, const XYinfo& axys,
+        const int thr_misclick=0, const int thr_doubleclick=0,
+        const OutputType output_type=OUTYPE_AUTO, const char* geometry=0);
+
+    virtual bool finish_data(const XYinfo new_axys);
+
+protected:
+    bool output_xorgconfd(const XYinfo new_axys);
+    bool output_hal(const XYinfo new_axys);
+};
+
+#endif
diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am
new file mode 100644 (file)
index 0000000..ddc3812
--- /dev/null
@@ -0,0 +1,3 @@
+EXTRA_DIST = \
+       gtkmm.cpp \
+       x11.cpp
diff --git a/src/gui/gtkmm.cpp b/src/gui/gtkmm.cpp
new file mode 100644 (file)
index 0000000..5d2142c
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * 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 "gui/gtkmm.hpp"
+
+// Timeout parameters
+const int time_step = 100;  // in milliseconds
+const int max_time = 15000; // 5000 = 5 sec
+
+// Clock appereance
+const int cross_lines = 25;
+const int cross_circle = 4;
+const int clock_radius = 50;
+const int clock_line_width = 10;
+
+// Text printed on screen
+const int font_size = 16;
+const int help_lines = 4;
+const std::string help_text[help_lines] = {
+    "Touchscreen Calibration",
+    "Press the point, use a stylus to increase precision.",
+    "",
+    "(To abort, press any key or wait)"
+};
+
+CalibrationArea::CalibrationArea(Calibrator* calibrator0)
+  : calibrator(calibrator0), time_elapsed(0), message(NULL)
+{
+    // Listen for mouse events
+    add_events(Gdk::KEY_PRESS_MASK | Gdk::BUTTON_PRESS_MASK);
+    set_flags(Gtk::CAN_FOCUS);
+
+    // parse geometry string
+    const char* geo = calibrator->get_geometry();
+    if (geo != NULL) {
+        int gw,gh;
+        int res = sscanf(geo,"%dx%d",&gw,&gh);
+        if (res != 2) {
+            fprintf(stderr,"Warning: error parsing geometry string - using defaults.\n");
+            geo = NULL;
+        } else {
+            set_display_size( gw, gh );
+        }
+    }
+    if (geo == NULL)
+        set_display_size(get_width(), get_height());
+
+    // Setup timer for animation
+    sigc::slot<bool> slot = sigc::mem_fun(*this, &CalibrationArea::on_timer_signal);
+    Glib::signal_timeout().connect(slot, time_step);
+}
+
+void CalibrationArea::set_display_size(int width, int height) {
+    display_width = width;
+    display_height = height;
+
+    // Compute absolute circle centers
+    const int delta_x = display_width/num_blocks;
+    const int delta_y = display_height/num_blocks;
+    X[UL] = delta_x;                     Y[UL] = delta_y;
+    X[UR] = display_width - delta_x - 1; Y[UR] = delta_y;
+    X[LL] = delta_x;                     Y[LL] = display_height - delta_y - 1;
+    X[LR] = display_width - delta_x - 1; Y[LR] = display_height - delta_y - 1;
+
+    // reset calibration if already started
+    calibrator->reset();
+}
+
+bool CalibrationArea::on_expose_event(GdkEventExpose *event)
+{
+    // check that screensize did not change (if no manually specified geometry)
+    if (calibrator->get_geometry() == NULL &&
+         (display_width != get_width() ||
+         display_height != get_height()) ) {
+        set_display_size(get_width(), get_height());
+    }
+
+    Glib::RefPtr<Gdk::Window> window = get_window();
+    if (window) {
+        Cairo::RefPtr<Cairo::Context> cr = window->create_cairo_context();
+        cr->save();
+
+        cr->rectangle(event->area.x, event->area.y, event->area.width, event->area.height);
+        cr->clip();
+
+        // Print the text
+        cr->set_font_size(font_size);
+        double text_height = -1;
+        double text_width = -1;
+        Cairo::TextExtents extent;
+        for (int i = 0; i != help_lines; i++) {
+            cr->get_text_extents(help_text[i], extent);
+            text_width = std::max(text_width, extent.width);
+            text_height = std::max(text_height, extent.height);
+        }
+        text_height += 2;
+
+        double x = (display_width - text_width) / 2;
+        double y = (display_height - text_height) / 2 - 60;
+        cr->set_line_width(2);
+        cr->rectangle(x - 10, y - (help_lines*text_height) - 10,
+                text_width + 20, (help_lines*text_height) + 20);
+
+        // Print help lines
+        y -= 3;
+        for (int i = help_lines-1; i != -1; i--) {
+            cr->get_text_extents(help_text[i], extent);
+            cr->move_to(x + (text_width-extent.width)/2, y);
+            cr->show_text(help_text[i]);
+            y -= text_height;
+        }
+        cr->stroke();
+
+        // Draw the points
+        for (int i = 0; i <= calibrator->get_numclicks(); i++) {
+            // set color: already clicked or not
+            if (i < calibrator->get_numclicks())
+                cr->set_source_rgb(1.0, 1.0, 1.0);
+            else
+                cr->set_source_rgb(0.8, 0.0, 0.0);
+
+            cr->set_line_width(1);
+            cr->move_to(X[i] - cross_lines, Y[i]);
+            cr->rel_line_to(cross_lines*2, 0);
+            cr->move_to(X[i], Y[i] - cross_lines);
+            cr->rel_line_to(0, cross_lines*2);
+            cr->stroke();
+
+            cr->arc(X[i], Y[i], cross_circle, 0.0, 2.0 * M_PI);
+            cr->stroke();
+        }
+
+        // Draw the clock background
+        cr->arc(display_width/2, display_height/2, clock_radius/2, 0.0, 2.0 * M_PI);
+        cr->set_source_rgb(0.5, 0.5, 0.5);
+        cr->fill_preserve();
+        cr->stroke();
+
+        cr->set_line_width(clock_line_width);
+        cr->arc(display_width/2, display_height/2, (clock_radius - clock_line_width)/2,
+             3/2.0*M_PI, (3/2.0*M_PI) + ((double)time_elapsed/(double)max_time) * 2*M_PI);
+        cr->set_source_rgb(0.0, 0.0, 0.0);
+        cr->stroke();
+
+
+        // Draw the message (if any)
+        if (message != NULL) {
+            // Frame the message
+            cr->set_font_size(font_size);
+            Cairo::TextExtents extent;
+            cr->get_text_extents(this->message, extent);
+            text_width = extent.width;
+            text_height = extent.height;
+
+            x = (display_width - text_width) / 2;
+            y = (display_height - text_height + clock_radius) / 2 + 60;
+            cr->set_line_width(2);
+            cr->rectangle(x - 10, y - text_height - 10,
+                    text_width + 20, text_height + 25);
+
+            // Print the message
+            cr->move_to(x, y);
+            cr->show_text(this->message);
+            cr->stroke();
+        }
+
+        cr->restore();
+    }
+
+    return true;
+}
+
+void CalibrationArea::redraw()
+{
+    Glib::RefPtr<Gdk::Window> win = get_window();
+    if (win) {
+        const Gdk::Rectangle rect(0, 0, display_width, display_height);
+        win->invalidate_rect(rect, false);
+    }
+}
+
+bool CalibrationArea::on_timer_signal()
+{
+    time_elapsed += time_step;
+    if (time_elapsed > max_time) {
+        exit(0);
+    }
+
+    // Update clock
+    Glib::RefPtr<Gdk::Window> win = get_window();
+    if (win) {
+        const Gdk::Rectangle rect(display_width/2 - clock_radius - clock_line_width,
+                                 display_height/2 - clock_radius - clock_line_width,
+                                 2 * clock_radius + 1 + 2 * clock_line_width,
+                                 2 * clock_radius + 1 + 2 * clock_line_width);
+        win->invalidate_rect(rect, false);
+    }
+
+    return true;
+}
+
+bool CalibrationArea::on_button_press_event(GdkEventButton *event)
+{
+    // Handle click
+    time_elapsed = 0;
+    bool success = calibrator->add_click((int)event->x_root, (int)event->y_root);
+
+    if (!success && calibrator->get_numclicks() == 0) {
+        draw_message("Mis-click detected, restarting...");
+    } else {
+        draw_message(NULL);
+    }
+
+    // Are we done yet?
+    if (calibrator->get_numclicks() >= 4) {
+        // Recalibrate
+        success = calibrator->finish(display_width, display_height);
+
+        if (success) {
+            exit(0);
+        } else {
+            // TODO, in GUI ?
+            fprintf(stderr, "Error: unable to apply or save configuration values");
+            exit(1);
+        }
+    }
+
+    // Force a redraw
+    redraw();
+
+    return true;
+}
+
+void CalibrationArea::draw_message(const char* msg)
+{
+    this->message = msg;
+}
+
+bool CalibrationArea::on_key_press_event(GdkEventKey *event)
+{
+    (void) event;
+    exit(0);
+}
diff --git a/src/gui/gtkmm.hpp b/src/gui/gtkmm.hpp
new file mode 100644 (file)
index 0000000..1548a35
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#ifndef GUI_GTKMM_HPP
+#define GUI_GTKMM_HPP
+
+#include <gtkmm/drawingarea.h>
+#include "calibrator.hh"
+
+/*******************************************
+ * GTK-mm class for the the calibration GUI
+ *******************************************/
+class CalibrationArea : public Gtk::DrawingArea
+{
+public:
+    CalibrationArea(Calibrator* w);
+
+protected:
+    // Data
+    Calibrator* calibrator;
+    double X[4], Y[4];
+    int display_width, display_height;
+    int time_elapsed;
+
+    const char* message;
+
+    // Signal handlers
+    bool on_timer_signal();
+    bool on_expose_event(GdkEventExpose *event);
+    bool on_button_press_event(GdkEventButton *event);
+    bool on_key_press_event(GdkEventKey *event);
+
+    // Helper functions
+    void set_display_size(int width, int height);
+    void redraw();
+    void draw_message(const char* msg);
+};
+
+#endif
diff --git a/src/gui/x11.cpp b/src/gui/x11.cpp
new file mode 100644 (file)
index 0000000..67424ec
--- /dev/null
@@ -0,0 +1,377 @@
+/*
+ * Copyright (c) 2009 Tias Guns
+ *
+ * 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 "gui/x11.hpp"
+
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xos.h> // strncpy, strlen
+
+#ifdef HAVE_X11_XRANDR
+// support for multi-head setups
+#include <X11/extensions/Xrandr.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+#include <string.h>
+
+
+// Timeout parameters
+const int time_step = 100;  // in milliseconds
+const int max_time = 15000; // in milliseconds, 5000 = 5 sec
+
+// Clock appereance
+const int cross_lines = 25;
+const int cross_circle = 4;
+const int clock_radius = 50;
+const int clock_line_width = 10;
+
+// Text printed on screen
+const int font_size = 16;
+const int help_lines = 4;
+const std::string help_text[help_lines] = {
+    "Touchscreen Calibration",
+    "Press the point, use a stylus to increase precision.",
+    "",
+    "(To abort, press any key or wait)"
+};
+
+const char* GuiCalibratorX11::colors[GuiCalibratorX11::NUM_COLORS] = {"BLACK", "WHITE", "GRAY", "DIMGRAY", "RED"};
+
+void sigalarm_handler(int num);
+
+/// Create singleton instance associated to calibrator w
+void GuiCalibratorX11::make_instance(Calibrator* w)
+{
+    instance = new GuiCalibratorX11(w);
+}
+
+// Singleton instance
+GuiCalibratorX11* GuiCalibratorX11::instance = NULL;
+
+GuiCalibratorX11::GuiCalibratorX11(Calibrator* calibrator0)
+  : calibrator(calibrator0), time_elapsed(0)
+{
+    display = XOpenDisplay(NULL);
+    if (display == NULL) {
+        throw std::runtime_error("Unable to connect to X server");
+    }
+    screen_num = DefaultScreen(display);
+    // Load font and get font information structure
+    font_info = XLoadQueryFont(display, "9x15");
+    if (font_info == NULL) {
+        // fall back to native font
+        font_info = XLoadQueryFont(display, "fixed");
+        if (font_info == NULL) {
+            XCloseDisplay(display);
+            throw std::runtime_error("Unable to open neither '9x15' nor 'fixed' font");
+        }
+    }
+
+#ifdef HAVE_X11_XRANDR
+    // get screensize from xrandr
+    int nsizes;
+    XRRScreenSize* randrsize = XRRSizes(display, screen_num, &nsizes);
+    if (nsizes != 0) {
+        Rotation current = 0;
+        XRRRotations(display, screen_num, &current);
+        bool rot = current & RR_Rotate_90 || current & RR_Rotate_270;
+        int width = rot ? randrsize->height : randrsize->width;
+        int height = rot ? randrsize->width : randrsize->height;
+        set_display_size(width, height);
+    } else {
+        set_display_size(DisplayWidth(display, screen_num),
+                         DisplayHeight(display, screen_num));
+    }
+# else
+    set_display_size(DisplayWidth(display, screen_num),
+                     DisplayHeight(display, screen_num));
+#endif
+
+    // parse geometry string
+    const char* geo = calibrator->get_geometry();
+    if (geo != NULL) {
+        int gw,gh;
+        int res = sscanf(geo,"%dx%d",&gw,&gh);
+        if (res != 2) {
+            fprintf(stderr,"Warning: error parsing geometry string - using defaults.\n");
+        } else {
+            set_display_size( gw, gh );
+        }
+    }
+
+    // Register events on the window
+    XSetWindowAttributes attributes;
+    attributes.override_redirect = True;
+    attributes.event_mask = ExposureMask | KeyPressMask | ButtonPressMask;
+
+    win = XCreateWindow(display, RootWindow(display, screen_num),
+                0, 0, display_width, display_height, 0,
+                CopyFromParent, InputOutput, CopyFromParent,
+                CWOverrideRedirect | CWEventMask,
+                &attributes);
+    XMapWindow(display, win);
+
+    // Listen to events
+    XGrabKeyboard(display, win, False, GrabModeAsync, GrabModeAsync,
+                CurrentTime);
+    XGrabPointer(display, win, False, ButtonPressMask, GrabModeAsync,
+                GrabModeAsync, None, None, CurrentTime);
+
+    Colormap colormap = DefaultColormap(display, screen_num);
+    XColor color;
+    for (int i = 0; i != NUM_COLORS; i++) {
+        XParseColor(display, colormap, colors[i], &color);
+        XAllocColor(display, colormap, &color);
+        pixel[i] = color.pixel;
+    }
+    XSetWindowBackground(display, win, pixel[GRAY]);
+    XClearWindow(display, win);
+
+    gc = XCreateGC(display, win, 0, NULL);
+    XSetFont(display, gc, font_info->fid);
+
+    // Setup timer for animation
+    signal(SIGALRM, sigalarm_handler);
+    struct itimerval timer;
+    timer.it_value.tv_sec = time_step/1000;
+    timer.it_value.tv_usec = (time_step % 1000) * 1000;
+    timer.it_interval = timer.it_value;
+    setitimer(ITIMER_REAL, &timer, NULL);
+}
+
+GuiCalibratorX11::~GuiCalibratorX11()
+{
+    XUngrabPointer(display, CurrentTime);
+    XUngrabKeyboard(display, CurrentTime);
+    XFreeGC(display, gc);
+    XCloseDisplay(display);
+}
+
+void GuiCalibratorX11::set_display_size(int width, int height) {
+    display_width = width;
+    display_height = height;
+
+    // Compute absolute circle centers
+    const int delta_x = display_width/num_blocks;
+    const int delta_y = display_height/num_blocks;
+    X[UL] = delta_x;                     Y[UL] = delta_y;
+    X[UR] = display_width - delta_x - 1; Y[UR] = delta_y;
+    X[LL] = delta_x;                     Y[LL] = display_height - delta_y - 1;
+    X[LR] = display_width - delta_x - 1; Y[LR] = display_height - delta_y - 1;
+
+    // reset calibration if already started
+    calibrator->reset();
+}
+
+void GuiCalibratorX11::redraw()
+{
+    if (calibrator->get_geometry() == NULL) {
+        int width;
+        int height;
+#ifdef HAVE_X11_XRANDR
+        // check that screensize did not change
+        int nsizes;
+        XRRScreenSize* randrsize = XRRSizes(display, screen_num, &nsizes);
+        if (nsizes != 0) {
+            Rotation current = 0;
+            XRRRotations(display, screen_num, &current);
+            bool rot = current & RR_Rotate_90 || current & RR_Rotate_270;
+            width = rot ? randrsize->height : randrsize->width;
+            height = rot ? randrsize->width : randrsize->height;
+        } else {
+            width = DisplayWidth(display, screen_num);
+            height = DisplayHeight(display, screen_num);
+        }
+#else
+        width = DisplayWidth(display, screen_num);
+        height = DisplayHeight(display, screen_num);
+#endif
+        if (display_width != width || display_height != height) {
+            set_display_size(width, height);
+        }
+    }
+
+    // Print the text
+    int text_height = font_info->ascent + font_info->descent;
+    int text_width = -1;
+    for (int i = 0; i != help_lines; i++) {
+        text_width = std::max(text_width, XTextWidth(font_info,
+            help_text[i].c_str(), help_text[i].length()));
+    }
+
+    int x = (display_width - text_width) / 2;
+    int y = (display_height - text_height) / 2 - 60;
+    XSetForeground(display, gc, pixel[BLACK]);
+    XSetLineAttributes(display, gc, 2, LineSolid, CapRound, JoinRound);
+    XDrawRectangle(display, win, gc, x - 10, y - (help_lines*text_height) - 10,
+                text_width + 20, (help_lines*text_height) + 20);
+
+    // Print help lines
+    y -= 3;
+    for (int i = help_lines-1; i != -1; i--) {
+        int w = XTextWidth(font_info, help_text[i].c_str(), help_text[i].length());
+        XDrawString(display, win, gc, x + (text_width-w)/2, y,
+                help_text[i].c_str(), help_text[i].length());
+        y -= text_height;
+    }
+
+    // Draw the points
+    for (int i = 0; i <= calibrator->get_numclicks(); i++) {
+        // set color: already clicked or not
+        if (i < calibrator->get_numclicks())
+            XSetForeground(display, gc, pixel[WHITE]);
+        else
+            XSetForeground(display, gc, pixel[RED]);
+        XSetLineAttributes(display, gc, 1, LineSolid, CapRound, JoinRound);
+
+        XDrawLine(display, win, gc, X[i] - cross_lines, Y[i],
+                X[i] + cross_lines, Y[i]);
+        XDrawLine(display, win, gc, X[i], Y[i] - cross_lines,
+                X[i], Y[i] + cross_lines);
+        XDrawArc(display, win, gc, X[i] - cross_circle, Y[i] - cross_circle,
+                (2 * cross_circle), (2 * cross_circle), 0, 360 * 64);
+    }
+
+    // Draw the clock background
+    XSetForeground(display, gc, pixel[DIMGRAY]);
+    XSetLineAttributes(display, gc, 0, LineSolid, CapRound, JoinRound);
+    XFillArc(display, win, gc, (display_width-clock_radius)/2, (display_height - clock_radius)/2,
+                clock_radius, clock_radius, 0, 360 * 64);
+}
+
+bool GuiCalibratorX11::on_expose_event()
+{
+    redraw();
+
+    return true;
+}
+
+bool GuiCalibratorX11::on_timer_signal()
+{
+    time_elapsed += time_step;
+    if (time_elapsed > max_time) {
+        exit(0);
+    }
+
+    // Update clock
+    XSetForeground(display, gc, pixel[BLACK]);
+    XSetLineAttributes(display, gc, clock_line_width,
+                LineSolid, CapButt, JoinMiter);
+    XDrawArc(display, win, gc, (display_width-clock_radius+clock_line_width)/2,
+                (display_height-clock_radius+clock_line_width)/2,
+                clock_radius-clock_line_width, clock_radius-clock_line_width,
+                90*64, ((double)time_elapsed/(double)max_time) * -360 * 64);
+
+    return true;
+}
+
+bool GuiCalibratorX11::on_button_press_event(XEvent event)
+{
+    // Clear window, maybe a bit overdone, but easiest for me atm.
+    // (goal is to clear possible message and other clicks)
+    XClearWindow(display, win);
+
+    // Handle click
+    time_elapsed = 0;
+    bool success = calibrator->add_click(event.xbutton.x, event.xbutton.y);
+
+    if (!success && calibrator->get_numclicks() == 0) {
+        draw_message("Mis-click detected, restarting...");
+    }
+
+    // Are we done yet?
+    if (calibrator->get_numclicks() >= 4) {
+        // Recalibrate
+        success = calibrator->finish(display_width, display_height);
+
+        if (success) {
+            exit(0);
+        } else {
+            // TODO, in GUI ?
+            fprintf(stderr, "Error: unable to apply or save configuration values");
+            exit(1);
+        }
+    }
+
+    // Force a redraw
+    redraw();
+
+    return true;
+}
+
+void GuiCalibratorX11::draw_message(const char* msg)
+{
+    int text_height = font_info->ascent + font_info->descent;
+    int text_width = XTextWidth(font_info, msg, strlen(msg));
+
+    int x = (display_width - text_width) / 2;
+    int y = (display_height - text_height) / 2 + clock_radius + 60;
+    XSetForeground(display, gc, pixel[BLACK]);
+    XSetLineAttributes(display, gc, 2, LineSolid, CapRound, JoinRound);
+    XDrawRectangle(display, win, gc, x - 10, y - text_height - 10,
+                text_width + 20, text_height + 25);
+
+    XDrawString(display, win, gc, x, y, msg, strlen(msg));
+}
+
+void GuiCalibratorX11::give_timer_signal()
+{
+    if (instance != NULL) {
+        // timer signal
+        //check timeout
+        instance->on_timer_signal();
+
+        // process events
+        XEvent event;
+        while (XCheckWindowEvent(instance->display, instance->win, -1, &event) == True) {
+            switch (event.type) {
+                case Expose:
+                    // only draw the last contiguous expose
+                    if (event.xexpose.count != 0)
+                        break;
+                    instance->on_expose_event();
+                    break;
+
+                case ButtonPress:
+                    instance->on_button_press_event(event);
+                    break;
+
+                case KeyPress:
+                    exit(0);
+                    break;
+            }
+        }
+    }
+}
+
+
+// handle SIGALRM signal, pass to singleton
+void sigalarm_handler(int num)
+{
+    if (num == SIGALRM) {
+        GuiCalibratorX11::give_timer_signal();
+    }
+}
diff --git a/src/gui/x11.hpp b/src/gui/x11.hpp
new file mode 100644 (file)
index 0000000..2bd4395
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2009 Tias Guns
+ *
+ * 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.
+ */
+
+#ifndef GUI_CALIBRATOR_X11
+#define GUI_CALIBRATOR_X11
+
+#include "calibrator.hh"
+
+/*******************************************
+ * X11 class for the the calibration GUI
+ *******************************************/
+class GuiCalibratorX11
+{
+public:
+    static void make_instance(Calibrator* w);
+    static void give_timer_signal();
+
+protected:
+    GuiCalibratorX11(Calibrator* w);
+    ~GuiCalibratorX11();
+
+    // Data
+    Calibrator* calibrator;
+    double X[NUM_POINTS], Y[NUM_POINTS];
+    int display_width, display_height;
+    int time_elapsed;
+
+    // X11 vars
+    Display* display;
+    int screen_num;
+    Window win;
+    GC gc;
+    XFontStruct* font_info;
+
+    // color management
+    enum { BLACK=0, WHITE=1, GRAY=2, DIMGRAY=3, RED=4, NUM_COLORS };
+    static const char* colors[NUM_COLORS];
+    unsigned long pixel[NUM_COLORS];
+
+    // Signal handlers
+    bool on_timer_signal();
+    bool on_expose_event();
+    bool on_button_press_event(XEvent event);
+
+    // Helper functions
+    void set_display_size(int width, int height);
+    void redraw();
+    void draw_message(const char* msg);
+
+private:
+    static GuiCalibratorX11* instance;
+};
+
+#endif
diff --git a/src/main_common.cpp b/src/main_common.cpp
new file mode 100644 (file)
index 0000000..08cc980
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+ * 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 "calibrator.hh"
+
+// Calibrator implementations
+#include "calibrator/Usbtouchscreen.hpp"
+#include "calibrator/Evdev.hpp"
+#include "calibrator/XorgPrint.hpp"
+
+#include <cstring>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdexcept>
+
+#include <X11/Xlib.h>
+#include <X11/extensions/XInput.h>
+
+// strdup: non-ansi
+static char* my_strdup(const char* s) {
+    size_t len = strlen(s) + 1;
+    void* p = malloc(len);
+
+    if (p == NULL)
+        return NULL;
+
+    return (char*) memcpy(p, s, len);
+}
+
+/**
+ * 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
+ */
+int Calibrator::find_device(const char* pre_device, bool list_devices,
+        XID& device_id, const char*& device_name, XYinfo& device_axys)
+{
+    bool 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);
+        for (int 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);
+    for (int 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);
+        for (int j=0; j<list->num_classes; j++)
+        {
+
+            if (any->c_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 = my_strdup(list->name);
+                    device_axys.x.min = ax[0].min_value;
+                    device_axys.x.max = ax[0].max_value;
+                    device_axys.y.min = ax[1].min_value;
+                    device_axys.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] [--geometry <w>x<h>]\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--output-type <auto|xorg.conf.d|hal|xinput>: type of config to ouput (auto=automatically detect, default: auto)\n");
+    fprintf(stderr, "\t--fake: emulate a fake device (for testing purposes)\n");
+    fprintf(stderr, "\t--geometry: manually provide the geometry (width and height) for the calibration window\n");
+}
+
+Calibrator* Calibrator::make_calibrator(int argc, char** argv)
+{
+    bool list_devices = false;
+    bool fake = false;
+    bool precalib = false;
+    XYinfo pre_axys;
+    const char* pre_device = NULL;
+    const char* geometry = NULL;
+    unsigned thr_misclick = 15;
+    unsigned thr_doubleclick = 7;
+    OutputType output_type = OUTYPE_AUTO;
+
+    // parse input
+    if (argc > 1) {
+        for (int 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", VERSION);
+                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_axys.x.min = atoi(argv[++i]);
+                if (argc > i+1)
+                    pre_axys.x.max = atoi(argv[++i]);
+                if (argc > i+1)
+                    pre_axys.y.min = atoi(argv[++i]);
+                if (argc > i+1)
+                    pre_axys.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
+
+            // Get output type ?
+            if (strcmp("--output-type", argv[i]) == 0) {
+                if (argc > i+1) {
+                    i++; // eat it or exit
+                    if (strcmp("auto", argv[i]) == 0)
+                        output_type = OUTYPE_AUTO;
+                    else if (strcmp("xorg.conf.d", argv[i]) == 0)
+                        output_type = OUTYPE_XORGCONFD;
+                    else if (strcmp("hal", argv[i]) == 0)
+                        output_type = OUTYPE_HAL;
+                    else if (strcmp("xinput", argv[i]) == 0)
+                        output_type = OUTYPE_XINPUT;
+                    else {
+                        fprintf(stderr, "Error: --output-type needs one of auto|xorg.conf.d|hal|xinput.\n\n");
+                        usage(argv[0], thr_misclick);
+                        exit(1);
+                    }
+                } else {
+                    fprintf(stderr, "Error: --output-type needs one argument.\n\n");
+                    usage(argv[0], thr_misclick);
+                    exit(1);
+                }
+            } else
+
+            // specify window geometry?
+            if (strcmp("--geometry", argv[i]) == 0) {
+                geometry = argv[++i];
+            } 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_axys;
+    if (fake) {
+        // Fake a calibratable device
+        device_name = "Fake_device";
+        device_axys = XYinfo(0,1000,0,1000);
+
+        if (verbose) {
+            printf("DEBUG: Faking device: %s\n", device_name);
+        }
+    } else {
+        // Find the right device
+        int nr_found = find_device(pre_device, list_devices, device_id, device_name, device_axys);
+
+        if (list_devices) {
+            // printed the list in find_device
+            if (nr_found == 0)
+                printf("No calibratable devices found.\n");
+            exit(2);
+        }
+
+        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_axys.x.min != -1)
+            device_axys.x.min = pre_axys.x.min;
+        if (pre_axys.x.max != -1)
+            device_axys.x.max = pre_axys.x.max;
+        if (pre_axys.y.min != -1)
+            device_axys.y.min = pre_axys.y.min;
+        if (pre_axys.y.max != -1)
+            device_axys.y.max = pre_axys.y.max;
+
+        if (verbose) {
+            printf("DEBUG: Setting precalibration: %i, %i, %i, %i\n",
+                device_axys.x.min, device_axys.x.max,
+                device_axys.y.min, device_axys.y.max);
+        }
+    }
+
+
+    // Different device/driver, different ways to apply the calibration values
+    try {
+        // try Usbtouchscreen driver
+        return new CalibratorUsbtouchscreen(device_name, device_axys,
+            thr_misclick, thr_doubleclick, output_type, geometry);
+
+    } catch(WrongCalibratorException& x) {
+        if (verbose)
+            printf("DEBUG: Not usbtouchscreen calibrator: %s\n", x.what());
+    }
+
+    try {
+        // next, try Evdev driver (with XID)
+        return new CalibratorEvdev(device_name, device_axys, device_id,
+            thr_misclick, thr_doubleclick, output_type, geometry);
+
+    } catch(WrongCalibratorException& x) {
+        if (verbose)
+            printf("DEBUG: Not evdev calibrator: %s\n", x.what());
+    }
+
+    // lastly, presume a standard Xorg driver (evtouch, mutouch, ...)
+    return new CalibratorXorgPrint(device_name, device_axys,
+            thr_misclick, thr_doubleclick, output_type, geometry);
+}
diff --git a/src/main_gtkmm.cpp b/src/main_gtkmm.cpp
new file mode 100644 (file)
index 0000000..2f00634
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+// Must be before Xlib stuff
+#include <gtkmm/main.h>
+#include <gtkmm/window.h>
+#include <cairomm/context.h>
+
+#include "calibrator.hh"
+#include "gui/gtkmm.hpp"
+
+int main(int argc, char** argv)
+{
+    Calibrator* calibrator = Calibrator::make_calibrator(argc, argv);
+
+    // GTK-mm setup
+    Gtk::Main kit(argc, argv);
+
+    Glib::RefPtr< Gdk::Screen > screen = Gdk::Screen::get_default();
+    //int num_monitors = screen->get_n_monitors(); TODO, multiple monitors?
+    Gdk::Rectangle rect;
+    screen->get_monitor_geometry(0, rect);
+
+    Gtk::Window win;
+    // when no window manager: explicitely take size of full screen
+    win.move(rect.get_x(), rect.get_y());
+    win.resize(rect.get_width(), rect.get_height());
+    // in case of window manager: set as full screen to hide window decorations
+    win.fullscreen();
+
+    CalibrationArea area(calibrator);
+    win.add(area);
+    area.show();
+
+    Gtk::Main::run(win);
+
+    Gtk::Main::quit();
+    delete calibrator;
+    return 0;
+}
diff --git a/src/main_x11.cpp b/src/main_x11.cpp
new file mode 100644 (file)
index 0000000..82258c7
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2009 Tias Guns
+ *
+ * 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 <unistd.h> // for pause()
+#include "calibrator.hh"
+#include "gui/x11.hpp"
+
+int main(int argc, char** argv)
+{
+    Calibrator* calibrator = Calibrator::make_calibrator(argc, argv);
+
+    GuiCalibratorX11::make_instance( calibrator );
+
+    // wait for timer signal, processes events
+    while(1)
+        pause();
+
+    delete calibrator;
+    return 0;
+}
diff --git a/src/tester.cpp b/src/tester.cpp
new file mode 100644 (file)
index 0000000..532e27a
--- /dev/null
@@ -0,0 +1,120 @@
+#include <algorithm>
+#include <stdio.h>
+#include <vector>
+
+#include "calibrator.hh"
+#include "calibrator/Tester.hpp"
+#include "calibrator/EvdevTester.hpp"
+
+int main() {
+    // screen dimensions
+    int width = 800;
+    int height = 600;
+    XYinfo screen_res(0, width, 0, height);
+
+    int delta_x = width/(float)num_blocks;
+    int delta_y = height/(float)num_blocks;
+    XYinfo target(delta_x, width-delta_x, delta_y, height-delta_y);
+
+    int slack = 2; // amount of pixels result can be off target
+
+    XYinfo dev_res(0, 1000, 0, 1000);
+
+    std::vector<XYinfo> old_axes;
+    old_axes.push_back( XYinfo(0, 1000, 0, 1000) );
+    old_axes.push_back( XYinfo(1000, 0, 0, 1000) );
+    old_axes.push_back( XYinfo(0, 1000, 1000, 0) );
+    old_axes.push_back( XYinfo(1000, 0, 0, 1000) );
+    old_axes.push_back( XYinfo(0, 1000, 0, 1000, 1, 0, 0) );
+    old_axes.push_back( XYinfo(0, 1000, 0, 1000, 1, 0, 1) );
+    old_axes.push_back( XYinfo(0, 1000, 0, 1000, 1, 1, 0) );
+    old_axes.push_back( XYinfo(0, 1000, 0, 1000, 1, 1, 1) );
+    old_axes.push_back( XYinfo(1000, 0, 0, 1000, 1, 0, 0) );
+    old_axes.push_back( XYinfo(1000, 0, 0, 1000, 1, 0, 1) );
+    old_axes.push_back( XYinfo(1000, 0, 0, 1000, 1, 1, 0) );
+    old_axes.push_back( XYinfo(1000, 0, 0, 1000, 1, 1, 1) );
+    // non device-resolution calibs
+    old_axes.push_back( XYinfo(42, 929, 20, 888) );
+    // xf86ScaleAxis rounds to min/max, this can lead to inaccurate
+    // results! Can we fix that?
+    old_axes.push_back( XYinfo(42, 929, 20, 888) );
+    //old_axes.push_back( XYinfo(-9, 895, 124, 990) ); // this is the true axis
+                                                       // rounding error when raw_coords are swapped???
+    //old_axes.push_back( XYinfo(75, 750, 20, 888) ); // rounding error on X axis
+    //old_axes.push_back( XYinfo(42, 929, 120, 888) ); // rounding error on Y axis
+
+    // raw device coordinates to emulate
+    std::vector<XYinfo> raw_coords;
+    // normal
+    raw_coords.push_back( XYinfo(105, 783, 233, 883) );
+    // invert x, y, x+y
+    raw_coords.push_back( XYinfo(783, 105, 233, 883) );
+    raw_coords.push_back( XYinfo(105, 783, 883, 233) );
+    raw_coords.push_back( XYinfo(783, 105, 883, 233) );
+    // swap
+    raw_coords.push_back( XYinfo(233, 883, 105, 783) );
+    // swap and inverts
+    raw_coords.push_back( XYinfo(233, 883, 783, 105) );
+    raw_coords.push_back( XYinfo(883, 233, 105, 783) );
+    raw_coords.push_back( XYinfo(883, 233, 783, 105) );
+
+    CalibratorTesterInterface* calib;
+    for (unsigned t=0; t<=1; t++) {
+        if (t == 0)
+            printf("CalibratorTester\n");
+        else if (t == 1)
+            printf("CalibratorEvdevTester\n");
+
+    for (unsigned a=0; a != old_axes.size(); a++) {
+        XYinfo old_axis(old_axes[a]);
+        printf("Old axis: "); old_axis.print();
+
+    for (unsigned c=0; c != raw_coords.size(); c++) {
+        XYinfo raw(raw_coords[c]);
+        //printf("Raw: "); raw.print();
+
+        // reset calibrator object
+        if (t == 0)
+            calib = new CalibratorTester("Tester", old_axis);
+        else if (t == 1)
+            calib = new CalibratorEvdevTester("Tester", old_axis);
+
+        // clicked from raw
+        XYinfo clicked = calib->emulate_driver(raw, false, screen_res, dev_res);// false=old_axis
+        //printf("\tClicked: "); clicked.print();
+
+        // emulate screen clicks
+        calib->add_click(clicked.x.min, clicked.y.min);
+        calib->add_click(clicked.x.max, clicked.y.min);
+        calib->add_click(clicked.x.min, clicked.y.max);
+        calib->add_click(clicked.x.max, clicked.y.max);
+        calib->finish(width, height);
+
+        // test result
+        XYinfo result = calib->emulate_driver(raw, true, screen_res, dev_res); // true=new_axis
+
+        int maxdiff = std::max(abs(target.x.min - result.x.min),
+                      std::max(abs(target.x.max - result.x.max),
+                      std::max(abs(target.y.min - result.y.min),
+                               abs(target.y.max - result.y.max)))); // no n-ary max in c++??
+        if (maxdiff > slack) {
+            printf("-\n");
+            printf("Old axis: "); old_axis.print();
+            printf("Raw: "); raw.print();
+            printf("Clicked: "); clicked.print();
+            printf("New axis: "); calib->new_axis_print();
+            printf("Error: difference between target and result: %i > %i:\n", maxdiff, slack);
+            printf("\tTarget: "); target.print();
+            printf("\tResult: "); result.print();
+            exit(1);
+        }
+
+        printf("%i", maxdiff);
+    } // loop over raw_coords
+
+        printf(". OK\n");
+    } // loop over old_axes
+
+        printf("\n");
+    } // loop over calibrators
+}