#define TALKTOREXX 1 #ifdef TALKTOREXX /* This program is an example of how to add a Rexx implementation to any program using the rexxapp.library. The original Freedraw program (without REXX) is from Fred Fish Disk 1. The rexxapp.library is based upon a C module by Radical Eye Software which was modified and down-coded to a 68000 shared library. All the REXX stuff is bracketed by "idef TALKTOREXX", so you can identify it easily. If you compile with TALKTOREXX unset, you will get the default program with no REXX port. The REXX port on this program increases the executable slightly, but a lot of functionality comes with that. You can draw from Rexx, spawn macros from Rexx, etc. But go to the next TALKTOREXX for more information. To run a rexx macro on startup, simply give that rexx macro as part of the command line, as in "freedraw sample" or "freedraw bspline 20 100 20 20 280 20 280 100". All modifications are placed in the public domain. */ #endif /* ************************************************************************* FreeDraw - PD graphics for Amiga This is an extremely simple graphics editor which works in the windowing environment of the Amiga. It is very limited in features. The basic idea of this program is to provide some minimal image editing functions which can be used to develop images for other programs. There are only two menu topics in this version, so using it is really quite easy. Boxes are not allowed to be drawn in areas outside of the window where border gadgets are located, and the pen-draw mode also clips to these same boundaries. If you have begun to draw a box by clicking the left button while the cursor is located in the FreeDraw window, then you can cancel that box by clicking the right button. In the pen mode pressing and holding the left button will draw. Colors are selected by simply releasing the menu button over the desired color in the Color menu. The erase feature always clears the window to the currently selected color. This is no gem of programming style, but you're getting it for the right price so be patient with its design flaws. New versions will appear here on BIX as soon as I can get them in shape for release. I apologize to anyone who objects to my lack of coding grace, but I just want to get the project off the ground, and improvements will be forthcoming. There are a lot of comments, but I didn't know what needed to be made clear so I just commented everything. Rick Ross 11/14/85 *********************************************************************** */ char *VERSION = "Freedraw 0.01 by Richard M. Ross"; #include #include #include #include #include #include #include #include #include #include #include /* These definitions are used for calls to OpenLibrary() in order to ensure that an appropriate ROM version is available. */ #define INTUITION_REV 1L #define GRAPHICS_REV 1L struct IntuitionBase *IntuitionBase; struct GfxBase *GfxBase; struct Window *myWindow = 0; /* ptr to applications window */ /* This is the Window structure declaration. Nothing fancy is going on here, but note that the Flags and IDCMPFlags members of the structure define which messages will be sent by Intuition. I haven't used them all and if you want to change the settings you should probably do it here instead of using ModifyIDCMP later. */ struct NewWindow NewWindow = { 10, 10, 600, 180, 0, 1, CLOSEWINDOW | MOUSEMOVE | MOUSEBUTTONS | MENUPICK | NEWSIZE | INACTIVEWINDOW, WINDOWCLOSE | SMART_REFRESH | ACTIVATE | WINDOWDRAG | WINDOWDEPTH | WINDOWSIZING | REPORTMOUSE, NULL, NULL, (UBYTE *)"AMIGA FreeDraw 0.01", NULL, NULL, 100, 35, -1, -1, WBENCHSCREEN, }; #ifdef TALKTOREXX /* We need this rexx include file */ #include /* Where we store the rexxapp.library base */ struct RexxBase *RexxBase = 0; /* We'll ship off unknown commands as macros to Rexx, and here's the extension */ char myExtension[] = "fd"; /* These are the rexxapp lib functions. */ extern long SetRexxPort(); extern void FreeRexxPort(); extern void ReceiveRexx(); extern struct RexxMsg *SendRexxCmd(); extern struct RexxMsg *SyncRexxCmd(); extern struct RexxMsg *ASyncRexxCmd(); extern void SetupResults(); extern char *RexxErrMsg; /* This comes from RexxInterface.asm */ /* These are the REXX handlers defined at the bottom of the file */ void rexxcolor(), rexxbox(), rexxfbox(), rexxline(), rexxtofront(), rexxtoback(), rexxexit(), rexxversion(), rexxspawn(); /* This is the Func (Dispatch) function for received Rexxmsgs */ BOOL disp(); /* This is the Error function for the return of Rexxmsgs we send out, and caused an error */ void RexxError(); /* This is the Result function for the return of Rexxmsgs we send out, and were handled successfully */ void RexxResult(); struct CmdEntry { char *CmdString; APTR CmdHandler; }; #define NUMCMDS 10 /* This will be application dependent */ struct RexxData { struct MsgPort RexxPort; char *Exten; APTR Func; struct RxsLib *RexxLib; /* defined by the ARexx rxslib.h file */ APTR Error; APTR Result; ULONG RexxMask; ULONG UserData; /* to be defined by and used by the application */ /* The command list goes here. It consists of one CmdEntry structure for each "command" that the application supports. Note that the number of commands (and therefore the size of the RexxData) will depend upon how many "commands" the application supports. The list must end with a NULL entry. */ struct CmdEntry AsscList[NUMCMDS]; }; /* Here is our initialized RexxData structure (for rexxapp lib) */ struct RexxData myRexxData = { {0}, &myExtension, (APTR) disp, 0, (APTR) RexxError, (APTR) RexxResult, 0, 0, /* Here is our imbedded command association list. Commands are all lower case, so we match either upper or lower. (This is a requirement of rexxapp.library.) */ { { "color", (APTR)&rexxcolor }, { "box", (APTR)&rexxbox }, { "fbox", (APTR)&rexxfbox }, { "line", (APTR)&rexxline }, { "tofront", (APTR)&rexxtofront }, { "toback", (APTR)&rexxtoback }, { "exit", (APTR)&rexxexit }, { "version", (APTR)&rexxversion }, { "spawn", (APTR)&rexxspawn }, { 0, 0 } } }; /* Note that the buffer for the PortName must be 2 bytes more than the name itself. THIS IS REQUIRED so that the lib can construct a new name if this one is in use. Note that is we run two copies of freedraw simultaneously, the first one's port will be "freedraw", and the second one will be "freedraw2". */ char PortName[10] = "freedraw"; #endif /*******************************************************************/ /* DrawBox - Simple routine to draw an unfilled rectangle */ /* It accepts the coordinates of the top-left and lower-right */ /* points of the rectangle, a pointer to the Window structure, */ /* and the color in which to render the rectangle. The current */ /* FgPen color of the window is preserved thru the call. No */ /* clipping is done. */ /*******************************************************************/ void DrawBox( tlx, tly, brx, bry, window, color ) SHORT tlx, tly; /* top-left x,y coordinates */ SHORT brx, bry; /* lower-right x,y coordinates */ struct Window *window; /* pointer to target window */ BYTE color; /* color to use for render */ { BYTE OldColor = window->RPort->FgPen; /* save window's FgPen */ SetAPen( window->RPort, (long)color ); /* set draw color for box */ Move(window->RPort, (long)tlx, (long)tly); /* move to top-left point */ Draw(window->RPort, (long)brx, (long)tly); /* and draw to each of the */ Draw(window->RPort, (long)brx, (long)bry); /* four corners of the box */ Draw(window->RPort, (long)tlx, (long)bry); Draw(window->RPort, (long)tlx, (long)tly); SetAPen( window->RPort, (long)OldColor ); /* restore old FgPen */ } /*********************************************************/ /* Color Select Menu */ /* */ /* This is where the menu for color selection is */ /* defined. It should be flexible enough to allow for */ /* increased palette sizes, but this version is only */ /* for the 4-color mode of the WorkBench screen. */ /*********************************************************/ /* A few definitions are needed here. Note that MAXPAL should be increased to allow for palette larger than four colors. */ #define ITEMSTUFF (ITEMENABLED | HIGHBOX) #define CW 40 #define CH 25 #define MAXPAL 4 /* Declare enough storage for required number of menu items and associated images. This menu will be using graphics renditions of menu items, so the Image structures must be declared. This menu is modeled after the one found in the IconEd source. */ struct MenuItem coloritem[MAXPAL]; struct Image colorimage[MAXPAL]; /* array of palette sizes to correspond with depth of window in bit-planes */ SHORT palette[] = { 2, 4, 8, 16, 32 }; /*****************************************************************/ /* The following function initializes the structure arrays */ /* needed to provide the Color menu topic. */ /*****************************************************************/ InitColorItems( depth ) SHORT depth; /* number of bit-planes in window */ { SHORT n, colors; colors = palette[depth-1]; for( n=0; nBorderLeft; MinY = myWindow->BorderTop; MaxX = myWindow->Width - myWindow->BorderRight - 1; MaxY = myWindow->Height - myWindow->BorderBottom - 1; InitColorItems( 2 ); /* initialize Color menu arrays */ InitDModeItems(); /* initialize DrawMode menu arrays */ InitMenu(); /* initialize the menu structures */ /* Now, having initialized the various arrays * of structures required for menu generation * we can tell Intuition to make our menus * available to the user when this window * is active. */ SetMenuStrip( myWindow, &menu[0] ); /* set initial drw mode and color */ SetDrMd( myWindow->RPort, JAM1 ); SetAPen( myWindow->RPort, DrawColor ); #ifdef TALKTOREXX /* For rexx, we must open up a Rexx port. */ if (! (rexxbit = SetRexxPort(&PortName, &myRexxData))) { puts("can't set up RexxPort"); doclean(); } /* Show the portname in the window titlebar */ SetWindowTitles(myWindow, &PortName, 0L); /* For FreeDraw, we're going to send out the user's args on the CLI as a Rexx macro invocation, if there was one. We send it out asynchronously; no reason not to. This is an example of how your program might invoke a Rexx script. */ firstcommand[0] = 0; for (x=1; xUserPort->mp_SigBit) | rexxbit); ReceiveRexx(&myRexxData); #else Wait( 1L << myWindow->UserPort->mp_SigBit); #endif MouseMoved = FALSE; /* clear this flag each time thru loop */ /* since more than one message may be waiting * a reply at this point, a loop is used to * process all that have come in until no more * are ready. Msg received is assigned to * NewMessage from the GetMsg() function. This * value will be NULL if no message is ready, * and control passes out of the loop at that time */ while( NewMessage=(struct IntuiMessage *)GetMsg(myWindow->UserPort) ) { /* copy some values from the message structure * to variables used in the switch statements * below */ class = NewMessage->Class; code = NewMessage->Code; x = myWindow->MouseX; y = myWindow->MouseY; /* SIZEVERIFY is a very high priority message * in our loop and requires some immediate * servicing. Any outstanding draw operations * are immediately cancelled, and the DrawMode * is nulled. This prevents any attempts to * render outside whatever new myWindow boundaries * the user chooses. * * (not anymore, it don't. -tgr) if( class == SIZEVERIFY ) { PenDown = FALSE; if( RubberBox ) { DrawBox( TLX, TLY, OldBRX, OldBRY, myWindow, DrawColor ); myWindow->Flags &= ( 0xFFFFFFFF ^ RMBTRAP ); RubberBox = FALSE; } } */ /* we have all the information needed from * the message, so we can now safely reply * to it without losing data */ ReplyMsg( NewMessage ); /* Examine point coords from message received * and set the clipping flag if out of bounds. * If user was drawing in PenMode when message * was received, then the ClippedLast flag * should also be set to indicate this to the * next draw operation. */ if(ClipIt = ( x < MinX || x > MaxX || y < MinY || y > MaxY )) if( PenDown ) ClippedLast = TRUE; /* enter switch on type of message received */ switch( class ) { case MOUSEMOVE: /* Don't really do anything with this one * until any other, more important, messages * are received and processed. */ MouseMoved = TRUE; break; case NEWSIZE: /* set new clipping boundaries */ MinX = myWindow->BorderLeft; MinY = myWindow->BorderTop; MaxX = myWindow->Width - myWindow->BorderRight - 1; MaxY = myWindow->Height - myWindow->BorderBottom - 1; break; case CLOSEWINDOW: /* User is ready to quit, so indicate * that execution should terminate * with next iteration of the loop. */ KeepGoing = FALSE; break; case MOUSEBUTTONS: /* A number of things could have happened * here, and further examination of data * received from message is needed to * determine what action should be taken. * The code variable holds important info * about what actually caused the message * to be sent in the first place. */ switch ( code ) { case SELECTUP: /* User was holding down the left button * and just released it. The PenMode * flag variables are set accordingly. * The pen can no longer be down, and * ClippedLast is reset for next time. */ PenDown = ClippedLast = FALSE; break; case SELECTDOWN: /* User has pressed the left button, and * several differnt actions may need to * be taken. If the ClipIt value is TRUE, * then no action should be taken at all. */ if( ClipIt ) break; /* If user is currently in PenMode, then * set up to draw when MOUSEMOVED messages * are received until a subsequent SELECTUP * message comes in. */ if( PenMode ) { PenDown = TRUE; ClippedLast = FALSE; /* make sure to set appropriate mode */ SetDrMd( myWindow->RPort, JAM1 ); /* and establish initial position to draw */ Move( myWindow->RPort, (long)x, (long)y ); break; } /* If user is currently rubberbanding a box, * then a SELECTDOWN message means it is time * to stop rubberbanding and actually draw it. * The following code will be executed if * this is the case, and it will determine if * a filled box is needed before rendering. */ if( RubberBox ) { /* set draw mode back to JAM1 since * it is now currently set to COMPLEMENT */ SetDrMd( myWindow->RPort, JAM1 ); RubberBox = FALSE; /* turn off rubberbanding */ /* Restore the condition of the RMBTRAP * bit in the myWindow structure's Flags * member. Menubutton events will no * be received by this loop. */ myWindow->Flags &= ( 0xFFFFFFFF ^ RMBTRAP ); /* RectFill is not condusive to the smooth * execution of programs iit arguments are * out of order, sot his code sorts them * in preparation for the call. */ if( FilledBox ) { /* first sort the x-coords */ if( TLX < OldBRX ) { x1 = TLX; x2 = OldBRX; } else { x1 = OldBRX; x2 = TLX; } /* then sort the y-coords */ if( TLY < OldBRY ) { y1 = TLY; y2 = OldBRY; } else { y1 = OldBRY; y2 = TLY; } /* now generate the filled rectangle */ RectFill( myWindow->RPort, (long)x1, (long)y1, (long)x2, (long)y2 ); } else { /* FilledBox not set, so draw hollow box */ DrawBox( TLX, TLY, OldBRX, OldBRY, myWindow, DrawColor ); } break; } /* If execution comes here, then PenMode was * not set and user was not rubberbanding. * SELECTDOWN therefore indicates to start the * rubberbanding process at this point. The * initial coords are set to the values we * received when the GetMsg() was executed. */ TLX = OldBRX = x; TLY = OldBRY = y; /* set to render in XOR mode */ SetDrMd( myWindow->RPort, COMPLEMENT ); /* set flag to indicate we are now rubberbanding */ RubberBox = TRUE; /* This instruction indicates to Intuition * that we now wish to receive a message * each time the Menubutton is pressed. * This is how we hijack the right button * for temporary use as a Cancel button * instead of a Menubutton. */ myWindow->Flags |= RMBTRAP; /* render the initial rubberbox and exit */ DrawBox( TLX, TLY, OldBRX, OldBRY, myWindow, DrawColor ); break; case MENUDOWN: /* WE only receive this message class if * the RMBTRAP flag bit has been set, so * it always means that we should cancel * the box which is currently rubberbanding. */ /* turn the flag off */ RubberBox = FALSE; /* restore control of menubutton to Intuition */ myWindow->Flags &= ( 0xFFFFFFFF ^ RMBTRAP ); /* erase (by double XOR'ing) the current * rubberbox and exit switch. */ DrawBox( TLX, TLY, OldBRX, OldBRY, myWindow, DrawColor ); break; default: /* Something unimportant happened, so just * continue thru the GetMsg() loop. */ continue; } break; case MENUPICK: /* A menu event has taken place and is * ready to be processed. Examine the * code variable received from the message * to determine what action should be taken. * The first check is for MENUNULL, which * means that nothing should be done at all. */ if( code != MENUNULL ) { /* get menu and item numbers from code */ MenuNum = MENUNUM( code ); ItemNum = ITEMNUM( code ); /* determine appropriate action by menu number */ switch ( MenuNum ) { case 0: /* Menu 0 is the Color menu. The * item number indicates which new * color to set. */ DrawColor = ItemNum; SetAPen( myWindow->RPort, (long)DrawColor ); break; case 1: /* Menu 1 is the DrawMode menu. The item * number indicates what to do. * NOTE: Since we cannot have received * this message if we were rubberbanding, * then there is no need to clean up before * changing drawing modes. */ switch ( ItemNum ) { case 0: /* Erase window to current color */ SetDrMd( myWindow->RPort, JAM1 ); RectFill( myWindow->RPort, (long)MinX, (long)MinY, (long)MaxX, (long)MaxY); break; case 1: /* set flag variables for hollow box */ PenMode = FALSE; FilledBox = FALSE; break; case 2: /* set flag variables for filled box */ PenMode = FALSE; FilledBox = TRUE; break; case 3: /* set flag variables for PenMode */ PenMode = TRUE; break; default: /* don't do anything */ break; } break; default: /* Menu number unrecognized, do nothing */ break; } } break; case INACTIVEWINDOW: /* User has de-selected our window, so a * little bit of cleaning up may be needed * to prevent untoward events when he comes * back to it. */ /* erase any outstanding rubberbox */ if( RubberBox ) DrawBox( TLX, TLY, OldBRX, OldBRY, myWindow, DrawColor ); /* reset all the flafg variables */ PenDown = ClippedLast = RubberBox = FALSE; /* return possibly diverted menubutton events to Big I */ myWindow->Flags &= ( 0xFFFFFFFF ^ RMBTRAP ); break; default: /* message class was unrecognized, so do nothing */ break; } } /* this brace ends the while(NewMessage) loop way back when */ /* There are no more messages waiting at the * IDCMP port, so we can now proceed to * process any MOUSEMOVED message we may * have received. */ if( MouseMoved && !ClipIt) { /* the mouse did move, and we don't need to clip */ /* check first if we are drawing in PenMode */ if( PenDown ) { /* We have to examine if we clipped the * last PenMode draw operation. If we did, * then this is the first move back into * window boundaries, so we mov instead of * drawing. */ if( ClippedLast ) { ClippedLast = FALSE; /* reset this flag now */ Move( myWindow->RPort, (long)x, (long)y ); } else Draw( myWindow->RPort, (long)x, (long)y ); /* draw to x,y coords */ } else { /* We weren't in PenMode, but we still might * be rubberbanding a box. If so, then we * should erase the current rubberbox and * draw a new one with the new mouse coords. */ if( RubberBox ) { /* erase the old rubberbox - draw mode is COMPLEMENT */ DrawBox( TLX, TLY, OldBRX, OldBRY, myWindow, DrawColor ); /* assign new values to box coords */ OldBRX = x; OldBRY = y; /* and draw the new rubberbox */ DrawBox( TLX, TLY, OldBRX, OldBRY, myWindow, DrawColor ); } } } } /* It must be time to quit, so we have to clean * up and exit. */ #ifdef TALKTOREXX /* With Rexx, we need to bring the port down. You might make this part of exit() for programs that have multiple paths to exit, but don't call it unless you called SetRexxPort() once anyway. */ FreeRexxPort(&myRexxData); #endif ClearMenuStrip( myWindow ); doclean(); } #ifdef TALKTOREXX /* Now we get into the actual code necessary for our REXX port; functions that do the real work. Note that this program was not structured particularly nicely for Rexx; I had to write each of these functions. Many programs have these subroutines already in place; they are called as part of the event loop. This progam, however, just has one big switch statement in main() with different actions . . . First, our locals. */ ULONG currrexxcolor = 1; /* what color is *rexx* drawing in? */ ULONG args[4]; /* what args did we see to this function? */ ULONG error; /* was argument parsing successful? */ char *ResultStr; /* the Result string to return if any */ /* ********************************************************************* * This function takes a pointer to a pointer to a string, grabs the * next number (unsigned), returns it, and advances the pointer to the * string to point after the number. ********************************************************************* */ ULONG getnm(where) char **where; { register char *p = *where; register ULONG val = 0; register ULONG gotone = 0; while (*p <= ' ' && *p) p++; while ('0' <= *p && *p <= '9') { gotone = 1; val = 10 * val + *p++ - '0'; } if (gotone == 0) error = 20; /* Indicate an error level of 20 with rexx arguments */ *where = p; return(val); } /* ********************************************************************** * This function trys to find `n' numeric arguments in the command * string, and stuffs them into the args array. ********************************************************************** */ void parseargs(p, n) char *p; UBYTE n; { register UBYTE i; while (*p > ' ' && *p) p++; for (i=0; iRPort->FgPen; SetAPen(myWindow->RPort, (LONG)currrexxcolor); /* Call the appropriate handler. The lib has determined which one */ ((void (*)())(routine))(msg, p, rxdata); /* restore the color */ SetAPen(myWindow->RPort, (LONG)t); /* Check for any errors */ if (! error) { /* No errors. Send back Result1 and Result2 = 0. Also return any Result string */ SetupResults(0L, 0L, ResultStr, msg, rxdata); } else { /* An error! Return Result1 = error. Must not send back a Result string */ SetupResults(error, 10L, NULL, msg, rxdata); } /* We want the lib to do the reply right now */ return(TRUE); } SetupResults(error, 10L, msg, NULL, rxdata); } /* ********************************************************************** * This handler sets the current rexx color. (our 'color' handler) ********************************************************************** */ void rexxcolor(msg, p, rxdata) struct RexxMsg *msg; char *p; struct RexxData *rxdata; { parseargs(p, 1); currrexxcolor = args[0]; } /* ********************************************************************* * This function silently clips the x and y values at `n' to the * window bounds. ********************************************************************* */ void clipxy(n) UBYTE n; { if (args[n] < MinX) args[n] = MinX; if (args[n] > MaxX) args[n] = MaxX; n++; if (args[n] < MinY) args[n] = MinY; if (args[n] > MaxY) args[n] = MaxY; } /* ********************************************************************** * This handler grabs four arguments and draws a box. ********************************************************************** */ void rexxbox(msg, p, rxdata) struct RexxMsg *msg; char *p; struct RexxData *rxdata; { parseargs(p, 4); clipxy(0); clipxy(2); DrawBox(args[0], args[1], args[2], args[3], myWindow, currrexxcolor); } /* ********************************************************************* * This handler grabs four arguments and draws a filled box. ********************************************************************** */ void rexxfbox(msg, p, rxdata) struct RexxMsg *msg; char *p; struct RexxData *rxdata; { register ULONG t; parseargs(p, 4); clipxy(0); clipxy(2); if (args[0] > args[2]) { t = args[0]; args[0] = args[2]; args[2] = t; } if (args[1] > args[3]) { t = args[1]; args[1] = args[3]; args[3] = t; } RectFill( myWindow->RPort, (long)args[0], (long)args[1], (long)args[2], (long)args[3]); } /* ************************************************************************ * This handler grabs four arguments and draws a line. ************************************************************************ */ void rexxline(msg, p, rxdata) struct RexxMsg *msg; char *p; struct RexxData *rxdata; { parseargs(p, 4); clipxy(0); clipxy(2); Move(myWindow->RPort, (long)args[0], (long)args[1]); Draw(myWindow->RPort, (long)args[2], (long)args[3]); } /* ************************************************************************* * This handler pops the window to front. ************************************************************************* */ void rexxtofront(msg, p, rxdata) struct RexxMsg *msg; char *p; struct RexxData *rxdata; { WindowToFront(myWindow); } /* ************************************************************************* * This handler pops the window to back. ************************************************************************* */ void rexxtoback(msg, p, rxdata) struct RexxMsg *msg; char *p; struct RexxData *rxdata; { WindowToBack(myWindow); } /* ************************************************************************* * This handler sets the exit flag. ************************************************************************* */ void rexxexit(msg, p, rxdata) struct RexxMsg *msg; char *p; struct RexxData *rxdata; { KeepGoing = FALSE; } /* ************************************************************************* * This handler sets ResultStr to the version of the program. ************************************************************************* */ void rexxversion(msg, p, rxdata) struct RexxMsg *msg; char *p; struct RexxData *rxdata; { ResultStr = VERSION; } /* *********************************************************************** * This handler sends the rest of the command asynchronously, * allowing us to run macros in parallel. *********************************************************************** */ void rexxspawn(msg, p, rxdata) struct RexxMsg *msg; char *p; struct RexxData *rxdata; { register struct Rexxmsg *rxmsg; if (! (rxmsg = ASyncRexxCmd(p, rxdata))) SetWindowTitles(myWindow, RexxErrMsg, 0L); } /* *********************************************************************** * This function is for when a RexxMsg we send out returns with an error. *********************************************************************** */ void RexxError(error, p, msg, rxdata) ULONG error; char *p; struct RexxMsg *msg; struct RexxData *rxdata; { SetWindowTitles(myWindow, p, 0L); } /* *********************************************************************** * This function is for when a RexxMsg we send out returns successfully. * Actually, we have nothing to do. We have no function that sends out a * RexxMsg and expects a returned Result string or Result1 code. We'll just * print out any result string. *********************************************************************** */ void RexxResult(error, p, msg, rxdata) ULONG error; char *p; struct RexxMsg *msg; struct RexxData *rxdata; { if (p) { SetWindowTitles(myWindow, p, 0L); } } #endif