[gnome-control-center] wacom: Bring over files from xinput-calibrator and build utility



commit e50dbea1953b24e2f3b5de137b339d31784f0dc7
Author: Jason Gerecke <killertofu gmail com>
Date:   Tue Jan 3 12:39:06 2012 -0800

    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

 configure.ac                         |    1 +
 panels/wacom/Makefile.am             |    7 +-
 panels/wacom/calibrator/Makefile.am  |   38 +++
 panels/wacom/calibrator/calibrator.c |  177 +++++++++++++++
 panels/wacom/calibrator/calibrator.h |  119 ++++++++++
 panels/wacom/calibrator/gui_gtk.c    |  411 ++++++++++++++++++++++++++++++++++
 panels/wacom/calibrator/gui_gtk.h    |   68 ++++++
 panels/wacom/calibrator/main.c       |  398 ++++++++++++++++++++++++++++++++
 panels/wacom/calibrator/main.h       |   57 +++++
 9 files changed, 1274 insertions(+), 2 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 1d7ac0d..d8cf527 100644
--- a/configure.ac
+++ b/configure.ac
@@ -401,6 +401,7 @@ panels/user-accounts/data/gnome-user-accounts-panel.desktop.in
 panels/user-accounts/data/faces/Makefile
 panels/user-accounts/data/icons/Makefile
 panels/wacom/Makefile
+panels/wacom/calibrator/Makefile
 panels/wacom/gnome-wacom-panel.desktop.in
 po/Makefile.in
 shell/Makefile
diff --git a/panels/wacom/Makefile.am b/panels/wacom/Makefile.am
index ba4ec69..6d61c1a 100644
--- a/panels/wacom/Makefile.am
+++ b/panels/wacom/Makefile.am
@@ -1,9 +1,12 @@
 # This is used in PANEL_CFLAGS
 cappletname = wacom
 
+SUBDIRS = calibrator
+
 INCLUDES = 						\
 	$(PANEL_CFLAGS)					\
 	$(WACOM_PANEL_CFLAGS)				\
+	-I$(srcdir)/calibrator				\
 	-DGNOMELOCALEDIR="\"$(datadir)/locale\""	\
 	-DGNOMECC_DATA_DIR="\"$(pkgdatadir)\""		\
 	-DGNOMECC_UI_DIR="\"$(uidir)\""			\
@@ -27,7 +30,7 @@ libwacom_properties_la_SOURCES =	\
 	cc-wacom-nav-button.c		\
 	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)
 
 noinst_PROGRAMS = test-wacom
@@ -44,7 +47,7 @@ test_wacom_SOURCES =			\
 	gsd-input-helper.h
 
 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@
 
diff --git a/panels/wacom/calibrator/Makefile.am b/panels/wacom/calibrator/Makefile.am
new file mode 100644
index 0000000..cf223c4
--- /dev/null
+++ b/panels/wacom/calibrator/Makefile.am
@@ -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
diff --git a/panels/wacom/calibrator/calibrator.c b/panels/wacom/calibrator/calibrator.c
new file mode 100644
index 0000000..213d098
--- /dev/null
+++ b/panels/wacom/calibrator/calibrator.c
@@ -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;
+}
+
diff --git a/panels/wacom/calibrator/calibrator.h b/panels/wacom/calibrator/calibrator.h
new file mode 100644
index 0000000..98bc71e
--- /dev/null
+++ b/panels/wacom/calibrator/calibrator.h
@@ -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 */
diff --git a/panels/wacom/calibrator/gui_gtk.c b/panels/wacom/calibrator/gui_gtk.c
new file mode 100644
index 0000000..2a3e970
--- /dev/null
+++ b/panels/wacom/calibrator/gui_gtk.c
@@ -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;
+}
+
diff --git a/panels/wacom/calibrator/gui_gtk.h b/panels/wacom/calibrator/gui_gtk.h
new file mode 100644
index 0000000..b376ff1
--- /dev/null
+++ b/panels/wacom/calibrator/gui_gtk.h
@@ -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 */
diff --git a/panels/wacom/calibrator/main.c b/panels/wacom/calibrator/main.c
new file mode 100644
index 0000000..85dc9e7
--- /dev/null
+++ b/panels/wacom/calibrator/main.c
@@ -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;
+}
diff --git a/panels/wacom/calibrator/main.h b/panels/wacom/calibrator/main.h
new file mode 100644
index 0000000..fa21073
--- /dev/null
+++ b/panels/wacom/calibrator/main.h
@@ -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



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]