# include "Ximage.h"

/* # define IgnoreMask (long) (ClientMessage | ButtonReleaseMask | PointerMotionMask) */
# define IgnoreMask (long) (~(StructureNotifyMask | SubstructureNotifyMask | ExposureMask | KeyPressMask | ButtonPressMask))

int LastEvent (Display *display, int type, XEvent *event);

int cursor () {

  Display        *display;
  XEvent          event;
  KeySym          keysym;
  int             status, value;
  XComposeStatus  composestatus;
  char            string[10], line[40], *name;
  double          x, y;
  char            buffer[10];
  Layout         *layout;
  XButtonEvent   *mouse_event;

  layout = &section[TheSection];

  while (1) {
    
    /* check the pipe for messages */
    status = read (sock, buffer, 4);
    buffer[4] = 0;
    
    if (status == -1) goto events;
    if (status ==  0) return (FALSE);
    if (status ==  4) {
      if (!strcmp (buffer, "NCUR")) return (TRUE);
      goto events;
    }
    fprintf (stderr, "weird signal: too many or few bytes!  %d\n", status);
    return (TRUE);

  events:
    if (XEventsQueued (graphic.display, QueuedAfterFlush) < 1) {
      usleep (50000);
      continue;
    }

    /* check for x events */
    display = graphic.display;

    /* grab the last entry for these events */
    if (LastEvent (display, ConfigureNotify, &event)) Reconfig (&event);
    if (LastEvent (display, CirculateNotify, &event)) Reconfig (&event);
    if (LastEvent (display, Expose,          &event)) Refresh (1);

    if (LastEvent (display, MappingNotify,   &event)) XRefreshKeyboardMapping ((XMappingEvent *) &event);
	
    /* drop and ignore the following StructureNotifyMask events */
    LastEvent (display, GravityNotify, &event);
    LastEvent (display, ReparentNotify, &event);
    LastEvent (display, MapNotify, &event);
    LastEvent (display, UnmapNotify, &event);

    /* handle button presses */
    if (LastEvent (display, ButtonPress,     &event)) {
      mouse_event = (XButtonEvent *) &event;
      sprintf (string, "Button%d", mouse_event[0].button);
      x = (mouse_event[0].x - layout[0].axis[0].fx)*(layout[0].axis[0].max - layout[0].axis[0].min)/layout[0].axis[0].dfx + layout[0].axis[0].min;
      y = (mouse_event[0].y - layout[0].axis[1].fy)*(layout[0].axis[1].max - layout[0].axis[1].min)/layout[0].axis[1].dfy + layout[0].axis[1].min;
      snprintf (line, 40, "%12s %12.6f %12.6f ", string, x, y);
      write (sock, line, 40);
    }

    /* handle key presses */
    if (LastEvent (display, KeyPress,        &event)) {
      value = XLookupString ((XKeyEvent *) &event, string, 9, &keysym, &composestatus);
      name = XKeysymToString (keysym);

      // ignore unmapped keys
      if (name == NULL) continue;

      x = (event.xkey.x - layout[0].axis[0].fx)*(layout[0].axis[0].max - layout[0].axis[0].min)/layout[0].axis[0].dfx + layout[0].axis[0].min;
      y = (event.xkey.y - layout[0].axis[1].fy)*(layout[0].axis[1].max - layout[0].axis[1].min)/layout[0].axis[1].dfy + layout[0].axis[1].min;

      // skip the following keys: 
      if (!strcmp (name, "Shift_L")) continue;
      if (!strcmp (name, "Shift_R")) continue;
      if (!strcmp (name, "Control_L")) continue;
      if (!strcmp (name, "Control_R")) continue;
      if (!strcmp (name, "Alt_L")) continue;
      if (!strcmp (name, "Alt_R")) continue;
      if (!strcmp (name, "Super_L")) continue;
      if (!strcmp (name, "Super_R")) continue;
      if (!strcmp (name, "Caps_Lock")) continue;
      if (!strcmp (name, "Pause")) continue;
      if (!strcmp (name, "Continue")) continue;
      if (!strcmp (name, "Num_Lock")) continue;
      if (!strcmp (name, "Scroll_Lock")) continue;
      if (!strcmp (name, "Print")) continue;
      if (!strcmp (name, "(null)")) continue;

      snprintf (line, 40, "%12s %12.6f %12.6f ", name, x, y);
      write (sock, line, 40);
    }

    /* remove those events we will ignore */
    while (XCheckMaskEvent (display, IgnoreMask, &event)) continue;

    /* events to remove which have no mask component */
    while (XCheckTypedEvent (display, ClientMessage, &event)) continue;
    while (XCheckTypedEvent (display, SelectionClear, &event)) continue;
    while (XCheckTypedEvent (display, SelectionNotify, &event)) continue;
    while (XCheckTypedEvent (display, SelectionRequest, &event)) continue;
  }
  return (FALSE);
}
