#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <errno.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/X.h>

Window GetBaseWindowAtLocation(
  Display *aDisplay,
  Window  aWindow,
  int x,
  int y);

Window GetBaseWindowAtLocation(
  Display *aDisplay,
  Window  aWindow,
  int x,
  int y)
{
  Window tRoot;
  Window tParent;
  Window *tChild;
  Window  tWindow;
  uint     tNumChild;
  XWindowAttributes tWindowAttributes;
  XWindowAttributes tWindowAttributes2;

  std::cout<<"Descending through windows using XQueryTree"<<std::endl;
  XQueryTree(aDisplay,aWindow,&tRoot, &tParent, &tChild, &tNumChild);
  if(tNumChild == 0)
  {
    XFree(tChild);
    return aWindow;
  }
  else
  {
    std::cout<<"Looking for widget at coordinates "<<x<<","<<y<<std::endl;
    for(int count=0; count <(int)tNumChild;++count)
    {
      XGetWindowAttributes(aDisplay,tChild[count], &tWindowAttributes);
      if(count + 1 < (int)tNumChild)
      {
       XGetWindowAttributes(aDisplay,tChild[count+1],&tWindowAttributes2);
      }
      if(tWindowAttributes.x < x && x < (tWindowAttributes.width + tWindowAttributes.x) && 
         tWindowAttributes.y < y && y < (tWindowAttributes.height + tWindowAttributes.y) &&
         tWindowAttributes.map_state == 2)
      {
        std::cout<<"Descending into "<<tChild[count]<<std::endl<<std::endl;
        tWindow = GetBaseWindowAtLocation(aDisplay,tChild[count],x-tWindowAttributes.x,y-tWindowAttributes.y);
        XFree(tChild);
        return tWindow;
      }
    }
  }
}

int main(int argc, char **argv)
{
  std::cout<<"You've got five seconds to put your mouse somewhere to test with"<<std::endl;
  sleep(5);

  Display *tDisplay = XOpenDisplay("sierra:12.0");
  XEvent   tEvent;
  Window   tWindow;
  XWindowAttributes tWindowAttributes;

  tEvent.type = ButtonPress;
  tEvent.xbutton.button = Button1;

  //Simply using the mouse to identify a location for testing purposes
  XQueryPointer(tDisplay, DefaultRootWindow(tDisplay), &tEvent.xbutton.root, 
                &tEvent.xbutton.window, &tEvent.xbutton.x_root, &tEvent.xbutton.y_root,
                &tEvent.xbutton.x, &tEvent.xbutton.y, &tEvent.xbutton.state);

  tWindow = GetBaseWindowAtLocation(tDisplay, tEvent.xbutton.window, tEvent.xbutton.x_root, tEvent.xbutton.y_root);
 
  tEvent.xbutton.subwindow = tEvent.xbutton.window;

  std::cout<<"Descending through windows using XQueryPointer"<<std::endl;
  while(tEvent.xbutton.subwindow)
  {
    tEvent.xbutton.window = tEvent.xbutton.subwindow;
    XGetWindowAttributes(tDisplay,tEvent.xbutton.window, &tWindowAttributes);
    std::cout<<"Current window is "<<tEvent.xbutton.window<<std::endl;
    
    XQueryPointer(tDisplay, tEvent.xbutton.window, &tEvent.xbutton.root, 
      &tEvent.xbutton.subwindow, &tEvent.xbutton.x_root, &tEvent.xbutton.y_root, 
      &tEvent.xbutton.x, &tEvent.xbutton.y, &tEvent.xbutton.state);
  }
  std::cout<<std::endl;

  std::cout<<"x = "<<tEvent.xbutton.x <<", x root = "<<tEvent.xbutton.x_root<<
  "y = "<<tEvent.xbutton.y <<", y root = "<<tEvent.xbutton.y_root<<std::endl;

  if(!XSendEvent(tDisplay, tEvent.xbutton.window, false, 0xfff, &tEvent))
    std::cout<<"There was a problem with the press"<<std::endl;

  XFlush(tDisplay);

//release event
  tEvent.type = ButtonRelease;
  tEvent.xbutton.state = 0x100;

  if(!XSendEvent(tDisplay, tEvent.xbutton.window, false, 0xfff, &tEvent))
    std::cout<<"There was a problem with the release"<<std::endl;

  XFlush(tDisplay);

  XCloseDisplay(tDisplay);
}
