Annotation of Examples/AppKit/Yap/YapOutput.m, revision 1.1

1.1     ! root        1: /*
        !             2:  *  YapOutput.m
        !             3:  *  Author: Ali Ozer
        !             4:  *  Created: Mar 6, 1989
        !             5:  *  Modified: Jun & Jul 1989 for 1.0. Added NX_HANDLER for error detection.
        !             6:  *  Modified: Aug 90 for 2.0. Added use of second context for robustness.
        !             7:  *  Modified: Jan 92 for 3.0. Localized.
        !             8:  *
        !             9:  *  This class is a subclass of view that manages the output in Yap. It
        !            10:  *  provides a method (executeCodeFrom:) to execute PS from a text object.
        !            11:  *  The PostScript output will be displayed in the view. The output is
        !            12:  *  also cached in a bitmap for fast redraw response.
        !            13:  *
        !            14:  *  You may freely copy, distribute and reuse the code in this example.
        !            15:  *  NeXT disclaims any warranty of any kind, expressed or implied,
        !            16:  *  as to its fitness for any particular use.
        !            17:  */
        !            18: 
        !            19: #import <appkit/appkit.h>
        !            20: #import <objc/NXBundle.h>
        !            21: #import <objc/error.h>
        !            22: #import <libc.h>
        !            23: #import <string.h>
        !            24: #import <sys/file.h>
        !            25: 
        !            26: #import "YapOutput.h"
        !            27: #import "YapApp.h"
        !            28: #import "YapWrap.h"
        !            29: 
        !            30: #define BUSY_STRING NXLocalString ("BUSY", NULL, "String shown when PostScript is being executed")
        !            31: #define EXECUTION_COMPLETE_STRING NXLocalString("Yap Postscript Output (Execution Time %d ms)", NULL, "Shown when PostScript has executed successfully")
        !            32: #define NONPOSTSCRIPT_ERROR_STRING NXLocalString("A non-PostScript error while running program.", NULL, "Shown if a non-PostScript error occurs during execution")
        !            33: #define NOCONTEXT_STRING NXLocalString("Could not connect to window server.", NULL, "Shown if a connection cannot be created with the window server")
        !            34: 
        !            35: @implementation YapOutput
        !            36: 
        !            37: /*
        !            38:  * initFrame: initializes the instance and creates a cache.
        !            39:  */
        !            40: - initFrame:(const NXRect *)viewFrame
        !            41: {
        !            42:     [super initFrame:viewFrame];
        !            43:     [self setCacheCleared:YES];
        !            44:     [self setCacheShown:NO];
        !            45:     cache = [[Window allocFromZone:[self zone]]
        !            46:                initContent:&bounds 
        !            47:                style:NX_PLAINSTYLE
        !            48:                backing:NX_RETAINED
        !            49:                buttonMask:0
        !            50:                defer:NO];
        !            51: 
        !            52:     return self;
        !            53: }
        !            54: 
        !            55: /*
        !            56:  * Set/get parameters that determine behaviour.
        !            57:  */
        !            58: - (BOOL)isCacheCleared
        !            59: {
        !            60:     return clearCache;
        !            61: }
        !            62: 
        !            63: - (BOOL)isCacheShown
        !            64: {
        !            65:     return showCache;
        !            66: }
        !            67: 
        !            68: - setCacheCleared:(BOOL)flag
        !            69: {
        !            70:     clearCache = flag;
        !            71:     return self;
        !            72: }
        !            73: 
        !            74: - setCacheShown:(BOOL)flag
        !            75: {
        !            76:     showCache = flag;
        !            77:     return self;
        !            78: }
        !            79: 
        !            80: /*
        !            81:  * sizeTo:: is called whenever the view is resized. It resizes the bitmap cache
        !            82:  * along with the view. It doesn't do anything if the new size is equal to the
        !            83:  * old one.
        !            84:  */
        !            85: - sizeTo:(NXCoord)width :(NXCoord)height
        !            86: {
        !            87:     if (width == frame.size.width && height == frame.size.height) return self;
        !            88: 
        !            89:     [super sizeTo:width :height];
        !            90:     [cache sizeWindow:width :height];
        !            91:     
        !            92:     return self;
        !            93: }
        !            94: 
        !            95: /*
        !            96:  * drawSelf: simply shows the cache.
        !            97:  */
        !            98: - drawSelf:(NXRect *)rects :(int)rectCount
        !            99: {
        !           100:     if (rectCount == 3) {  /* Scrolling diagonally; use last two rectangles */
        !           101:        rects++;
        !           102:        PScomposite (NX_X(rects), NX_Y(rects), NX_WIDTH(rects), NX_HEIGHT(rects), 
        !           103:                        [cache gState], NX_X(rects), NX_Y(rects), NX_COPY);
        !           104:        rects++;
        !           105:        PScomposite (NX_X(rects), NX_Y(rects), NX_WIDTH(rects), NX_HEIGHT(rects), 
        !           106:                        [cache gState], NX_X(rects), NX_Y(rects), NX_COPY);
        !           107:     } else {
        !           108:        PScomposite (NX_X(rects), NX_Y(rects), NX_WIDTH(rects), NX_HEIGHT(rects), 
        !           109:                        [cache gState], NX_X(rects), NX_Y(rects), NX_COPY);
        !           110:     }
        !           111: 
        !           112:     return self;
        !           113: }
        !           114: 
        !           115: - free
        !           116: {
        !           117:     [cache free];
        !           118:     return [super free];
        !           119: }
        !           120: 
        !           121: /*
        !           122:  * Ugly function to write PostScript error.
        !           123:  */
        !           124: void WritePostScriptError (char *errStr, int errStrLength, NXHandler *errorState)
        !           125: {
        !           126:     char *streamAddr;
        !           127:     int streamLength, maxLength;
        !           128:     NXStream *errorStream;
        !           129: 
        !           130:     if ((errorState->code == dps_err_ps) && 
        !           131:        (errorStream = NXOpenMemory (NULL, 0, NX_WRITEONLY))) {
        !           132:         DPSPrintErrorToStream (errorStream, (DPSBinObjSeq)(errorState->data2));
        !           133:        NXFlush (errorStream);
        !           134:        NXGetMemoryBuffer (errorStream, &streamAddr, &streamLength, &maxLength);
        !           135:        if (streamLength > errStrLength-1) streamLength = errStrLength-1;
        !           136:        strncpy (errStr, streamAddr, streamLength);
        !           137:        errStr[streamLength] = 0;
        !           138:        NXCloseMemory (errorStream, NX_FREEBUFFER);
        !           139:     } else {
        !           140:        sprintf (errStr, NONPOSTSCRIPT_ERROR_STRING);
        !           141:     }
        !           142: }
        !           143: 
        !           144: /*
        !           145:  * SwitchContextsWithFocus() will make the specified context the current
        !           146:  * context and make it focus on the same area the old context was 
        !           147:  * focused on.
        !           148:  */
        !           149: static void SwitchContextsWithFocus (DPSContext newContext)
        !           150: {
        !           151:     float c1x, c1y, c2x, c2y;
        !           152:     float winCTM[6];
        !           153:     int realWinNum;
        !           154:     
        !           155:     GetFocus (&c1x, &c1y, &c2x, &c2y, winCTM, &realWinNum);
        !           156:     DPSSetContext (newContext);
        !           157:     ReFocus (realWinNum, winCTM, c1x, c1y, c2x, c2y);
        !           158: }
        !           159: 
        !           160: #define STATUSLENGTH 200       // Some large number for error string length
        !           161: 
        !           162: /*
        !           163:  * executeCodeFrom: treats the contents of the specified text object as
        !           164:  * a PostScript program and executes it. The code is copied from the
        !           165:  * text object into a memory stream and then sent to the server using
        !           166:  * DPSWriteData(). 
        !           167:  *
        !           168:  * For protection against errors, the PostScript code is interpreted in a
        !           169:  * context separate from the Application's own context (which is created
        !           170:  * in the +new method of Application).  We first focus on the cache,
        !           171:  * note the various parameters (global window number, the transformation
        !           172:  * matrix, and the clip path), and then switch to the alternate context and
        !           173:  * reapply the parameters to establish a focus on the same area.
        !           174:  *
        !           175:  * Protection against PostScript errors is provided through the use of
        !           176:  * NX_DURING/NX_HANDLER.   If an error occurs, we immediately blast the
        !           177:  * second context and report the first error encountered.  If no errors
        !           178:  * occur during the execution, then we hang on to the context as it can
        !           179:  * be reused.
        !           180:  *
        !           181:  * Note that the NXEPSImageRep class provides a similar (but more powerful)
        !           182:  * sort of functionality for EPS files.  Use that class rather than the code
        !           183:  * here if you wish to make use of EPS files in your application.  This code
        !           184:  * here is meant for unstructured, short pieces of PostScript code, 
        !           185:  * eactly the kind that Yap encounters...
        !           186:  */
        !           187: - executeCodeFrom:textObj
        !           188: {
        !           189:     int utime;                 /* Time taken to execute the code */
        !           190:     char status[STATUSLENGTH]; /* Array for error messages */
        !           191:     NXStream *psStream;                /* Memory stream for the PostScript */
        !           192:     char *psBuffer;            /* The buffer used by the stream */
        !           193:     int psLen;                 /* And the length of this buffer */
        !           194:     static DPSContext yapContext = NULL;       /* The second context */
        !           195:     DPSContext curContext = DPSGetCurrentContext();
        !           196:     NXHandler exception;
        !           197: 
        !           198:     /* Open a memory stream and write the text into it... */ 
        !           199: 
        !           200:     if (psStream = NXOpenMemory (NULL, 0, NX_WRITEONLY)) {
        !           201:        int dummy;
        !           202:         NXPrintf (psStream, "/yaptime usertime def /yapsave save def "
        !           203:                            "/yapwidth %f def /yapheight %f def "
        !           204:                            "/showpage {} def\n",
        !           205:                             bounds.size.width, bounds.size.height);
        !           206:         [textObj writeText:psStream];
        !           207:         NXPrintf (psStream, "\nyapsave restore "
        !           208:                            "/yaptime usertime yaptime sub def\n");
        !           209:         NXFlush (psStream);
        !           210:        NXGetMemoryBuffer (psStream, &psBuffer, &psLen, &dummy);
        !           211:     } else {
        !           212:        [[self window] setTitle:NONPOSTSCRIPT_ERROR_STRING];
        !           213:        return self;
        !           214:     }
        !           215: 
        !           216:     [[self window] setTitle:BUSY_STRING];
        !           217: 
        !           218:     /* Lock focus on the cache. If user wishes to see the cache, bring it up. */
        !           219: 
        !           220:     [[cache contentView] lockFocus];
        !           221:     if (clearCache) NXEraseRect (&bounds);
        !           222:     if (showCache) [[cache center] orderFront:self];  
        !           223: 
        !           224:     /* Create the second context if it needs to be created. */
        !           225: 
        !           226:     if (yapContext == NULL) {
        !           227:        const char *app = [NXApp appName];
        !           228:        yapContext = DPSCreateNonsecureContext(
        !           229:                        NXGetDefaultValue(app, "NXHost"),
        !           230:                        NXGetDefaultValue(app, "NXPSName"),
        !           231:                        NULL, NULL, 60000, [self zone]);
        !           232:        DPSSetContext (curContext);
        !           233:     }
        !           234: 
        !           235:     if (yapContext) {
        !           236: 
        !           237:        /* Focus the second context to whatever the first context is focused on. */
        !           238:     
        !           239:        SwitchContextsWithFocus (yapContext);
        !           240:     
        !           241:        /* This will let us know if there were any errors. */
        !           242:     
        !           243:        exception.code = 0;
        !           244:     
        !           245:        NX_DURING {
        !           246:            DPSWriteData (yapContext, psBuffer, psLen);
        !           247:            NXPing ();  /* This does not return until the execution is done. */
        !           248:                        /* If there were any errors, we jump to the handler. */
        !           249:            GetUserTime (&utime);
        !           250:            sprintf (status, EXECUTION_COMPLETE_STRING, utime);
        !           251:        } NX_HANDLER {
        !           252:            exception = NXLocalHandler; /* Make note of the error... */
        !           253:        } NX_ENDHANDLER
        !           254:     
        !           255:        /* Switch back to the app context. */
        !           256:     
        !           257:        DPSSetContext(curContext);
        !           258:     
        !           259:        /* In case of error, report it and blow the second context away. */
        !           260:     
        !           261:        if (exception.code != 0) {
        !           262:            DPSDestroyContext(yapContext);
        !           263:            yapContext = NULL;
        !           264:            WritePostScriptError (status, STATUSLENGTH, &exception);
        !           265:        }
        !           266: 
        !           267:     } else {
        !           268:        sprintf (status, NOCONTEXT_STRING, utime);
        !           269:     }
        !           270: 
        !           271:     if (showCache) [cache orderOut:self];
        !           272:     [[cache contentView] unlockFocus];
        !           273:     [self display];
        !           274:     [[self window] setTitle:status];
        !           275: 
        !           276:     NXCloseMemory (psStream, NX_FREEBUFFER);
        !           277:     
        !           278:     return self;
        !           279: }
        !           280: 
        !           281: 
        !           282: @end

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.