#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <X11/Xutil.h>

#include <stdio.h>

Display                 *display;
int                     screen_num;
Window                  root,main_win,child;
Window                  parent_win,*child_list;
XSetWindowAttributes    win_att;
XEvent                  the_event;
XImage                  *ximage;
GC                      the_GC;
unsigned long           black_pix, white_pix;
XColor                  screen_color,exact_color;
int                     width,height;
int                     rel_x,rel_y,border,abs_x,abs_y;
int                     x,y,oldx,oldy,root_x,root_y,win_x,win_y;
int                     posx=-1,posy=-1;
int                     moving=0,mousex,mousey,winx,winy;
int                     orix,oriy, newx, newy;
unsigned int            w, h, bw, num_children,depth;
unsigned int            mask;
char                    cpu[256];
char                    *keyptr;
XComposeStatus          cs;
KeySym                  key;
unsigned int            keys_buttons;

void usage(void) {
  fprintf(stderr,"Usage: mag options.\n");
  fprintf(stderr,"           -s                 small window.\n");
  fprintf(stderr,"           -m                 medium window.\n");
  fprintf(stderr,"           -l                 large window.\n");
  fprintf(stderr,"           -d                 Dynamic placement.\n");
  fprintf(stderr,"           -z n               Zoom factor.\n");
  fprintf(stderr,"           -x nnnn            Original X placement.\n");
  fprintf(stderr,"           -y nnnn            Original Y placement.\n");
  exit(1);
}

int main(argc,argv)
int argc; char *argv[]; {
  int r,sx,sy,dx,dy,px=0,py=0,opt;
  int width=120;
  int height=120;
  int zoom=2;
  int dynamic=0;
  unsigned long pix;
  int screenwidth, screenheight;
  if ((display=XOpenDisplay(NULL)) == NULL) {
      (void) fprintf(stderr, "Can't connect to display\n");
      exit(-1);
  }
  while((opt=getopt(argc,argv,"dx:y:z:sml"))!=-1) {
    switch(opt) {
      case 'd' : dynamic=1; break;
      case 'x' : x=atoi(optarg); break;
      case 'y' : y=atoi(optarg); break;
      case 'z' : zoom=atoi(optarg); break;
      case 's' : width=30; height=30; break;
      case 'm' : width=60; height=60; break;
      case 'l' : width=120; height=120; break;
      default  : usage(); break;
    }
  }
  if(zoom<1 || zoom>4) { fprintf(stderr,"0>zoom>5 please.\n"); exit(1); }
  width*=zoom;
  height*=zoom;
  screenwidth=DisplayWidth(display,DefaultScreen(display));
  screenheight=DisplayHeight(display,DefaultScreen(display));
  main_win = XCreateSimpleWindow(display,DefaultRootWindow(display),x,y,        /* x, y */
                  width, height,
                  1,             /* border width */
                  black_pix,     /* foreground */
                  white_pix);    /* background */
  /* Get the window tree information */
  if (!XQueryTree(display,main_win,&root,&parent_win,&child_list,&num_children))
      printf("Can't query window tree\n.");
  XFree(child_list);
  win_att.override_redirect = True;
  XChangeWindowAttributes(display,main_win, CWOverrideRedirect, &win_att);
  // XSelectInput(display,main_win,StructureNotifyMask|ExposureMask|ButtonPressMask|ButtonReleaseMask|KeyPressMask);
  XSelectInput(display,main_win,ButtonPressMask|ButtonReleaseMask|KeyPressMask);
  the_GC=XCreateGC(display,main_win,0,0);
  XMapWindow(display,main_win);
  XFlush(display);
  while(1) {
    while(XPending(display)) {
      XNextEvent(display,&the_event);
      switch(the_event.type) {
        case KeyPress: {
          r=XLookupString(&the_event.xkey,keyptr,1,&key,&cs);
          if(r>0) keyptr++;
          switch(key) {
            case XK_Q:
            case XK_q:
            case XK_Escape: {
              exit(0);
              break;
            }
          }
        }
        case ButtonRelease: {
          moving=0;
          break;
        }
        case ButtonPress: {
          switch (the_event.xbutton.button) {
            case Button1: {
              XGetGeometry(display,main_win,&root,&orix,&oriy,&w,&h,&bw,&depth);
              newx=orix;
              newy=oriy; 
              posx=newx;
              posy=newy;
              XQueryPointer(display,DefaultRootWindow(display),&root,&child,&mousex,&mousey,&winx,&winy,&mask);
              moving=1;
            }
          }
        }
      }
    }
    XQueryPointer(display,DefaultRootWindow(display),&root,&child,&x,&y,&winx,&winy,&mask);
    if(moving) {
      if(x!=oldx || y!=oldy) {
        XMoveWindow(display,main_win,posx+x-mousex,posy+y-mousey);
        oldx=x; oldy=y;
      }
    }
    if(x!=oldx || y!=oldy) {
      if(dynamic) {
        if(x>screenwidth/2+screenwidth/4) {
          if(px) {
            px=0;
            XMoveWindow(display,main_win,px,py);
            // fprintf(stderr,"DCCD X moved to 0\n");
          }
        } 
        if(x<screenwidth/2-screenwidth/4) {
          if(!px) {
            px=screenwidth-width;
            XMoveWindow(display,main_win,px,py);
            // fprintf(stderr,"DCCD X moved to max\n");
          }
        }
        if(y>screenheight/2+screenheight/4) {
          if(py) {
            py=0;
            XMoveWindow(display,main_win,px,py);
            // fprintf(stderr,"DCCD Y moved to 0\n");
          }
        }
        if(y<screenheight/2-screenheight/4) {
          if(!py) {
            py=screenheight-height;
            XMoveWindow(display,main_win,px,py);
            // fprintf(stderr,"DCCD Y moved to max\n");
          }
        }
      }
      oldx=x; oldy=y;
      sx=width/zoom/2;
      sy=height/zoom/2;
      if(x-sx<0) x=sx;
      if(y-sy<0) y=sy;
      if(x>screenwidth-sx) x=screenwidth-sx;
      if(y>screenheight-sy) y=screenheight-sy;
      // fprintf(stderr,"DCCD X:%d Y:%d\n",x,y);
      ximage=XGetImage(display,root,x-sx,y-sy,width/zoom,height/zoom,AllPlanes,ZPixmap);
      // fprintf(stderr,"XGetImage returns:%d\n",(int)ximage);
      // XPutImage(display,main_win,the_GC,ximage,0,0,0,0,width,height);
      XDestroyImage(ximage);
      for(sx=0;sx<width/zoom;sx++) {
        for(sy=0;sy<height/zoom;sy++) {
          pix=XGetPixel(ximage,sx,sy);
          for(dx=0;dx<zoom;dx++) {
            for(dy=0;dy<zoom;dy++) {
              XSetForeground(display,the_GC,pix);
              XDrawPoint(display,main_win,the_GC,sx*zoom+dx,sy*zoom+dy);
            }
          }
        }
      }
      XFlush(display);
    } else {
      usleep(30000);
    }
  }
}
