gtktscal/main.c

Go to the documentation of this file.
00001 /*
00002  * File Name: main.c
00003  */
00004 
00005 /*
00006  * This file is part of gtktscal.
00007  *
00008  * gtktscal is free software: you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation, either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * gtktscal is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program. If not, see <http://www.gnu.org/licenses/>.
00020  */
00021 
00022 /*
00023  * This code is originally from xtscal:
00024  *
00025  * Copyright (C) 2003, 2004 Philip Blundell <philb@gnu.org>
00026  *
00027  * Modifications:
00028  *
00029  * Copyright (C) 2008 iRex Technologies B.V.
00030  */
00031 
00032 #include <stdlib.h>
00033 #include <stdio.h>
00034 #include <errno.h>
00035 #include <unistd.h>
00036 #include <math.h>
00037 #include <string.h>
00038 #include <sys/ioctl.h>
00039 
00040 #include <glib.h>
00041 #include <gtk/gtk.h>
00042 #include <gdk/gdk.h>
00043 #include <gdk/gdkx.h>
00044 
00045 #include <X11/extensions/xcalibrate.h>
00046 #include <X11/extensions/Xrandr.h>
00047 
00048 #include "h3600_ts.h"
00049 #include "calibrate.h"
00050 #include "i18n.h"
00051 #include "ts.h"
00052 
00053 Display *dpy;
00054 int screen_x = 768;
00055 int screen_y = 1024;
00056 int flag_debug = 0;
00057 int flag_sanityCheck = 1;
00058 int flag_firstBoot = 0;
00059 int rotation = 0;
00060 int xcal_error_base;
00061 int xcal_event_base;
00062 int calibration_done = 0;
00063 GtkWidget *da;
00064 char* g_defaultcalfile = "/home/root/.pointercal";
00065 char* g_calfile = NULL;
00066 GdkGC* gc = NULL;
00067 
00068 /**
00069   * Show usage
00070   */ 
00071 void usage (const char *name)
00072 {
00073     fprintf (stderr, "usage: %s -view\n", name);
00074     fprintf (stderr, "       %s [-rotate <0 | 90 | 180 | 270>]\n", name);
00075     fprintf (stderr, "       %s -cal <xs> <xt> <ys> <yt> <xyswap>\n", name);
00076     fprintf (stderr, "       %s [-nocheck]\n", name);
00077     fprintf (stderr, "       %s [-firstboot]\n", name);
00078     fprintf (stderr, "       %s [-debug]\n", name);
00079     
00080     exit (1);
00081 }
00082 
00083 /**
00084   * Parse commandline args
00085   */ 
00086 void parse_args(int argc, char *argv[])
00087 {
00088     int i;
00089     for (i = 1; i < argc; i++)
00090     {
00091         if (!strcmp (argv[i], "-view"))
00092         {
00093             ts_show_calibration();
00094             exit (0);
00095         }
00096         else if (!strcmp (argv[i], "-debug"))
00097         {
00098             flag_debug = 1;
00099         }
00100         else if (!strcmp (argv[i], "-firstboot"))
00101         {
00102             flag_firstBoot = 1;
00103         }
00104         else if (!strcmp (argv[i], "-nocheck"))
00105         {
00106             flag_sanityCheck = 0;
00107         }
00108         else if (!strcmp (argv[i], "-cal"))
00109         {
00110             if (argc > (i + 5))
00111             {
00112                 ts_set_calibration(argv + i + 1);
00113                 exit(0); 
00114             }
00115             else
00116             {
00117                 usage (argv[0]);
00118             }
00119         }
00120         else if (!strcmp (argv[i], "-rotate"))
00121         {
00122             if (argc > (i + 1))
00123                 rotation = atoi (argv[++i]);
00124             else
00125                 usage (argv[0]);
00126         }
00127         else
00128         {
00129             usage(argv[0]);
00130         }
00131     }
00132 }
00133 
00134 /**
00135   * Check for XRandR
00136   */
00137 int xrandr_supported()
00138 {
00139     int xrr_event_base, xrr_error_base;
00140     int xrr_major, xrr_minor;
00141     
00142     if (XRRQueryExtension (dpy, &xrr_event_base, &xrr_error_base) == False
00143         || XRRQueryVersion (dpy, &xrr_major, &xrr_minor) == 0
00144         || xrr_major != 1
00145         || xrr_minor < 1)
00146         return 0;
00147     
00148     return 1;
00149 }
00150 
00151 /**
00152   * Update the drawing area when we move to a new target (the crosshair needs
00153   * to be moved)
00154   */
00155 void next_target()
00156 {
00157     gtk_widget_queue_draw(da);    
00158     gdk_flush();
00159 }
00160 
00161 
00162 /**
00163   * Quit application on timeout 
00164   */ 
00165 gboolean on_delayed_quit(gpointer data)
00166 { 
00167     gtk_main_quit();
00168     return FALSE;
00169 }
00170 
00171 /**
00172   * Handle a XCalibrate event
00173   */ 
00174 GdkFilterReturn evt_filter(GdkXEvent *xevent, GdkEvent *event, gpointer data)
00175 {
00176     XEvent *xev = (XEvent*)xevent;
00177     int ret;
00178     // check if this is a xcalibrate event
00179     if (xev->type==xcal_event_base && (!calibration_done)) 
00180     {
00181         XCalibrateRawTouchscreenEvent *tev = (XCalibrateRawTouchscreenEvent*)xev;
00182         ret = ts_handle_event (tev->x, tev->y, tev->pressure);
00183         // if we're done, save, disable xcalibrate, and quit
00184         if (ret==TS_CALIBRATION_DONE)
00185         {
00186             calibration_done = 1;
00187             ts_write_calibration (g_calfile);
00188             XCalibrateSetRawMode (dpy, False);
00189             // Show confirmation message
00190             next_target();
00191             g_timeout_add_seconds(flag_firstBoot ? 1 : 2, on_delayed_quit, NULL);
00192         }
00193     }
00194     return GDK_FILTER_CONTINUE;  
00195 }
00196 
00197 /**
00198   * Draw a cross icon on a widget
00199   */ 
00200 static void draw_cross(GtkWidget *widget, gdouble x, gdouble y)
00201 {
00202     int size = 8;
00203 
00204     if (!gc)
00205     {
00206         gc = gdk_gc_new(widget->window);
00207         gdk_gc_copy(gc, widget->style->black_gc);
00208         gdk_gc_set_line_attributes (gc, 2, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER);
00209     }
00210     gdk_draw_line(widget->window, gc, 
00211                   x-size, y-size, x+size, y+size);
00212     gdk_draw_line(widget->window, gc, 
00213                   x-size, y+size, x+size, y-size);
00214 }
00215 
00216 /**
00217   * Handle the drawing area expose event. Draw crosshair and text.
00218   */ 
00219 static gboolean da_expose (GtkWidget *da, GdkEventExpose *evt, gpointer data)
00220 {
00221     char *msg = NULL;
00222     
00223     if (calibration_done) 
00224     {
00225         msg = g_strdup(_("The stylus is now calibrated with this device."));
00226     }
00227     else
00228     {
00229         char *tip = NULL; 
00230         tip = _("Touch the center of each cross with the stylus as they appear on the screen.\n\n"
00231                 "For the most accurate result, hold the stylus comfortably in your hand and "
00232                 "touch the screen at the same angle as you would when you write with a regular "
00233                 "pen on paper.");
00234 
00235         if (flag_firstBoot)
00236         {
00237             msg = g_strconcat(_("Before you continue, you need to calibrate the stylus. After this short "
00238                                 "calibration, you will be able to work more accurately with the device.\n\n"), tip, NULL);
00239         }
00240         else
00241         {
00242             msg = g_strdup(tip);
00243         }
00244     }
00245 
00246     // draw text
00247     PangoLayout *layout = gtk_widget_create_pango_layout(da, msg);
00248     pango_layout_set_width(layout, pango_units_from_double(screen_x)*2/3);
00249     int x, y;
00250     int lw, lh;
00251     ts_get_target(0, &x, &y);
00252     pango_layout_get_pixel_size(layout, &lw, &lh);
00253     // top of text box = 
00254     //    centre point between top cross and middle cross ((screen_y/2)+y)/2
00255     //    -
00256     //    half height of text box (lh/2)
00257     int ypos = (((screen_y/2)+y)/2) - (lh/2); 
00258     pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
00259     gdk_draw_layout(da->window, da->style->black_gc, screen_x/6, ypos, layout);
00260     g_object_unref(layout);
00261     if (!calibration_done) 
00262     {
00263         // get crosshair locations and draw
00264         int x,y;
00265         ts_get_current_target(&x, &y);
00266         draw_cross(da, x, y);
00267     }
00268     g_free(msg);
00269     gdk_flush();
00270     return TRUE;
00271 }
00272 
00273 
00274 static gboolean my_gdk_flush(gpointer data)
00275 {
00276     gdk_flush();
00277     return FALSE;
00278 }
00279 
00280 /**
00281   * Main
00282   */ 
00283 int main (int argc, char *argv[])
00284 {
00285     GtkWidget *window;
00286     int screen;
00287 
00288     // init domain for translations
00289     textdomain(GETTEXT_PACKAGE);
00290 
00291     // Initialise
00292     gtk_init(&argc, &argv);
00293     parse_args(argc, argv);
00294     if ((g_calfile = getenv("TSLIB_CALIBFILE")) == NULL)
00295     {
00296         g_calfile = g_defaultcalfile;
00297     }
00298     // read current calibration settings
00299     ts_read_current_settings(g_calfile);
00300     // create window
00301     window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
00302     gtk_window_set_title(GTK_WINDOW(window), PACKAGE " " VERSION);
00303     gtk_window_maximize(GTK_WINDOW(window));
00304     gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
00305     gtk_container_set_border_width(GTK_CONTAINER(window), 0);
00306     gtk_window_set_modal(GTK_WINDOW(window), TRUE);
00307     gtk_window_fullscreen(GTK_WINDOW(window));
00308     // add listener for XCalibrate events
00309     gdk_window_add_filter(NULL, evt_filter, NULL);
00310     // Get X Display
00311     GdkDisplay *gdpy = gdk_display_get_default();
00312     dpy = gdk_x11_display_get_xdisplay(gdpy);
00313     screen = DefaultScreen(dpy);
00314     // Create drawing area    
00315     da = gtk_drawing_area_new ();
00316     gtk_widget_set_size_request (da, screen_x, screen_y);
00317     gtk_container_add (GTK_CONTAINER (window), da);
00318     g_signal_connect (da, "expose_event", G_CALLBACK (da_expose), NULL);
00319     // Setup XCalibrate
00320     if (XCalibrateQueryExtension (dpy, &xcal_event_base, &xcal_error_base))
00321     {
00322         int r;   
00323         r = XCalibrateSetRawMode (dpy, True);
00324         if (r)
00325         {
00326             fprintf (stderr, "failed to set raw mode: error %d\n", r);
00327             exit (1);
00328         }
00329     } else {
00330         fprintf (stderr, "XCalibrate extension not available, unable to calibrate\n");
00331         exit (1);
00332     }
00333     // Setup XRandR
00334     if (xrandr_supported())
00335     {
00336         // read screen info
00337         XRRScreenConfiguration *rr_screen;
00338         XRRScreenSize *rr_sizes;
00339         int rr_num_sizes;
00340         Rotation current_rotation;
00341         rr_screen = XRRGetScreenInfo (dpy, RootWindow (dpy, screen));
00342         XRRRotations (dpy, screen, &current_rotation);
00343         rr_sizes = XRRSizes(dpy, screen, &rr_num_sizes);
00344         XRRFreeScreenConfigInfo (rr_screen);
00345         // set rotation
00346         switch (current_rotation)
00347         {
00348             case RR_Rotate_0:   rotation = 0; break;
00349             case RR_Rotate_90:  rotation = 90; break;
00350             case RR_Rotate_180: rotation = 180; break;
00351             case RR_Rotate_270: rotation = 270; break;
00352         }
00353         // set width/height if rotated
00354         if (rotation==90 || rotation==270)
00355         {
00356             screen_x = rr_sizes->height;
00357             screen_y = rr_sizes->width;
00358         }
00359         else
00360         {
00361             screen_x = rr_sizes->width;
00362             screen_y = rr_sizes->height;
00363         }
00364     }
00365     if (flag_debug)
00366     {
00367         fprintf (stderr, "Screen %dx%d rotated %d\n", screen_x, screen_y, rotation);
00368     }
00369     
00370     // initialise calibration structure
00371     ts_init(screen_x, screen_y, rotation);
00372     // show it
00373     gtk_widget_show_all(window);
00374     g_idle_add(my_gdk_flush, NULL);
00375     
00376     gtk_main();
00377     
00378     return 0;
00379 }
Generated by  doxygen 1.6.2-20100208