/*
  xpointer.c - do things to the pointer.
*/

#include <stdio.h>
#include <sys/time.h>
#include <signal.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/cursorfont.h>

/* String constants */
#define NO_DISPLAY	"Can't open Display.\n"
#define DO_STR		"C'mon, do something!"

/* Macros */
#define quick_write(s)	write(0, s, sizeof(s)/sizeof(char))

/* Data for "blank" pixmaps */
static char fore[] = { '\000' };
static char mask[] = { '\000' };

/* Prototypes */
int time_func();
int main(int argc, char *argv[]);

/*
  Here's what we do.
  Set up an event loop to wait for pointer movement events.
  When they are received, reset the counter.
  When the counter expires, do some requested action.

  The action should be:
  
    int action(void);
*/

/* These are global so that the interupt proc can see them */
static struct itimerval itval;
static Display *display = NULL;
static Cursor curs;
static int grabbed;

int main(int argc, char *argv[])
{
  int	 	screen;
  XEvent	xev;
  KeySym	mykey;
  int		done;
  char		text[10];
  int 		i;
  Pixmap	forepm, maskpm;
  XColor	white, black;
  
  if (!(display = XOpenDisplay(NULL))) {
    quick_write(NO_DISPLAY);
    return(1);
  }
  
  screen = DefaultScreen(display);
  
  /* Find color values for black and white. */
  bzero(&black, sizeof(XColor));
  bzero(&white, sizeof(XColor));
  black.pixel = BlackPixel(display, screen);
  white.pixel = WhitePixel(display, screen); 
  XQueryColor(display, DefaultColormap(display, screen), &black);
  XQueryColor(display, DefaultColormap(display, screen), &white);
  
  /* Create the Blank Cursor */
  forepm =
  XCreatePixmapFromBitmapData(display, RootWindow(display, screen),
			      fore, 1, 1, 
			      BlackPixel(display, screen), 
			      WhitePixel(display, screen),
			      1);
  maskpm =
  XCreatePixmapFromBitmapData(display, RootWindow(display, screen),
			      mask, 1, 1, 
			      BlackPixel(display, screen), 
			      WhitePixel(display, screen),
			      1);
  curs = XCreatePixmapCursor(display, forepm, maskpm, black, white, 1, 1);
  
  
  /* input event selection */
  XSelectInput(display, RootWindow(display, screen),
	       KeyPressMask | ExposureMask
	       | PointerMotionMask);
  
  /* main event-reading loop */
  done = 0;
  
  /* Set up clock values */
  itval.it_interval.tv_sec = 0;
  itval.it_value.tv_sec = 5;
  itval.it_value.tv_usec = 0;
  
  signal(SIGALRM, time_func);
  setitimer(ITIMER_REAL, &itval, 0);
  
  while (!done) {
    /* read the next event */
    XNextEvent(display, &xev);
    
    switch(xev.type) {
      /* repaint window on Expose events */
    case MotionNotify:
      if (grabbed) {
	XUngrabPointer(display, CurrentTime);
	grabbed = 0;
      }
      
      /* Reset clock values */
      itval.it_interval.tv_sec = 0;
      itval.it_value.tv_sec = 5;
      itval.it_value.tv_usec = 0;
      setitimer(ITIMER_REAL, &itval, 0);
      break;

      /* process keyboard mapping changes */
    case MappingNotify:
      XRefreshKeyboardMapping(&xev);
      break;
      
      /* process keyboard input */
    case KeyPress:
      i = XLookupString (&xev, text, 10, &mykey, 0);
      if (i == 1 && text[0] == 'q') done = 1;
      break;
      
    }
  }
  
  return(0);
}

int time_func()
{
  Window root, child;
  int root_x, root_y;
  int win_x, win_y;
  unsigned int keys_buttons;
  
  /* Don't do anything if display is NULL */
  if (!display) return(0);
  
  /* Find the window the pointer is in */
  XQueryPointer(display, RootWindow(display, DefaultScreen(display)),
		&root, &child, &root_x, &root_y, &win_x, &win_y,
		&keys_buttons);
  
  if (child == 0) {
    child = RootWindow(display, DefaultScreen(display));
  }

  XGrabPointer(display, child,
	       True, PointerMotionMask, GrabModeAsync, GrabModeAsync,
	       None, curs, CurrentTime);
  
  grabbed = 1;
  
  return(0);
}


  



