/*
  wpointer v.0.0
  By Ali Rahimi (ali@mit.edu)

  Here's what he experts have to say about wpointer:

  (rand wacker, randal@csua.berkeley.edu)
  Message from randal on ttyRy at 14:03:04 ...
   randal> let you know.  This is an awesome idea dude.  An emminent hack
  EOF(randal)

  (my advisor sandy pentland, pentland@media.mit.edu)
  "Where is that face detector you promised?"

  (sumit basu, sbasu@media.mit.edu)
  "Yeah, I guess it's useful. Whatever."

  (carson's mom, yourmom@media.mit.edu)
  "Come here big boy."



  This was a quick hack. Like most hacks, it's not polished, and would
  probably have been better done in some even less aesthetic language,
  like perl.

  Switching between lots of windows on your desktop is a pain. I don't
  like to use the mouse, because it provides much more feedom than I
  need, and it's a pain to guide it. I use this program to map a 3x3
  grid overlayed on my screen to the number pad. Pushing each number
  pad key warps the cursor to a corresponding window on the
  screen. For example, KP 7 warps the mouse to some window that's
  roughly in the upper left corner of your screen.  The algorithm
  tries to be somewhat smart about what it does, but you might want to
  fine tune it for your own tastes.

  In your window manager config file, bind your numberpad keys to run this
  program. In fvwm2, I bind the number pad keys thusly:

Key KP_1	A	N	Exec wpointer 1
Key KP_2	A	N	Exec wpointer 2
Key KP_3	A	N	Exec wpointer 3
Key KP_4	A	N	Exec wpointer 4
Key KP_5	A	N	Exec wpointer 5
Key KP_6	A	N	Exec wpointer 6
Key KP_7	A	N	Exec wpointer 7
Key KP_8	A	N	Exec wpointer 8
Key KP_9	A	N	Exec wpointer 9


Compile using

g++ wpointer.cc -o wpointer -lX11

(sorry for using c++. i like to take freedom in declaring my vars where
i'm comfortable).

*/


extern "C" {
#include <X11/X.h>
#include <X11/Xlib.h>
}
#include <stdio.h>
#include <stdlib.h>


void
warp_mouse_to_rect(Display *dpy, Window *children, int nchildren,
		   int minx, int miny, int maxx, int maxy,
		   int px, int py)
{
	Window closest_win;
	int closest_dist;
	int closest_x, closest_y;
	XWindowAttributes closest_attrs;

	closest_win = None;


	for(int i=0; i<nchildren; ++i) {
		int x, y;
		unsigned int width, height, border, depth;
		XWindowAttributes attrs;
		XGetWindowAttributes(dpy, children[i], &attrs);

		x = attrs.x + attrs.width/2;
		y = attrs.y + attrs.height/2;

		if((x<minx) || (x>maxx) || (y<miny) || (y>maxy))
			continue;

		if(attrs.border_width == 0)
			continue;

		if(attrs.override_redirect)
			continue;

		int dist = (px-x)*(px-x) + (py-y)*(py-y);

		if((closest_win==None) || (dist < closest_dist)) {
			closest_dist = dist;
			closest_win = children[i];
			closest_x = x;
			closest_y = y;
			closest_attrs = attrs;
		}
	}

	if(!closest_win) return;

	printf("warping to %d %d (%dx%d+%d+%d) = %x\n",
	       closest_x, closest_y,
	       closest_attrs.width, closest_attrs.height,
	       closest_attrs.x, closest_attrs.y,
	       closest_win);

	/*
	XGCValues gcv;
	gcv.subwindow_mode = IncludeInferiors;
	GC gc = XCreateGC(dpy, DefaultRootWindow(dpy), GCSubwindowMode, &gcv);
	XSetForeground(dpy, gc, 0x2);
	XDrawRectangle(dpy, DefaultRootWindow(dpy),
		       gc,
		       closest_attrs.x-5, closest_attrs.y-5,
		       closest_attrs.width+5, closest_attrs.height+5);
	XFreeGC(dpy, gc); */

	XWarpPointer(dpy, None, DefaultRootWindow(dpy),
		     0, 0, 0, 0,
		     /*closest_x, closest_y*/
		     closest_x, closest_attrs.y+10);
	XRaiseWindow(dpy, closest_win);
	XFlush(dpy);
}


void
warpmouse(Display *dpy, int rgn)
{
	Window rootw, parentw;
	Window *children;
	unsigned int nchildren;

	XQueryTree(dpy, DefaultRootWindow(dpy), &rootw, &parentw,
		   &children, &nchildren);

	if(children == NULL) return;

	int dx = DisplayWidth(dpy,DefaultScreen(dpy))/3;
	int dy = DisplayHeight(dpy,DefaultScreen(dpy))/3;

	int rgn_r = 2-rgn/3;
	int rgn_c = rgn%3;

	int minx = dx * rgn_c;
	int miny = dy * rgn_r;
	int maxx = dx * rgn_c + dx;
	int maxy = dy * rgn_r + dy;

	int x = (minx+maxx)/2;
	int y = (miny+maxy)/2;

	warp_mouse_to_rect(dpy, children, (int)nchildren,
			   minx, miny, maxx, maxy, x, y);

	XFree(children);
}


int
main(int argc, char **argv)
{
	if(argc < 2) {
		fprintf(stderr, "usage: %s region\n", argv[0]);
		exit(-1);
	}

	Display *dpy = XOpenDisplay(NULL);
	warpmouse(dpy, atoi(argv[1])-1);

	return 0;
}
