home *** CD-ROM | disk | FTP | other *** search
/ Fish 'n' More 2 / fishmore-publicdomainlibraryvol.ii1991xetec.iso / dirs / rexxlib_393.lzh / RexxLib / C_Example / FreeDraw.c < prev    next >
C/C++ Source or Header  |  1990-10-28  |  46KB  |  1,274 lines

  1. #define TALKTOREXX 1
  2. #ifdef TALKTOREXX
  3. /*
  4.  This program is an example of how to add a Rexx implementation to any
  5.  program using the rexxapp.library.  The original Freedraw program (without
  6.  REXX) is from Fred Fish Disk 1. The rexxapp.library is based upon a C module
  7.  by Radical Eye Software which was modified and down-coded to a 68000 shared
  8.  library.
  9.  All the REXX stuff is bracketed by "idef TALKTOREXX", so you can identify it
  10.  easily.  If you compile with TALKTOREXX unset, you will get the default
  11.  program with no REXX port. The REXX port on this program increases the
  12.  executable slightly, but a lot of functionality comes with that. You can draw
  13.  from Rexx, spawn macros from Rexx, etc.  But go to the next TALKTOREXX for
  14.  more information. To run a rexx macro on startup, simply give that rexx macro
  15.  as part of the command line, as in "freedraw sample" or "freedraw bspline 20
  16.  100 20 20 280 20 280 100". All modifications are placed in the public domain.
  17. */
  18. #endif
  19.  
  20. /* *************************************************************************
  21.                FreeDraw - PD graphics for Amiga           
  22.  
  23.  This is an extremely simple graphics editor which works in the windowing
  24.  environment of the Amiga.  It is very limited in features. The basic idea of
  25.  this program is to provide some minimal image editing functions which can be
  26.  used to develop images for other programs.
  27.  There are only two menu topics in this version, so using it is really
  28.  quite easy.  Boxes are not allowed to be drawn in areas outside of the window
  29.  where border gadgets are located, and the pen-draw mode also clips to these
  30.  same boundaries. If you have begun to draw a box by clicking the left button
  31.  while the cursor is located in the FreeDraw window, then you can cancel that
  32.  box by clicking the right button. In the pen mode pressing and holding the
  33.  left button will draw.  Colors are selected by simply releasing the menu
  34.  button over the desired color in the Color menu. The erase feature always
  35.  clears the window to the currently selected color. This is no gem of
  36.  programming style, but you're getting it for the right price so be patient
  37.  with its design flaws. New versions will appear here on BIX as soon as I can
  38.  get them in shape for release.  I apologize to anyone who objects to my lack
  39.  of coding grace, but I just want to get the project off the ground, and
  40.  improvements will be forthcoming.  There are a lot of comments, but I didn't
  41.  know what needed to be made clear so I just commented everything.             
  42.  
  43. Rick Ross 11/14/85
  44.  
  45.  *********************************************************************** */
  46. char *VERSION = "Freedraw 0.01 by Richard M. Ross";
  47.  
  48. #include <exec/types.h>
  49. #include <exec/exec.h>
  50. #include <intuition/intuition.h>
  51. #include <intuition/intuitionbase.h>
  52. #include <graphics/gfx.h>
  53. #include <graphics/regions.h>
  54. #include <graphics/copper.h>
  55. #include <graphics/gels.h>
  56. #include <graphics/gfxbase.h>
  57. #include <devices/keymap.h>
  58. #include <hardware/blit.h>
  59.  
  60. /*
  61.   These definitions are used for calls to OpenLibrary() in order to ensure
  62.   that an appropriate ROM version is available.
  63. */
  64.  
  65. #define INTUITION_REV 1L
  66. #define GRAPHICS_REV  1L
  67. struct IntuitionBase *IntuitionBase;
  68. struct GfxBase *GfxBase;
  69.  
  70. struct Window *myWindow = 0;  /* ptr to applications window */
  71.  
  72. /*
  73.   This is the Window structure declaration.
  74.   Nothing fancy is going on here, but note
  75.   that the Flags and IDCMPFlags members of the
  76.   structure define which messages will be
  77.   sent by Intuition.  I haven't used them all
  78.   and if you want to change the settings you
  79.   should probably do it here instead of using
  80.   ModifyIDCMP later.
  81. */
  82.  
  83. struct NewWindow NewWindow = {
  84.    10,
  85.    10,
  86.    600,
  87.    180,
  88.    0,
  89.    1,
  90.    CLOSEWINDOW | MOUSEMOVE | MOUSEBUTTONS | MENUPICK
  91.    | NEWSIZE | INACTIVEWINDOW,
  92.    WINDOWCLOSE | SMART_REFRESH | ACTIVATE | WINDOWDRAG
  93.    | WINDOWDEPTH | WINDOWSIZING | REPORTMOUSE,
  94.    NULL,
  95.    NULL,
  96.    (UBYTE *)"AMIGA FreeDraw 0.01",
  97.    NULL,
  98.    NULL,
  99.    100, 35,
  100.    -1, -1,
  101.    WBENCHSCREEN,
  102. };
  103.  
  104. #ifdef TALKTOREXX
  105.  
  106. /*  We need this rexx include file */
  107. #include <rexx/rxslib.h>
  108.  
  109. /* Where we store the rexxapp.library base */
  110. struct RexxBase *RexxBase = 0;
  111.  
  112. /* We'll ship off unknown commands as macros to Rexx, and here's the extension */
  113. char myExtension[] = "fd";
  114.  
  115. /* These are the rexxapp lib functions. */
  116. extern long SetRexxPort();
  117. extern void FreeRexxPort();
  118. extern void ReceiveRexx();
  119. extern struct RexxMsg *SendRexxCmd();
  120. extern struct RexxMsg *SyncRexxCmd();
  121. extern struct RexxMsg *ASyncRexxCmd();
  122. extern void SetupResults();
  123. extern char *RexxErrMsg;    /* This comes from RexxInterface.asm */
  124.  
  125. /* These are the REXX handlers defined at the bottom of the file */
  126. void rexxcolor(), rexxbox(), rexxfbox(), rexxline(), rexxtofront(),
  127.     rexxtoback(), rexxexit(), rexxversion(), rexxspawn();
  128. /* This is the Func (Dispatch) function for received Rexxmsgs */
  129. BOOL disp();
  130. /* This is the Error function for the return of Rexxmsgs we send out, and caused an error */
  131. void RexxError();
  132. /* This is the Result function for the return of Rexxmsgs we send out, and were handled successfully */
  133. void RexxResult();
  134.  
  135. struct CmdEntry {
  136.    char *CmdString;
  137.    APTR CmdHandler;
  138. };
  139.  
  140. #define NUMCMDS 10  /* This will be application dependent */
  141.  
  142. struct RexxData {
  143.    struct MsgPort RexxPort;
  144.    char *Exten;
  145.    APTR Func;
  146.    struct RxsLib *RexxLib; /* defined by the ARexx rxslib.h file */
  147.    APTR Error;
  148.    APTR Result;
  149.    ULONG RexxMask;
  150.    ULONG UserData; /* to be defined by and used by the application */
  151.    /* The command list goes here. It consists of one CmdEntry structure for
  152.       each "command" that the application supports. Note that the number of
  153.       commands (and therefore the size of the RexxData) will depend upon how
  154.       many "commands" the application supports. The list must end with a NULL
  155.       entry.
  156.    */
  157.    struct CmdEntry AsscList[NUMCMDS];
  158. };
  159.  
  160. /*
  161.   Here is our initialized RexxData structure (for rexxapp lib)
  162. */
  163. struct RexxData myRexxData = {
  164.    {0},
  165.    &myExtension,
  166.    (APTR) disp,
  167.    0,
  168.    (APTR) RexxError,
  169.    (APTR) RexxResult,
  170.    0,
  171.    0,
  172. /*
  173.   Here is our imbedded command association list.
  174.   Commands are all lower case, so we match either upper or lower.
  175.   (This is a requirement of rexxapp.library.)
  176. */
  177.  { { "color", (APTR)&rexxcolor },
  178.    { "box", (APTR)&rexxbox },
  179.    { "fbox", (APTR)&rexxfbox },
  180.    { "line", (APTR)&rexxline },
  181.    { "tofront", (APTR)&rexxtofront },
  182.    { "toback", (APTR)&rexxtoback },
  183.    { "exit", (APTR)&rexxexit },
  184.    { "version", (APTR)&rexxversion },
  185.    { "spawn", (APTR)&rexxspawn },
  186.    { 0, 0 } }
  187. };
  188.  
  189. /* Note that the buffer for the PortName must be 2 bytes more than the name itself.
  190.    THIS IS REQUIRED so that the lib can construct a new name if this one is in use.
  191.    Note that is we run two copies of freedraw simultaneously, the first one's port
  192.    will be "freedraw", and the second one will be "freedraw2".
  193. */
  194. char PortName[10] = "freedraw";
  195.  
  196. #endif
  197.  
  198. /*******************************************************************/
  199. /*      DrawBox - Simple routine to draw an unfilled rectangle     */
  200. /*   It accepts the  coordinates of the top-left and lower-right   */
  201. /*   points of the rectangle, a pointer to the Window structure,   */
  202. /*   and the color in which to render the rectangle.  The current  */
  203. /*   FgPen color of the window is preserved thru the call.  No     */
  204. /*   clipping is done.                                             */
  205. /*******************************************************************/
  206. void DrawBox( tlx, tly, brx, bry, window, color )
  207. SHORT tlx, tly;                  /* top-left x,y coordinates */
  208. SHORT brx, bry;                  /* lower-right x,y coordinates */
  209. struct Window *window;           /* pointer to target window */
  210. BYTE color;                      /* color to use for render */
  211. {
  212.    BYTE OldColor = window->RPort->FgPen;   /* save window's FgPen */
  213.  
  214.    SetAPen( window->RPort, (long)color );        /* set draw color for box  */
  215.    Move(window->RPort, (long)tlx, (long)tly);          /* move to top-left point  */
  216.    Draw(window->RPort, (long)brx, (long)tly);          /* and draw to each of the */
  217.    Draw(window->RPort, (long)brx, (long)bry);          /* four corners of the box */
  218.    Draw(window->RPort, (long)tlx, (long)bry);
  219.    Draw(window->RPort, (long)tlx, (long)tly);
  220.    SetAPen( window->RPort, (long)OldColor );     /* restore old FgPen */
  221. }
  222.  
  223.  
  224. /*********************************************************/
  225. /*                 Color Select Menu                     */
  226. /*                                                       */
  227. /*      This is where the menu for color selection is    */
  228. /*   defined.  It should be flexible enough to allow for */
  229. /*   increased palette sizes, but this version is only   */
  230. /*   for the 4-color mode of the WorkBench screen.       */
  231. /*********************************************************/
  232.  
  233. /*
  234.   A few definitions are needed here.
  235.   Note that MAXPAL should be increased
  236.   to allow for palette larger than
  237.   four colors.    
  238. */
  239. #define ITEMSTUFF (ITEMENABLED | HIGHBOX)
  240. #define CW 40
  241. #define CH 25
  242. #define MAXPAL 4
  243.  
  244. /*
  245.   Declare enough storage for required
  246.   number of menu items and associated
  247.   images.  This menu will be using
  248.   graphics renditions of menu items,
  249.   so the Image structures must be
  250.   declared.  This menu is modeled after
  251.   the one found in the IconEd source.
  252. */
  253. struct MenuItem coloritem[MAXPAL];
  254. struct Image colorimage[MAXPAL];
  255.  
  256. /*
  257.   array of palette sizes to correspond with
  258.   depth of window in bit-planes
  259. */
  260. SHORT palette[] = { 2, 4, 8, 16, 32 };
  261.  
  262.  
  263. /*****************************************************************/
  264. /*    The following function initializes the structure arrays    */
  265. /*   needed to provide the Color menu topic.                     */
  266. /*****************************************************************/
  267. InitColorItems( depth )
  268. SHORT depth;               /* number of bit-planes in window */
  269. {
  270.    SHORT n, colors;
  271.  
  272.    colors = palette[depth-1];
  273.    for( n=0; n<colors; n++ )           /* loop for max number of items */
  274.    {
  275.       coloritem[n].NextItem = &coloritem[n+1];
  276.       coloritem[n].ItemFill = (APTR)&colorimage[n];
  277.       /*   the next two items might be changed for
  278.        *   when bit-planes is greater than 2
  279.        */
  280.       coloritem[n].LeftEdge = 2 + CW * (n % 4);
  281.       coloritem[n].TopEdge = CH * (n / 4);
  282.       coloritem[n].Width = CW;
  283.       coloritem[n].Height = CH;
  284.       coloritem[n].Flags = ITEMSTUFF;
  285.       coloritem[n].MutualExclude = 0;
  286.       coloritem[n].SelectFill = NULL;
  287.       coloritem[n].Command = 0;
  288.       coloritem[n].SubItem = NULL;
  289.       coloritem[n].NextSelect = 0;
  290.  
  291.       colorimage[n].LeftEdge = 1;
  292.       colorimage[n].TopEdge = 1;
  293.       colorimage[n].Width = CW-2;
  294.       colorimage[n].Height = CH-2;
  295.       colorimage[n].Depth = depth;
  296.       colorimage[n].ImageData = NULL;
  297.       colorimage[n].PlanePick = 0;
  298.       colorimage[n].PlaneOnOff = n;
  299.    }
  300.    coloritem[colors-1].NextItem = NULL;   /* needed for last item in list */
  301.    return( 0 );
  302. }
  303.  
  304.  
  305. /*****************************************************/
  306. /*                Draw Mode Menu                     */
  307. /*                                                   */
  308. /*      Here are the code and data declarations for  */
  309. /*   the DrawMode menu.  Current choices are limited */
  310. /*   to Erase, Filled Box, Hollow Box, and PenDraw.  */
  311. /*****************************************************/
  312.  
  313. /* define maximum number of menu items */
  314. #define DMODEMAX 4
  315.  
  316. /*
  317.   declare storage space for menu items and
  318.   their associated IntuiText structures
  319. */
  320. struct MenuItem DModeItem[DMODEMAX];
  321. struct IntuiText DModeText[DMODEMAX];
  322.  
  323. /*****************************************************************/
  324. /*    The following function initializes the structure arrays    */
  325. /*   needed to provide the DrawMode menu topic.                  */
  326. /*****************************************************************/
  327. InitDModeItems()
  328. {
  329.    short n;
  330.  
  331.    /* initialize each meu item and IntuiText with loop */
  332.    for( n=0; n<DMODEMAX; n++ )
  333.    {
  334.       DModeItem[n].NextItem = &DModeItem[n+1];
  335.       DModeItem[n].LeftEdge = 0;
  336.       DModeItem[n].TopEdge = 10 * n;
  337.       DModeItem[n].Width = 112;
  338.       DModeItem[n].Height = 10;
  339.       DModeItem[n].Flags = ITEMTEXT | ITEMENABLED | HIGHBOX;
  340.       DModeItem[n].MutualExclude = 0;
  341.       DModeItem[n].ItemFill = (APTR)&DModeText[n];
  342.       DModeItem[n].SelectFill = NULL;
  343.       DModeItem[n].Command = 0;
  344.       DModeItem[n].SubItem = NULL;
  345.       DModeItem[n].NextSelect = 0;
  346.  
  347.       DModeText[n].FrontPen = 0;
  348.       DModeText[n].BackPen = 1;
  349.       DModeText[n].DrawMode = JAM2;     /* render in fore and background */
  350.       DModeText[n].LeftEdge = 0;
  351.       DModeText[n].TopEdge = 1;
  352.       DModeText[n].ITextFont = NULL;
  353.       DModeText[n].NextText = NULL;
  354.    }
  355.    DModeItem[DMODEMAX-1].NextItem = NULL;
  356.  
  357.    /* initialize text for specific menu items */
  358.    DModeText[0].IText = (UBYTE *)"Erase All";
  359.    DModeText[1].IText = (UBYTE *)"Hollow Box";
  360.    DModeText[2].IText = (UBYTE *)"Filled Box";
  361.    DModeText[3].IText = (UBYTE *)"Pen Draw";
  362.  
  363.    return( 0 );
  364. }
  365.  
  366.  
  367. /***************************************************/
  368. /*                Menu Definition                  */
  369. /*                                                 */
  370. /*      This section of code is where the simple   */
  371. /*   menu definition goes.  For now it supports    */
  372. /*   only Color and Drawmode selection, but new    */
  373. /*   choices can easily be added by creating       */
  374. /*   structures and initializations functions      */
  375. /*   similar to those provided above.              */
  376. /***************************************************/
  377.  
  378. /* current number of available menu topics */
  379. #define MAXMENU 2
  380.  
  381. /*
  382.   declaration of menu structure array for
  383.   number of current topics.  Intuition
  384.   will use the address of this array to
  385.   set and clear the menus associated with
  386.   the window.
  387. */
  388. struct Menu menu[MAXMENU];
  389.  
  390. /**********************************************************************/
  391. /*   The following function initializes the Menu structure array with */
  392. /*  appropriate values for our simple menu strip.  Review the manual  */
  393. /*  if you need to know what each value means.                        */
  394. /**********************************************************************/
  395. InitMenu()
  396. {
  397.    menu[0].NextMenu = &menu[1];
  398.    menu[0].LeftEdge = 10;
  399.    menu[0].TopEdge = 0;
  400.    menu[0].Width = 50;
  401.    menu[0].Height = 10;
  402.    menu[0].Flags = MENUENABLED;
  403.    menu[0].MenuName = "Color";           /* text for menu-bar display */
  404.    menu[0].FirstItem = &coloritem[0];    /* pointer to first item in list */
  405.  
  406.    menu[1].NextMenu = NULL;
  407.    menu[1].LeftEdge = 65;
  408.    menu[1].TopEdge = 0;
  409.    menu[1].Width = 85;
  410.    menu[1].Height = 10;
  411.    menu[1].Flags = MENUENABLED;
  412.    menu[1].MenuName = "DrawMode";        /* text for menu-bar display */
  413.    menu[1].FirstItem = &DModeItem[0];    /* pointer to first item in list */
  414.  
  415.    return( 0 );
  416. }
  417.  
  418. /**********************************************************************/
  419. /*   The following function is our exit point for the program. It     */
  420. /*  closes/frees any allocated resources.                             */
  421. /**********************************************************************/
  422. doclean()
  423. {
  424.   if (myWindow) CloseWindow( myWindow );
  425.   if (IntuitionBase) CloseLibrary(IntuitionBase);
  426.   if (GfxBase) CloseLibrary(GfxBase);
  427. #ifdef TALKTOREXX
  428.   if (RexxBase) CloseLibrary(RexxBase);
  429. #endif
  430.   exit(TRUE);
  431. }
  432.  
  433. /******************************************************/
  434. /*                   Main Program                     */
  435. /*                                                    */
  436. /*      This is the main body of the program.         */
  437. /******************************************************/
  438.  
  439. SHORT MinX, MinY, MaxX, MaxY;       /* clipping boundary variables */
  440. SHORT KeepGoing = TRUE;             /* main loop control value */
  441.  
  442. main(argc, argv)
  443. int argc;
  444. char *argv[];
  445. {
  446.    struct Library *OpenLibrary();
  447.    struct Window *OpenWindow();
  448.    struct Message *GetMsg();
  449.    struct IntuiMessage *NewMessage;    /* msg structure for GetMsg() */
  450.    BYTE DrawColor = 1;                 /* initial drawing color */
  451.    SHORT OldBRX = 30, OldBRY = 30;     /* point coords used for boxes */
  452.    SHORT TLX = 20, TLY = 20;           /* initial top-left point coords */
  453.    ULONG class;                        /* used in message monitor loop */
  454.    USHORT code;                        /* used in message monitor loop */
  455.    SHORT x, y, x1, y1, x2, y2;         /* various coordinate variables */
  456.    USHORT MenuNum, ItemNum;
  457.    /*   The following is a set of declarations
  458.     *   for a number of flag values used by the
  459.     *   program.  These would perhaps be better
  460.     *   coded as a bit-field for all the flags,
  461.     *   but I'm lazy, and this is easier.
  462.     */
  463.    SHORT MouseMoved = FALSE;     /* indicates new mouse position ready */
  464.    SHORT ClipIt = FALSE;         /* are new point coords out of bounds? */
  465.    SHORT ClippedLast = FALSE;    /* was last PenDraw operation clipped? */
  466.    SHORT PenMode = FALSE;        /* indicates PenDraw mode is set */      
  467.    SHORT PenDown = FALSE;        /* if mouse moved, then should it draw? */
  468.    SHORT RubberBox = FALSE;      /* are we currently rubberbanding a box? */
  469.    SHORT FilledBox = FALSE;      /* should boxes be filled when drawn? */
  470.  
  471. #ifdef TALKTOREXX
  472.    /* If we are talking to REXX, we need these 3 additional locals */
  473.    ULONG rexxbit;
  474.    char firstcommand[256];
  475.    struct RexxMsg *rxmsg;
  476. #endif
  477.  
  478.    /* attempt to Open Library to access Intuition */
  479.    IntuitionBase = (struct IntuitionBase *)
  480.       OpenLibrary("intuition.library", INTUITION_REV);
  481.    if( IntuitionBase == NULL )
  482.       doclean();
  483.  
  484.    /* attempt to OpenLibrary to access Graphics functions */
  485.    GfxBase = (struct GfxBase *)
  486.       OpenLibrary("graphics.library",GRAPHICS_REV);
  487.    if( GfxBase == NULL )
  488.      doclean();
  489.  
  490.    /* Try to open new window for application */
  491.    if(( myWindow = OpenWindow(&NewWindow) ) == NULL) doclean();
  492.  
  493. #ifdef TALKTOREXX
  494.    /* Open the rexxapp.library */
  495.    if (!(RexxBase = (struct RexxBase *) OpenLibrary("rexxapp.library",0L)))
  496.      {
  497.      puts("Need the rexxapp.library");
  498.      doclean();
  499.      }
  500. #endif
  501.  
  502.    /*   set initial clipping boundaries
  503.     *   from the values found in the window
  504.     *   structure for border dimensions
  505.     */
  506.    MinX = myWindow->BorderLeft;
  507.    MinY = myWindow->BorderTop;
  508.    MaxX = myWindow->Width - myWindow->BorderRight - 1;
  509.    MaxY = myWindow->Height - myWindow->BorderBottom - 1;
  510.  
  511.    InitColorItems( 2 );         /* initialize Color menu arrays */
  512.    InitDModeItems();            /* initialize DrawMode menu arrays */
  513.    InitMenu();                  /* initialize the menu structures */
  514.  
  515.    /*   Now, having initialized the various arrays
  516.     *   of structures required for menu generation
  517.     *   we can tell Intuition to make our menus
  518.     *   available to the user when this window
  519.     *   is active.
  520.     */
  521.    SetMenuStrip( myWindow, &menu[0] );
  522.  
  523.    /* set initial drw mode and color */
  524.    SetDrMd( myWindow->RPort, JAM1 );
  525.    SetAPen( myWindow->RPort, DrawColor );
  526.  
  527. #ifdef TALKTOREXX
  528. /*  For rexx, we must open up a Rexx port. */
  529.    if (! (rexxbit = SetRexxPort(&PortName, &myRexxData)))
  530.      {
  531.      puts("can't set up RexxPort");
  532.      doclean();
  533.      }
  534.  
  535.    /* Show the portname in the window titlebar */
  536.    SetWindowTitles(myWindow, &PortName, 0L);
  537.  
  538.   /*
  539.   For FreeDraw, we're going to send out the user's args on the CLI as a Rexx
  540.   macro invocation, if there was one. We send it out asynchronously; no reason
  541.   not to. This is an example of how your program might invoke a Rexx script.
  542.   */
  543.    firstcommand[0] = 0;
  544.    for (x=1; x<argc; x++)
  545.    {
  546.       strcat(firstcommand, argv[x]);
  547.       strcat(firstcommand, " ");
  548.    }
  549.    if (firstcommand[0])
  550.    {
  551.    /* Send it out. If an error, print out the returned error message */
  552.    if (! (rxmsg = ASyncRexxCmd(firstcommand, &myRexxData)))
  553.       SetWindowTitles(myWindow, RexxErrMsg, 0L);
  554.    }
  555. #endif
  556.  
  557.    /*   Everything the program needs is now
  558.     *   initialized and put in place.  The
  559.     *   program enters the following loop
  560.     *   and processes message continuously as
  561.     *   they are received from Intuition.
  562.     *      I guess this loop is the real workhorse
  563.     *   of the program.  By the way, the loop
  564.     *   control variable KeepGoing remains TRUE
  565.     *   until a CLOSEWINDOW message is received.
  566.     *   At that point it goes FALSE, and the
  567.     *   program cleans up and exits.
  568.     */
  569.    while( KeepGoing )
  570.       {
  571.  
  572.       /* stay here until a message is received from Intuition */
  573. #ifdef TALKTOREXX
  574. /*
  575.  *   If we're working with Rexx, we wait on the Rexx bit as well.
  576.  *   Then, we handle any Rexx messages.
  577.  */
  578.       Wait( (1L << myWindow->UserPort->mp_SigBit) | rexxbit);
  579.       ReceiveRexx(&myRexxData);
  580. #else
  581.       Wait( 1L << myWindow->UserPort->mp_SigBit);
  582. #endif
  583.       MouseMoved = FALSE;    /* clear this flag each time thru loop */
  584.  
  585.       /*   since more than one message may be waiting
  586.        *   a reply at this point, a loop is used to
  587.        *   process all that have come in until no more
  588.        *   are ready.  Msg received is assigned to
  589.        *   NewMessage from the GetMsg() function.  This
  590.        *   value will be NULL if no message is ready,
  591.        *   and control passes out of the loop at that time
  592.        */
  593.       while( NewMessage=(struct IntuiMessage *)GetMsg(myWindow->UserPort) )
  594.          {
  595.  
  596.          /*   copy some values from the message structure
  597.           *   to variables used in the switch statements
  598.           *   below
  599.           */
  600.          class = NewMessage->Class;
  601.          code = NewMessage->Code;
  602.          x = myWindow->MouseX;
  603.          y = myWindow->MouseY;
  604.  
  605.          /*   SIZEVERIFY is a very high priority message
  606.           *   in our loop and requires some immediate
  607.           *   servicing.  Any outstanding draw operations
  608.           *   are immediately cancelled, and the DrawMode
  609.           *   is nulled.  This prevents any attempts to
  610.           *   render outside whatever new myWindow boundaries
  611.           *   the user chooses.
  612.           *
  613.           *   (not anymore, it don't.  -tgr)
  614.  
  615.          if( class == SIZEVERIFY )
  616.             {
  617.             PenDown = FALSE;
  618.             if( RubberBox )
  619.                {
  620.                DrawBox( TLX, TLY, OldBRX, OldBRY, myWindow, DrawColor );
  621.                myWindow->Flags &= ( 0xFFFFFFFF ^ RMBTRAP );
  622.                RubberBox = FALSE;
  623.                }
  624.             }
  625.           */
  626.  
  627.          /*   we have all the information needed from
  628.           *   the message, so we can now safely reply
  629.           *   to it without losing data
  630.           */
  631.          ReplyMsg( NewMessage );
  632.  
  633.          /*  Examine point coords from message received
  634.           *  and set the clipping flag if out of bounds.
  635.           *  If user was drawing in PenMode when message
  636.           *  was received, then the ClippedLast flag
  637.           *  should also be set to indicate this to the
  638.           *  next draw operation.
  639.           */
  640.          if(ClipIt = ( x < MinX || x > MaxX || y < MinY || y > MaxY ))
  641.             if( PenDown )
  642.                ClippedLast = TRUE;
  643.  
  644.  
  645.          /* enter switch on type of message received */
  646.          switch( class )
  647.          {
  648.             case MOUSEMOVE:
  649.                /*   Don't really do anything with this one
  650.                 *   until any other, more important, messages
  651.                 *   are received and processed.
  652.                 */
  653.                MouseMoved = TRUE;
  654.                break;
  655.  
  656.             case NEWSIZE:
  657.                /*  set new clipping boundaries */
  658.                MinX = myWindow->BorderLeft;
  659.                MinY = myWindow->BorderTop;
  660.                MaxX = myWindow->Width - myWindow->BorderRight - 1;
  661.                MaxY = myWindow->Height - myWindow->BorderBottom - 1;
  662.                break;
  663.  
  664.             case CLOSEWINDOW:
  665.                /*   User is ready to quit, so indicate
  666.                 *   that execution should terminate
  667.                 *   with next iteration of the loop.
  668.                 */
  669.                KeepGoing = FALSE;
  670.                break;
  671.  
  672.             case MOUSEBUTTONS:
  673.                /*   A number of things could have happened
  674.                 *   here, and further examination of data
  675.                 *   received from message is needed to
  676.                 *   determine what action should be taken.
  677.                 *   The code variable holds important info
  678.                 *   about what actually caused the message
  679.                 *   to be sent in the first place.
  680.                 */
  681.                switch ( code )
  682.                   {
  683.                   case SELECTUP:
  684.                      /*   User was holding down the left button
  685.                       *   and just released it.  The PenMode
  686.                       *   flag variables are set accordingly.
  687.                       *   The pen can no longer be down, and
  688.                       *   ClippedLast is reset for next time.
  689.                       */
  690.                      PenDown = ClippedLast = FALSE;
  691.                      break;
  692.  
  693.                   case SELECTDOWN:
  694.                      /*   User has pressed the left button, and
  695.                       *   several differnt actions may need to
  696.                       *   be taken.  If the ClipIt value is TRUE,
  697.                       *   then no action should be taken at all.
  698.                       */
  699.                      if( ClipIt )
  700.                         break;
  701.  
  702.                      /*   If user is currently in PenMode, then
  703.                       *   set up to draw when MOUSEMOVED messages
  704.                       *   are received until a subsequent SELECTUP
  705.                       *   message comes in.
  706.                       */
  707.                      if( PenMode )
  708.                         {
  709.                         PenDown = TRUE;
  710.                         ClippedLast = FALSE;
  711.  
  712.                         /* make sure to set appropriate mode */
  713.                         SetDrMd( myWindow->RPort, JAM1 );
  714.  
  715.                         /* and establish initial position to draw */
  716.                         Move( myWindow->RPort, (long)x, (long)y );
  717.                         break;
  718.                         }
  719.  
  720.                      /*   If user is currently rubberbanding a box,
  721.                       *   then a SELECTDOWN message means it is time
  722.                       *   to stop rubberbanding and actually draw it.
  723.                       *   The following code will be executed if
  724.                       *   this is the case, and it will determine if
  725.                       *   a filled box is needed before rendering.
  726.                       */
  727.                      if( RubberBox )
  728.                         {
  729.                         /*   set draw mode back to JAM1 since
  730.                          *   it is now currently set to COMPLEMENT
  731.                          */
  732.                         SetDrMd( myWindow->RPort, JAM1 );
  733.                         RubberBox = FALSE;   /* turn off rubberbanding */
  734.  
  735.                         /*   Restore the condition of the RMBTRAP
  736.                          *   bit in the myWindow structure's Flags
  737.                          *   member.  Menubutton events will no
  738.                          *   be received by this loop.
  739.                          */
  740.                         myWindow->Flags &= ( 0xFFFFFFFF ^ RMBTRAP );
  741.  
  742.                         /*   RectFill is not condusive to the smooth
  743.                          *   execution of programs iit arguments are
  744.                          *   out of order, sot his code sorts them
  745.                          *   in preparation for the call.
  746.                          */
  747.                         if( FilledBox )
  748.                            {
  749.                            /* first sort the x-coords */
  750.                            if( TLX < OldBRX )  {
  751.                               x1 = TLX;  x2 = OldBRX;  }
  752.                            else  {
  753.                               x1 = OldBRX;  x2 = TLX;  }
  754.  
  755.                            /* then sort the y-coords */
  756.                            if( TLY < OldBRY )  {
  757.                               y1 = TLY;  y2 = OldBRY;  }
  758.                            else  {
  759.                               y1 = OldBRY;  y2 = TLY;  }
  760.  
  761.                            /* now generate the filled rectangle */
  762.                            RectFill( myWindow->RPort, (long)x1, (long)y1,
  763.                                                     (long)x2, (long)y2 );
  764.                            }
  765.                         else
  766.                            {
  767.                            /* FilledBox not set, so draw hollow box */
  768.                            DrawBox( TLX, TLY, OldBRX, OldBRY, myWindow, DrawColor );
  769.                            }
  770.                         break;
  771.                         }
  772.  
  773.                      /*   If execution comes here, then PenMode was
  774.                       *   not set and user was not rubberbanding.
  775.                       *   SELECTDOWN therefore indicates to start the
  776.                       *   rubberbanding process at this point.  The
  777.                       *   initial coords are set to the values we
  778.                       *   received when the GetMsg() was executed.
  779.                       */
  780.                      TLX = OldBRX = x;  TLY = OldBRY = y;
  781.  
  782.                      /* set to render in XOR mode */
  783.                      SetDrMd( myWindow->RPort, COMPLEMENT );
  784.  
  785.                      /* set flag to indicate we are now rubberbanding */
  786.                      RubberBox = TRUE;
  787.  
  788.                      /*   This instruction indicates to Intuition
  789.                       *   that we now wish to receive a message
  790.                       *   each time the Menubutton is pressed.
  791.                       *   This is how we hijack the right button
  792.                       *   for temporary use as a Cancel button
  793.                       *   instead of a Menubutton.
  794.                       */
  795.                      myWindow->Flags |= RMBTRAP;
  796.  
  797.                      /* render the initial rubberbox and exit */
  798.                      DrawBox( TLX, TLY, OldBRX, OldBRY, myWindow, DrawColor );
  799.                      break;
  800.  
  801.                   case MENUDOWN:
  802.                      /*   WE only receive this message class if
  803.                       *   the RMBTRAP flag bit has been set, so
  804.                       *   it always means that we should cancel
  805.                       *   the box which is currently rubberbanding.
  806.                       */
  807.                      /* turn the flag off */
  808.                      RubberBox = FALSE;
  809.  
  810.                      /* restore control of menubutton to Intuition */
  811.                      myWindow->Flags &= ( 0xFFFFFFFF ^ RMBTRAP );
  812.  
  813.                      /*   erase (by double XOR'ing) the current
  814.                       *   rubberbox and exit switch.
  815.                       */
  816.                      DrawBox( TLX, TLY, OldBRX, OldBRY, myWindow, DrawColor );
  817.                      break;
  818.  
  819.                   default:
  820.                      /*   Something unimportant happened, so just
  821.                       *   continue thru the GetMsg() loop.
  822.                       */
  823.                      continue;
  824.                }
  825.                break;
  826.  
  827.             case MENUPICK:
  828.                /*   A menu event has taken place and is
  829.                 *   ready to be processed.  Examine the
  830.                 *   code variable received from the message
  831.                 *   to determine what action should be taken.
  832.                 *   The first check is for MENUNULL, which
  833.                 *   means that nothing should be done at all.
  834.                 */
  835.                if( code != MENUNULL )
  836.                   {
  837.                   /* get menu and item numbers from code */
  838.                   MenuNum = MENUNUM( code );
  839.                   ItemNum = ITEMNUM( code );
  840.  
  841.                   /* determine appropriate action by menu number */
  842.                   switch ( MenuNum )
  843.                      {
  844.                      case 0:
  845.                         /*   Menu 0 is the Color menu.  The
  846.                          *   item number indicates which new
  847.                          *   color to set.
  848.                          */
  849.                         DrawColor = ItemNum;
  850.                         SetAPen( myWindow->RPort, (long)DrawColor );
  851.                         break;
  852.  
  853.                      case 1:
  854.                         /*   Menu 1 is the DrawMode menu.  The item
  855.                          *   number indicates what to do.
  856.                          *   NOTE:  Since we cannot have received
  857.                          *   this message if we were rubberbanding,
  858.                          *   then there is no need to clean up before
  859.                          *   changing drawing modes.
  860.                          */
  861.                         switch ( ItemNum )
  862.                            {
  863.                            case 0:
  864.                               /* Erase window to current color */
  865.                               SetDrMd( myWindow->RPort, JAM1 );
  866.                               RectFill( myWindow->RPort, (long)MinX, (long)MinY,
  867.                                                        (long)MaxX, (long)MaxY);
  868.                               break;
  869.  
  870.                            case 1:
  871.                               /* set flag variables for hollow box */
  872.                               PenMode = FALSE;
  873.                               FilledBox = FALSE;
  874.                               break;
  875.  
  876.                            case 2:
  877.                               /* set flag variables for filled box */
  878.                               PenMode = FALSE;
  879.                               FilledBox = TRUE;
  880.                               break;
  881.  
  882.                            case 3:
  883.                               /* set flag variables for PenMode */
  884.                               PenMode = TRUE;
  885.                               break;
  886.  
  887.                            default:
  888.                               /* don't do anything */
  889.                               break;
  890.                            }
  891.                         break;
  892.  
  893.                      default:
  894.                         /* Menu number unrecognized, do nothing */
  895.                         break;
  896.                      }
  897.                   }
  898.                break;
  899.  
  900.             case INACTIVEWINDOW:
  901.                /*   User has de-selected our window, so a
  902.                 *   little bit of cleaning up may be needed
  903.                 *   to prevent untoward events when he comes
  904.                 *   back to it.
  905.                 */
  906.                /* erase any outstanding rubberbox */
  907.                if( RubberBox )
  908.                   DrawBox( TLX, TLY, OldBRX, OldBRY, myWindow, DrawColor );
  909.  
  910.                /* reset all the flafg variables */
  911.                PenDown = ClippedLast = RubberBox = FALSE;
  912.  
  913.                /* return possibly diverted menubutton events to Big I */
  914.                myWindow->Flags &= ( 0xFFFFFFFF ^ RMBTRAP );
  915.                break;
  916.  
  917.             default:
  918.                /* message class was unrecognized, so do nothing */
  919.                break;
  920.             }
  921.          }   /* this brace ends the while(NewMessage) loop way back when */
  922.  
  923.       /*   There are no more messages waiting at the
  924.        *   IDCMP port, so we can now proceed to
  925.        *   process any MOUSEMOVED message we may
  926.        *   have received.
  927.        */
  928.       if( MouseMoved && !ClipIt)
  929.          {
  930.          /* the mouse did move, and we don't need to clip */
  931.  
  932.          /* check first if we are drawing in PenMode */
  933.          if( PenDown )
  934.             {
  935.             /*   We have to examine if we clipped the
  936.              *   last PenMode draw operation.  If we did,
  937.              *   then this is the first move back into
  938.              *   window boundaries, so we mov instead of
  939.              *   drawing.
  940.              */
  941.             if( ClippedLast )
  942.                {
  943.                ClippedLast = FALSE;         /* reset this flag now */
  944.                Move( myWindow->RPort, (long)x, (long)y );
  945.                }
  946.             else
  947.                Draw( myWindow->RPort, (long)x, (long)y ); /* draw to x,y coords */
  948.          }
  949.          else
  950.             {
  951.             /*   We weren't in PenMode, but we still might
  952.              *   be rubberbanding a box.  If so, then we
  953.              *   should erase the current rubberbox and
  954.              *   draw a new one with the new mouse coords.
  955.              */
  956.             if( RubberBox )
  957.                {
  958.                /* erase the old rubberbox - draw mode is COMPLEMENT */
  959.                DrawBox( TLX, TLY, OldBRX, OldBRY, myWindow, DrawColor );
  960.  
  961.                /* assign new values to box coords */
  962.                OldBRX = x;  OldBRY = y;
  963.  
  964.                /* and draw the new rubberbox */ 
  965.                DrawBox( TLX, TLY, OldBRX, OldBRY, myWindow, DrawColor );
  966.                }
  967.             }
  968.          }
  969.       }
  970.  
  971.    /*   It must be time to quit, so we have to clean
  972.     *   up and exit.
  973.     */
  974.  
  975. #ifdef TALKTOREXX
  976. /*
  977.   With Rexx, we need to bring the port down.  You might make this
  978.   part of exit() for programs that have multiple paths to exit, but
  979.   don't call it unless you called SetRexxPort() once anyway.
  980. */
  981.    FreeRexxPort(&myRexxData);
  982. #endif
  983.  
  984.    ClearMenuStrip( myWindow );
  985.    doclean();
  986. }
  987.  
  988. #ifdef TALKTOREXX
  989. /*
  990.    Now we get into the actual code necessary for our REXX port; functions
  991.    that do the real work.  Note that this program was not structured
  992.    particularly nicely for Rexx; I had to write each of these functions.
  993.    Many programs have these subroutines already in place; they are called
  994.    as part of the event loop.  This progam, however, just has one big
  995.    switch statement in main() with different actions . . .
  996.  
  997.    First, our locals.
  998. */
  999. ULONG currrexxcolor = 1;  /* what color is *rexx* drawing in? */
  1000. ULONG args[4];            /* what args did we see to this function? */
  1001. ULONG error;              /* was argument parsing successful? */
  1002. char *ResultStr;          /* the Result string to return if any */
  1003.  
  1004. /* *********************************************************************
  1005.  *   This function takes a pointer to a pointer to a string, grabs the
  1006.  *   next number (unsigned), returns it, and advances the pointer to the
  1007.  *   string to point after the number.
  1008.  ********************************************************************* */
  1009. ULONG getnm(where)
  1010. char **where;
  1011. {
  1012.    register char *p = *where;
  1013.    register ULONG val = 0;
  1014.    register ULONG gotone = 0;
  1015.  
  1016.    while (*p <= ' ' && *p)
  1017.       p++;
  1018.    while ('0' <= *p && *p <= '9')
  1019.    {
  1020.      gotone = 1;
  1021.      val = 10 * val + *p++ - '0';
  1022.    }
  1023.    if (gotone == 0) error = 20; /* Indicate an error level of 20 with rexx arguments */
  1024.    *where = p;
  1025.    return(val);
  1026. }
  1027.  
  1028. /* **********************************************************************
  1029.  *   This function trys to find `n' numeric arguments in the command
  1030.  *   string, and stuffs them into the args array.
  1031.  ********************************************************************** */
  1032. void parseargs(p, n)
  1033. char *p;
  1034. UBYTE n;
  1035. {
  1036.    register UBYTE i;
  1037.  
  1038.    while (*p > ' ' && *p)
  1039.      p++;
  1040.    for (i=0; i<n; i++)
  1041.      args[i] = getnm(&p);
  1042. }
  1043.  
  1044. /* *************************************************************************
  1045.  *   This is our rexx Func (Dispatch) routine. The rexxapp.library calls this
  1046.  *   when some other program sends us a Rexxmsg that has one of the commands
  1047.  *   in our command association list. We check to make sure a Window
  1048.  *   currently exists.  Then, we store away the `current color' and change
  1049.  *   it to Rexx's current color, call our handler function, and then restore
  1050.  *   the color. If no errors, error will be 0. If our handler has any return
  1051.  *   Result string, that is placed in ResultStr. We setup the Results codes
  1052.  *   via SetupResults() and return(TRUE) because we always want the lib to
  1053.  *   reply. If the parse and everything else was successful, we set Results as
  1054.  *   0. Otherwise, we set Results to the value of error to indicate that
  1055.  *   something failed.
  1056.  ************************************************************************* */
  1057. BOOL disp(msg, routine, p, rxdata)
  1058. register struct RexxMsg *msg;
  1059. void *routine();
  1060. register char *p;
  1061. struct RexxData *rxdata;
  1062. {
  1063.    register UBYTE t;
  1064.  
  1065.    /* Initially, no error or Result string to return */
  1066.    error = 0;
  1067.    ResultStr = 0;
  1068.  
  1069.    if (myWindow)
  1070.    {
  1071.       /* Get the current pen color in case this rexx handler alters it */
  1072.       t = myWindow->RPort->FgPen;
  1073.       SetAPen(myWindow->RPort, (LONG)currrexxcolor);
  1074.  
  1075.       /* Call the appropriate handler. The lib has determined which one */
  1076.       ((void (*)())(routine))(msg, p, rxdata);
  1077.  
  1078.       /* restore the color */
  1079.       SetAPen(myWindow->RPort, (LONG)t);
  1080.  
  1081.       /* Check for any errors */
  1082.       if (! error)
  1083.       {
  1084.          /* No errors. Send back Result1 and Result2 = 0. Also return any
  1085.             Result string
  1086.           */
  1087.          SetupResults(0L, 0L, ResultStr, msg, rxdata);
  1088.       }
  1089.       else
  1090.       {
  1091.          /* An error! Return Result1 = error. Must not send back a Result string */
  1092.          SetupResults(error, 10L, NULL, msg, rxdata);
  1093.       }
  1094.       /* We want the lib to do the reply right now */
  1095.       return(TRUE);
  1096.    }
  1097.    SetupResults(error, 10L, msg, NULL, rxdata);
  1098. }
  1099.  
  1100. /* **********************************************************************
  1101.  *   This handler sets the current rexx color. (our 'color' handler)
  1102.  ********************************************************************** */
  1103. void rexxcolor(msg, p, rxdata)
  1104. struct RexxMsg *msg;
  1105. char *p;
  1106. struct RexxData *rxdata;
  1107. {
  1108.    parseargs(p, 1);
  1109.    currrexxcolor = args[0];
  1110. }
  1111.  
  1112. /* *********************************************************************
  1113.  *   This function silently clips the x and y values at `n' to the
  1114.  *   window bounds.
  1115.  ********************************************************************* */
  1116. void clipxy(n)
  1117. UBYTE n;
  1118. {
  1119.    if (args[n] < MinX)
  1120.       args[n] = MinX;
  1121.    if (args[n] > MaxX)
  1122.       args[n] = MaxX;
  1123.    n++;
  1124.    if (args[n] < MinY)
  1125.       args[n] = MinY;
  1126.    if (args[n] > MaxY)
  1127.       args[n] = MaxY;
  1128. }
  1129.  
  1130. /* **********************************************************************
  1131.  *   This handler grabs four arguments and draws a box.
  1132.  ********************************************************************** */
  1133. void rexxbox(msg, p, rxdata)
  1134. struct RexxMsg *msg;
  1135. char *p;
  1136. struct RexxData *rxdata;
  1137. {
  1138.    parseargs(p, 4);
  1139.    clipxy(0);
  1140.    clipxy(2);
  1141.    DrawBox(args[0], args[1], args[2], args[3], myWindow, currrexxcolor);
  1142. }
  1143.  
  1144. /* *********************************************************************
  1145.  *   This handler grabs four arguments and draws a filled box.
  1146.  ********************************************************************** */
  1147. void rexxfbox(msg, p, rxdata)
  1148. struct RexxMsg *msg;
  1149. char *p;
  1150. struct RexxData *rxdata;
  1151. {
  1152.    register ULONG t;
  1153.  
  1154.    parseargs(p, 4);
  1155.    clipxy(0);
  1156.    clipxy(2);
  1157.    if (args[0] > args[2])
  1158.    {
  1159.       t = args[0]; args[0] = args[2]; args[2] = t;
  1160.    }
  1161.    if (args[1] > args[3])
  1162.    {
  1163.       t = args[1]; args[1] = args[3]; args[3] = t;
  1164.    }
  1165.    RectFill( myWindow->RPort, (long)args[0], (long)args[1],
  1166.                             (long)args[2], (long)args[3]);
  1167. }
  1168.  
  1169. /* ************************************************************************
  1170.  *   This handler grabs four arguments and draws a line.
  1171.  ************************************************************************ */
  1172. void rexxline(msg, p, rxdata)
  1173. struct RexxMsg *msg;
  1174. char *p;
  1175. struct RexxData *rxdata;
  1176. {
  1177.    parseargs(p, 4);
  1178.    clipxy(0);
  1179.    clipxy(2);
  1180.    Move(myWindow->RPort, (long)args[0], (long)args[1]);
  1181.    Draw(myWindow->RPort, (long)args[2], (long)args[3]);
  1182. }
  1183.  
  1184. /* *************************************************************************
  1185.  *   This handler pops the window to front.
  1186.  ************************************************************************* */
  1187. void rexxtofront(msg, p, rxdata)
  1188. struct RexxMsg *msg;
  1189. char *p;
  1190. struct RexxData *rxdata;
  1191. {
  1192.    WindowToFront(myWindow);
  1193. }
  1194.  
  1195. /* *************************************************************************
  1196.  *   This handler pops the window to back.
  1197.  ************************************************************************* */
  1198. void rexxtoback(msg, p, rxdata)
  1199. struct RexxMsg *msg;
  1200. char *p;
  1201. struct RexxData *rxdata;
  1202. {
  1203.    WindowToBack(myWindow);
  1204. }
  1205.  
  1206. /* *************************************************************************
  1207.  *   This handler sets the exit flag.
  1208.  ************************************************************************* */
  1209. void rexxexit(msg, p, rxdata)
  1210. struct RexxMsg *msg;
  1211. char *p;
  1212. struct RexxData *rxdata;
  1213. {
  1214.    KeepGoing = FALSE;
  1215. }
  1216.  
  1217. /* *************************************************************************
  1218.  *   This handler sets ResultStr to the version of the program.
  1219.  ************************************************************************* */
  1220. void rexxversion(msg, p, rxdata)
  1221. struct RexxMsg *msg;
  1222. char *p;
  1223. struct RexxData *rxdata;
  1224. {
  1225.    ResultStr = VERSION;
  1226. }
  1227.  
  1228. /* ***********************************************************************
  1229.  *   This handler sends the rest of the command asynchronously,
  1230.  *   allowing us to run macros in parallel.
  1231.  *********************************************************************** */
  1232. void rexxspawn(msg, p, rxdata)
  1233. struct RexxMsg *msg;
  1234. char *p;
  1235. struct RexxData *rxdata;
  1236. {
  1237.    register struct Rexxmsg *rxmsg;
  1238.  
  1239.    if (! (rxmsg = ASyncRexxCmd(p, rxdata)))
  1240.       SetWindowTitles(myWindow, RexxErrMsg, 0L);
  1241. }
  1242.  
  1243. /* ***********************************************************************
  1244.  *   This function is for when a RexxMsg we send out returns with an error.
  1245.  *********************************************************************** */
  1246. void RexxError(error, p, msg, rxdata)
  1247. ULONG error;
  1248. char *p;
  1249. struct RexxMsg *msg;
  1250. struct RexxData *rxdata;
  1251. {
  1252.    SetWindowTitles(myWindow, p, 0L);
  1253. }
  1254.  
  1255. /* ***********************************************************************
  1256.  *   This function is for when a RexxMsg we send out returns successfully.
  1257.  * Actually, we have nothing to do. We have no function that sends out a
  1258.  * RexxMsg and expects a returned Result string or Result1 code. We'll just
  1259.  * print out any result string.
  1260.  *********************************************************************** */
  1261. void RexxResult(error, p, msg, rxdata)
  1262. ULONG error;
  1263. char *p;
  1264. struct RexxMsg *msg;
  1265. struct RexxData *rxdata;
  1266. {
  1267.    if (p)
  1268.    {
  1269.      SetWindowTitles(myWindow, p, 0L);
  1270.    }
  1271. }
  1272.  
  1273. #endif
  1274.