Annotation of Examples/AppKit/Yap/YapOutput.m, revision 1.1.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.