This is YapOutput.m in view mode; [Download] [Up]
/* * YapOutput.m * Author: Ali Ozer * Created: Mar 6, 1989 * Modified: Jun & Jul 1989 for 1.0. Added NX_HANDLER for error detection. * Modified: Aug 90 for 2.0. Added use of second context for robustness. * Modified: Jan 92 for 3.0. Localized. * * This class is a subclass of view that manages the output in Yap. It * provides a method (executeCodeFrom:) to execute PS from a text object. * The PostScript output will be displayed in the view. The output is * also cached in a bitmap for fast redraw response. * * You may freely copy, distribute and reuse the code in this example. * NeXT disclaims any warranty of any kind, expressed or implied, * as to its fitness for any particular use. */ #import <appkit/appkit.h> #import <objc/NXBundle.h> #import <objc/error.h> #import <libc.h> #import <string.h> #import <sys/file.h> #import "YapOutput.h" #import "YapApp.h" #import "YapWrap.h" #define BUSY_STRING NXLocalString ("BUSY", NULL, "String shown when PostScript is being executed") #define EXECUTION_COMPLETE_STRING NXLocalString("Yap Postscript Output (Execution Time %d ms)", NULL, "Shown when PostScript has executed successfully") #define NONPOSTSCRIPT_ERROR_STRING NXLocalString("A non-PostScript error while running program.", NULL, "Shown if a non-PostScript error occurs during execution") #define NOCONTEXT_STRING NXLocalString("Could not connect to window server.", NULL, "Shown if a connection cannot be created with the window server") @implementation YapOutput /* * initFrame: initializes the instance and creates a cache. */ - initFrame:(const NXRect *)viewFrame { [super initFrame:viewFrame]; [self setCacheCleared:YES]; [self setCacheShown:NO]; cache = [[Window allocFromZone:[self zone]] initContent:&bounds style:NX_PLAINSTYLE backing:NX_RETAINED buttonMask:0 defer:NO]; return self; } /* * Set/get parameters that determine behaviour. */ - (BOOL)isCacheCleared { return clearCache; } - (BOOL)isCacheShown { return showCache; } - setCacheCleared:(BOOL)flag { clearCache = flag; return self; } - setCacheShown:(BOOL)flag { showCache = flag; return self; } /* * sizeTo:: is called whenever the view is resized. It resizes the bitmap cache * along with the view. It doesn't do anything if the new size is equal to the * old one. */ - sizeTo:(NXCoord)width :(NXCoord)height { if (width == frame.size.width && height == frame.size.height) return self; [super sizeTo:width :height]; [cache sizeWindow:width :height]; return self; } /* * drawSelf: simply shows the cache. */ - drawSelf:(NXRect *)rects :(int)rectCount { if (rectCount == 3) { /* Scrolling diagonally; use last two rectangles */ rects++; PScomposite (NX_X(rects), NX_Y(rects), NX_WIDTH(rects), NX_HEIGHT(rects), [cache gState], NX_X(rects), NX_Y(rects), NX_COPY); rects++; PScomposite (NX_X(rects), NX_Y(rects), NX_WIDTH(rects), NX_HEIGHT(rects), [cache gState], NX_X(rects), NX_Y(rects), NX_COPY); } else { PScomposite (NX_X(rects), NX_Y(rects), NX_WIDTH(rects), NX_HEIGHT(rects), [cache gState], NX_X(rects), NX_Y(rects), NX_COPY); } return self; } - free { [cache free]; return [super free]; } /* * Ugly function to write PostScript error. */ void WritePostScriptError (char *errStr, int errStrLength, NXHandler *errorState) { char *streamAddr; int streamLength, maxLength; NXStream *errorStream; if ((errorState->code == dps_err_ps) && (errorStream = NXOpenMemory (NULL, 0, NX_WRITEONLY))) { DPSPrintErrorToStream (errorStream, (DPSBinObjSeq)(errorState->data2)); NXFlush (errorStream); NXGetMemoryBuffer (errorStream, &streamAddr, &streamLength, &maxLength); if (streamLength > errStrLength-1) streamLength = errStrLength-1; strncpy (errStr, streamAddr, streamLength); errStr[streamLength] = 0; NXCloseMemory (errorStream, NX_FREEBUFFER); } else { sprintf (errStr, NONPOSTSCRIPT_ERROR_STRING); } } /* * SwitchContextsWithFocus() will make the specified context the current * context and make it focus on the same area the old context was * focused on. */ static void SwitchContextsWithFocus (DPSContext newContext) { float c1x, c1y, c2x, c2y; float winCTM[6]; int realWinNum; GetFocus (&c1x, &c1y, &c2x, &c2y, winCTM, &realWinNum); DPSSetContext (newContext); ReFocus (realWinNum, winCTM, c1x, c1y, c2x, c2y); } #define STATUSLENGTH 200 // Some large number for error string length /* * executeCodeFrom: treats the contents of the specified text object as * a PostScript program and executes it. The code is copied from the * text object into a memory stream and then sent to the server using * DPSWriteData(). * * For protection against errors, the PostScript code is interpreted in a * context separate from the Application's own context (which is created * in the +new method of Application). We first focus on the cache, * note the various parameters (global window number, the transformation * matrix, and the clip path), and then switch to the alternate context and * reapply the parameters to establish a focus on the same area. * * Protection against PostScript errors is provided through the use of * NX_DURING/NX_HANDLER. If an error occurs, we immediately blast the * second context and report the first error encountered. If no errors * occur during the execution, then we hang on to the context as it can * be reused. * * Note that the NXEPSImageRep class provides a similar (but more powerful) * sort of functionality for EPS files. Use that class rather than the code * here if you wish to make use of EPS files in your application. This code * here is meant for unstructured, short pieces of PostScript code, * eactly the kind that Yap encounters... */ - executeCodeFrom:textObj { int utime; /* Time taken to execute the code */ char status[STATUSLENGTH]; /* Array for error messages */ NXStream *psStream; /* Memory stream for the PostScript */ char *psBuffer; /* The buffer used by the stream */ int psLen; /* And the length of this buffer */ static DPSContext yapContext = NULL; /* The second context */ DPSContext curContext = DPSGetCurrentContext(); NXHandler exception; /* Open a memory stream and write the text into it... */ if (psStream = NXOpenMemory (NULL, 0, NX_WRITEONLY)) { int dummy; NXPrintf (psStream, "/yaptime usertime def /yapsave save def " "/yapwidth %f def /yapheight %f def " "/showpage {} def\n", bounds.size.width, bounds.size.height); [textObj writeText:psStream]; NXPrintf (psStream, "\nyapsave restore " "/yaptime usertime yaptime sub def\n"); NXFlush (psStream); NXGetMemoryBuffer (psStream, &psBuffer, &psLen, &dummy); } else { [[self window] setTitle:NONPOSTSCRIPT_ERROR_STRING]; return self; } [[self window] setTitle:BUSY_STRING]; /* Lock focus on the cache. If user wishes to see the cache, bring it up. */ [[cache contentView] lockFocus]; if (clearCache) NXEraseRect (&bounds); if (showCache) [[cache center] orderFront:self]; /* Create the second context if it needs to be created. */ if (yapContext == NULL) { const char *app = [NXApp appName]; yapContext = DPSCreateNonsecureContext( NXGetDefaultValue(app, "NXHost"), NXGetDefaultValue(app, "NXPSName"), NULL, NULL, 60000, [self zone]); DPSSetContext (curContext); } if (yapContext) { /* Focus the second context to whatever the first context is focused on. */ SwitchContextsWithFocus (yapContext); /* This will let us know if there were any errors. */ exception.code = 0; NX_DURING { DPSWriteData (yapContext, psBuffer, psLen); NXPing (); /* This does not return until the execution is done. */ /* If there were any errors, we jump to the handler. */ GetUserTime (&utime); sprintf (status, EXECUTION_COMPLETE_STRING, utime); } NX_HANDLER { exception = NXLocalHandler; /* Make note of the error... */ } NX_ENDHANDLER /* Switch back to the app context. */ DPSSetContext(curContext); /* In case of error, report it and blow the second context away. */ if (exception.code != 0) { DPSDestroyContext(yapContext); yapContext = NULL; WritePostScriptError (status, STATUSLENGTH, &exception); } } else { sprintf (status, NOCONTEXT_STRING, utime); } if (showCache) [cache orderOut:self]; [[cache contentView] unlockFocus]; [self display]; [[self window] setTitle:status]; NXCloseMemory (psStream, NX_FREEBUFFER); return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.