/***************************************************************************
 *
 * Mouse V1.0
 *
 * This program opens :VDI:, deletes all windows, creates a new full screen
 * window on bitmap 0, creates a 1BPP bitmap and a small window on it, and
 * then starts a locator.  Each time a mouse button is pressed we report
 * the current cursor location to the small window.
 * if control-c then stop input, push window, and exit.
 */

#pragma extend

/*
 * The standard iC 286 V3.2 include files are first
 */
#include <stdio.h>
#include <string.h>
#include <udi.h>
#include <math.h>

#include <rmxc.h>
#include <rmxerr.h>

#include <rgi.h>

static CGIDevice  cgidev;
static char       cginame[] = ":VDI:";
static char       ucginame[256];
static TOKEN      cgiconn;
static char       cgibuff[8192];

static EXCEPTIONSTRUCT noexcept = {0,0,0};

#define xleft = 10;
#define ytop = 400;

static char *prompt =  "Press Left/Right Mouse Button"; 
static char *aprompt = "to Report Coordinates.";
static char *nprompt = "Press Middle Mouse Button to Exit.";
static char *info =    "Current Position Report: %d, %d";
static char rinfo[256];

/* MouseCursor
	X X X X X X X X _ _ _ _ _ _ _ _
	X _ _ _ _ _ X _ _ _ _ _ _ _ _ _
	X _ _ _ _ X _ _ _ _ _ _ _ _ _ _
	X _ _ _ _ _ X _ _ _ _ _ _ _ _ _
	X _ _ _ _ _ _ X _ _ _ _ _ _ _ _
	X _ X _ _ _ _ _ X _ _ _ _ _ _ _
	X X _ X _ _ _ _ _ X _ _ _ _ _ _
	X _ _ _ X _ _ _ X _ _ _ _ _ _ _
	_ _ _ _ _ X _ X _ _ _ _ _ _ _ _
	_ _ _ _ _ _ X _ _ _ _ _ _ _ _ _
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
*/

static cursor_struc MouseCursor = {
    0, 0,
    0x0ff00,    0x08200,    0x08400,    0x08200,
    0x08100,    0x0a080,    0x0d040,    0x08880,
    0x00500,    0x00200,    0x00000,    0x00000,
    0x00000,    0x00000,    0x00000,    0x00000
};

#define X_RES 640
#define Y_RES 480

static int x = X_RES/2;
static int y = Y_RES/2;
static int b = 0;

void wait_event ( void )
{
 POINT     pt;
 RGI_Index devtype, flags;
 WORD      except;
 Word      rgi_except;
 char      str[10];
 unsigned  long ti;

  /* note the flush.  in a synchronous model we flush all output.
   * request input does not flush pending buffers since it may be
   * running in another task (the input task) asynchronously with
   * the display task.  if regions were used to sync all output tasks,
   * the input task would NOT enter the output region because it will
   * block here for the duration of the interaction.  the async input
   * routines perform atomic writes to avoid corrupting the other
   * data streams.  The display task(s) should NEVER allow the library
   * to flush the buffer since that could cause a partial command to
   * be written, corrupting the data stream (for both input and output
   * tasks).  Use a large buffer and flush it explicitly.
   */
  cgi_flush(cgidev, &rgi_except);
  /* time out is forever, str is 1 longer than needed since the
   * first byte of the response is the count.
   */
  gqrequestinput(cgidev, WAIT_FOREVER, &devtype, &flags, &ti, &pt,
                (void *)str, (Word)10, &rgi_except);

  if (rgi_except != EOK) {
    /* Control-C returns E$FLUSHING here asynchronously with cchandler.
     * Real programmers would call suspendtask(0) at this point to
     * correctly synchronize.  cchandler could delete/recreate as
     * needed...
     */
    flags = devtype = 0;
    x = y = b = 0;
    fprintf(stderr,"requestevent error %d\n",except);
  } else {
    if (devtype == STRING_DEVICE) {
      str[str[0]+1] = '\0';
      fprintf(stderr, "%d.%d t=%ld str(%d)=%s\n",
                      devtype, flags, ti, str[0], &str[1]);
    } else if (devtype == LOCATOR_DEVICE) {
      x = pt.x;
      y = pt.y;
      b = (int) (flags & BUTTON_MASK);
      fprintf(stderr, "%d.%d t=%ld @ %d,%d\n",
                      devtype, flags, ti, x, y);
    } else {
      fprintf(stderr,"unrecognized event:\n");
      fprintf(stderr, "    %d.%d t=%ld @ %d,%d, str(%d)=%s\n",
                      devtype, flags, ti, x, y, str[0], &str[1]);
    }
  }
}

