wacom: Bring over files from xinput-calibrator and build utility
Copies over files from a trimmed version of xinput-calibrator and modifies the Makefile.am to build the program as a seperate utility. This is just to verify the functionality of the code when built with gnome-control-center. https://bugzilla.gnome.org/show_bug.cgi?id=657423
This commit is contained in:
parent
a54c382377
commit
e50dbea195
9 changed files with 1274 additions and 2 deletions
|
@ -401,6 +401,7 @@ panels/user-accounts/data/gnome-user-accounts-panel.desktop.in
|
||||||
panels/user-accounts/data/faces/Makefile
|
panels/user-accounts/data/faces/Makefile
|
||||||
panels/user-accounts/data/icons/Makefile
|
panels/user-accounts/data/icons/Makefile
|
||||||
panels/wacom/Makefile
|
panels/wacom/Makefile
|
||||||
|
panels/wacom/calibrator/Makefile
|
||||||
panels/wacom/gnome-wacom-panel.desktop.in
|
panels/wacom/gnome-wacom-panel.desktop.in
|
||||||
po/Makefile.in
|
po/Makefile.in
|
||||||
shell/Makefile
|
shell/Makefile
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
# This is used in PANEL_CFLAGS
|
# This is used in PANEL_CFLAGS
|
||||||
cappletname = wacom
|
cappletname = wacom
|
||||||
|
|
||||||
|
SUBDIRS = calibrator
|
||||||
|
|
||||||
INCLUDES = \
|
INCLUDES = \
|
||||||
$(PANEL_CFLAGS) \
|
$(PANEL_CFLAGS) \
|
||||||
$(WACOM_PANEL_CFLAGS) \
|
$(WACOM_PANEL_CFLAGS) \
|
||||||
|
-I$(srcdir)/calibrator \
|
||||||
-DGNOMELOCALEDIR="\"$(datadir)/locale\"" \
|
-DGNOMELOCALEDIR="\"$(datadir)/locale\"" \
|
||||||
-DGNOMECC_DATA_DIR="\"$(pkgdatadir)\"" \
|
-DGNOMECC_DATA_DIR="\"$(pkgdatadir)\"" \
|
||||||
-DGNOMECC_UI_DIR="\"$(uidir)\"" \
|
-DGNOMECC_UI_DIR="\"$(uidir)\"" \
|
||||||
|
@ -27,7 +30,7 @@ libwacom_properties_la_SOURCES = \
|
||||||
cc-wacom-nav-button.c \
|
cc-wacom-nav-button.c \
|
||||||
cc-wacom-nav-button.h
|
cc-wacom-nav-button.h
|
||||||
|
|
||||||
libwacom_properties_la_LIBADD = $(PANEL_LIBS) $(WACOM_PANEL_LIBS)
|
libwacom_properties_la_LIBADD = $(PANEL_LIBS) $(WACOM_PANEL_LIBS) $(builddir)/calibrator/libwacom-calibrator.la
|
||||||
libwacom_properties_la_LDFLAGS = $(PANEL_LDFLAGS)
|
libwacom_properties_la_LDFLAGS = $(PANEL_LDFLAGS)
|
||||||
|
|
||||||
noinst_PROGRAMS = test-wacom
|
noinst_PROGRAMS = test-wacom
|
||||||
|
@ -44,7 +47,7 @@ test_wacom_SOURCES = \
|
||||||
gsd-input-helper.h
|
gsd-input-helper.h
|
||||||
|
|
||||||
test_wacom_CPPFLAGS = $(INCLUDES)
|
test_wacom_CPPFLAGS = $(INCLUDES)
|
||||||
test_wacom_LDADD = $(PANEL_LIBS) $(WACOM_PANEL_LIBS)
|
test_wacom_LDADD = $(PANEL_LIBS) $(WACOM_PANEL_LIBS) $(builddir)/calibrator/libwacom-calibrator.la
|
||||||
|
|
||||||
@INTLTOOL_DESKTOP_RULE@
|
@INTLTOOL_DESKTOP_RULE@
|
||||||
|
|
||||||
|
|
38
panels/wacom/calibrator/Makefile.am
Normal file
38
panels/wacom/calibrator/Makefile.am
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
# This is used in PANEL_CFLAGS
|
||||||
|
cappletname = wacom
|
||||||
|
|
||||||
|
INCLUDES = \
|
||||||
|
$(PANEL_CFLAGS) \
|
||||||
|
$(WACOM_PANEL_CFLAGS) \
|
||||||
|
-DGNOMELOCALEDIR="\"$(datadir)/locale\"" \
|
||||||
|
-DGNOMECC_DATA_DIR="\"$(pkgdatadir)\"" \
|
||||||
|
-DGNOMECC_UI_DIR="\"$(uidir)\"" \
|
||||||
|
-DPIXMAP_DIR=\""$(datadir)/gnome-control-center/pixmaps"\" \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
|
||||||
|
noinst_LTLIBRARIES = libwacom-calibrator.la
|
||||||
|
|
||||||
|
libwacom_calibrator_la_SOURCES = \
|
||||||
|
calibrator.c \
|
||||||
|
calibrator.h \
|
||||||
|
gui_gtk.c \
|
||||||
|
gui_gtk.h
|
||||||
|
|
||||||
|
libwacom_calibrator_la_LIBADD = $(PANEL_LIBS) $(WACOM_PANEL_LIBS)
|
||||||
|
libwacom_calibrator_la_LDFLAGS = $(PANEL_LDFLAGS)
|
||||||
|
|
||||||
|
noinst_PROGRAMS = test-calibrator
|
||||||
|
|
||||||
|
test_calibrator_SOURCES = \
|
||||||
|
main.c \
|
||||||
|
main.h \
|
||||||
|
calibrator.c \
|
||||||
|
calibrator.h \
|
||||||
|
gui_gtk.c \
|
||||||
|
gui_gtk.h
|
||||||
|
|
||||||
|
test_calibrator_CPPFLAGS = $(INCLUDES)
|
||||||
|
test_calibrator_LDADD = $(PANEL_LIBS) $(WACOM_PANEL_LIBS)
|
||||||
|
|
||||||
|
-include $(top_srcdir)/git.mk
|
177
panels/wacom/calibrator/calibrator.c
Normal file
177
panels/wacom/calibrator/calibrator.c
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
/*
|
||||||
|
* 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 <stdlib.h>
|
||||||
|
|
||||||
|
#include "calibrator.h"
|
||||||
|
|
||||||
|
#define SWAP(x,y) do { int t; t=(x); x=(y); y=t; } while (0)
|
||||||
|
|
||||||
|
/* reset clicks */
|
||||||
|
void
|
||||||
|
reset (struct Calib *c)
|
||||||
|
{
|
||||||
|
c->num_clicks = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add a click with the given coordinates */
|
||||||
|
bool
|
||||||
|
add_click (struct Calib *c,
|
||||||
|
int x,
|
||||||
|
int y)
|
||||||
|
{
|
||||||
|
/* Double-click detection */
|
||||||
|
if (c->threshold_doubleclick > 0 && c->num_clicks > 0)
|
||||||
|
{
|
||||||
|
int i = c->num_clicks-1;
|
||||||
|
while (i >= 0)
|
||||||
|
{
|
||||||
|
if (abs(x - c->clicked_x[i]) <= c->threshold_doubleclick &&
|
||||||
|
abs(y - c->clicked_y[i]) <= c->threshold_doubleclick)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mis-click detection */
|
||||||
|
if (c->threshold_misclick > 0 && c->num_clicks > 0)
|
||||||
|
{
|
||||||
|
bool misclick = true;
|
||||||
|
|
||||||
|
if (c->num_clicks == 1)
|
||||||
|
{
|
||||||
|
/* check that along one axis of first point */
|
||||||
|
if (along_axis(c, x,c->clicked_x[0],c->clicked_y[0]) ||
|
||||||
|
along_axis(c, y,c->clicked_x[0],c->clicked_y[0]))
|
||||||
|
{
|
||||||
|
misclick = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (c->num_clicks == 2)
|
||||||
|
{
|
||||||
|
/* check that along other axis of first point than second point */
|
||||||
|
if ((along_axis(c, y,c->clicked_x[0],c->clicked_y[0]) &&
|
||||||
|
along_axis(c, c->clicked_x[1],c->clicked_x[0],c->clicked_y[0])) ||
|
||||||
|
(along_axis(c, x,c->clicked_x[0],c->clicked_y[0]) &&
|
||||||
|
along_axis(c, c->clicked_y[1],c->clicked_x[0],c->clicked_y[0])))
|
||||||
|
{
|
||||||
|
misclick = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (c->num_clicks == 3)
|
||||||
|
{
|
||||||
|
/* check that along both axis of second and third point */
|
||||||
|
if ((along_axis(c, x,c->clicked_x[1],c->clicked_y[1]) &&
|
||||||
|
along_axis(c, y,c->clicked_x[2],c->clicked_y[2])) ||
|
||||||
|
(along_axis(c, y,c->clicked_x[1],c->clicked_y[1]) &&
|
||||||
|
along_axis(c, x,c->clicked_x[2],c->clicked_y[2])))
|
||||||
|
{
|
||||||
|
misclick = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (misclick)
|
||||||
|
{
|
||||||
|
reset(c);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c->clicked_x[c->num_clicks] = x;
|
||||||
|
c->clicked_y[c->num_clicks] = y;
|
||||||
|
c->num_clicks++;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check whether the coordinates are along the respective axis */
|
||||||
|
bool
|
||||||
|
along_axis (struct Calib *c,
|
||||||
|
int xy,
|
||||||
|
int x0,
|
||||||
|
int y0)
|
||||||
|
{
|
||||||
|
return ((abs(xy - x0) <= c->threshold_misclick) ||
|
||||||
|
(abs(xy - y0) <= c->threshold_misclick));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* calculate and apply the calibration */
|
||||||
|
bool
|
||||||
|
finish (struct Calib *c,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
XYinfo *new_axys,
|
||||||
|
bool *swap)
|
||||||
|
{
|
||||||
|
bool swap_xy;
|
||||||
|
float scale_x;
|
||||||
|
float scale_y;
|
||||||
|
int delta_x;
|
||||||
|
int delta_y;
|
||||||
|
XYinfo axys = {-1, -1, -1, -1};
|
||||||
|
|
||||||
|
if (c->num_clicks != 4)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Should x and y be swapped? */
|
||||||
|
swap_xy = (abs (c->clicked_x [UL] - c->clicked_x [UR]) < abs (c->clicked_y [UL] - c->clicked_y [UR]));
|
||||||
|
if (swap_xy)
|
||||||
|
{
|
||||||
|
SWAP(c->clicked_x[LL], c->clicked_x[UR]);
|
||||||
|
SWAP(c->clicked_y[LL], c->clicked_y[UR]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compute min/max coordinates. */
|
||||||
|
/* These are scaled using the values of old_axys */
|
||||||
|
scale_x = (c->old_axys.x_max - c->old_axys.x_min)/(float)width;
|
||||||
|
axys.x_min = ((c->clicked_x[UL] + c->clicked_x[LL]) * scale_x/2) + c->old_axys.x_min;
|
||||||
|
axys.x_max = ((c->clicked_x[UR] + c->clicked_x[LR]) * scale_x/2) + c->old_axys.x_min;
|
||||||
|
scale_y = (c->old_axys.y_max - c->old_axys.y_min)/(float)height;
|
||||||
|
axys.y_min = ((c->clicked_y[UL] + c->clicked_y[UR]) * scale_y/2) + c->old_axys.y_min;
|
||||||
|
axys.y_max = ((c->clicked_y[LL] + c->clicked_y[LR]) * scale_y/2) + c->old_axys.y_min;
|
||||||
|
|
||||||
|
/* Add/subtract the offset that comes from not having the points in the
|
||||||
|
* corners (using the same coordinate system they are currently in)
|
||||||
|
*/
|
||||||
|
delta_x = (axys.x_max - axys.x_min) / (float)(NUM_BLOCKS - 2);
|
||||||
|
axys.x_min -= delta_x;
|
||||||
|
axys.x_max += delta_x;
|
||||||
|
delta_y = (axys.y_max - axys.y_min) / (float)(NUM_BLOCKS - 2);
|
||||||
|
axys.y_min -= delta_y;
|
||||||
|
axys.y_max += delta_y;
|
||||||
|
|
||||||
|
/* If x and y has to be swapped we also have to swap the parameters */
|
||||||
|
if (swap_xy)
|
||||||
|
{
|
||||||
|
SWAP(axys.x_min, axys.y_max);
|
||||||
|
SWAP(axys.y_min, axys.x_max);
|
||||||
|
}
|
||||||
|
|
||||||
|
*new_axys = axys;
|
||||||
|
*swap = swap_xy;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
119
panels/wacom/calibrator/calibrator.h
Normal file
119
panels/wacom/calibrator/calibrator.h
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
/*
|
||||||
|
* 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 _calibrator_h
|
||||||
|
#define _calibrator_h
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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--+
|
||||||
|
* | | | | | | | | |
|
||||||
|
* +--+--+--+--+--+--+--+--+
|
||||||
|
*/
|
||||||
|
#define NUM_BLOCKS 8
|
||||||
|
|
||||||
|
/* Names of the points */
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
UL = 0, /* Upper-left */
|
||||||
|
UR = 1, /* Upper-right */
|
||||||
|
LL = 2, /* Lower-left */
|
||||||
|
LR = 3 /* Lower-right */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* struct to hold min/max info of the X and Y axis */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int x_min;
|
||||||
|
int x_max;
|
||||||
|
int y_min;
|
||||||
|
int y_max;
|
||||||
|
} XYinfo;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
false = 0,
|
||||||
|
true = 1
|
||||||
|
} bool;
|
||||||
|
|
||||||
|
struct Calib
|
||||||
|
{
|
||||||
|
/* original axys values */
|
||||||
|
XYinfo old_axys;
|
||||||
|
|
||||||
|
/* nr of clicks registered */
|
||||||
|
int num_clicks;
|
||||||
|
|
||||||
|
/* click coordinates */
|
||||||
|
int clicked_x[4], clicked_y[4];
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
/* manually specified geometry string */
|
||||||
|
const char* geometry;
|
||||||
|
};
|
||||||
|
|
||||||
|
void reset (struct Calib *c);
|
||||||
|
bool add_click (struct Calib *c,
|
||||||
|
int x,
|
||||||
|
int y);
|
||||||
|
bool along_axis (struct Calib *c,
|
||||||
|
int xy,
|
||||||
|
int x0,
|
||||||
|
int y0);
|
||||||
|
bool finish (struct Calib *c,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
XYinfo *new_axys,
|
||||||
|
bool *swap);
|
||||||
|
|
||||||
|
#endif /* _calibrator_h */
|
411
panels/wacom/calibrator/gui_gtk.c
Normal file
411
panels/wacom/calibrator/gui_gtk.c
Normal file
|
@ -0,0 +1,411 @@
|
||||||
|
/*
|
||||||
|
* 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 <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
#include <cairo.h>
|
||||||
|
|
||||||
|
#include "calibrator.h"
|
||||||
|
#include "gui_gtk.h"
|
||||||
|
|
||||||
|
#define MAXIMUM(x,y) ((x) > (y) ? (x) : (y))
|
||||||
|
|
||||||
|
#ifndef M_PI
|
||||||
|
#define M_PI 3.14159265358979323846264338327
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
#define HELP_LINES (sizeof help_text / sizeof help_text[0])
|
||||||
|
const char *help_text[] = {
|
||||||
|
"Touchscreen Calibration",
|
||||||
|
"Press the point, use a stylus to increase precision.",
|
||||||
|
"",
|
||||||
|
"(To abort, press any key or wait)"
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CalibArea*
|
||||||
|
CalibrationArea_(struct Calib *c)
|
||||||
|
{
|
||||||
|
struct CalibArea *calib_area;
|
||||||
|
const char *geo = c->geometry;
|
||||||
|
|
||||||
|
calib_area = (struct CalibArea*)calloc(1, sizeof(struct CalibArea));
|
||||||
|
calib_area->calibrator = c;
|
||||||
|
calib_area->drawing_area = gtk_drawing_area_new();
|
||||||
|
|
||||||
|
/* Listen for mouse events */
|
||||||
|
gtk_widget_add_events(calib_area->drawing_area, GDK_KEY_PRESS_MASK | GDK_BUTTON_PRESS_MASK);
|
||||||
|
gtk_widget_set_can_focus(calib_area->drawing_area, TRUE);
|
||||||
|
|
||||||
|
/* Connect callbacks */
|
||||||
|
g_signal_connect(calib_area->drawing_area, "expose-event", G_CALLBACK(on_expose_event), calib_area);
|
||||||
|
g_signal_connect(calib_area->drawing_area, "draw", G_CALLBACK(draw), calib_area);
|
||||||
|
g_signal_connect(calib_area->drawing_area, "button-press-event", G_CALLBACK(on_button_press_event), calib_area);
|
||||||
|
g_signal_connect(calib_area->drawing_area, "key-press-event", G_CALLBACK(on_key_press_event), calib_area);
|
||||||
|
|
||||||
|
/* parse geometry string */
|
||||||
|
if (geo != NULL)
|
||||||
|
{
|
||||||
|
int gw,gh;
|
||||||
|
int res = sscanf(geo,"%dx%d",&gw,&gh);
|
||||||
|
if (res != 2)
|
||||||
|
geo = NULL;
|
||||||
|
else
|
||||||
|
set_display_size(calib_area, gw, gh );\
|
||||||
|
}
|
||||||
|
if (geo == NULL)
|
||||||
|
{
|
||||||
|
GtkAllocation allocation;
|
||||||
|
gtk_widget_get_allocation(calib_area->drawing_area, &allocation);
|
||||||
|
set_display_size(calib_area, allocation.width, allocation.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setup timer for animation */
|
||||||
|
g_timeout_add(time_step, (GSourceFunc)on_timer_signal, calib_area);
|
||||||
|
|
||||||
|
return calib_area;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
set_display_size(struct CalibArea *calib_area,
|
||||||
|
int width,
|
||||||
|
int height)
|
||||||
|
{
|
||||||
|
int delta_x;
|
||||||
|
int delta_y;
|
||||||
|
|
||||||
|
calib_area->display_width = width;
|
||||||
|
calib_area->display_height = height;
|
||||||
|
|
||||||
|
/* Compute absolute circle centers */
|
||||||
|
delta_x = calib_area->display_width/NUM_BLOCKS;
|
||||||
|
delta_y = calib_area->display_height/NUM_BLOCKS;
|
||||||
|
|
||||||
|
calib_area->X[UL] = delta_x;
|
||||||
|
calib_area->Y[UL] = delta_y;
|
||||||
|
|
||||||
|
calib_area->X[UR] = calib_area->display_width - delta_x - 1;
|
||||||
|
calib_area->Y[UR] = delta_y;
|
||||||
|
|
||||||
|
calib_area->X[LL] = delta_x;
|
||||||
|
calib_area->Y[LL] = calib_area->display_height - delta_y - 1;
|
||||||
|
|
||||||
|
calib_area->X[LR] = calib_area->display_width - delta_x - 1;
|
||||||
|
calib_area->Y[LR] = calib_area->display_height - delta_y - 1;
|
||||||
|
|
||||||
|
/* reset calibration if already started */
|
||||||
|
reset(calib_area->calibrator);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
resize_display(struct CalibArea *calib_area)
|
||||||
|
{
|
||||||
|
/* check that screensize did not change (if no manually specified geometry) */
|
||||||
|
GtkAllocation allocation;
|
||||||
|
gtk_widget_get_allocation(calib_area->drawing_area, &allocation);
|
||||||
|
if (calib_area->calibrator->geometry == NULL &&
|
||||||
|
(calib_area->display_width != allocation.width ||
|
||||||
|
calib_area->display_height != allocation.height ))
|
||||||
|
{
|
||||||
|
set_display_size(calib_area, allocation.width, allocation.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
on_expose_event(GtkWidget *widget,
|
||||||
|
GdkEventExpose *event,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
struct CalibArea *calib_area = (struct CalibArea*)data;
|
||||||
|
GdkWindow *window = gtk_widget_get_window(calib_area->drawing_area);
|
||||||
|
|
||||||
|
if (window)
|
||||||
|
{
|
||||||
|
cairo_t *cr = gdk_cairo_create(window);
|
||||||
|
cairo_save(cr);
|
||||||
|
cairo_rectangle(cr, event->area.x, event->area.y, event->area.width, event->area.height);
|
||||||
|
cairo_clip(cr);
|
||||||
|
draw(widget, cr, data);
|
||||||
|
cairo_restore(cr);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
draw(GtkWidget *widget, cairo_t *cr, gpointer data)
|
||||||
|
{
|
||||||
|
struct CalibArea *calib_area = (struct CalibArea*)data;
|
||||||
|
int i;
|
||||||
|
double text_height;
|
||||||
|
double text_width;
|
||||||
|
double x;
|
||||||
|
double y;
|
||||||
|
cairo_text_extents_t extent;
|
||||||
|
|
||||||
|
resize_display(calib_area);
|
||||||
|
|
||||||
|
/* Print the text */
|
||||||
|
cairo_set_font_size(cr, font_size);
|
||||||
|
text_height = -1;
|
||||||
|
text_width = -1;
|
||||||
|
for (i = 0; i != HELP_LINES; i++)
|
||||||
|
{
|
||||||
|
cairo_text_extents(cr, help_text[i], &extent);
|
||||||
|
text_width = MAXIMUM(text_width, extent.width);
|
||||||
|
text_height = MAXIMUM(text_height, extent.height);
|
||||||
|
}
|
||||||
|
text_height += 2;
|
||||||
|
|
||||||
|
x = (calib_area->display_width - text_width) / 2;
|
||||||
|
y = (calib_area->display_height - text_height) / 2 - 60;
|
||||||
|
cairo_set_line_width(cr, 2);
|
||||||
|
cairo_rectangle(cr, x - 10, y - (HELP_LINES*text_height) - 10,
|
||||||
|
text_width + 20, (HELP_LINES*text_height) + 20);
|
||||||
|
|
||||||
|
/* Print help lines */
|
||||||
|
y -= 3;
|
||||||
|
for (i = HELP_LINES-1; i != -1; i--)
|
||||||
|
{
|
||||||
|
cairo_text_extents(cr, help_text[i], &extent);
|
||||||
|
cairo_move_to(cr, x + (text_width-extent.width)/2, y);
|
||||||
|
cairo_show_text(cr, help_text[i]);
|
||||||
|
y -= text_height;
|
||||||
|
}
|
||||||
|
cairo_stroke(cr);
|
||||||
|
|
||||||
|
/* Draw the points */
|
||||||
|
for (i = 0; i <= calib_area->calibrator->num_clicks; i++)
|
||||||
|
{
|
||||||
|
/* set color: already clicked or not */
|
||||||
|
if (i < calib_area->calibrator->num_clicks)
|
||||||
|
cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
|
||||||
|
else
|
||||||
|
cairo_set_source_rgb(cr, 0.8, 0.0, 0.0);
|
||||||
|
|
||||||
|
cairo_set_line_width(cr, 1);
|
||||||
|
cairo_move_to(cr, calib_area->X[i] - cross_lines, calib_area->Y[i]);
|
||||||
|
cairo_rel_line_to(cr, cross_lines*2, 0);
|
||||||
|
cairo_move_to(cr, calib_area->X[i], calib_area->Y[i] - cross_lines);
|
||||||
|
cairo_rel_line_to(cr, 0, cross_lines*2);
|
||||||
|
cairo_stroke(cr);
|
||||||
|
|
||||||
|
cairo_arc(cr, calib_area->X[i], calib_area->Y[i], cross_circle, 0.0, 2.0 * M_PI);
|
||||||
|
cairo_stroke(cr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Draw the clock background */
|
||||||
|
cairo_arc(cr, calib_area->display_width/2, calib_area->display_height/2, clock_radius/2, 0.0, 2.0 * M_PI);
|
||||||
|
cairo_set_source_rgb(cr, 0.5, 0.5, 0.5);
|
||||||
|
cairo_fill_preserve(cr);
|
||||||
|
cairo_stroke(cr);
|
||||||
|
|
||||||
|
cairo_set_line_width(cr, clock_line_width);
|
||||||
|
cairo_arc(cr, calib_area->display_width/2, calib_area->display_height/2, (clock_radius - clock_line_width)/2,
|
||||||
|
3/2.0*M_PI, (3/2.0*M_PI) + ((double)calib_area->time_elapsed/(double)max_time) * 2*M_PI);
|
||||||
|
cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
|
||||||
|
cairo_stroke(cr);
|
||||||
|
|
||||||
|
|
||||||
|
/* Draw the message (if any) */
|
||||||
|
if (calib_area->message != NULL)
|
||||||
|
{
|
||||||
|
/* Frame the message */
|
||||||
|
cairo_set_font_size(cr, font_size);
|
||||||
|
cairo_text_extents(cr, calib_area->message, &extent);
|
||||||
|
text_width = extent.width;
|
||||||
|
text_height = extent.height;
|
||||||
|
|
||||||
|
x = (calib_area->display_width - text_width) / 2;
|
||||||
|
y = (calib_area->display_height - text_height + clock_radius) / 2 + 60;
|
||||||
|
cairo_set_line_width(cr, 2);
|
||||||
|
cairo_rectangle(cr, x - 10, y - text_height - 10,
|
||||||
|
text_width + 20, text_height + 25);
|
||||||
|
|
||||||
|
/* Print the message */
|
||||||
|
cairo_move_to(cr, x, y);
|
||||||
|
cairo_show_text(cr, calib_area->message);
|
||||||
|
cairo_stroke(cr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
redraw(struct CalibArea *calib_area)
|
||||||
|
{
|
||||||
|
GdkWindow *win = gtk_widget_get_window(calib_area->drawing_area);
|
||||||
|
if (win)
|
||||||
|
{
|
||||||
|
GdkRectangle rect;
|
||||||
|
rect.x = 0;
|
||||||
|
rect.y = 0;
|
||||||
|
rect.width = calib_area->display_width;
|
||||||
|
rect.height = calib_area->display_height;
|
||||||
|
gdk_window_invalidate_rect(win, &rect, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
on_timer_signal(struct CalibArea *calib_area)
|
||||||
|
{
|
||||||
|
GdkWindow *win;
|
||||||
|
GtkWidget *parent = gtk_widget_get_parent(calib_area->drawing_area);
|
||||||
|
|
||||||
|
calib_area->time_elapsed += time_step;
|
||||||
|
if (calib_area->time_elapsed > max_time || parent == NULL)
|
||||||
|
{
|
||||||
|
if (parent)
|
||||||
|
gtk_widget_destroy(parent);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update clock */
|
||||||
|
win = gtk_widget_get_window(calib_area->drawing_area);
|
||||||
|
if (win)
|
||||||
|
{
|
||||||
|
GdkRectangle rect;
|
||||||
|
rect.x = calib_area->display_width/2 - clock_radius - clock_line_width;
|
||||||
|
rect.y = calib_area->display_height/2 - clock_radius - clock_line_width;
|
||||||
|
rect.width = 2 * clock_radius + 1 + 2 * clock_line_width;
|
||||||
|
rect.height = 2 * clock_radius + 1 + 2 * clock_line_width;
|
||||||
|
gdk_window_invalidate_rect(win, &rect, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
on_button_press_event(GtkWidget *widget,
|
||||||
|
GdkEventButton *event,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
struct CalibArea *calib_area = (struct CalibArea*)data;
|
||||||
|
bool success;
|
||||||
|
|
||||||
|
/* Handle click */
|
||||||
|
calib_area->time_elapsed = 0;
|
||||||
|
success = add_click(calib_area->calibrator, (int)event->x_root, (int)event->y_root);
|
||||||
|
|
||||||
|
if (!success && calib_area->calibrator->num_clicks == 0)
|
||||||
|
draw_message(calib_area, "Mis-click detected, restarting...");
|
||||||
|
else
|
||||||
|
draw_message(calib_area, NULL);
|
||||||
|
|
||||||
|
/* Are we done yet? */
|
||||||
|
if (calib_area->calibrator->num_clicks >= 4)
|
||||||
|
{
|
||||||
|
GtkWidget *parent = gtk_widget_get_parent(calib_area->drawing_area);
|
||||||
|
if (parent)
|
||||||
|
gtk_widget_destroy(parent);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Force a redraw */
|
||||||
|
redraw(calib_area);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
draw_message(struct CalibArea *calib_area,
|
||||||
|
const char *msg)
|
||||||
|
{
|
||||||
|
calib_area->message = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
on_key_press_event(GtkWidget *widget,
|
||||||
|
GdkEventKey *event,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
struct CalibArea *calib_area = (struct CalibArea*)data;
|
||||||
|
GtkWidget *parent = gtk_widget_get_parent(calib_area->drawing_area);
|
||||||
|
if (parent)
|
||||||
|
gtk_widget_destroy(parent);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the windows and other objects required to do calibration
|
||||||
|
* under GTK and then starts the main loop. When the main loop exits,
|
||||||
|
* the calibration will be calculated (if possible) and this function
|
||||||
|
* will then return ('true' if successful, 'false' otherwise).
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
run_gui(struct Calib *c,
|
||||||
|
XYinfo *new_axys,
|
||||||
|
bool *swap)
|
||||||
|
{
|
||||||
|
bool success;
|
||||||
|
struct CalibArea *calib_area = CalibrationArea_(c);
|
||||||
|
|
||||||
|
printf("Current calibration: %d, %d, %d, %d\n",
|
||||||
|
c->old_axys.x_min,
|
||||||
|
c->old_axys.y_min,
|
||||||
|
c->old_axys.x_max,
|
||||||
|
c->old_axys.y_max);
|
||||||
|
|
||||||
|
GdkScreen *screen = gdk_screen_get_default();
|
||||||
|
GtkWidget *win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||||
|
GdkRectangle rect;
|
||||||
|
/*int num_monitors = screen->get_n_monitors(); TODO, multiple monitors?*/
|
||||||
|
|
||||||
|
g_signal_connect(G_OBJECT(win), "destroy", G_CALLBACK(gtk_main_quit), NULL);
|
||||||
|
|
||||||
|
gdk_screen_get_monitor_geometry(screen, 0, &rect);
|
||||||
|
|
||||||
|
/* when no window manager: explicitely take size of full screen */
|
||||||
|
gtk_window_move(GTK_WINDOW(win), rect.x, rect.y);
|
||||||
|
gtk_window_set_default_size(GTK_WINDOW(win), rect.width, rect.height);
|
||||||
|
|
||||||
|
/* in case of window manager: set as full screen to hide window decorations */
|
||||||
|
gtk_window_fullscreen(GTK_WINDOW(win));
|
||||||
|
|
||||||
|
gtk_container_add(GTK_CONTAINER(win), calib_area->drawing_area);
|
||||||
|
gtk_widget_show_all(win);
|
||||||
|
|
||||||
|
printf("gtk_main entered!\n");
|
||||||
|
gtk_main();
|
||||||
|
printf("gtk_main returned!\n");
|
||||||
|
|
||||||
|
success = finish(calib_area->calibrator, calib_area->display_width, calib_area->display_height, new_axys, swap);
|
||||||
|
|
||||||
|
printf("Final calibration: %d, %d, %d, %d\n",
|
||||||
|
new_axys->x_min,
|
||||||
|
new_axys->y_min,
|
||||||
|
new_axys->x_max,
|
||||||
|
new_axys->y_max);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
68
panels/wacom/calibrator/gui_gtk.h
Normal file
68
panels/wacom/calibrator/gui_gtk.h
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* 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_gtk_h
|
||||||
|
#define _gui_gtk_h
|
||||||
|
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
|
#include "calibrator.h"
|
||||||
|
|
||||||
|
struct CalibArea
|
||||||
|
{
|
||||||
|
struct Calib* calibrator;
|
||||||
|
double X[4], Y[4];
|
||||||
|
int display_width, display_height;
|
||||||
|
int time_elapsed;
|
||||||
|
|
||||||
|
const char* message;
|
||||||
|
|
||||||
|
GtkWidget *drawing_area;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CalibArea* CalibrationArea_ (struct Calib *c);
|
||||||
|
void set_display_size (struct CalibArea *calib_area,
|
||||||
|
int width,
|
||||||
|
int height);
|
||||||
|
void resize_display (struct CalibArea *calib_area);
|
||||||
|
bool on_expose_event (GtkWidget *widget,
|
||||||
|
GdkEventExpose *event,
|
||||||
|
gpointer data);
|
||||||
|
void draw (GtkWidget *widget,
|
||||||
|
cairo_t *cr,
|
||||||
|
gpointer data);
|
||||||
|
void redraw (struct CalibArea *calib_area);
|
||||||
|
bool on_timer_signal (struct CalibArea *calib_area);
|
||||||
|
bool on_button_press_event (GtkWidget *widget,
|
||||||
|
GdkEventButton *event,
|
||||||
|
gpointer data);
|
||||||
|
void draw_message (struct CalibArea *calib_area,
|
||||||
|
const char *msg);
|
||||||
|
bool on_key_press_event (GtkWidget *widget,
|
||||||
|
GdkEventKey *event,
|
||||||
|
gpointer data);
|
||||||
|
bool run_gui (struct Calib *c,
|
||||||
|
XYinfo *new_axys,
|
||||||
|
bool *swap);
|
||||||
|
|
||||||
|
#endif /* _gui_gtk_h */
|
398
panels/wacom/calibrator/main.c
Normal file
398
panels/wacom/calibrator/main.c
Normal file
|
@ -0,0 +1,398 @@
|
||||||
|
/*
|
||||||
|
* 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 <stdlib.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
|
||||||
|
#include <X11/extensions/XInput.h>
|
||||||
|
|
||||||
|
#include "gui_gtk.h"
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 find_device(const char* pre_device, bool verbose, 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);
|
||||||
|
int loop;
|
||||||
|
for (loop=0; loop<len; loop++) {
|
||||||
|
if (!isdigit(pre_device[loop])) {
|
||||||
|
pre_device_is_id = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
printf("DEBUG: Skipping virtual master devices and devices without axis valuators.\n");
|
||||||
|
int ndevices;
|
||||||
|
XDeviceInfoPtr list, slist;
|
||||||
|
slist=list=(XDeviceInfoPtr) XListInputDevices (display, &ndevices);
|
||||||
|
int i;
|
||||||
|
for (i=0; i<ndevices; i++, list++)
|
||||||
|
{
|
||||||
|
if (list->use == IsXKeyboard || list->use == IsXPointer) /* virtual master device */
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* if we are looking for a specific device */
|
||||||
|
if (pre_device != NULL) {
|
||||||
|
if ((pre_device_is_id && list->id == (XID) atoi(pre_device)) ||
|
||||||
|
(!pre_device_is_id && strcmp(list->name, pre_device) == 0)) {
|
||||||
|
/* OK, fall through */
|
||||||
|
} else {
|
||||||
|
/* skip, not this device */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XAnyClassPtr any = (XAnyClassPtr) (list->inputclassinfo);
|
||||||
|
int j;
|
||||||
|
for (j=0; j<list->num_classes; j++)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (any->class == ValuatorClass)
|
||||||
|
{
|
||||||
|
XValuatorInfoPtr V = (XValuatorInfoPtr) any;
|
||||||
|
XAxisInfoPtr ax = (XAxisInfoPtr) V->axes;
|
||||||
|
|
||||||
|
if (V->mode != Absolute) {
|
||||||
|
if (verbose)
|
||||||
|
printf("DEBUG: Skipping device '%s' id=%i, does not report Absolute events.\n",
|
||||||
|
list->name, (int)list->id);
|
||||||
|
} else if (V->num_axes < 2 ||
|
||||||
|
(ax[0].min_value == -1 && ax[0].max_value == -1) ||
|
||||||
|
(ax[1].min_value == -1 && ax[1].max_value == -1)) {
|
||||||
|
if (verbose)
|
||||||
|
printf("DEBUG: Skipping device '%s' id=%i, does not have two calibratable axes.\n",
|
||||||
|
list->name, (int)list->id);
|
||||||
|
} else {
|
||||||
|
/* a calibratable device (has 2 axis valuators) */
|
||||||
|
found++;
|
||||||
|
*device_id = list->id;
|
||||||
|
*device_name = 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--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");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Calib* main_common(int argc, char** argv)
|
||||||
|
{
|
||||||
|
bool verbose = false;
|
||||||
|
bool list_devices = false;
|
||||||
|
bool fake = false;
|
||||||
|
bool precalib = false;
|
||||||
|
XYinfo pre_axys = {-1, -1, -1, -1};
|
||||||
|
const char* pre_device = NULL;
|
||||||
|
const char* geometry = 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) {
|
||||||
|
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
|
||||||
|
|
||||||
|
/* specify window geometry? */
|
||||||
|
if (strcmp("--geometry", argv[i]) == 0) {
|
||||||
|
geometry = argv[++i];
|
||||||
|
/* sscanf(argv[++i],"%dx%d",&win_width,&win_height); */
|
||||||
|
} 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 = {-1, -1, -1, -1};
|
||||||
|
if (fake) {
|
||||||
|
/* Fake a calibratable device */
|
||||||
|
device_name = "Fake_device";
|
||||||
|
device_axys.x_min=0;
|
||||||
|
device_axys.x_max=1000;
|
||||||
|
device_axys.y_min=0;
|
||||||
|
device_axys.y_max=1000;
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
printf("DEBUG: Faking device: %s\n", device_name);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Find the right device */
|
||||||
|
int nr_found = find_device(pre_device, verbose, list_devices, &device_id, &device_name, &device_axys);
|
||||||
|
|
||||||
|
if (list_devices) {
|
||||||
|
/* printed the list in find_device */
|
||||||
|
if (nr_found == 0)
|
||||||
|
printf("No calibratable devices found.\n");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nr_found == 0) {
|
||||||
|
if (pre_device == NULL)
|
||||||
|
fprintf (stderr, "Error: No calibratable devices found.\n");
|
||||||
|
else
|
||||||
|
fprintf (stderr, "Error: Device \"%s\" not found; use --list to list the calibratable input devices.\n", pre_device);
|
||||||
|
exit(1);
|
||||||
|
|
||||||
|
} else if (nr_found > 1) {
|
||||||
|
printf ("Warning: multiple calibratable devices found, calibrating last one (%s)\n\tuse --device to select another one.\n", device_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
printf("DEBUG: Selected device: %s\n", device_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* override min/max XY from command line ? */
|
||||||
|
if (precalib) {
|
||||||
|
if (pre_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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* lastly, presume a standard Xorg driver (evtouch, mutouch, ...) */
|
||||||
|
return CalibratorXorgPrint(device_name, &device_axys,
|
||||||
|
verbose, thr_misclick, thr_doubleclick, geometry);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Calib* CalibratorXorgPrint(const char* const device_name0, const XYinfo *axys0, const bool verbose0, const int thr_misclick, const int thr_doubleclick, const char* geometry)
|
||||||
|
{
|
||||||
|
struct Calib* c = (struct Calib*)calloc(1, sizeof(struct Calib));
|
||||||
|
c->old_axys = *axys0;
|
||||||
|
c->threshold_misclick = thr_misclick;
|
||||||
|
c->threshold_doubleclick = thr_doubleclick;
|
||||||
|
c->geometry = geometry;
|
||||||
|
|
||||||
|
printf("Calibrating standard Xorg driver \"%s\"\n", device_name0);
|
||||||
|
printf("\tcurrent calibration values: min_x=%d, max_x=%d and min_y=%d, max_y=%d\n",
|
||||||
|
c->old_axys.x_min, c->old_axys.x_max, c->old_axys.y_min, c->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");
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool finish_data(struct Calib* c, const XYinfo new_axys, int swap_xy)
|
||||||
|
{
|
||||||
|
bool success = true;
|
||||||
|
|
||||||
|
/* we suppose the previous 'swap_xy' value was 0 */
|
||||||
|
/* (unfortunately there is no way to verify this (yet)) */
|
||||||
|
int new_swap_xy = swap_xy;
|
||||||
|
|
||||||
|
printf("\n\n--> Making the calibration permanent <--\n");
|
||||||
|
success &= output_xorgconfd(c, new_axys, swap_xy, new_swap_xy);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool output_xorgconfd(struct Calib* c, const XYinfo new_axys, int swap_xy, int new_swap_xy)
|
||||||
|
{
|
||||||
|
const char* sysfs_name = "!!Name_Of_TouchScreen!!";
|
||||||
|
|
||||||
|
/* xorg.conf.d snippet */
|
||||||
|
printf(" copy the snippet below into '/etc/X11/xorg.conf.d/99-calibration.conf'\n");
|
||||||
|
printf("Section \"InputClass\"\n");
|
||||||
|
printf(" Identifier \"calibration\"\n");
|
||||||
|
printf(" MatchProduct \"%s\"\n", sysfs_name);
|
||||||
|
printf(" Option \"MinX\" \"%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);
|
||||||
|
if (swap_xy != 0)
|
||||||
|
printf(" Option \"SwapXY\" \"%d\" # unless it was already set to 1\n", new_swap_xy);
|
||||||
|
printf("EndSection\n");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
int success = 0;
|
||||||
|
XYinfo axys;
|
||||||
|
bool swap_xy;
|
||||||
|
|
||||||
|
struct Calib* calibrator = main_common(argc, argv);
|
||||||
|
|
||||||
|
/* GTK setup */
|
||||||
|
gtk_init(&argc, &argv);
|
||||||
|
|
||||||
|
success = run_gui(calibrator, &axys, &swap_xy);
|
||||||
|
if (success)
|
||||||
|
success = finish_data(calibrator, axys, swap_xy);
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
/* TODO, in GUI ? */
|
||||||
|
fprintf(stderr, "Error: unable to apply or save configuration values\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
free(calibrator);
|
||||||
|
return success;
|
||||||
|
}
|
57
panels/wacom/calibrator/main.h
Normal file
57
panels/wacom/calibrator/main.h
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
* 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 _main_h
|
||||||
|
#define _main_h
|
||||||
|
|
||||||
|
#include "calibrator.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* strdup: non-ansi */
|
||||||
|
char* my_strdup(const char* s);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
int find_device(const char*, bool, bool, XID*, const char**, XYinfo*);
|
||||||
|
|
||||||
|
static void usage(char* cmd, unsigned thr_misclick);
|
||||||
|
|
||||||
|
struct Calib* main_common(int argc, char** argv);
|
||||||
|
|
||||||
|
struct Calib* CalibratorXorgPrint(const char* const device_name, const XYinfo *axys,
|
||||||
|
const bool verbose, const int thr_misclick, const int thr_doubleclick,
|
||||||
|
const char* geometry);
|
||||||
|
|
||||||
|
bool finish_data(struct Calib*, const XYinfo new_axys, int swap_xy);
|
||||||
|
bool output_xorgconfd(struct Calib*, const XYinfo new_axys, int swap_xy, int new_swap_xy);
|
||||||
|
|
||||||
|
int main(int argc, char** argv);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Add table
Add a link
Reference in a new issue