1 /* Copyright (C) 2001-2019 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied,
8    modified or distributed except as expressly authorized under the terms
9    of the license contained in the file LICENSE in this distribution.
10 
11    Refer to licensing information at http://www.artifex.com or contact
12    Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
13    CA 94945, U.S.A., +1(415)492-9861, for further information.
14 */
15 
16 
17 /* Ghostscript shlib example wrapper for Macintosh (Classic/Carbon) contributed
18    by Nigel Hathaway. Uses the Metrowerks CodeWarrior SIOUX command-line library.
19  */
20 
21 #if __ide_target("Ghostscript PPC (Debug)") || __ide_target("Ghostscript PPC (Release)")
22 #define TARGET_API_MAC_CARBON 0
23 #define TARGET_API_MAC_OS8 1
24 #define ACCESSOR_CALLS_ARE_FUNCTIONS 1
25 #endif
26 
27 #include <Carbon.h>
28 
29 #include <stdlib.h>
30 #include <string.h>
31 #include <stdio.h>
32 #include <console.h>
33 #include <SIOUX.h>
34 #include <SIOUXGlobals.h>
35 #include <SIOUXMenus.h>
36 
37 #include "gscdefs.h"
38 #define GSREVISION gs_revision
39 #include "ierrors.h"
40 #include "iapi.h"
41 
42 #include "gdevdsp.h"
43 
44 #define kScrollBarWidth   15
45 #define MAX_ARGS 25
46 
47 Boolean   gRunningOnX = false;
48 Boolean   gDone;
49 ControlActionUPP gActionFunctionScrollUPP;
50 
51 const char start_string[] = "systemdict /start get exec\n";
52 void *instance = NULL;
53 
54 const unsigned int display_format = DISPLAY_COLORS_RGB | DISPLAY_UNUSED_FIRST |
55                                     DISPLAY_DEPTH_8 | DISPLAY_BIGENDIAN |
56                                     DISPLAY_TOPFIRST;
57 typedef struct IMAGE_S IMAGE;
58 struct IMAGE_S {
59     void *handle;
60     void *device;
61     WindowRef  windowRef;
62     ControlRef scrollbarVertRef;
63     ControlRef scrollbarHorizRef;
64     PixMapHandle pixmapHdl;
65     UInt64 update_time;
66     int update_interval;
67     IMAGE *next;
68 };
69 
70 IMAGE *first_image;
71 
72 static IMAGE *image_find(void *handle, void *device);
73 
74 static int GSDLLCALL gsdll_stdin(void *instance, char *buf, int len);
75 static int GSDLLCALL gsdll_stdout(void *instance, const char *str, int len);
76 static int GSDLLCALL gsdll_stderr(void *instance, const char *str, int len);
77 static int GSDLLCALL gsdll_poll(void *handle);
78 
79 static int display_open(void *handle, void *device);
80 static int display_preclose(void *handle, void *device);
81 static int display_close(void *handle, void *device);
82 static int display_presize(void *handle, void *device, int width, int height,
83     int raster, unsigned int format);
84 static int display_size(void *handle, void *device, int width, int height,
85     int raster, unsigned int format, unsigned char *pimage);
86 static int display_sync(void *handle, void *device);
87 static int display_page(void *handle, void *device, int copies, int flush);
88 static int display_update(void *handle, void *device,
89     int x, int y, int w, int h);
90 
91 static size_t get_input(void *ptr, size_t size);
92 
93 static void window_create (IMAGE *img);
94 static void window_invalidate (WindowRef windowRef);
95 static void window_adjust_scrollbars (WindowRef windowRef);
96 
97 void    main                      (void);
98 OSErr   quitAppEventHandler       (AppleEvent *,AppleEvent *,SInt32);
99 void    doEvents                  (EventRecord *);
100 void    doMouseDown               (EventRecord *);
101 void    doUpdate                  (EventRecord *);
102 void    doUpdateWindow            (EventRecord *);
103 void    doOSEvent                 (EventRecord *);
104 void    doInContent               (EventRecord *,WindowRef);
105 pascal void    actionFunctionScroll      (ControlRef,ControlPartCode);
106 
107 /*********************************************************************/
108 /* stdio functions */
109 static int GSDLLCALL
gsdll_stdin(void * instance,char * buf,int len)110 gsdll_stdin(void *instance, char *buf, int len)
111 {
112     if (isatty(fileno(stdin)))
113        return get_input(buf, len);
114     else
115        return fread(buf, 1, len, stdin);
116 }
117 
118 static int GSDLLCALL
gsdll_stdout(void * instance,const char * str,int len)119 gsdll_stdout(void *instance, const char *str, int len)
120 {
121     int n = fwrite(str, 1, len, stdout);
122     fflush(stdout);
123     return n;
124 }
125 
126 static int GSDLLCALL
gsdll_stderr(void * instance,const char * str,int len)127 gsdll_stderr(void *instance, const char *str, int len)
128 {
129     return gsdll_stdout(instance, str, len);
130 }
131 
132 /* Poll the caller for cooperative multitasking. */
133 /* If this function is NULL, polling is not needed */
gsdll_poll(void * handle)134 static int GSDLLCALL gsdll_poll(void *handle)
135 {
136     EventRecord eventStructure;
137 
138     while (WaitNextEvent(everyEvent, &eventStructure, 0, NULL))
139         doEvents(&eventStructure);
140 
141     return (gDone ? gs_error_Fatal : 0);
142 }
143 /*********************************************************************/
144 
145 /* new dll display device */
146 
147 /* New device has been opened */
148 /* This is the first event from this device. */
display_open(void * handle,void * device)149 static int display_open(void *handle, void *device)
150 {
151     IMAGE *img = (IMAGE *)malloc(sizeof(IMAGE));
152     if (img == NULL)
153        return -1;
154     memset(img, 0, sizeof(IMAGE));
155 
156     /* add to list */
157     if (first_image)
158        img->next = first_image;
159     first_image = img;
160 
161     /* remember device and handle */
162     img->handle = handle;
163     img->device = device;
164 
165     /* create window */
166     window_create(img);
167 
168     gsdll_poll(handle);
169     return 0;
170 }
171 
172 /* Device is about to be closed. */
173 /* Device will not be closed until this function returns. */
display_preclose(void * handle,void * device)174 static int display_preclose(void *handle, void *device)
175 {
176     /* do nothing - no thread synchonisation needed */
177     return 0;
178 }
179 
180 /* Device has been closed. */
181 /* This is the last event from this device. */
display_close(void * handle,void * device)182 static int display_close(void *handle, void *device)
183 {
184     IMAGE *img = image_find(handle, device);
185     if (img == NULL)
186        return -1;
187 
188     gsdll_poll(handle);
189 
190     /* remove from list */
191     if (img == first_image)
192         first_image = img->next;
193     else
194     {
195         IMAGE *tmp;
196         for (tmp = first_image; tmp!=0; tmp=tmp->next)
197         {
198             if (img == tmp->next)
199             tmp->next = img->next;
200         }
201     }
202 
203     DisposePixMap(img->pixmapHdl);   // need to go in doCloseWindow()
204     DisposeWindow(img->windowRef);
205 
206     free(img);
207 
208     return 0;
209 }
210 
211 /* Device is about to be resized. */
212 /* Resize will only occur if this function returns 0. */
display_presize(void * handle,void * device,int width,int height,int raster,unsigned int format)213 static int display_presize(void *handle, void *device, int width, int height,
214     int raster, unsigned int format)
215 {
216     /* Check for correct format (32-bit RGB), fatal error if not */
217     if (format != display_format)
218     {
219         printf("DisplayFormat has been set to an incompatible value.\n");
220         fflush(stdout);
221         return gs_error_rangecheck;
222     }
223 
224     return 0;
225 }
226 
227 /* Device has been resized. */
228 /* New pointer to raster returned in pimage */
display_size(void * handle,void * device,int width,int height,int raster,unsigned int format,unsigned char * pimage)229 static int display_size(void *handle, void *device, int width, int height,
230     int raster, unsigned int format, unsigned char *pimage)
231 {
232     PixMapPtr pixmap;
233     IMAGE *img = image_find(handle, device);
234     if (img == NULL)
235        return -1;
236 
237     /* Check that image is within allowable bounds */
238     if (raster > 0x3fff)
239     {
240        printf("QuickDraw can't cope with an image this big.\n");
241        fflush(stdout);
242        if (img->pixmapHdl)
243        {
244            DisposePixMap(img->pixmapHdl);
245            img->pixmapHdl = NULL;
246        }
247        return gs_error_rangecheck;
248     }
249 
250     /* Create the PixMap */
251     if (!img->pixmapHdl)
252         img->pixmapHdl = NewPixMap();
253 
254     pixmap = *(img->pixmapHdl);
255     pixmap->baseAddr = (char*)pimage;
256     pixmap->rowBytes = (((SInt16)raster) & 0x3fff) | 0x8000;
257     pixmap->bounds.right = width;
258     pixmap->bounds.bottom = height;
259     pixmap->packType = 0;
260     pixmap->packSize = 0;
261     pixmap->pixelType = RGBDirect;
262     pixmap->pixelSize = 32;
263     pixmap->cmpCount = 3;
264     pixmap->cmpSize = 8;
265 
266     /* Update the display window */
267     window_adjust_scrollbars(img->windowRef);
268     window_invalidate(img->windowRef);
269     return gsdll_poll(handle);
270 }
271 
272 /* flushpage */
display_sync(void * handle,void * device)273 static int display_sync(void *handle, void *device)
274 {
275     IMAGE *img = image_find(handle, device);
276     if (img == NULL)
277        return -1;
278 
279     window_invalidate(img->windowRef);
280     gsdll_poll(handle);
281 
282     return 0;
283 }
284 
285 /* showpage */
286 /* If you want to pause on showpage, then don't return immediately */
display_page(void * handle,void * device,int copies,int flush)287 static int display_page(void *handle, void *device, int copies, int flush)
288 {
289     return display_sync(handle, device);
290 }
291 
292 /* Poll the caller for cooperative multitasking. */
293 /* If this function is NULL, polling is not needed */
display_update(void * handle,void * device,int x,int y,int w,int h)294 static int display_update(void *handle, void *device,
295     int x, int y, int w, int h)
296 {
297     UInt64 t1;
298     UInt64 t2;
299     int delta;
300     IMAGE *img = image_find(handle, device);
301     if (img == NULL)
302        return -1;
303 
304     Microseconds((UnsignedWide*)&t1);
305     delta = (t1 - img->update_time) / 1000000L;
306     if (img->update_interval < 1)
307     img->update_interval = 1;    /* seconds */
308     if (delta < 0)
309         img->update_time = t1;
310     else if (delta > img->update_interval)
311     {
312         /* redraw window */
313         window_invalidate(img->windowRef);
314 
315         /* Make sure the update interval is at least 10 times
316          * what it takes to paint the window
317          */
318         Microseconds((UnsignedWide*)&t2);
319         delta = (t2 - t1) / 1000;
320         if (delta < 0)
321             delta += 60000;    /* delta = time to redraw */
322         if (delta > img->update_interval * 100)
323             img->update_interval = delta/100;
324         img->update_time = t2;
325     }
326 
327     return gsdll_poll(handle);
328 }
329 
330 display_callback display = {
331     sizeof(display_callback),
332     DISPLAY_VERSION_MAJOR,
333     DISPLAY_VERSION_MINOR,
334     display_open,
335     display_preclose,
336     display_close,
337     display_presize,
338     display_size,
339     display_sync,
340     display_page,
341     display_update,
342     NULL,    /* memalloc */
343     NULL,    /* memfree */
344     NULL	 /* display_separation */
345 };
346 
image_find(void * handle,void * device)347 static IMAGE * image_find(void *handle, void *device)
348 {
349     IMAGE *img;
350     for (img = first_image; img!=0; img=img->next) {
351     if ((img->handle == handle) && (img->device == device))
352         return img;
353     }
354     return NULL;
355 }
356 
357 /*********************************************************************/
358 
359 static char *stdin_buf = NULL;
360 static size_t stdin_bufpos = 0;
361 static size_t stdin_bufsize = 0;
362 
363 /* This function is a fudge which allows the SIOUX window to be waiting for
364    input and not be modal at the same time. (Why didn't MetroWerks think of that?)
365    It is based on the SIOUX function ReadCharsFromConsole(), and contains an
366    event loop which allows other windows to be active.
367    It collects characters up to when the user presses ENTER, stores the complete
368    buffer and gives as much to the calling function as it wants until it runs
369    out, at which point it gets another line (or set of lines if pasting from the
370    clipboard) from the user.
371 */
get_input(void * ptr,size_t size)372 static size_t get_input(void *ptr, size_t size)
373 {
374     EventRecord eventStructure;
375     long charswaiting, old_charswaiting = 0;
376     char *text;
377 
378 #if SIOUX_USE_WASTE
379     Handle textHandle;
380 #endif
381 
382     /* If needing more input, set edit start position */
383     if (!stdin_buf)
384 #if SIOUX_USE_WASTE
385         SIOUXselstart = WEGetTextLength(SIOUXTextWindow->edit);
386 #else
387         SIOUXselstart = (*SIOUXTextWindow->edit)->teLength;
388 #endif
389 
390     /* Wait until user presses exit (or quits) */
391     while(!gDone && !stdin_buf)
392     {
393 #if SIOUX_USE_WASTE
394         charswaiting = WEGetTextLength(SIOUXTextWindow->edit) - SIOUXselstart;
395 #else
396         if ((*SIOUXTextWindow->edit)->teLength > 0)
397             charswaiting = (*SIOUXTextWindow->edit)->teLength - SIOUXselstart;
398         else
399             charswaiting = ((unsigned short) (*SIOUXTextWindow->edit)->teLength) - SIOUXselstart;
400 #endif
401 
402         /* If something has happened, see if we need to do anything */
403         if (charswaiting != old_charswaiting)
404         {
405 #if SIOUX_USE_WASTE
406             textHandle = WEGetText(SIOUXTextWindow->edit);
407             HLock(textHandle);
408             text = *textHandle + SIOUXselstart;
409 #else
410             text = (*(*SIOUXTextWindow->edit)->hText) + SIOUXselstart;
411 #endif
412             /* If user has pressed enter, gather up the buffer ready for returning */
413             if (text[charswaiting-1] == '\r')
414             {
415                 stdin_buf = malloc(charswaiting);
416                 if (!stdin_buf)
417                     return -1;
418                 stdin_bufsize = charswaiting;
419                 memcpy(stdin_buf, text, stdin_bufsize);
420                 SIOUXselstart += charswaiting;
421 
422                 text = stdin_buf;
423                 while (text = memchr(text, '\r', charswaiting - (text - stdin_buf)))
424                     *text = '\n';
425             }
426 #if SIOUX_USE_WASTE
427             HUnlock(textHandle);
428 #endif
429             old_charswaiting = charswaiting;
430 
431             if (stdin_buf)
432                 break;
433         }
434 
435         /* Wait for next event and process it */
436         SIOUXState = SCANFING;
437 
438         if(WaitNextEvent(everyEvent, &eventStructure, SIOUXSettings.sleep ,NULL))
439             doEvents(&eventStructure);
440         else
441             SIOUXHandleOneEvent(&eventStructure);
442 
443         SIOUXState = IDLE;
444     }
445 
446     /* If data has been entered, return as much as has been requested */
447     if (stdin_buf && !gDone)
448     {
449         if (size >= stdin_bufsize - stdin_bufpos)
450         {
451             size = stdin_bufsize - stdin_bufpos;
452             memcpy (ptr, stdin_buf + stdin_bufpos, size);
453             free(stdin_buf);
454             stdin_buf = NULL;
455             stdin_bufpos = 0;
456             stdin_bufsize = 0;
457         }
458         else
459         {
460             memcpy (ptr, stdin_buf + stdin_bufpos, size);
461             stdin_bufpos += size;
462         }
463         return size;
464     }
465     else if (stdin_buf)
466     {
467         free(stdin_buf);
468         stdin_buf = NULL;
469         stdin_bufpos = 0;
470         stdin_bufsize = 0;
471     }
472 
473     return 0;
474 }
475 
476 /*********************************************************************/
477 
window_create(IMAGE * img)478 static void window_create(IMAGE *img)
479 {
480     WindowRef windowRef;
481     Str255    windowTitle = "\pGhostscript Image";
482     Rect      windowRect = {20,4,580,420};//, portRect;
483     Rect      scrollbarRect = {0,0,0,0};
484 
485 #if TARGET_API_MAC_CARBON
486     GetAvailableWindowPositioningBounds(GetMainDevice(),&windowRect);
487 #endif
488 
489     /* Create a new suitablty positioned window */
490     windowRect.top = windowRect.top * 2 + 2;
491     windowRect.bottom -= 10;
492     windowRect.left += 4;
493     windowRect.right = ((windowRect.bottom - windowRect.top) * 3) / 4 + windowRect.left;
494 
495     if(!(windowRef = NewCWindow(NULL, &windowRect, windowTitle, true,
496                                 zoomDocProc, (WindowRef) -1, false, 0)))
497         ExitToShell();
498 
499     img->windowRef = windowRef;
500 
501     SetWRefCon(img->windowRef, (SInt32)img);
502 
503     /* Create the window's scrollbars */
504 #if TARGET_API_MAC_CARBON
505     if(gRunningOnX)
506         ChangeWindowAttributes(windowRef,kWindowLiveResizeAttribute,0);
507 
508     CreateScrollBarControl(windowRef, &scrollbarRect, 0, 0, 0, 0,
509                            true, gActionFunctionScrollUPP, &(img->scrollbarVertRef));
510 
511     CreateScrollBarControl(windowRef, &scrollbarRect, 0, 0, 0, 0,
512                            true, gActionFunctionScrollUPP, &(img->scrollbarHorizRef));
513 #else
514     img->scrollbarVertRef = NewControl(windowRef,&scrollbarRect,"\p",false,0,0,0,scrollBarProc,0);
515     img->scrollbarHorizRef = NewControl(windowRef,&scrollbarRect,"\p",false,0,0,0,scrollBarProc,0);
516 #endif
517 
518     window_adjust_scrollbars(windowRef);
519 }
520 
window_invalidate(WindowRef windowRef)521 static void window_invalidate(WindowRef windowRef)
522 {
523     Rect portRect;
524 
525     GetWindowPortBounds(windowRef, &portRect);
526     InvalWindowRect(windowRef, &portRect);
527 }
528 
window_adjust_scrollbars(WindowRef windowRef)529 static void window_adjust_scrollbars(WindowRef windowRef)
530 {
531     IMAGE *img;
532     Rect   portRect;
533 
534     img = (IMAGE*)GetWRefCon(windowRef);
535     GetWindowPortBounds(windowRef,&portRect);
536 
537     /* Move the crollbars to the edges of the window */
538     HideControl(img->scrollbarVertRef);
539     HideControl(img->scrollbarHorizRef);
540 
541     MoveControl(img->scrollbarVertRef,portRect.right - kScrollBarWidth,
542                 portRect.top - 1);
543     MoveControl(img->scrollbarHorizRef,portRect.left - 1,
544                 portRect.bottom - kScrollBarWidth);
545 
546     SizeControl(img->scrollbarVertRef,kScrollBarWidth + 1,
547                 portRect.bottom - portRect.top - kScrollBarWidth + 1);
548     SizeControl(img->scrollbarHorizRef, portRect.right - portRect.left - kScrollBarWidth + 1,
549                 kScrollBarWidth + 1);
550 
551     /* Adjust the scroll position showing */
552     if (img->pixmapHdl)
553     {
554         PixMap *pixmap = *(img->pixmapHdl);
555         int visibleHeight = portRect.bottom - portRect.top - kScrollBarWidth;
556         int visibleWidth = portRect.right - portRect.left - kScrollBarWidth;
557 
558         if (pixmap->bounds.bottom > visibleHeight)
559         {
560             SetControl32BitMaximum(img->scrollbarVertRef,
561                                    pixmap->bounds.bottom - visibleHeight);
562             SetControlViewSize(img->scrollbarVertRef,visibleHeight);
563         }
564         else
565             SetControlMaximum(img->scrollbarVertRef, 0);
566 
567         if (pixmap->bounds.right > visibleWidth)
568         {
569             SetControl32BitMaximum(img->scrollbarHorizRef,
570                                    pixmap->bounds.right - visibleWidth);
571             SetControlViewSize(img->scrollbarHorizRef, visibleWidth);
572         }
573         else
574             SetControlMaximum(img->scrollbarHorizRef, 0);
575     }
576 
577     ShowControl(img->scrollbarVertRef);
578     ShowControl(img->scrollbarHorizRef);
579 }
580 
581 /*********************************************************************/
main(void)582 void main(void)
583 {
584     int code;
585     int exit_code;
586     int argc;
587     char **argv;
588     char dformat[64], ddevice[32];
589     SInt32        response;
590 
591     /* Initialize operating environment */
592 #if TARGET_API_MAC_CARBON
593     MoreMasterPointers(224);
594 #else
595     MoreMasters();
596 #endif
597     InitCursor();
598     FlushEvents(everyEvent,0);
599 
600     if (AEInstallEventHandler(kCoreEventClass,kAEQuitApplication,
601                               NewAEEventHandlerUPP((AEEventHandlerProcPtr) quitAppEventHandler),
602                               0L,false) != noErr)
603         ExitToShell();
604 
605         gActionFunctionScrollUPP = NewControlActionUPP(&actionFunctionScroll);
606 
607     Gestalt(gestaltMenuMgrAttr,&response);
608     if(response & gestaltMenuMgrAquaLayoutMask)
609                 gRunningOnX = true;
610 
611     /* Initialize SIOUX */
612     SIOUXSettings.initializeTB = false;
613     SIOUXSettings.standalone = false;
614     SIOUXSettings.asktosaveonclose = false;
615     SIOUXSettings.sleep = GetCaretTime();
616     SIOUXSettings.userwindowtitle = "\pGhostscript";
617 
618     /* Get arguments from user */
619     argc = ccommand(&argv);
620 
621     /* Show command line window */
622     if (InstallConsole(0))
623         ExitToShell();
624 
625     /* Part of fudge to make SIOUX accept characters without becoming modal */
626     SelectWindow(SIOUXTextWindow->window);
627     PostEvent(keyDown, 0x4c00);  // Enter
628     ReadCharsFromConsole(dformat, 0x7FFF);
629     clrscr();
630 
631     /* Add in the display format as the first command line argument */
632     if (argc >= MAX_ARGS - 1)
633     {
634        printf("Too many command line arguments\n");
635        return;
636     }
637 
638     memmove(&argv[3], &argv[1], (argc-1) * sizeof(char**));
639     argc += 2;
640     argv[1] = ddevice;
641     argv[2] = dformat;
642 
643     gs_sprintf(ddevice, "-sDEVICE=display");
644     gs_sprintf(dformat, "-dDisplayFormat=%d", display_format);
645 
646     /* Run Ghostscript */
647     if (gsapi_new_instance(&instance, NULL) < 0)
648     {
649        printf("Can't create Ghostscript instance\n");
650        return;
651     }
652 
653     gsapi_set_stdio(instance, gsdll_stdin, gsdll_stdout, gsdll_stderr);
654     gsapi_set_poll(instance, gsdll_poll);
655     gsapi_set_display_callback(instance, &display);
656 
657     code = gsapi_init_with_args(instance, argc, argv);
658     if (code == 0)
659        code = gsapi_run_string(instance, start_string, 0, &exit_code);
660     else
661     {
662        printf("Failed to initialize. Error %d.\n", code);
663        fflush(stdout);
664     }
665     code = gsapi_exit(instance);
666     if (code != 0)
667     {
668        printf("Failed to terminate. Error %d.\n", code);
669        fflush(stdout);
670     }
671 
672     gsapi_delete_instance(instance);
673 
674     /* Ghostscript has finished - let user see output before quitting */
675     WriteCharsToConsole("\r[Finished - hit any key to quit]", 33);
676     fflush(stdout);
677 
678     /* Process events until a key is hit or user quits from menu */
679     while(!gDone)
680     {
681         EventRecord eventStructure;
682 
683         if(WaitNextEvent(everyEvent,&eventStructure,SIOUXSettings.sleep,NULL))
684         {
685             if (eventStructure.what == keyDown)
686             gDone = true;
687 
688             doEvents(&eventStructure);
689         }
690         else
691             SIOUXHandleOneEvent(&eventStructure);
692     }
693 }
694 
695 /*********************************************************************/
696 
doEvents(EventRecord * eventStrucPtr)697 void doEvents(EventRecord *eventStrucPtr)
698 {
699     WindowRef      windowRef;
700 
701     if (eventStrucPtr->what == mouseDown &&
702         FindWindow(eventStrucPtr->where,&windowRef) == inMenuBar)
703         SelectWindow(SIOUXTextWindow->window);
704 
705     SIOUXSettings.standalone = true;
706     if (SIOUXHandleOneEvent(eventStrucPtr))
707     {
708         if (SIOUXQuitting)
709             gDone = true;
710         SIOUXSettings.standalone = false;
711         return;
712     }
713     SIOUXSettings.standalone = false;
714 
715     switch(eventStrucPtr->what)
716     {
717     case kHighLevelEvent:
718         AEProcessAppleEvent(eventStrucPtr);
719         break;
720 
721     case mouseDown:
722         doMouseDown(eventStrucPtr);
723         break;
724 
725     case keyDown:
726     case autoKey:
727         break;
728 
729     case updateEvt:
730         doUpdate(eventStrucPtr);
731         break;
732 
733     case activateEvt:
734         DrawGrowIcon(windowRef);
735         break;
736 
737     case osEvt:
738         doOSEvent(eventStrucPtr);
739         break;
740     }
741 }
742 
doMouseDown(EventRecord * eventStrucPtr)743 void doMouseDown(EventRecord *eventStrucPtr)
744 {
745     WindowRef      windowRef;
746     WindowPartCode partCode, zoomPart;
747     BitMap         screenBits;
748     Rect           constraintRect, mainScreenRect;
749     Point          standardStateHeightAndWidth;
750     long           newSize;
751 
752     partCode = FindWindow(eventStrucPtr->where,&windowRef);
753 
754     switch(partCode)
755     {
756     case inMenuBar:
757         break;
758 
759     case inContent:
760         if(windowRef != FrontWindow())
761             SelectWindow(windowRef);
762         else
763             doInContent(eventStrucPtr,windowRef);
764         break;
765 
766     case inDrag:
767         DragWindow(windowRef,eventStrucPtr->where,NULL);
768         break;
769 
770     case inGoAway:
771         break;
772 
773     case inGrow:
774         constraintRect.top   = 75;
775         constraintRect.left = 250;
776         constraintRect.bottom = constraintRect.right = 32767;
777         newSize = GrowWindow(windowRef,eventStrucPtr->where,&constraintRect);
778         if (newSize != 0)
779             SizeWindow(windowRef,LoWord(newSize),HiWord(newSize),true);
780         window_adjust_scrollbars(windowRef);
781         window_invalidate(windowRef);
782         break;
783 
784     case inZoomIn:
785     case inZoomOut:
786         mainScreenRect = GetQDGlobalsScreenBits(&screenBits)->bounds;
787         standardStateHeightAndWidth.v = mainScreenRect.bottom;
788         standardStateHeightAndWidth.h = mainScreenRect.right;
789 
790         if(IsWindowInStandardState(windowRef,&standardStateHeightAndWidth,NULL))
791             zoomPart = inZoomIn;
792         else
793             zoomPart = inZoomOut;
794 
795         if(TrackBox(windowRef,eventStrucPtr->where,partCode))
796         {
797             ZoomWindowIdeal(windowRef,zoomPart,&standardStateHeightAndWidth);
798             window_adjust_scrollbars(windowRef);
799         }
800         break;
801     }
802 }
803 
doUpdate(EventRecord * eventStrucPtr)804 void doUpdate(EventRecord *eventStrucPtr)
805 {
806     WindowRef windowRef;
807 
808     windowRef = (WindowRef) eventStrucPtr->message;
809 
810     window_adjust_scrollbars(windowRef);
811 
812     BeginUpdate(windowRef);
813 
814     SetPortWindowPort(windowRef);
815     doUpdateWindow(eventStrucPtr);
816 
817     EndUpdate(windowRef);
818 }
819 
doUpdateWindow(EventRecord * eventStrucPtr)820 void doUpdateWindow(EventRecord *eventStrucPtr)
821 {
822     IMAGE *img;
823     WindowRef    windowRef;
824     Rect         srcRect, destRect, fillRect;
825     PixMapHandle srcPixmapHdl, destPixmapHdl;
826     RGBColor     grayColour = { 0xC000,0xC000,0xC000 };
827     SInt32  hScroll, vScroll;
828 
829     windowRef = (WindowRef) eventStrucPtr->message;
830     img = (IMAGE*)GetWRefCon(windowRef);
831     srcPixmapHdl = img->pixmapHdl;
832     destPixmapHdl = GetPortPixMap(GetWindowPort(windowRef));
833     hScroll = GetControl32BitValue(img->scrollbarHorizRef);
834     vScroll = GetControl32BitValue(img->scrollbarVertRef);
835 
836     if (srcPixmapHdl)
837     {
838         PixMap *pixmap = *srcPixmapHdl;
839         PixPatHandle hdlPixPat = NewPixPat();
840         MakeRGBPat(hdlPixPat, &grayColour);
841 
842         GetWindowPortBounds(windowRef,&destRect);
843         destRect.right  -= kScrollBarWidth;
844         destRect.bottom -= kScrollBarWidth;
845 
846         if (destRect.right > pixmap->bounds.right)
847         {
848             fillRect.top = destRect.top;
849             fillRect.bottom = destRect.bottom;
850             fillRect.left = pixmap->bounds.right;
851             fillRect.right = destRect.right;
852             FillCRect(&fillRect, hdlPixPat);
853             destRect.right = pixmap->bounds.right;
854         }
855         if (destRect.bottom > pixmap->bounds.bottom)
856         {
857             fillRect.top = pixmap->bounds.bottom;
858             fillRect.bottom = destRect.bottom;
859             fillRect.left = destRect.left;
860             fillRect.right = destRect.right;
861             FillCRect(&fillRect, hdlPixPat);
862             destRect.bottom = pixmap->bounds.bottom;
863         }
864         DisposePixPat(hdlPixPat);
865 
866         srcRect = destRect;
867         srcRect.left += hScroll;
868         srcRect.right += hScroll;
869         srcRect.top += vScroll;
870         srcRect.bottom += vScroll;
871 
872         CopyBits((BitMap*)*srcPixmapHdl, (BitMap*)*destPixmapHdl,
873                  &srcRect, &destRect, srcCopy, NULL);
874     }
875 
876     DrawGrowIcon(windowRef);
877 }
878 
doOSEvent(EventRecord * eventStrucPtr)879 void doOSEvent(EventRecord *eventStrucPtr)
880 {
881     switch((eventStrucPtr->message >> 24) & 0x000000FF)
882     {
883     case suspendResumeMessage:
884         if((eventStrucPtr->message & resumeFlag) == 1)
885           SetThemeCursor(kThemeArrowCursor);
886         break;
887     }
888 }
889 
doInContent(EventRecord * eventStrucPtr,WindowRef windowRef)890 void doInContent(EventRecord *eventStrucPtr,WindowRef windowRef)
891 {
892     ControlPartCode controlPartCode;
893     ControlRef      controlRef;
894 
895     SetPortWindowPort(windowRef);
896     GlobalToLocal(&eventStrucPtr->where);
897 
898     if(controlRef = FindControlUnderMouse(eventStrucPtr->where,windowRef,&controlPartCode))
899     {
900 #if TARGET_API_MAC_CARBON
901         TrackControl(controlRef,eventStrucPtr->where,(ControlActionUPP) -1);
902 #else
903         if (controlPartCode == kControlIndicatorPart)
904             TrackControl(controlRef,eventStrucPtr->where,NULL);
905         else
906             TrackControl(controlRef,eventStrucPtr->where,gActionFunctionScrollUPP);
907 #endif
908 
909         window_invalidate(windowRef);
910     }
911 }
912 
actionFunctionScroll(ControlRef controlRef,ControlPartCode controlPartCode)913 pascal void actionFunctionScroll(ControlRef controlRef,ControlPartCode controlPartCode)
914 {
915     SInt32 scrollDistance, controlValue, oldControlValue, controlMax;
916 
917     if(controlPartCode != kControlNoPart)
918     {
919         if(controlPartCode != kControlIndicatorPart)
920         {
921             switch(controlPartCode)
922             {
923             case kControlUpButtonPart:
924             case kControlDownButtonPart:
925                 scrollDistance = 10;
926                 break;
927 
928             case kControlPageUpPart:
929             case kControlPageDownPart:
930                 scrollDistance = 100;
931                 break;
932 
933             default:
934                 scrollDistance = 0;
935                 break;
936             }
937 
938             if (scrollDistance)
939             {
940                 if((controlPartCode == kControlDownButtonPart) ||
941                    (controlPartCode == kControlPageDownPart))
942                     scrollDistance = -scrollDistance;
943 
944                 controlValue = GetControl32BitValue(controlRef);
945 
946                 if(((controlValue == GetControl32BitMaximum(controlRef)) && scrollDistance < 0) ||
947                    ((controlValue == GetControl32BitMinimum(controlRef)) && scrollDistance > 0))
948                     return;
949 
950                 oldControlValue = controlValue;
951                 controlMax = GetControl32BitMaximum(controlRef);
952                 controlValue = oldControlValue - scrollDistance;
953 
954                 if(controlValue < 0)
955                     controlValue = 0;
956                 else if(controlValue > controlMax)
957                     controlValue = controlMax;
958 
959                 SetControl32BitValue(controlRef,controlValue);
960             }
961         }
962     }
963 }
964 
quitAppEventHandler(AppleEvent * appEvent,AppleEvent * reply,SInt32 handlerRefcon)965 OSErr quitAppEventHandler(AppleEvent *appEvent,AppleEvent *reply,SInt32 handlerRefcon)
966 {
967     OSErr    osError;
968     DescType returnedType;
969     Size     actualSize;
970 
971     osError = AEGetAttributePtr(appEvent,keyMissedKeywordAttr,typeWildCard,&returnedType,NULL,0,
972                                 &actualSize);
973 
974     if(osError == errAEDescNotFound)
975     {
976         gDone = true;
977         osError = noErr;
978     }
979     else if(osError == noErr)
980         osError = errAEParamMissed;
981 
982     return osError;
983 }
984 
985 /*********************************************************************/
986