home *** CD-ROM | disk | FTP | other *** search
- /*
- * 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 !0qe 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))) {
- DPSPrintErrorToStr!0r(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[STATUSLENG!0s /* 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