Index: /liacs/README
===================================================================
--- /liacs/README	(revision 21)
+++ /liacs/README	(revision 22)
@@ -16,6 +16,8 @@
 nc              =   Natural Computing
 net             =   Netwerken
+mms             =   MultiMediaSystems
 os              =   Operating Systems
 penc            =   Programmeren en Correctheid
+pnbm            =   PetriNets and BioModeling
 pm              =   ProgrammeerMethoden
 re              =   Requirements Engineering
Index: /liacs/mms/assignment2/TalkShadowFun.diff
===================================================================
--- /liacs/mms/assignment2/TalkShadowFun.diff	(revision 22)
+++ /liacs/mms/assignment2/TalkShadowFun.diff	(revision 22)
@@ -0,0 +1,110 @@
+diff -ur ../SRWorkshop/TalkShadowFun/cmdmode.xml ./cmdmode.xml
+--- ../SRWorkshop/TalkShadowFun/cmdmode.xml	2003-10-25 23:19:52.000000000 +0200
++++ ./cmdmode.xml	2009-10-28 14:50:14.000000000 +0100
+@@ -5,6 +5,9 @@
+         <ID NAME="PID_CmdRight" VAL="2"/>
+         <ID NAME="PID_CmdUp" VAL="3"/>
+         <ID NAME="PID_CmdDown" VAL="4"/>
++        <ID NAME="PID_CmdForward" VAL="5"/>
++        <ID NAME="PID_CmdBackward" VAL="6"/>
++
+ 		<ID NAME="PID_CmdNavigation" VAL="1000"/>
+ 			<ID NAME="PID_Moving" VAL="1001"/>
+     </DEFINE>
+@@ -19,6 +22,9 @@
+             <P VAL="PID_CmdUp">higher</P>
+             <P VAL="PID_CmdDown">down</P>
+             <P VAL="PID_CmdDown">lower</P>
++            <P VAL="PID_CmdForward">forward</P>
++            <P VAL="PID_CmdBackward">backward</P>
++
+ 		</L>
+     </RULE>
+ 
+diff -ur ../SRWorkshop/TalkShadowFun/shadowfun.cpp ./shadowfun.cpp
+--- ../SRWorkshop/TalkShadowFun/shadowfun.cpp	2003-10-25 23:14:56.000000000 +0200
++++ ./shadowfun.cpp	2009-10-28 14:50:26.000000000 +0100
+@@ -102,7 +102,7 @@
+ //SR Workshop
+ // Commands
+ enum { 
+-	C_NONE, C_LEFT, C_RIGHT, C_UP, C_DOWN, C_HOME, C_STOP
++	C_NONE, C_LEFT, C_RIGHT, C_UP, C_DOWN, C_HOME, C_STOP, C_FORWARD, C_BACKWARD
+ };
+ 
+ int listening = 0;  // boolean use: 0 = false, 1= true
+@@ -326,6 +326,8 @@
+ 			 if (recogstr.Find("down") != -1) { command = C_DOWN; }
+ 			 if (recogstr.Find("home") != -1) { command = C_HOME; }
+ 			 if (recogstr.Find("stop") != -1) { command = C_STOP; }
++			 if (recogstr.Find("forward") != -1) { command = C_FORWARD; }
++			 if (recogstr.Find("backward") != -1) { command = C_BACKWARD; }
+ 
+              if (fUseTTS)
+              {
+@@ -1080,32 +1082,48 @@
+   glutSwapBuffers();
+ }
+ 
++#define MOVE_FACTOR 0.5
++
+ //SR Workshop
+ void MoveLeft(int value)
+ {
+ 	// value should be in range M_TORUS, M_CUBE, M_SPHERE
+-	animPos[value][X] -= 1.0;
++	animPos[value][X] -= MOVE_FACTOR;
+ }
+ 
+ //SR Workshop
+ void MoveRight(int value)
+ {
+ 	// value should be in range M_TORUS, M_CUBE, M_SPHERE
+-	animPos[value][X] += 1.0;
++	animPos[value][X] += MOVE_FACTOR;
+ }
+ 
+ //SR Workshop
+ void MoveUp(int value)
+ {
+ 	// value should be in range M_TORUS, M_CUBE, M_SPHERE
+-	animPos[value][Y] += 1.0;
++	animPos[value][Y] += MOVE_FACTOR;
+ }
+ 
+ //SR Workshop
+ void MoveDown(int value)
+ {
+ 	// value should be in range M_TORUS, M_CUBE, M_SPHERE
+-	animPos[value][Y] -= 1.0;
++	animPos[value][Y] -= MOVE_FACTOR;
++}
++
++//SR Workshop
++void MoveForward(int value)
++{
++	// value should be in range M_TORUS, M_CUBE, M_SPHERE
++	animPos[value][Z] += MOVE_FACTOR;
++}
++
++//SR Workshop
++void MoveBackward(int value)
++{
++	// value should be in range M_TORUS, M_CUBE, M_SPHERE
++	animPos[value][Z] -= MOVE_FACTOR;
+ }
+ 
+ //SR Workshop
+@@ -1144,6 +1162,12 @@
+ 	  case C_DOWN:
+ 		  MoveDown(M_SPHERE);
+ 		  break;
++      case C_FORWARD:
++		  MoveForward(M_SPHERE);
++		  break;
++	  case C_BACKWARD:
++		  MoveBackward(M_SPHERE);
++		  break;
+ 	  case C_HOME:
+ 		  MoveHome(M_SPHERE);
+ 		  break;
Index: /liacs/mms/assignment2/new.txt
===================================================================
--- /liacs/mms/assignment2/new.txt	(revision 22)
+++ /liacs/mms/assignment2/new.txt	(revision 22)
@@ -0,0 +1,14 @@
+he found himself stemming united states of the facts of the lack of a
+joint chessboard, and prevent where
+
+there was a monster there were 2lbs. next and live with three rows of the
+whole 400 folks and five have
+
+given things and so when he was so to speak looking up through the eyes of
+the young hero of the story
+
+imposed like being a passenger of an optimal you all have to do with
+sports bribery here is that one
+
+month's time offset other benefits funds have to do it just board to work
+towards down power at the end
Index: /liacs/mms/assignment2/new2.txt
===================================================================
--- /liacs/mms/assignment2/new2.txt	(revision 22)
+++ /liacs/mms/assignment2/new2.txt	(revision 22)
@@ -0,0 +1,13 @@
+he found himself standing in a man's it.  Except the recon giant transfer
+from ActiveX where there was a
+
+monster there were some terms makes an eye of the three rows of its and
+400 jobs and 500 human beings and
+
+some he was so to speak milk in a row the eyes of Joan Miro mystery
+thousand I'd be best served "the
+
+mobile all have to do was watch bother to dispatch one monster after
+another and abounds up to just work
+
+towards awards don't talk at the end
Index: /liacs/mms/assignment2/original.txt
===================================================================
--- /liacs/mms/assignment2/original.txt	(revision 22)
+++ /liacs/mms/assignment2/original.txt	(revision 22)
@@ -0,0 +1,8 @@
+He found himself standing in a landscape that looked exactly like a 
+giant chessboard. On every black square there was a monster: there were 
+two-tongued snakes and lions with three rows of teeth, and four-headed 
+dogs and five-headed demon kings and so on. He was, so to speak, 
+looking out through the eyes of the young hero of the story. It was like 
+being in the passenger seat of an automobile: all he had to do was watch, 
+while the hero dispatched one monster after another and advanced up the 
+chessboard towards the white stone tower at the end.
Index: /liacs/mms/assignment2/wer.pl
===================================================================
--- /liacs/mms/assignment2/wer.pl	(revision 22)
+++ /liacs/mms/assignment2/wer.pl	(revision 22)
@@ -0,0 +1,119 @@
+#!/usr/bin/env perl -w
+#
+# Little algoritm to determine the Word Error Rate of speech recognition
+# systems detection.
+#
+# Rick van der Zwet <info@rickvanderzwet.nl>
+# Licence: BSDlike - http://rickvanderzwet.nl/license
+
+
+# While processing look this many words ahead for potential matches. Roughly
+# spoken this number will limit your ability to detect at maximum LOOKFORWARD
+# number of insertions and substitution in one detection cycle.
+$LOOKFORWARD = 10;
+
+# Correct user if needed.
+if ($#ARGV < 1) {
+    print STDERR "Usage: $ARGV[0] <orignal> <new>\n";
+    exit 64;
+}
+
+open ORGINAL, "<$ARGV[0]";
+open NEW, "<$ARGV[1]";
+
+# Sanitize input, put into array
+$tmp = join(" ",<ORGINAL>);
+# Ignore case for the time beeing
+$tmp = lc($tmp);
+# Currently ignoring all punctations and newlines.
+$tmp =~ tr/[\.:,;\n\r]//d;
+@original = split(/[\t\ ]+/,$tmp);
+
+# Sanitize input, put into array
+$tmp = join(" ",<NEW>);
+$tmp = lc($tmp);
+$tmp =~ tr/[\.:,;\n\r]//d;
+@new = split(/[\t\ ]+/, $tmp);
+
+close ORGINAL;
+close NEW;
+
+# Bookkeeping values
+$insert = 0;
+$delete = 0;
+$substitution = 0;
+
+print "------------------\n";
+# XXX: Some way of pretty print the actual text hits/misses
+# Walktrough list comparing matches
+$lasthit_orig = -1;
+$lasthit_new = -1;
+$newhit_orig = -1;
+$newhit_new = -1;
+foreach $np (0 .. $#new) {
+    # Try to find word hit in next words
+    $newhit_orig = -1;
+    $end = $lasthit_orig + $LOOKFORWARD;
+    $end = $#original if $end > $#original;
+    foreach $op ($lasthit_orig .. $end) {
+        if ( $new[$np] eq $original[$op] ) {
+            $newhit_orig = $op;
+            $newhit_new = $np;
+            print "$new[$np] ";
+            last;
+        }
+    }
+    
+    #Little hack to force processing the last words, on end of array, if none
+    #found, deleting does not work properly, will be handled seperately
+    if ($np == $#new and $newhit_orig == -1) {
+        $newhit_orig = $#original + 1;
+        $newhit_new = $#new + 1;
+    }
+
+    # We got a hit
+    if ($newhit_orig >= 0) {
+        # Calculate given diffences till (no including!) last hit
+        $diff_orig = $newhit_orig - $lasthit_orig - 1;
+        $diff_new = $newhit_new - $lasthit_new - 1;
+        $diff_words = $diff_new - $diff_orig;
+
+        # More means inserts, less deleting
+        if ($diff_words > 0) {
+           $insert += $diff_words;
+        } else {
+           $delete += abs($diff_words);
+        }
+
+        # The smallest number defines the substitutions
+        if ($diff_new < $diff_orig) {
+            $substitution += $diff_new;
+        } else {
+            $substitution += $diff_orig;
+        }
+
+        # Bookkeeping
+        $lasthit_orig = $newhit_orig;
+        $lasthit_new = $newhit_new;
+    }
+}
+
+# Make sure to process last deletions
+if ($#new < $#original) {
+    $delete += $#original - $#new;
+}
+
+print "\n";
+print "------------------\n";
+print "Total orig : $#original\n";
+print "Total new  : $#new\n";
+print "------------------\n";
+print "Insert     : $insert\n";
+print "Delete     : $delete\n";
+print "Subsitute  : $substitution\n";
+print "------------------\n";
+printf "WeR        : %.3f\n", ($insert + $delete + $substitution) / $#original, "\n";
+
+exit 0;
+
+
Index: /liacs/mms/project/Makefile
===================================================================
--- /liacs/mms/project/Makefile	(revision 22)
+++ /liacs/mms/project/Makefile	(revision 22)
@@ -0,0 +1,10 @@
+CFLAGS=-g
+
+CFLAGS+= -I/usr/include/opencv  -lcxcore -lcv -lhighgui -lcvaux -lml -lX11 -lXtst
+
+tracking: colour-tracking
+#	./colour-tracking 1 `xrandr  | awk '/\*/ {print $$1}' | tr 'x' ' '`
+	./colour-tracking 1 1400 900
+
+colour-tracking: xdo.o
+
Index: /liacs/mms/project/chessboard.pl
===================================================================
--- /liacs/mms/project/chessboard.pl	(revision 22)
+++ /liacs/mms/project/chessboard.pl	(revision 22)
@@ -0,0 +1,61 @@
+#!/usr/bin/env perl
+# Build a full screen black/white checkerboard using imagemagick (the hard way)
+# Rick van der Zwet, 2009
+$BLOCK_SIZE=100;
+
+($WIDTH, $HEIGHT) = split(' ',`xrandr  | awk '/\\*/ {print $$1}' | tr 'x' ' '`);
+print "Screen: ". $WIDTH . "x" . $HEIGHT . "\n";
+
+$X_NUM=$HEIGHT/$BLOCK_SIZE;
+$Y_NUM=$WIDTH/$BLOCK_SIZE;
+
+$X_NUM--;
+$Y_NUM--;
+
+print "Blocks x,y: " . $X_NUM . "," . $Y_NUM . "\n";
+
+$FILE='chessboard.gif';
+#`convert -size 640x480 pattern:checkerboard -monochrome gif:$FILE`;
+#`display gif:$FILE` ;
+
+$SIZE=" -size ${BLOCK_SIZE}x${BLOCK_SIZE}";
+
+$LINE = [];
+
+$COLOR="black";
+$LINESTART="black";
+sub blockswap() {
+    if ($COLOR eq "black") {
+        $COLOR = "white";
+    } else {
+        $COLOR = "black";
+    }
+}
+
+sub newline() {
+    if ($LINESTART eq "black") {
+        $LINESTART = "white";
+    } else {
+        $LINESTART = "black";
+    }
+    $COLOR=$LINESTART;
+}
+
+for($i = 0; $i < $X_NUM; $i++) {
+    for($j =0; $j < $Y_NUM; $j++) {
+        print "Block $i,$j\n";
+        $LINE[$i] = $LINE[$i] . $SIZE . " xc:$COLOR";
+        blockswap();
+    }    
+    newline();
+}
+
+for($i = 0; $i < $X_NUM; $i++) {
+    $LINE[$i] = " \\(" . $LINE[$i] . " +append \\) -append ";
+}
+
+$CMD = "convert" . join("  ",@LINE) . " gif:$FILE";
+print $CMD;
+`$CMD`;
+`display gif:$FILE`;
+
Index: /liacs/mms/project/colour-tracking.c
===================================================================
--- /liacs/mms/project/colour-tracking.c	(revision 22)
+++ /liacs/mms/project/colour-tracking.c	(revision 22)
@@ -0,0 +1,232 @@
+/* OpenCV Hello world, with filtering of various filters 
+ * Based on http://home.iitk.ac.in/~swagatk/faq/opencv.html#Colar_Based_Tracking 
+ * Rick van der Zwet <info@rickvanderzwet.nl>
+ */
+
+#include <cv.h>
+#include <cxcore.h>
+#include <cvaux.h>
+#include <highgui.h>
+#include <stdio.h>
+#include "xdo.h"
+
+#define DEBUG 1
+
+#define RVALUE(x,y,step) (x*step+y*3+2)
+#define GVALUE(x,y,step) (x*step+y*3+1)
+#define BVALUE(x,y,step) (x*step+y*3+0)
+
+/* XXX: Global variables */
+xdo_t *xdo;
+
+/* Used for playing with bounderies, returned max value of the pair */
+int max(const int x, const int y) {
+  return ((x > y) ? x : y);
+}
+
+/* Used for playing with bounderies, returned min value of the pair */
+int min(const int x, const int y) {
+  return ((x < y) ? x : y);
+
+}
+
+/* Convert the virtual mapping to screen size */
+int ratio (const int size, const int current_size, const int orig_size) {
+    double t = (double)size / current_size;
+    t *= orig_size;
+    // printf("%i/%i -> %i\n", size, current_size, (int)t);
+    return((int)t);
+}
+
+int InitSystem(int argc, char *argv[]) {
+    // Don't care which camera to use. Use specified number elsewise
+    if (argc < 3) {
+        printf("Usage: %s <cam number> <screen width> <screen height>\n",
+            argv[0]);
+        return(64);
+    }
+    const int cam_number = atoi(argv[1]);
+    const int screen_width = atoi(argv[2]);
+    const int screen_height = atoi(argv[3]);
+    printf("INFO Using camera %i\n", cam_number);
+    printf("INFO Screen size %ix%i\n", screen_width, screen_height);
+    CvCapture *capture = cvCaptureFromCAM(cam_number);
+    int width = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
+    int height = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);
+
+
+    uchar *filterdata, *outdata, *routdata, *goutdata, *boutdata, *targetdata;
+
+    
+    //Create a window
+    cvNamedWindow("RGB_Image", CV_WINDOW_AUTOSIZE);
+    cvMoveWindow("RGB_Image",0,0);
+    cvNamedWindow("R_Image", CV_WINDOW_AUTOSIZE);    
+    cvMoveWindow("R_Image",0,height);
+    cvNamedWindow("G_Image", CV_WINDOW_AUTOSIZE);    
+    cvMoveWindow("G_Image",width,0);
+    cvNamedWindow("B_Image", CV_WINDOW_AUTOSIZE);    
+    cvMoveWindow("B_Image",width,height);
+    cvNamedWindow("F_Image", CV_WINDOW_AUTOSIZE);
+
+
+    //Create Image Skeletons
+    IplImage *image   = NULL;
+    IplImage *output  = cvCreateImage( cvSize(width,height), 8, 3);
+    IplImage *boutput = cvCreateImage( cvSize(width,height), 8, 3);
+    IplImage *routput = cvCreateImage( cvSize(width,height), 8, 3);
+    IplImage *goutput = cvCreateImage( cvSize(width,height), 8, 3);
+    IplImage *filter  = cvCreateImage( cvSize(width,height), 8, 3);
+    IplImage *target  = cvCreateImage( cvSize(width,height), 8, 3);
+
+
+    // Some temp pointers
+    int i, j, k, m, n, o, p;
+    int r, g, b;
+    int q;
+    int retval;
+    char arg1[4], arg2[4];
+    int keycode;
+    // Actually move the pointer to it's location
+    int mouse_flag = 1;
+    // XXX: Hack to have the pointer posted on the second screen.
+    int ex_screen_flag = 0;
+	
+    
+    int cvalue = 0;
+    int xmax = -10;
+    int ymax = -10;
+    // Video run starts here ...
+    while (1)
+    {                 
+        image = cvQueryFrame(capture);
+	
+	// We need some input before running any further
+	if (image == NULL) {
+	  printf("Ehm no input in the image\n");
+	  continue;
+	}
+
+        //This is needed for accessing pixel elements
+        int step = image->widthStep/sizeof(uchar);
+
+        //cvCopy(image, output, NULL);
+	//Remove Noise from images
+	cvSmooth(image,output,CV_BLUR, 3, 3, 3,3);
+        cvCopy(image, routput, NULL);
+        cvCopy(image, goutput, NULL);
+        cvCopy(image, boutput, NULL);
+	
+
+        outdata = (uchar *) output->imageData;
+        routdata = (uchar *) routput->imageData;
+        goutdata = (uchar *) goutput->imageData;
+        boutdata = (uchar *) boutput->imageData;
+        targetdata = (uchar *) target->imageData;
+
+	cvSub(output,filter,target,NULL);
+	cvalue = 20;
+        k = 0, p = 0, q = 0;
+        for( m = 0; m < image->height; m++) //row
+        {
+            for( n = 0; n < image->width; n++) //column
+            {
+		//p = targetdata[RVALUE(m,n,step)] + targetdata[GVALUE(m,n,step)] + targetdata[BVALUE(m,n,step)];
+		p = targetdata[RVALUE(m,n,step)] + targetdata[GVALUE(m,n,step)];
+		if ( p > cvalue)
+		{
+			q++;
+			if (q > 5) {
+				cvalue = p;
+				xmax = n;
+				ymax = m;
+				//printf("Current value: %ix%i=%i\n", xmax, ymax, cvalue);
+			}
+		} else {
+			q = 0;
+		}
+		routdata[BVALUE(m,n,step)] = 0; // clear blue part
+		routdata[GVALUE(m,n,step)] = 0; // clear green part
+
+		goutdata[BVALUE(m,n,step)] = 0; // clear blue part
+		goutdata[RVALUE(m,n,step)] = 0; // clear red part
+
+		boutdata[GVALUE(m,n,step)] = 0; // clear green part
+		boutdata[RVALUE(m,n,step)] = 0; // clear red part
+            }
+        } 
+
+	// Clear filter for new use
+	// cvSetZero(filter);
+	// ... or clone orginal image for mapping over it
+	//cvCopy(goutput, filter, NULL);
+
+        // Make it yellow
+        //cvOr( routput, goutput, filter, NULL);
+
+	// XXX: Use stuff like cvMat, cvGetRawData instead of internal hacking
+	// Make green 'fade' out by the presence of many red as well
+        // filterdata = (uchar *) filter->imageData;
+	
+	// Prepare combined output
+	// Some way of making the picture more pretty
+	//cvSmooth(filter,target, CV_MEDIAN, 3, 3, 3, 3);
+        cvCopy(output,filter, NULL);
+        cvCircle(target, cvPoint(xmax, ymax), 10, CV_RGB(255,0,0),4, 8, 0);
+        // Set to pointer to new location
+        if (mouse_flag) {
+            if (ex_screen_flag) {
+                xdo_mousemove(xdo, ratio(xmax,width,screen_width) + screen_width - 250, 
+                    ratio(ymax,height,screen_height));
+            } else {
+                xdo_mousemove(xdo, ratio(xmax,width,screen_width), 
+                    ratio(ymax,height,screen_height));
+            }
+        }
+                        
+
+        // Show all the images
+        cvShowImage("RGB_Image", output);
+        cvShowImage("R_Image", routput);
+        cvShowImage("B_Image", boutput);       
+        cvShowImage("G_Image", goutput);       
+        cvShowImage("F_Image", target);       
+                    
+                
+        // Process some keyboard input for handy selection
+        // Eeks! also HACK to make it refresh properly
+        keycode = cvWaitKey(20);
+        if (keycode != -1) {
+            printf("Keycode: %i\n", keycode);
+            if (keycode == 'q') {
+		        break;
+            } else if (keycode == 'm') {
+                mouse_flag =  (mouse_flag == 1) ? 0 : 1;
+            } else if (keycode == 'e') {
+                ex_screen_flag =  (ex_screen_flag == 1) ? 0 : 1;
+
+            }
+	    }
+    } //for each frame ...
+
+
+    cvReleaseCapture(&capture);
+    cvDestroyWindow("RGB_Image");
+    cvDestroyWindow("R_Image");
+    cvDestroyWindow("G_Image");
+    cvDestroyWindow("B_Image");
+    cvDestroyWindow("F_Image");
+
+    return 0;
+
+}
+
+// Get ourself into the highGUI main stuff
+// Quick at 1.0.0, not needing in  2.0x anymore
+int main(int argc, char *argv[]) {
+   int retval;
+   xdo = xdo_new(getenv("DISPLAY"));
+   retval = InitSystem(argc, argv);
+   xdo_free(xdo);
+   return(retval);
+}
Index: /liacs/mms/project/uinput.c
===================================================================
--- /liacs/mms/project/uinput.c	(revision 22)
+++ /liacs/mms/project/uinput.c	(revision 22)
@@ -0,0 +1,182 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <linux/input.h>
+#include <linux/uinput.h>
+#include <signal.h>
+#include <X11/Xlib.h>
+
+static int fd;
+
+struct coords {
+	int x;
+	int y; 
+};
+
+void close_pointer() {
+    ioctl(fd, UI_DEV_DESTROY);
+    close(fd);
+}
+
+// Close stuff nicely in case of issues
+void ex_program(int sig) {
+    close_pointer();
+    printf("Terminated signal: %d\n", sig);
+    (void) signal(SIGINT, SIG_DFL);
+    exit(-1);
+}
+
+// Wrapper to send cool stuff over the wire
+int send_event(int fd, __u16 type, __u16 code, __s32 value)
+{
+    struct input_event event;
+
+    memset(&event, 0, sizeof(event));
+    event.type = type;
+    event.code = code;
+    event.value = value;
+    gettimeofday(&event.time, NULL);
+
+    if (write(fd, &event, sizeof(event)) != sizeof(event)) {
+        fprintf(stderr, "Error on send_event");
+        return -1;
+    }
+
+    return 0;
+}
+
+//XXX: Make me more effient
+struct coords 
+get_coords() {
+	Display *dsp = XOpenDisplay( NULL );
+	
+	struct coords xy_current = { -1, -1 };
+	if( !dsp ){ return xy_current; }
+	
+	int screenNumber = DefaultScreen(dsp);
+	
+	XEvent event;
+	
+	/* get info about current pointer position */
+	XQueryPointer(dsp, RootWindow(dsp, screenNumber),
+	&event.xbutton.root, &event.xbutton.window,
+	&event.xbutton.x_root, &event.xbutton.y_root,
+	&event.xbutton.x, &event.xbutton.y,
+	&event.xbutton.state);
+	
+	printf("Mouse Coordinates: %d %d\n", event.xbutton.x, event.xbutton.y);
+	XCloseDisplay( dsp );
+	xy_current.x = event.xbutton.x;
+	xy_current.y = event.xbutton.y;
+	return(xy_current);
+}
+
+
+// Set the pointer to a certain location
+int
+init_pointer()
+{
+    int i;
+    struct uinput_user_dev device;
+    memset(&device, 0, sizeof device);
+
+    fd=open("/dev/uinput",O_WRONLY | O_NDELAY);
+    strcpy(device.name,"test mouse");
+
+    device.id.bustype=BUS_USB;
+    device.id.vendor= 0x0001;
+    device.id.product=0x0001;
+    device.id.version=UINPUT_VERSION;
+
+    //for (i=0; i < ABS_MAX; i++) {
+    //    device.absmax[i] = -1;
+    //    device.absmin[i] = -1;
+    //    device.absfuzz[i] = -1;
+    //    device.absflat[i] = -1;
+    //}
+
+    if (write(fd,&device,sizeof(device)) != sizeof(device))
+    {
+        fprintf(stderr, "error setup\n");
+	return -1;
+    }
+
+    (void) signal(SIGINT, ex_program);
+
+    /* mousedev only recognize our device as a mouse
+     * if it has at least two axis and one left button.
+     * Also, mouse buttons have to send sync events. 
+     */
+    //ioctl(fd, UI_SET_EVBIT, EV_KEY);
+    ioctl(fd, UI_SET_EVBIT, EV_REL);
+    ioctl(fd, UI_SET_EVBIT, EV_SYN);
+
+    ioctl(fd, UI_SET_RELBIT, REL_X);
+    ioctl(fd, UI_SET_RELBIT, REL_Y);
+    //ioctl(fd, UI_SET_RELBIT, REL_WHEEL);
+
+    ioctl(fd, UI_SET_KEYBIT, BTN_LEFT);
+    //ioctl(fd, UI_SET_KEYBIT, BTN_RIGHT);
+    //ioctl(fd, UI_SET_KEYBIT, BTN_MIDDLE);
+
+    //for (i=0; i < 256; i++) {
+	//    ioctl(fd, UI_SET_KEYBIT, i);
+    //}
+
+    ioctl(fd, UI_DEV_CREATE, NULL);
+
+}
+
+int set_pointer(const struct coords xy_target) {
+    struct coords xy_diff, xy_prev;
+    struct coords xy_current = { -1 , -1 }; // Bogus inital value
+    char c;
+    // Force pointer to absolute location on the screen
+    while ( 1 ) {
+        //XXX: Screen pointer get updated really slow
+        xy_prev.x = xy_current.x;
+        xy_prev.y = xy_current.y;
+        while ( 1 ) {
+            xy_current = get_coords();
+            // Found ourself an update
+            printf("old->new coordinates %ix%i -> %ix%i\n",
+                xy_prev.x,xy_prev.y,
+                xy_current.x,xy_current.y); 
+            if (xy_prev.x != xy_current.x || xy_prev.y != xy_current.y) {
+                //ex_program(1);
+                break;
+            }
+            usleep(200000);
+        }
+
+        xy_diff.x = (xy_target.x - xy_current.x);
+        xy_diff.y = (xy_target.y - xy_current.y);
+        if (xy_diff.x == 0 && xy_diff.y == 0) {
+            printf("Location %ix%i\n", xy_current.x, xy_current.y);
+            break;
+        } else {
+            printf("Trying to sync current:%ix%i target:%ix%i diff:%ix%i\n",
+                xy_current.x, xy_current.y,
+                xy_target.x, xy_target.y,
+                xy_diff.x, xy_diff.y);
+            send_event(fd, EV_REL, REL_X, xy_diff.x);
+            send_event(fd, EV_REL, REL_Y, xy_diff.y);
+            send_event(fd, EV_SYN, SYN_REPORT, 0);
+            // Wait some small period of time to get it populated (and the screen get updated)
+            usleep(200000);
+        }
+    }
+}
+
+int 
+main() {
+    struct coords xy_target = { 200,200 };
+    init_pointer();
+	set_pointer(xy_target);	
+    xy_target.x = 500;
+    xy_target.y = 500;
+	set_pointer(xy_target);	
+    close_pointer();
+	return(0);
+}
Index: /liacs/mms/project/xdo.c
===================================================================
--- /liacs/mms/project/xdo.c	(revision 22)
+++ /liacs/mms/project/xdo.c	(revision 22)
@@ -0,0 +1,986 @@
+/* xdo library
+ *
+ * $Id: xdo.c 2172 2009-03-30 02:38:06Z jordansissel $
+ *
+ * - getwindowfocus contributed by Lee Pumphret
+ * - keysequence_{up,down} contributed by Magnus Boman
+ *
+ */
+
+#define _XOPEN_SOURCE 500
+#include <sys/select.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <regex.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xresource.h>
+#include <X11/Xutil.h>
+#include <X11/extensions/XTest.h>
+
+#include "xdo.h"
+#include "xdo_util.h"
+
+static void _xdo_populate_charcode_map(xdo_t *xdo);
+static int _xdo_has_xtest(xdo_t *xdo);
+
+static int _xdo_keycode_from_char(xdo_t *xdo, char key);
+static int _xdo_get_shiftcode_if_needed(xdo_t *xdo, char key);
+
+static void _xdo_get_child_windows(xdo_t *xdo, Window window,
+                                   Window **total_window_list, 
+                                   int *ntotal_windows, 
+                                   int *window_list_size);
+
+static int _xdo_keysequence_to_keycode_list(xdo_t *xdo, char *keyseq,
+                                            charcodemap_t **keys, int *nkeys);
+static int _xdo_keysequence_do(xdo_t *xdo, char *keyseq, int pressed);
+static int _xdo_regex_match_window(xdo_t *xdo, Window window, int flags, regex_t *re);
+static int _xdo_is_window_visible(xdo_t *xdo, Window wid);
+static unsigned char * _xdo_getwinprop(xdo_t *xdo, Window window, Atom atom,
+                                       long *nitems, Atom *type, int *size);
+static int _xdo_ewmh_is_supported(xdo_t *xdo, const char *feature);
+
+static int _is_success(const char *funcname, int code);
+
+/* context-free functions */
+static char _keysym_to_char(const char *keysym);
+
+xdo_t* xdo_new(char *display_name) {
+  Display *xdpy;
+
+  if ((xdpy = XOpenDisplay(display_name)) == NULL) {
+    fprintf(stderr, "Error: Can't open display: %s\n", display_name);
+    return NULL;
+  }
+
+  return xdo_new_with_opened_display(xdpy, display_name, 1);
+}
+
+xdo_t* xdo_new_with_opened_display(Display *xdpy, const char *display,
+                                   int close_display_when_freed) {
+  xdo_t *xdo = NULL;
+
+  if (xdpy == NULL) {
+    fprintf(stderr, "xdo_new: xdisplay I was given is a null pointer\n");
+    return NULL;
+  }
+
+  /* XXX: Check for NULL here */
+  xdo = malloc(sizeof(xdo_t));
+  memset(xdo, 0, sizeof(xdo_t));
+
+  xdo->xdpy = xdpy;
+  xdo->close_display_when_freed = close_display_when_freed;
+
+  if (display == NULL)
+    display = "unknown";
+
+  if (!_xdo_has_xtest(xdo)) {
+    fprintf(stderr, "Error: XTEST extension unavailable on '%s'.", 
+            xdo->display_name);
+    xdo_free(xdo);
+    return NULL;
+  }
+
+  /* populate the character map? */
+  _xdo_populate_charcode_map(xdo);
+
+  return xdo;
+}
+
+void xdo_free(xdo_t *xdo) {
+  if (xdo->display_name)
+    free(xdo->display_name);
+  if (xdo->charcodes)
+    free(xdo->charcodes);
+  if (xdo->xdpy && xdo->close_display_when_freed)
+    XCloseDisplay(xdo->xdpy);
+  free(xdo);
+}
+
+int xdo_window_map(xdo_t *xdo, Window wid) {
+  int ret = 0;
+  ret = XMapWindow(xdo->xdpy, wid);
+  XFlush(xdo->xdpy);
+  return _is_success("XMapWindow", ret == 0);
+}
+
+int xdo_window_unmap(xdo_t *xdo, Window wid) {
+  int ret = 0;
+  ret = XUnmapWindow(xdo->xdpy, wid);
+  XFlush(xdo->xdpy);
+  return _is_success("XUnmapWindow", ret == 0);
+}
+
+int xdo_window_list_by_regex(xdo_t *xdo, char *regex, int flags,
+                              Window **windowlist, int *nwindows) {
+  regex_t re;
+  Window *total_window_list = NULL;
+  int ntotal_windows = 0;
+  int window_list_size = 0;
+  int matched_window_list_size = 100;
+
+  int ret = 0;
+  int i = 0;
+
+  ret = regcomp(&re, regex, REG_EXTENDED | REG_ICASE);
+  if (ret != 0) {
+    fprintf(stderr, "Failed to compile regex: '%s'\n", regex);
+    return 1;
+  }
+
+  /* Default search settings:
+   * All windows (visible and hidden) and search all text pieces
+   */
+  if ((flags & (SEARCH_TITLE | SEARCH_CLASS | SEARCH_NAME)) == 0) {
+    fprintf(stderr, "No text fields specified for regex search. \nDefaulting to"
+            " window title, class, and name searching\n");
+    flags |= SEARCH_TITLE | SEARCH_CLASS | SEARCH_NAME;
+  }
+
+  *nwindows = 0;
+  *windowlist = malloc(matched_window_list_size * sizeof(Window));
+
+  _xdo_get_child_windows(xdo, RootWindow(xdo->xdpy, 0),
+                         &total_window_list, &ntotal_windows,
+                         &window_list_size);
+  for (i = 0; i < ntotal_windows; i++) {
+    Window wid = total_window_list[i];
+    if (flags & SEARCH_VISIBLEONLY && !_xdo_is_window_visible(xdo, wid))
+      continue;
+    if (!_xdo_regex_match_window(xdo, wid, flags, &re))
+      continue;
+
+    (*windowlist)[*nwindows] = wid;
+    (*nwindows)++;
+
+    if (matched_window_list_size == *nwindows) {
+      matched_window_list_size *= 2;
+      *windowlist = realloc(*windowlist, 
+                            matched_window_list_size * sizeof(Window));
+    }
+  }
+
+  regfree(&re);
+  return 0;
+}
+
+int xdo_window_move(xdo_t *xdo, Window wid, int x, int y) {
+  XWindowChanges wc;
+  int ret = 0;
+  wc.x = x;
+  wc.y = y;
+
+  ret = XConfigureWindow(xdo->xdpy, wid, CWX | CWY, &wc);
+  return _is_success("XConfigureWindow", ret == 0);
+}
+
+int xdo_window_setsize(xdo_t *xdo, Window wid, int width, int height, int flags) {
+  XWindowChanges wc;
+  int ret = 0;
+  int cw_flags = 0;
+
+  wc.width = width;
+  wc.height = height;
+
+  if (flags & SIZE_USEHINTS) {
+    XSizeHints hints;
+    long supplied_return;
+    memset(&hints, 0, sizeof(hints));
+    XGetWMNormalHints(xdo->xdpy, wid, &hints, &supplied_return);
+    if (supplied_return & PResizeInc) {
+      wc.width *= hints.width_inc;
+      wc.height *= hints.height_inc;
+    } else {
+      fprintf(stderr, "No size hints found for this window\n");
+    }
+
+    if (supplied_return & PBaseSize) {
+      wc.width += hints.base_width;
+      wc.height += hints.base_height;
+    }
+
+  }
+
+  if (width > 0)
+    cw_flags |= CWWidth;
+  if (height > 0)
+    cw_flags |= CWHeight;
+
+  ret = XConfigureWindow(xdo->xdpy, wid, cw_flags, &wc);
+  XFlush(xdo->xdpy);
+  return _is_success("XConfigureWindow", ret == 0);
+}
+
+int xdo_window_focus(xdo_t *xdo, Window wid) {
+  int ret = 0;
+  ret = XSetInputFocus(xdo->xdpy, wid, RevertToParent, CurrentTime);
+  XFlush(xdo->xdpy);
+  return _is_success("XSetInputFocus", ret == 0);
+}
+
+int xdo_window_activate(xdo_t *xdo, Window wid) {
+  int ret = 0;
+  long desktop = 0;
+  XEvent xev;
+  XWindowAttributes wattr;
+
+  if (_xdo_ewmh_is_supported(xdo, "_NET_ACTIVE_WINDOW") == False) {
+    fprintf(stderr,
+            "Your windowmanager claims not to support _NET_ACTIVE_WINDOW, "
+            "so the attempt to activate the window was aborted.\n");
+    return 1;
+  }
+
+  /* If this window is on another desktop, let's go to that desktop first */
+
+  if (_xdo_ewmh_is_supported(xdo, "_NET_WM_DESKTOP") == True
+      && _xdo_ewmh_is_supported(xdo, "_NET_CURRENT_DESKTOP") == True) {
+    xdo_get_desktop_for_window(xdo, wid, &desktop);
+    xdo_set_current_desktop(xdo, desktop);
+  }
+
+  memset(&xev, 0, sizeof(xev));
+  xev.type = ClientMessage;
+  xev.xclient.display = xdo->xdpy;
+  xev.xclient.window = wid;
+  xev.xclient.message_type = XInternAtom(xdo->xdpy, "_NET_ACTIVE_WINDOW", False);
+  xev.xclient.format = 32;
+  xev.xclient.data.l[0] = 2L; /* 2 == Message from a window pager */
+  xev.xclient.data.l[1] = CurrentTime;
+
+  XGetWindowAttributes(xdo->xdpy, wid, &wattr);
+  ret = XSendEvent(xdo->xdpy, wattr.screen->root, False,
+                   SubstructureNotifyMask | SubstructureRedirectMask,
+                   &xev);
+
+  /* XXX: XSendEvent returns 0 on conversion failure, nonzero otherwise.
+   * Manpage says it will only generate BadWindow or BadValue errors */
+  return _is_success("XSendEvent[EWMH:_NET_ACTIVE_WINDOW]", ret == 0);
+}
+
+int xdo_set_number_of_desktops(xdo_t *xdo, long ndesktops) {
+  /* XXX: This should support passing a screen number */
+  XEvent xev;
+  Window root;
+  int ret = 0;
+
+  if (_xdo_ewmh_is_supported(xdo, "_NET_NUMBER_OF_DESKTOPS") == False) {
+    fprintf(stderr,
+            "Your windowmanager claims not to support _NET_NUMBER_OF_DESKTOPS, "
+            "so the attempt to change the number of desktops was aborted.\n");
+    return 1;
+  }
+
+  root = RootWindow(xdo->xdpy, 0);
+
+  memset(&xev, 0, sizeof(xev));
+  xev.type = ClientMessage;
+  xev.xclient.display = xdo->xdpy;
+  xev.xclient.window = root;
+  xev.xclient.message_type = XInternAtom(xdo->xdpy, "_NET_NUMBER_OF_DESKTOPS", 
+                                         False);
+  xev.xclient.format = 32;
+  xev.xclient.data.l[0] = ndesktops;
+
+  ret = XSendEvent(xdo->xdpy, root, False,
+                   SubstructureNotifyMask | SubstructureRedirectMask,
+                   &xev);
+
+  return _is_success("XSendEvent[EWMH:_NET_NUMBER_OF_DESKTOPS]", ret == 0);
+}
+
+int xdo_get_number_of_desktops(xdo_t *xdo, long *ndesktops) {
+  Atom type;
+  int size;
+  long nitems;
+  unsigned char *data;
+  Window root;
+  Atom request;
+
+  if (_xdo_ewmh_is_supported(xdo, "_NET_NUMBER_OF_DESKTOPS") == False) {
+    fprintf(stderr,
+            "Your windowmanager claims not to support _NET_NUMBER_OF_DESKTOPS, "
+            "so the attempt to query the number of desktops was aborted.\n");
+    return 1;
+  }
+
+  request = XInternAtom(xdo->xdpy, "_NET_NUMBER_OF_DESKTOPS", False);
+  root = XDefaultRootWindow(xdo->xdpy);
+
+  data = _xdo_getwinprop(xdo, root, request, &nitems, &type, &size);
+
+  if (nitems > 0)
+    *ndesktops = *((long*)data);
+  else
+    *ndesktops = 0;
+
+  return _is_success("XGetWindowProperty[_NET_NUMBER_OF_DESKTOPS]",
+                     *ndesktops == 0);
+
+}
+
+int xdo_set_current_desktop(xdo_t *xdo, long desktop) {
+  /* XXX: This should support passing a screen number */
+  XEvent xev;
+  Window root;
+  int ret = 0;
+
+  root = RootWindow(xdo->xdpy, 0);
+
+  if (_xdo_ewmh_is_supported(xdo, "_NET_CURRENT_DESKTOP") == False) {
+    fprintf(stderr,
+            "Your windowmanager claims not to support _NET_CURRENT_DESKTOP, "
+            "so the attempt to change desktops was aborted.\n");
+    return 1;
+  }
+
+  memset(&xev, 0, sizeof(xev));
+  xev.type = ClientMessage;
+  xev.xclient.display = xdo->xdpy;
+  xev.xclient.window = root;
+  xev.xclient.message_type = XInternAtom(xdo->xdpy, "_NET_CURRENT_DESKTOP", 
+                                         False);
+  xev.xclient.format = 32;
+  xev.xclient.data.l[0] = desktop;
+  xev.xclient.data.l[1] = CurrentTime;
+
+  ret = XSendEvent(xdo->xdpy, root, False,
+                   SubstructureNotifyMask | SubstructureRedirectMask,
+                   &xev);
+
+  return _is_success("XSendEvent[EWMH:_NET_CURRENT_DESKTOP]", ret == 0);
+}
+
+int xdo_get_current_desktop(xdo_t *xdo, long *desktop) {
+  Atom type;
+  int size;
+  long nitems;
+  unsigned char *data;
+  Window root;
+
+  Atom request;
+
+  if (_xdo_ewmh_is_supported(xdo, "_NET_CURRENT_DESKTOP") == False) {
+    fprintf(stderr,
+            "Your windowmanager claims not to support _NET_CURRENT_DESKTOP, "
+            "so the query for the current desktop was aborted.\n");
+    return 1;
+  }
+
+  request = XInternAtom(xdo->xdpy, "_NET_CURRENT_DESKTOP", False);
+  root = XDefaultRootWindow(xdo->xdpy);
+
+  data = _xdo_getwinprop(xdo, root, request, &nitems, &type, &size);
+
+  if (nitems > 0)
+    *desktop = *((long*)data);
+  else
+    *desktop = -1;
+
+  return _is_success("XGetWindowProperty[_NET_CURRENT_DESKTOP]",
+                     *desktop == -1);
+}
+
+int xdo_set_desktop_for_window(xdo_t *xdo, Window wid, long desktop) {
+  XEvent xev;
+  int ret = 0;
+  XWindowAttributes wattr;
+  XGetWindowAttributes(xdo->xdpy, wid, &wattr);
+
+  if (_xdo_ewmh_is_supported(xdo, "_NET_WM_DESKTOP") == False) {
+    fprintf(stderr,
+            "Your windowmanager claims not to support _NET_WM_DESKTOP, "
+            "so the attempt to change a window's desktop location was "
+            "aborted.\n");
+    return 1;
+  }
+
+  memset(&xev, 0, sizeof(xev));
+  xev.type = ClientMessage;
+  xev.xclient.display = xdo->xdpy;
+  xev.xclient.window = wid;
+  xev.xclient.message_type = XInternAtom(xdo->xdpy, "_NET_WM_DESKTOP", 
+                                         False);
+  xev.xclient.format = 32;
+  xev.xclient.data.l[0] = desktop;
+  xev.xclient.data.l[1] = 2; /* indicate we are messaging from a pager */
+
+  ret = XSendEvent(xdo->xdpy, wattr.screen->root, False,
+                   SubstructureNotifyMask | SubstructureRedirectMask,
+                   &xev);
+
+  return _is_success("XSendEvent[EWMH:_NET_WM_DESKTOP]", ret == 0);
+}
+
+int xdo_get_desktop_for_window(xdo_t *xdo, Window wid, long *desktop) {
+  Atom type;
+  int size;
+  long nitems;
+  unsigned char *data;
+  Atom request;
+
+  if (_xdo_ewmh_is_supported(xdo, "_NET_WM_DESKTOP") == False) {
+    fprintf(stderr,
+            "Your windowmanager claims not to support _NET_WM_DESKTOP, "
+            "so the attempt to query a window's desktop location was "
+            "aborted.\n");
+    return 1;
+  }
+
+  request = XInternAtom(xdo->xdpy, "_NET_WM_DESKTOP", False);
+
+  data = _xdo_getwinprop(xdo, wid, request, &nitems, &type, &size);
+
+  if (nitems > 0)
+    *desktop = *((long*)data);
+  else
+    *desktop = -1;
+
+  return _is_success("XGetWindowProperty[_NET_WM_DESKTOP]",
+                     *desktop == -1);
+}
+
+int xdo_window_get_active(xdo_t *xdo, Window *window_ret) {
+  Atom type;
+  int size;
+  long nitems;
+  unsigned char *data;
+  Atom request;
+  Window root;
+
+  if (_xdo_ewmh_is_supported(xdo, "_NET_ACTIVE_WINDOW") == False) {
+    fprintf(stderr,
+            "Your windowmanager claims not to support _NET_ACTIVE_WINDOW, "
+            "so the attempt to query the active window aborted.\n");
+    return 1;
+  }
+
+  request = XInternAtom(xdo->xdpy, "_NET_ACTIVE_WINDOW", False);
+  root = XDefaultRootWindow(xdo->xdpy);
+  data = _xdo_getwinprop(xdo, root, request, &nitems, &type, &size);
+
+  if (nitems > 0)
+    *window_ret = *((Window*)data);
+  else
+    *window_ret = 0;
+
+  return _is_success("XGetWindowProperty[_NET_ACTIVE_WINDOW]",
+                     *window_ret == 0);
+}
+
+/* XRaiseWindow is ignored in ion3 and Gnome2. Is it even useful? */
+int xdo_window_raise(xdo_t *xdo, Window wid) {
+  int ret = 0;
+  ret = XRaiseWindow(xdo->xdpy, wid);
+  XFlush(xdo->xdpy);
+  return _is_success("XRaiseWindow", ret == 0);
+}
+
+/* XXX: Include 'screen number' support? */
+int xdo_mousemove(xdo_t *xdo, int x, int y)  {
+  int ret = 0;
+  ret = XTestFakeMotionEvent(xdo->xdpy, -1, x, y, CurrentTime);
+  XFlush(xdo->xdpy);
+  return _is_success("XTestFakeMotionEvent", ret == 0);
+}
+
+int xdo_mousemove_relative(xdo_t *xdo, int x, int y)  {
+  int ret = 0;
+  ret = XTestFakeRelativeMotionEvent(xdo->xdpy, x, y, CurrentTime);
+  XFlush(xdo->xdpy);
+  return _is_success("XTestFakeRelativeMotionEvent", ret == 0);
+}
+
+int xdo_mousedown(xdo_t *xdo, int button) {
+  int ret = 0;
+  ret = XTestFakeButtonEvent(xdo->xdpy, button, True, CurrentTime);
+  XFlush(xdo->xdpy);
+  return _is_success("XTestFakeButtonEvent(down)", ret == 0);
+}
+
+int xdo_mouseup(xdo_t *xdo, int button) {
+  int ret = 0;
+  ret = XTestFakeButtonEvent(xdo->xdpy, button, False, CurrentTime);
+  XFlush(xdo->xdpy);
+  return _is_success("XTestFakeButtonEvent(up)", ret == 0);
+}
+
+int xdo_mouselocation(xdo_t *xdo, int *x_ret, int *y_ret, int *screen_num_ret) {
+  int ret = False;
+  int x = 0, y = 0, screen_num = 0;
+  int i = 0;
+  Window dummy_win = 0;
+  int dummy_int = 0;
+  unsigned int dummy_uint = 0;
+  int screencount = ScreenCount(xdo->xdpy);
+
+  for (i = 0; i < screencount; i++) {
+    Screen *screen = ScreenOfDisplay(xdo->xdpy, i);
+    ret = XQueryPointer(xdo->xdpy, RootWindowOfScreen(screen),
+                        &dummy_win, &dummy_win,
+                        &x, &y, &dummy_int, &dummy_int, &dummy_uint);
+    if (ret == True) {
+      screen_num = i;
+      break;
+    }
+  }
+
+  if (ret == True) {
+    if (x_ret != NULL) *x_ret = x;
+    if (y_ret != NULL) *y_ret = y;
+    if (screen_num_ret != NULL) *screen_num_ret = screen_num;
+  }
+
+  return _is_success("XQueryPointer", ret == False);
+
+}
+
+int xdo_click(xdo_t *xdo, int button) {
+  int ret = 0;
+  ret = xdo_mousedown(xdo, button);
+  if (ret)
+    return ret;
+  ret = xdo_mouseup(xdo, button);
+  return ret;
+}
+
+/* XXX: Return proper code if errors found */
+int xdo_type(xdo_t *xdo, char *string) {
+  int i = 0;
+  char key = '0';
+  int keycode = 0;
+  int shiftcode = 0;
+
+  /* XXX: Add error handling */
+  for (i = 0; string[i] != '\0'; i++) {
+    key = string[i];
+    keycode = _xdo_keycode_from_char(xdo, key);
+    shiftcode = _xdo_get_shiftcode_if_needed(xdo, key);
+
+    if (shiftcode > 0)
+      XTestFakeKeyEvent(xdo->xdpy, shiftcode, True, CurrentTime);
+    XTestFakeKeyEvent(xdo->xdpy, keycode, True, CurrentTime);
+    XTestFakeKeyEvent(xdo->xdpy, keycode, False, CurrentTime);
+    if (shiftcode > 0)
+      XTestFakeKeyEvent(xdo->xdpy, shiftcode, False, CurrentTime);
+
+    /* XXX: Flush here or at the end? */
+    XFlush(xdo->xdpy);
+  }
+
+  return 0;
+}
+
+int _xdo_keysequence_do(xdo_t *xdo, char *keyseq, int pressed) {
+  int ret = 0;
+  charcodemap_t *keys = NULL;
+  int nkeys = 0;
+  int i;
+  KeyCode shiftcode;
+
+  if (_xdo_keysequence_to_keycode_list(xdo, keyseq, &keys, &nkeys) == False) {
+    fprintf(stderr, "Failure converting key sequence '%s' to keycodes\n", keyseq);
+    return False;
+  }
+
+  /* If shiftcode is necessary, send shift before the key if pressed is true,
+   * otherwise release the shift key after the key is released */
+  for (i = 0; i < nkeys; i++) {
+    shiftcode = keys[i].shift;
+
+    if (pressed > 0 && shiftcode)
+      ret += !XTestFakeKeyEvent(xdo->xdpy, shiftcode, pressed, CurrentTime);
+
+    ret += !XTestFakeKeyEvent(xdo->xdpy, keys[i].code, pressed, CurrentTime);
+
+    if (pressed == 0 && shiftcode)
+      ret += !XTestFakeKeyEvent(xdo->xdpy, shiftcode, pressed, CurrentTime);
+  }
+
+  if (keys != NULL) {
+    free(keys);
+  }
+  XFlush(xdo->xdpy);
+  return ret;
+}
+  
+int xdo_keysequence_down(xdo_t *xdo, char *keyseq) {
+  return _xdo_keysequence_do(xdo, keyseq, True);
+}
+
+int xdo_keysequence_up(xdo_t *xdo, char *keyseq) {
+  return _xdo_keysequence_do(xdo, keyseq, False);
+}
+
+int xdo_keysequence(xdo_t *xdo, char *keyseq) {
+  int ret = 0;
+  ret += _xdo_keysequence_do(xdo, keyseq, True);
+  ret += _xdo_keysequence_do(xdo, keyseq, False);
+  return ret;
+}
+
+/* Add by Lee Pumphret 2007-07-28
+ * Modified slightly by Jordan Sissel */
+int xdo_window_get_focus(xdo_t *xdo, Window *window_ret) {
+  int ret = 0;
+  int unused_revert_ret;
+
+  ret = XGetInputFocus(xdo->xdpy, window_ret, &unused_revert_ret);
+  return _is_success("XGetInputFocus", ret == 0);
+}
+
+/* Like xdo_window_get_focus, but return the first ancestor-or-self window
+ * having a property of WM_CLASS. This allows you to get the "real" or
+ * top-level-ish window having focus rather than something you may
+ * not expect to be the window having focused. */
+int xdo_window_sane_get_focus(xdo_t *xdo, Window *window_ret) {
+  int done = 0;
+  Window w;
+  XClassHint classhint;
+
+  /* for XQueryTree */
+  Window dummy, parent, *children = NULL;
+  unsigned int nchildren;
+
+  xdo_window_get_focus(xdo, &w);
+
+  while (!done) {
+    Status s;
+    s = XGetClassHint(xdo->xdpy, w, &classhint);
+    //fprintf(stderr, "%d\n", s);
+
+    if (s == 0) {
+      /* Error. This window doesn't have a class hint */
+      //fprintf(stderr, "no class on: %d\n", w);
+      XQueryTree(xdo->xdpy, w, &dummy, &parent, &children, &nchildren);
+
+      /* Don't care about the children, but we still need to free them */
+      if (children != NULL)
+        XFree(children);
+      //fprintf(stderr, "parent: %d\n", parent);
+      w = parent;
+    } else {
+      /* Must XFree the class and name items. */
+      XFree(classhint.res_class);
+      XFree(classhint.res_name);
+
+      done = 1;
+    }
+  }
+
+  *window_ret = w;
+  return _is_success("xdo_window_sane_get_focus", w == 0);
+}
+
+/* Helper functions */
+static int _xdo_keycode_from_char(xdo_t *xdo, char key) {
+  int i = 0;
+  int len = xdo->keycode_high - xdo->keycode_low;
+
+  for (i = 0; i < len; i++)
+    if (xdo->charcodes[i].key == key)
+      return xdo->charcodes[i].code;
+
+  return -1;
+}
+
+static int _xdo_get_shiftcode_if_needed(xdo_t *xdo, char key) {
+  int i = 0;
+  int len = xdo->keycode_high - xdo->keycode_low;
+
+  for (i = 0; i < len; i++)
+    if (xdo->charcodes[i].key == key)
+      return xdo->charcodes[i].shift;
+
+  return -1;
+}
+
+static int _xdo_has_xtest(xdo_t *xdo) {
+  int dummy;
+  return (XTestQueryExtension(xdo->xdpy, &dummy, &dummy, &dummy, &dummy) == True);
+}
+
+static void _xdo_populate_charcode_map(xdo_t *xdo) {
+  /* assert xdo->display is valid */
+  int keycodes_length = 0;
+  int shift_keycode = 0;
+  int i, j;
+
+  XDisplayKeycodes(xdo->xdpy, &(xdo->keycode_low), &(xdo->keycode_high));
+
+  /* Double size of keycode range because some 
+   * keys have "shift" values. ie; 'a' and 'A', '2' and '@' */
+  /* Add 2 to the size because the range [low, high] is inclusive */
+  keycodes_length = (xdo->keycode_high - xdo->keycode_low) * 2 + 2;
+  xdo->charcodes = malloc(keycodes_length * sizeof(charcodemap_t));
+  memset(xdo->charcodes, 0, keycodes_length * sizeof(charcodemap_t));
+
+  /* Fetch the keycode for Shift_L */
+  /* XXX: Make 'Shift_L' configurable? */
+  shift_keycode = XKeysymToKeycode(xdo->xdpy, XStringToKeysym("Shift_L"));
+
+  for (i = xdo->keycode_low; i <= xdo->keycode_high; i++) {
+    char *keybuf = 0;
+
+    /* Index '0' in KeycodeToKeysym == no shift key
+     * Index '1' in ... == shift key held
+     * hence this little loop. */
+    for (j = 0; j <= 1; j++) { 
+     int idx = (i - xdo->keycode_low) * 2 + j;
+     keybuf = XKeysymToString(XKeycodeToKeysym(xdo->xdpy, i, j));
+
+     xdo->charcodes[idx].key = _keysym_to_char(keybuf);
+     xdo->charcodes[idx].code = i;
+     xdo->charcodes[idx].shift = j ? shift_keycode : 0;
+    }
+  }
+}
+
+/* context-free functions */
+char _keysym_to_char(const char *keysym) {
+  int i;
+
+  if (keysym == NULL)
+    return -1;
+
+  /* keysymcharmap comes from xdo_util.h */
+  for (i = 0; keysymcharmap[i].keysym; i++) {
+    if (!strcmp(keysymcharmap[i].keysym, keysym))
+      return keysymcharmap[i].key;
+  }
+
+  if (strlen(keysym) == 1)
+    return keysym[0];
+
+  return -1;
+}
+
+  /* regexec(&re, string, 0, NULL, 0) == 0 means MATCH */
+
+static void _xdo_get_child_windows(xdo_t *xdo, Window window,
+                                   Window **total_window_list, 
+                                   int *ntotal_windows,
+                                   int *window_list_size) {
+  Window dummy;
+  Window *children;
+  unsigned int i, nchildren;
+
+  if (*window_list_size == 0) {
+    *ntotal_windows = 0;
+    *window_list_size = 100;
+    *total_window_list = malloc(*window_list_size * sizeof(Window));
+  }
+
+  if (!XQueryTree(xdo->xdpy, window, &dummy, &dummy, &children, &nchildren))
+    return;
+
+  for (i = 0; i < nchildren; i++) {
+    Window w = children[i];
+    (*total_window_list)[*ntotal_windows] = w;
+    *ntotal_windows += 1;
+    if (*ntotal_windows == *window_list_size) {
+      *window_list_size *= 2;
+      *total_window_list = realloc(*total_window_list,
+                                   *window_list_size * sizeof(Window));
+    }
+    _xdo_get_child_windows(xdo, w, total_window_list,
+                           ntotal_windows, window_list_size);
+  }
+
+  XFree(children);
+}
+
+int _xdo_keysequence_to_keycode_list(xdo_t *xdo, char *keyseq,
+                                     charcodemap_t **keys, int *nkeys) {
+  char *tokctx = NULL;
+  const char *tok = NULL;
+  char *keyseq_copy = NULL, *strptr = NULL;
+  int i;
+  KeyCode shift_keycode;
+  
+  /* Array of keys to press, in order given by keyseq */
+  int keys_size = 10;
+  *nkeys = 0;
+
+  if (strcspn(keyseq, " \t\n.-[]{}\\|") != strlen(keyseq)) {
+    fprintf(stderr, "Error: Invalid key sequence '%s'\n", keyseq);
+    return False;
+  }
+
+  shift_keycode = XKeysymToKeycode(xdo->xdpy, XStringToKeysym("Shift_L"));
+
+  *keys = malloc(keys_size * sizeof(charcodemap_t));
+  keyseq_copy = strptr = strdup(keyseq);
+  while ((tok = strtok_r(strptr, "+", &tokctx)) != NULL) {
+    KeySym sym;
+    KeyCode key;
+
+    if (strptr != NULL)
+      strptr = NULL;
+
+    /* Check if 'tok' (string keysym) is an alias to another key */
+    /* symbol_map comes from xdo.util */
+    for (i = 0; symbol_map[i] != NULL; i+=2)
+      if (!strcasecmp(tok, symbol_map[i]))
+        tok = symbol_map[i + 1];
+
+    sym = XStringToKeysym(tok);
+    if (sym == NoSymbol) {
+      fprintf(stderr, "(symbol) No such key name '%s'. Ignoring it.\n", tok);
+      continue;
+    }
+
+    key = XKeysymToKeycode(xdo->xdpy, sym);
+    (*keys)[*nkeys].code = key;
+    if (XKeycodeToKeysym(xdo->xdpy, key, 0) == sym) {
+      (*keys)[*nkeys].shift = 0;
+    } else  {
+      (*keys)[*nkeys].shift = shift_keycode;
+    }
+
+    if ((*keys)[*nkeys].code == 0) {
+      fprintf(stderr, "No such key '%s'. Ignoring it.\n", tok);
+      continue;
+    }
+
+    (*nkeys)++;
+    if (*nkeys == keys_size) {
+      keys_size *= 2;
+      *keys = realloc(*keys, keys_size * sizeof(KeyCode));
+    }
+  }
+
+  free(keyseq_copy);
+
+  return True;
+}
+
+int _xdo_regex_match_window(xdo_t *xdo, Window window, int flags, regex_t *re) {
+  XWindowAttributes attr;
+  XTextProperty tp;
+  XClassHint classhint;
+  int i;
+
+  XGetWindowAttributes(xdo->xdpy, window, &attr);
+
+  /* XXX: Memory leak here according to valgrind? */
+  XGetWMName(xdo->xdpy, window, &tp);
+
+  if (flags & SEARCH_TITLE) {
+    if (tp.nitems > 0) {
+      int count = 0;
+      char **list = NULL;
+      XmbTextPropertyToTextList(xdo->xdpy, &tp, &list, &count);
+      for (i = 0; i < count; i++) {
+        if (regexec(re, list[i], 0, NULL, 0) == 0) {
+          XFreeStringList(list);
+          return True;
+        }
+        XFreeStringList(list);
+      }
+    }
+  }
+
+  if (XGetClassHint(xdo->xdpy, window, &classhint)) {
+    if ((flags & SEARCH_NAME) && classhint.res_name) {
+      if (regexec(re, classhint.res_name, 0, NULL, 0) == 0) {
+        XFree(classhint.res_name);
+        XFree(classhint.res_class);
+        return True;
+      }
+      XFree(classhint.res_name);
+    }
+    if ((flags & SEARCH_CLASS) && classhint.res_class) {
+      if (regexec(re, classhint.res_class, 0, NULL, 0) == 0) {
+        XFree(classhint.res_class);
+        return True;
+      }
+      XFree(classhint.res_class);
+    }
+  }
+  return False;
+}
+
+int _is_success(const char *funcname, int code) {
+  if (code != 0)
+    fprintf(stderr, "%s failed (code=%d)\n", funcname, code);
+  return code;
+}
+
+int _xdo_is_window_visible(xdo_t *xdo, Window wid) {
+  XWindowAttributes wattr;
+
+  XGetWindowAttributes(xdo->xdpy, wid, &wattr);
+  if (wattr.map_state != IsViewable)
+    return False;
+
+  return True;
+}
+
+/* Arbitrary window property retrieval
+ * slightly modified version from xprop.c from Xorg */
+unsigned char * _xdo_getwinprop(xdo_t *xdo, Window window, Atom atom,
+                                long *nitems, Atom *type, int *size) {
+  Atom actual_type;
+  int actual_format;
+  unsigned long _nitems;
+  unsigned long nbytes;
+  unsigned long bytes_after; /* unused */
+  unsigned char *prop;
+  int status;
+
+  status = XGetWindowProperty(xdo->xdpy, window, atom, 0, (~0L),
+                              False, AnyPropertyType, &actual_type,
+                              &actual_format, &_nitems, &bytes_after,
+                              &prop);
+  if (status == BadWindow) {
+    fprintf(stderr, "window id # 0x%lx does not exists!", window);
+    return NULL;
+  } if (status != Success) {
+    fprintf(stderr, "XGetWindowProperty failed!");
+    return NULL;
+  }
+
+  if (actual_format == 32)
+    nbytes = sizeof(long);
+  else if (actual_format == 16)
+    nbytes = sizeof(short);
+  else if (actual_format == 8)
+    nbytes = 1;
+  else if (actual_format == 0)
+    nbytes = 0;
+
+  *nitems = _nitems;
+  *type = actual_type;
+  *size = actual_format;
+  return prop;
+}
+
+int _xdo_ewmh_is_supported(xdo_t *xdo, const char *feature) {
+  Atom type = 0;
+  long nitems = 0L;
+  int size = 0;
+  Atom *results = NULL;
+  long i = 0;
+
+  Window root;
+  Atom request;
+  Atom feature_atom;
+  
+  request = XInternAtom(xdo->xdpy, "_NET_SUPPORTED", False);
+  feature_atom = XInternAtom(xdo->xdpy, feature, False);
+  root = RootWindow(xdo->xdpy, 0);
+
+  results = (Atom *) _xdo_getwinprop(xdo, root, request, &nitems, &type, &size);
+  for (i = 0L; i < nitems; i++) {
+    if (results[i] == feature_atom)
+      return True;
+  }
+
+  return False;
+}
Index: /liacs/mms/project/xdo.h
===================================================================
--- /liacs/mms/project/xdo.h	(revision 22)
+++ /liacs/mms/project/xdo.h	(revision 22)
@@ -0,0 +1,83 @@
+/*
+ * xdo library header
+ * - include this if you have code that uses xdo
+ *
+ * $Id: xdo.h 2158 2009-01-26 11:05:03Z jordansissel $
+ */
+
+#include <X11/Xlib.h>
+
+#define SEARCH_VISIBLEONLY (1L << 0)
+#define SEARCH_TITLE (1L << 1)
+#define SEARCH_CLASS (1L << 2)
+#define SEARCH_NAME (1L << 3)
+
+#define SEARCH_IGNORE_TRANSIENTS (1L << 4)
+#define SEARCH_IGNORE_WINDOW_INPUTONLY (1L << 5)
+
+#define SIZE_USEHINTS (1L << 0)
+
+/* Map keysym name to actual ascii */
+typedef struct keysymcharmap {
+  const char *keysym;
+  char key;
+} keysymcharmap_t;
+
+/* map character to keycode */
+typedef struct charcodemap {
+  char key;
+  int code;
+  int shift;
+} charcodemap_t;
+
+typedef struct xdo {
+  Display *xdpy;
+  char *display_name;
+  charcodemap_t *charcodes;
+  int keycode_high; /* highest and lowest keycodes */
+  int keycode_low;  /* used by this X server */
+
+  int close_display_when_freed;
+} xdo_t;
+
+xdo_t* xdo_new(char *display);
+xdo_t* xdo_new_with_opened_display(Display *xdpy, const char *display,
+                                   int close_display_when_freed);
+void xdo_free(xdo_t *xdo);
+
+int xdo_mousemove(xdo_t *xdo, int x, int y);
+int xdo_mousemove_relative(xdo_t *xdo, int x, int y);
+int xdo_mousedown(xdo_t *xdo, int button);
+int xdo_mouseup(xdo_t *xdo, int button);
+int xdo_mouselocation(xdo_t *xdo, int *x, int *y, int *screen_num);
+
+int xdo_click(xdo_t *xdo, int button);
+
+int xdo_type(xdo_t *xdo, char *string);
+int xdo_keysequence(xdo_t *xdo, char *keysequence);
+int xdo_keysequence_up(xdo_t *xdo, char *keysequence);
+int xdo_keysequence_down(xdo_t *xdo, char *keysequence);
+
+int xdo_window_move(xdo_t *xdo, Window wid, int x, int y);
+int xdo_window_setsize(xdo_t *xdo, Window wid, int w, int h, int flags);
+int xdo_window_focus(xdo_t *xdo, Window wid);
+int xdo_window_raise(xdo_t *xdo, Window wid);
+int xdo_window_get_focus(xdo_t *xdo, Window *window_ret);
+int xdo_window_sane_get_focus(xdo_t *xdo, Window *window_ret);
+int xdo_window_activate(xdo_t *xdo, Window wid);
+
+int xdo_window_map(xdo_t *xdo, Window wid);
+int xdo_window_unmap(xdo_t *xdo, Window wid);
+
+/* pager-like behaviors */
+int xdo_window_get_active(xdo_t *xdo, Window *window_ret);
+int xdo_set_number_of_desktops(xdo_t *xdo, long ndesktops);
+int xdo_get_number_of_desktops(xdo_t *xdo, long *ndesktops);
+int xdo_set_current_desktop(xdo_t *xdo, long desktop);
+int xdo_get_current_desktop(xdo_t *xdo, long *desktop);
+int xdo_set_desktop_for_window(xdo_t *xdo, Window wid, long desktop);
+int xdo_get_desktop_for_window(xdo_t *xdo, Window wid, long *desktop);
+
+/* Returns: windowlist and nwindows */
+int xdo_window_list_by_regex(xdo_t *xdo, char *regex, int flags,
+                             Window **windowlist, int *nwindows);
Index: /liacs/templates/latex.mk
===================================================================
--- /liacs/templates/latex.mk	(revision 21)
+++ /liacs/templates/latex.mk	(revision 22)
@@ -11,4 +11,7 @@
 ASPELL = aspell
 ASPELL_ARGS = -c --mode=tex
+
+#XXX: Make me dynamic
+VIEWPDF = evince
 .SUFFIXES: .pdf
 
@@ -34,5 +37,5 @@
 
 viewpdf: buildpdf
-	xpdf $(TARGET).pdf
+	$(VIEWPDF) $(TARGET).pdf
 
 spell: spell-en
