2012-01-03 12:39:06 -08:00
/*
* 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 .
*/
2012-01-11 16:22:24 +00:00
# include "config.h"
2012-01-03 12:39:06 -08:00
# include <stdlib.h>
# include <ctype.h>
# include <string.h>
# include <dirent.h>
2012-01-11 16:22:24 +00:00
# include <glib/gi18n.h>
2013-04-08 18:44:12 +02:00
# include <clutter-gtk/clutter-gtk.h>
2012-01-03 12:39:06 -08:00
# include <X11/extensions/XInput.h>
2013-04-08 18:44:12 +02:00
# include "calibrator-gui.h"
2012-01-12 18:57:45 +00:00
# include "calibrator.h"
2012-01-03 12:39:06 -08:00
/**
* 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
*/
2012-01-10 19:21:30 +00:00
static int find_device ( const char * pre_device , gboolean verbose , gboolean list_devices ,
2012-01-10 19:19:24 +00:00
XID * device_id , const char * * device_name , XYinfo * device_axis )
2012-01-03 12:39:06 -08:00
{
2012-01-10 18:33:26 +00:00
gboolean pre_device_is_id = TRUE ;
2012-01-03 12:39:06 -08:00
int found = 0 ;
Display * display = XOpenDisplay ( NULL ) ;
if ( display = = NULL ) {
fprintf ( stderr , " Unable to connect to X server \n " ) ;
exit ( 1 ) ;
}
int xi_opcode , event , error ;
if ( ! XQueryExtension ( display , " XInputExtension " , & xi_opcode , & event , & error ) ) {
fprintf ( stderr , " X Input extension not available. \n " ) ;
exit ( 1 ) ;
}
/* verbose, get Xi version */
if ( verbose ) {
XExtensionVersion * version = XGetExtensionVersion ( display , INAME ) ;
if ( version & & ( version ! = ( XExtensionVersion * ) NoSuchExtension ) ) {
printf ( " DEBUG: %s version is %i.%i \n " ,
INAME , version - > major_version , version - > minor_version ) ;
XFree ( version ) ;
}
}
if ( pre_device ! = NULL ) {
/* check whether the pre_device is an ID (only digits) */
int len = strlen ( pre_device ) ;
int loop ;
for ( loop = 0 ; loop < len ; loop + + ) {
if ( ! isdigit ( pre_device [ loop ] ) ) {
2012-01-10 18:33:26 +00:00
pre_device_is_id = FALSE ;
2012-01-03 12:39:06 -08:00
break ;
}
}
}
if ( verbose )
printf ( " DEBUG: Skipping virtual master devices and devices without axis valuators. \n " ) ;
int ndevices ;
XDeviceInfoPtr list , slist ;
slist = list = ( XDeviceInfoPtr ) XListInputDevices ( display , & ndevices ) ;
int i ;
for ( i = 0 ; i < ndevices ; i + + , list + + )
{
if ( list - > use = = IsXKeyboard | | list - > use = = IsXPointer ) /* virtual master device */
continue ;
/* if we are looking for a specific device */
if ( pre_device ! = NULL ) {
if ( ( pre_device_is_id & & list - > id = = ( XID ) atoi ( pre_device ) ) | |
( ! pre_device_is_id & & strcmp ( list - > name , pre_device ) = = 0 ) ) {
/* OK, fall through */
} else {
/* skip, not this device */
continue ;
}
}
XAnyClassPtr any = ( XAnyClassPtr ) ( list - > inputclassinfo ) ;
int j ;
for ( j = 0 ; j < list - > num_classes ; j + + )
{
if ( any - > class = = ValuatorClass )
{
XValuatorInfoPtr V = ( XValuatorInfoPtr ) any ;
XAxisInfoPtr ax = ( XAxisInfoPtr ) V - > axes ;
if ( V - > mode ! = Absolute ) {
if ( verbose )
printf ( " DEBUG: Skipping device '%s' id=%i, does not report Absolute events. \n " ,
list - > name , ( int ) list - > id ) ;
} else if ( V - > num_axes < 2 | |
( ax [ 0 ] . min_value = = - 1 & & ax [ 0 ] . max_value = = - 1 ) | |
( ax [ 1 ] . min_value = = - 1 & & ax [ 1 ] . max_value = = - 1 ) ) {
if ( verbose )
printf ( " DEBUG: Skipping device '%s' id=%i, does not have two calibratable axes. \n " ,
list - > name , ( int ) list - > id ) ;
} else {
/* a calibratable device (has 2 axis valuators) */
found + + ;
* device_id = list - > id ;
2012-01-10 18:32:54 +00:00
* device_name = g_strdup ( list - > name ) ;
2012-01-10 19:19:24 +00:00
device_axis - > x_min = ax [ 0 ] . min_value ;
device_axis - > x_max = ax [ 0 ] . max_value ;
device_axis - > y_min = ax [ 1 ] . min_value ;
device_axis - > y_max = ax [ 1 ] . max_value ;
2012-01-03 12:39:06 -08:00
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 )
{
2012-01-11 20:09:20 +00:00
fprintf ( stderr , " Usage: %s [-h|--help] [-v|--verbose] [--list] [--device <device name or id>] [--precalib <minx> <maxx> <miny> <maxy>] [--misclick <nr of pixels>] [--output-type <auto|xorg.conf.d|hal|xinput>] [--fake] \n " , cmd ) ;
2012-01-03 12:39:06 -08:00
fprintf ( stderr , " \t -h, --help: print this help message \n " ) ;
fprintf ( stderr , " \t -v, --verbose: print debug messages during the process \n " ) ;
fprintf ( stderr , " \t --list: list calibratable input devices and quit \n " ) ;
fprintf ( stderr , " \t --device <device name or id>: select a specific device to calibrate \n " ) ;
fprintf ( stderr , " \t --precalib: manually provide the current calibration setting (eg. the values in xorg.conf) \n " ) ;
fprintf ( stderr , " \t --misclick: set the misclick threshold (0=off, default: %i pixels) \n " ,
thr_misclick ) ;
fprintf ( stderr , " \t --fake: emulate a fake device (for testing purposes) \n " ) ;
}
2012-01-11 20:09:20 +00:00
static struct Calib * CalibratorXorgPrint ( const char * const device_name0 , const XYinfo * axis0 , const gboolean verbose0 , const int thr_misclick , const int thr_doubleclick )
2012-01-10 19:21:30 +00:00
{
struct Calib * c = ( struct Calib * ) calloc ( 1 , sizeof ( struct Calib ) ) ;
c - > old_axis = * axis0 ;
c - > threshold_misclick = thr_misclick ;
c - > threshold_doubleclick = thr_doubleclick ;
printf ( " Calibrating standard Xorg driver \" %s \" \n " , device_name0 ) ;
2016-11-16 14:28:39 +01:00
printf ( " \t current calibration values: min_x=%lf, max_x=%lf and min_y=%lf, max_y=%lf \n " ,
2012-01-10 19:21:30 +00:00
c - > old_axis . x_min , c - > old_axis . x_max , c - > old_axis . y_min , c - > old_axis . y_max ) ;
printf ( " \t If these values are estimated wrong, either supply it manually with the --precalib option, or run the 'get_precalib.sh' script to automatically get it (through HAL). \n " ) ;
return c ;
}
static struct Calib * main_common ( int argc , char * * argv )
2012-01-03 12:39:06 -08:00
{
2012-01-10 18:33:26 +00:00
gboolean verbose = FALSE ;
gboolean list_devices = FALSE ;
gboolean fake = FALSE ;
gboolean precalib = FALSE ;
2012-01-10 19:19:24 +00:00
XYinfo pre_axis = { - 1 , - 1 , - 1 , - 1 } ;
2012-01-03 12:39:06 -08:00
const char * pre_device = NULL ;
unsigned thr_misclick = 15 ;
unsigned thr_doubleclick = 7 ;
/* parse input */
if ( argc > 1 ) {
int i ;
for ( i = 1 ; i ! = argc ; i + + ) {
/* Display help ? */
if ( strcmp ( " -h " , argv [ i ] ) = = 0 | |
strcmp ( " --help " , argv [ i ] ) = = 0 ) {
fprintf ( stderr , " xinput_calibratior, v%s \n \n " , " 0.0.0 " ) ;
usage ( argv [ 0 ] , thr_misclick ) ;
exit ( 0 ) ;
} else
/* Verbose output ? */
if ( strcmp ( " -v " , argv [ i ] ) = = 0 | |
strcmp ( " --verbose " , argv [ i ] ) = = 0 ) {
2012-01-10 18:33:26 +00:00
verbose = TRUE ;
2012-01-03 12:39:06 -08:00
} else
/* Just list devices ? */
if ( strcmp ( " --list " , argv [ i ] ) = = 0 ) {
2012-01-10 18:33:26 +00:00
list_devices = TRUE ;
2012-01-03 12:39:06 -08:00
} 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 ) {
2012-01-10 18:33:26 +00:00
precalib = TRUE ;
2012-01-03 12:39:06 -08:00
if ( argc > i + 1 )
2012-01-10 19:19:24 +00:00
pre_axis . x_min = atoi ( argv [ + + i ] ) ;
2012-01-03 12:39:06 -08:00
if ( argc > i + 1 )
2012-01-10 19:19:24 +00:00
pre_axis . x_max = atoi ( argv [ + + i ] ) ;
2012-01-03 12:39:06 -08:00
if ( argc > i + 1 )
2012-01-10 19:19:24 +00:00
pre_axis . y_min = atoi ( argv [ + + i ] ) ;
2012-01-03 12:39:06 -08:00
if ( argc > i + 1 )
2012-01-10 19:19:24 +00:00
pre_axis . y_max = atoi ( argv [ + + i ] ) ;
2012-01-03 12:39:06 -08:00
} else
/* Get mis-click threshold ? */
if ( strcmp ( " --misclick " , argv [ i ] ) = = 0 ) {
if ( argc > i + 1 )
thr_misclick = atoi ( argv [ + + i ] ) ;
else {
fprintf ( stderr , " Error: --misclick needs a number (the pixel threshold) as argument. Set to 0 to disable mis-click detection. \n \n " ) ;
usage ( argv [ 0 ] , thr_misclick ) ;
exit ( 1 ) ;
}
} else
/* Fake calibratable device ? */
if ( strcmp ( " --fake " , argv [ i ] ) = = 0 ) {
2012-01-10 18:33:26 +00:00
fake = TRUE ;
2012-01-03 12:39:06 -08:00
}
/* 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 ;
2012-01-10 19:19:24 +00:00
XYinfo device_axis = { - 1 , - 1 , - 1 , - 1 } ;
2012-01-03 12:39:06 -08:00
if ( fake ) {
/* Fake a calibratable device */
device_name = " Fake_device " ;
2012-01-10 19:19:24 +00:00
device_axis . x_min = 0 ;
device_axis . x_max = 1000 ;
device_axis . y_min = 0 ;
device_axis . y_max = 1000 ;
2012-01-03 12:39:06 -08:00
if ( verbose ) {
printf ( " DEBUG: Faking device: %s \n " , device_name ) ;
}
} else {
/* Find the right device */
2012-01-10 19:19:24 +00:00
int nr_found = find_device ( pre_device , verbose , list_devices , & device_id , & device_name , & device_axis ) ;
2012-01-03 12:39:06 -08:00
if ( list_devices ) {
/* printed the list in find_device */
if ( nr_found = = 0 )
printf ( " No calibratable devices found. \n " ) ;
exit ( 0 ) ;
}
if ( nr_found = = 0 ) {
if ( pre_device = = NULL )
fprintf ( stderr , " Error: No calibratable devices found. \n " ) ;
else
fprintf ( stderr , " Error: Device \" %s \" not found; use --list to list the calibratable input devices. \n " , pre_device ) ;
exit ( 1 ) ;
} else if ( nr_found > 1 ) {
printf ( " Warning: multiple calibratable devices found, calibrating last one (%s) \n \t use --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 ) {
2012-01-10 19:19:24 +00:00
if ( pre_axis . x_min ! = - 1 )
device_axis . x_min = pre_axis . x_min ;
if ( pre_axis . x_max ! = - 1 )
device_axis . x_max = pre_axis . x_max ;
if ( pre_axis . y_min ! = - 1 )
device_axis . y_min = pre_axis . y_min ;
if ( pre_axis . y_max ! = - 1 )
device_axis . y_max = pre_axis . y_max ;
2012-01-03 12:39:06 -08:00
if ( verbose ) {
2016-11-16 14:28:39 +01:00
printf ( " DEBUG: Setting precalibration: %lf, %lf, %lf, %lf \n " ,
2012-01-10 19:19:24 +00:00
device_axis . x_min , device_axis . x_max ,
device_axis . y_min , device_axis . y_max ) ;
2012-01-03 12:39:06 -08:00
}
}
/* lastly, presume a standard Xorg driver (evtouch, mutouch, ...) */
2012-01-10 19:19:24 +00:00
return CalibratorXorgPrint ( device_name , & device_axis ,
2012-01-11 20:09:20 +00:00
verbose , thr_misclick , thr_doubleclick ) ;
2012-01-03 12:39:06 -08:00
}
2012-01-12 18:57:45 +00:00
static gboolean output_xorgconfd ( const XYinfo new_axis , int swap_xy , int new_swap_xy )
2012-01-03 12:39:06 -08:00
{
const char * sysfs_name = " !!Name_Of_TouchScreen!! " ;
/* xorg.conf.d snippet */
printf ( " copy the snippet below into '/etc/X11/xorg.conf.d/99-calibration.conf' \n " ) ;
printf ( " Section \" InputClass \" \n " ) ;
printf ( " Identifier \" calibration \" \n " ) ;
printf ( " MatchProduct \" %s \" \n " , sysfs_name ) ;
2016-11-16 14:28:39 +01:00
printf ( " Option \" MinX \" \" %lf \" \n " , new_axis . x_min ) ;
printf ( " Option \" MaxX \" \" %lf \" \n " , new_axis . x_max ) ;
printf ( " Option \" MinY \" \" %lf \" \n " , new_axis . y_min ) ;
printf ( " Option \" MaxY \" \" %lf \" \n " , new_axis . y_max ) ;
2012-01-03 12:39:06 -08:00
if ( swap_xy ! = 0 )
printf ( " Option \" SwapXY \" \" %d \" # unless it was already set to 1 \n " , new_swap_xy ) ;
printf ( " EndSection \n " ) ;
2012-01-10 18:33:26 +00:00
return TRUE ;
2012-01-03 12:39:06 -08:00
}
2012-01-12 18:57:45 +00:00
static gboolean finish_data ( const XYinfo new_axis , int swap_xy )
2012-01-10 19:21:30 +00:00
{
gboolean success = TRUE ;
/* we suppose the previous 'swap_xy' value was 0 */
/* (unfortunately there is no way to verify this (yet)) */
int new_swap_xy = swap_xy ;
printf ( " \n \n --> Making the calibration permanent <-- \n " ) ;
2012-01-12 18:57:45 +00:00
success & = output_xorgconfd ( new_axis , swap_xy , new_swap_xy ) ;
2012-01-10 19:21:30 +00:00
return success ;
}
2012-01-12 18:57:45 +00:00
static void
calibration_finished_cb ( CalibArea * area ,
gpointer user_data )
{
gboolean success ;
XYinfo axis ;
gboolean swap_xy ;
success = calib_area_finish ( area , & axis , & swap_xy ) ;
if ( success )
success = finish_data ( axis , swap_xy ) ;
else
fprintf ( stderr , " Error: unable to apply or save configuration values \n " ) ;
gtk_main_quit ( ) ;
}
2012-01-03 12:39:06 -08:00
int main ( int argc , char * * argv )
{
struct Calib * calibrator = main_common ( argc , argv ) ;
2012-01-12 18:57:45 +00:00
CalibArea * calib_area ;
2012-01-03 12:39:06 -08:00
2012-01-11 16:22:24 +00:00
bindtextdomain ( GETTEXT_PACKAGE , GNOMELOCALEDIR ) ;
bind_textdomain_codeset ( GETTEXT_PACKAGE , " UTF-8 " ) ;
textdomain ( GETTEXT_PACKAGE ) ;
2012-01-11 16:22:44 +00:00
g_setenv ( " G_MESSAGES_DEBUG " , " all " , TRUE ) ;
2012-01-03 12:39:06 -08:00
/* GTK setup */
2013-04-08 18:44:12 +02:00
if ( gtk_clutter_init ( & argc , & argv ) ! = CLUTTER_INIT_SUCCESS )
{
g_critical ( " Unable to initialize Clutter " ) ;
return 1 ;
}
2012-01-03 12:39:06 -08:00
2012-01-12 18:57:45 +00:00
calib_area = calib_area_new ( NULL ,
2012-07-18 14:23:29 +02:00
0 , /* monitor */
- 1 , /* -1 to ignore device ID */
2012-01-12 18:57:45 +00:00
calibration_finished_cb ,
NULL ,
& calibrator - > old_axis ,
calibrator - > threshold_doubleclick ,
calibrator - > threshold_misclick ) ;
2012-01-03 12:39:06 -08:00
2012-01-12 18:57:45 +00:00
gtk_main ( ) ;
calib_area_free ( calib_area ) ;
2012-01-03 12:39:06 -08:00
free ( calibrator ) ;
2012-01-12 18:57:45 +00:00
return 0 ;
2012-01-03 12:39:06 -08:00
}