void far mouse_error ( void )
{
  WORD except;

  Word rgi_except;


  gqassigncursor        (cgidev, (CursorId)0, (WindowId)0);
  gqdeletecursor        (cgidev, (CursorId)1);

  gqdeletewindow        (cgidev, (WindowId)1);
  gqdeletewindow        (cgidev, (WindowId)0);

  gqdeletebitmap        (cgidev, (BitmapId)1);
  gqdeletebitmap        (cgidev, (BitmapId)0);

  gqenablesystemmenu    (cgidev);
  gqselectdrawingbitmap (cgidev, (BitmapId)0);
  gqpushwindow          (cgidev, (WindowId)0);

  cgi_terminate (cgidev, &rgi_except);

  if (rgi_except != EOK) dqexit((WORD)1);

  dqclose(cgiconn, &except);

  if (except != EOK) dqexit((WORD)1);

  dqdetach(cgiconn, &except);

  if (except != EOK) dqexit((WORD)1);

  dqexit((WORD)1);
}

main(
int   argc,
char  **argv)
{
  WORD except = 0;
  Word rgi_except = 0;

  rqsetexceptionhandler(&noexcept, &except);
  dqtrapcc( (HANDLERPTRSTRUCT *) mouse_error, &except);
  if (except != EOK) dqexit((WORD)1);


  cgiconn = rqsattachfile( (STRING *) udistr(ucginame, (const char *)cginame),
                           &except);
  if (except != EOK) {
    fprintf(stderr, "Error %d Attaching Output File: %s\n", except, cginame);
    dqexit((WORD)1);
  }

  rqsopen(cgiconn, (BYTE)3, (BYTE)0, &except);


  if (except != EOK) {
    fprintf(stderr, "Error %d Opening Output File: %s\n",except,cginame);
    dqexit((WORD)1);
  }

  cgidev = cgi_initialize(cgiconn, cgibuff, sizeof cgibuff, &rgi_except);
  if (rgi_except != EOK) {
    fprintf(stderr, "Error %d Initializing CGI library: %s\n",
            rgi_except, cginame);
    dqexit((WORD)1);
  }
  gqdeleteallbitmaps    (cgidev);
  gqdeleteallwindows    (cgidev);
  gqcreatebitmap        (cgidev, (BitmapId)0,
                                 (DC)X_RES, (DC)Y_RES,
                                 (RGI_Index)1);
  gqcreatewindow        (cgidev, (WindowId)0, (BitmapId)0, 
                                 (RGI_Index)TOP_WINDOW,
                                 (RGI_Index)(VISIBLE | BORDER_VISI),
                                 (DC)0, (DC)0,
                                 (DC)0, (DC)0,
                                 (DC)X_RES, (DC)Y_RES);
  gqcreatebitmap        (cgidev, (BitmapId)1,
                                 (DC)X_RES, (DC)Y_RES,
                                 (RGI_Index)1);
  gqsetvdcextent        (cgidev, (VDC)0, (VDC)0,
                                 (VDC)(X_RES-1), (VDC)(Y_RES-1));
  gqsetdeviceviewport   (cgidev, (DC)0, (DC)0,
                                 (DC)(X_RES-1), (DC)(Y_RES-1));
  gqcreatewindow        (cgidev, (WindowId)1, (BitmapId)1,
                                 (RGI_Index)TOP_WINDOW,
                                 (RGI_Index)(VISIBLE | BORDER_VISI),
                                 (DC)0, (DC)(Y_RES-426),
                                 (DC)10, (DC)10,
                                 (DC)290, (DC)95);
  gqselectdrawingbitmap (cgidev, (BitmapId)1);
  gqsettransparency     (cgidev, (RGI_Index)OPAQUE);
  gqsetbackgroundcolor  (cgidev, (RGI_Index)BLACK);
  gqsetdrawingmode      (cgidev, (RGI_Index)OP_REPLACE);
  gqclearviewsurface    (cgidev);

  gqsettextalignment    (cgidev, (RGI_Index)ALIGN_LEFT,
                                 (RGI_Index)ALIGN_BOTTOM,
                                 (Real)0.0, (Real)0.0);
  gqsettextfontindex    (cgidev, (RGI_Index)RASTER_FONT);

  gqsetbordercolor      (cgidev, (ColorIndex)255);
  gqsetcursorcolorpad   (cgidev, (ColorIndex)255);
  gqloadcursor          (cgidev, (CursorId)1, &MouseCursor);
  gqassigncursor        (cgidev, (CursorId)1, (WindowId)0);

  gqsettextcolor        (cgidev, (ColorIndex)WHITE);
  gqtext                (cgidev, (VDC)10, (VDC)400,
                                 (RGI_Index)END_OF_STRING, 
                                 (Integer)strlen((const char *)prompt),
                                 (void *)prompt);
  gqtext                (cgidev, (VDC)10, (VDC)380, 
                                 (RGI_Index)END_OF_STRING,
                                 (Integer)strlen((const char *)aprompt),
                                 (void *)aprompt);
  gqtext                (cgidev, (VDC)10, (VDC)360, 
                                 (RGI_Index)END_OF_STRING,
                                 (Integer)strlen((const char *)nprompt),
                                 (void *)nprompt);
  gqpopwindow           (cgidev, (WindowId)1);

  /* note the flush before starting input... */
  cgi_flush             (cgidev, &rgi_except);

  /* note that -1 is used to ignore events from a particular device... */
  /* note that 0 is the only valid locator or string device in this release */
  /* note that mode refers to locator echo state ECHO_ON/ECHO_OFF */
  /* x and y are the initial position. */
  /* cursor type and echo region follow */
  gqstartinput          (cgidev, (RGI_Index)-1,
                                 (RGI_Index)0,
                                 (RGI_Index)ECHO_ON,
                                 (VDC)x, (VDC)y,
                                 (RGI_Index)HARDWARE_CURSOR,
                                 (VDC)0, (VDC)0,
                                 (VDC)(X_RES-1), (VDC)(Y_RES-1),
                                 &rgi_except);


  gqsetlocatortrigger   (cgidev, (RGI_Index)0,
                                 (Byte)(INPUT_MOVE | INPUT_BUTTON_DOWN) );

  wait_event();  /* does a flush */

  while (b != MIDDLE_BUTTON) {
    /* format it */
    sprintf(rinfo, (const char *)info, x, y);

    /* print it */
    gqsettextcolor (cgidev, (ColorIndex)WHITE);
    gqtext         (cgidev, (VDC)10, (VDC)340, (RGI_Index)END_OF_STRING,
                            (Integer)strlen((const char*)rinfo),
                            (void *)rinfo);

    wait_event();

    /* erase it */
    gqsettextcolor (cgidev, (ColorIndex)BLACK);
    gqtext         (cgidev, (VDC)10, (VDC)340, (RGI_Index)END_OF_STRING,
                            (Integer)strlen((const char*)rinfo),
                            (void *)rinfo);
  }

  /* erase it */
  gqassigncursor (cgidev, (CursorId)0, (WindowId)0);
  gqdeletecursor (cgidev, (CursorId)1);
  gqdeletewindow (cgidev, (WindowId)1);
  gqdeletewindow (cgidev, (WindowId)0);

  gqdeletebitmap (cgidev, (BitmapId)1);
  gqdeletebitmap (cgidev, (BitmapId)0);

  gqendinput     (cgidev, &rgi_except);

  cgi_terminate  (cgidev, &rgi_except);  /* forces flush */
  if (rgi_except != EOK) dqexit((WORD)1);

  rqsclose(cgiconn,&except);
  if (except != EOK) dqexit((WORD)1);

  rqsdeleteconnection(cgiconn,&except);
  if (except != EOK) dqexit((WORD)1);
}
