home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume6 / glib / part09 / mac-vt.c < prev   
Encoding:
C/C++ Source or Header  |  1989-05-14  |  18.6 KB  |  845 lines

  1. /* $Id: mac-vt.c,v 1.6 89/05/06 17:13:35 lee Exp $
  2. **
  3. ** vt.c - a replacement dev:console driver for the Keynote musical expression
  4. **        language.
  5. **
  6. ** Provides a cursor, constant-width characters, and (someday) all the escape
  7. ** sequences for vt100 emulation.  The driver (handler) is installed at
  8. ** run-time (for MPW 1.0) by doing the following call (before doing any I/O,
  9. ** since that would auto-initialize the default system driver). 
  10. **
  11. ** _addDevHandler(1, 'CONS', vt_faccess, vt_close, vt_read, vt_write, vt_ioctl);
  12. **
  13. ** WARNING: this code assumes the MPW 1.0 development system.  It hooks itself
  14. ** in as a device driver using the undocumented _addDevHandler call, which
  15. ** may change in future releases of MPW.  It expects the system driver to be
  16. ** in slot 1 - this also may change.
  17. **
  18. ** If you are not using MPW, some or all of this driver may be unnecessary.
  19. ** The vt_getch and vt_peekch functions probably ARE necessary and probably
  20. ** work correctly under any development system.  They mainly provide the 
  21. ** ability to stat the console to do non-blocking input.  They completely
  22. ** avoid MPW's stdio (and all other libraries for that matter), although
  23. ** the vt_read call provides an stdio interface if desired (blocking input
  24. ** only, of course).  They DO assume that the mac has been initialized and
  25. ** the event queue has been set up (InitGraf et.al.).
  26. **
  27. ** The problem is printf.  If your development system has an acceptable
  28. ** implementation (MPW *does NOT*), then just comment out the definition
  29. ** of MPW in Keynote source file machdep.h and give 'er a try.  If, however,
  30. ** you want to use my vt_putch or vt_write routines, you will have to figure
  31. ** out how to hook them into your system. The only thing to beware of is to
  32. ** call vt_open before using vt_putch.  This is done automatically via the
  33. ** vt_faccess call for MPW 1.0.
  34. **
  35. ** Steven A. Falco  4/30/87  moss!saf
  36. */
  37. #include <types.h>
  38. #include <quickdraw.h>
  39. #include <toolutils.h>
  40. #include <fonts.h>
  41. #include <events.h>
  42. #include <windows.h>
  43. #include <dialogs.h>
  44. #include <menus.h>
  45. #include <desk.h>
  46. #include <textedit.h>
  47. #include <scrap.h>
  48. #include <segload.h>
  49. #include <resources.h>
  50. #include <osutils.h>
  51. #include <ioctl.h>
  52. #include <fcntl.h>
  53. #include "vt.h"
  54. #include <stdio.h>
  55.  
  56. #define MAXROW        24
  57. #define MAXCOL        80
  58. #define TABVAL        8
  59.  
  60. #define ENONE        0
  61. #define EFIRST        1
  62. #define EBRACKET    2
  63.  
  64. /* note - the pixel location is based on the character baseline. */
  65. #define    XL(x)    ((x) * vt_font.widMax + 4)    /* x offset from chars to pixels */
  66. #define    YL(y)    (((y) + 1) * vt_line - 2)      /* y offset from chars to pixels */
  67. #define HOP        MoveTo(XL(vt_col), YL(vt_row)); GetPen(&vt_pen)
  68.  
  69. /* BLANK(1,1) scrubs one cell.  (1,2) does a cell and the cell below it,
  70.  * while (2,1) does a cell and the cell to the right of it.  etc.
  71.  */
  72. #define BLANK(i, j) SetRect(&vt_one_char, vt_pen.h, vt_pen.v - vt_above, \
  73.                   vt_pen.h + (i) * vt_font.widMax, \
  74.                   vt_pen.v + vt_below + ((j) - 1) * vt_line); \
  75.                   EraseRect(&vt_one_char)
  76.                   
  77. #define CURSOR    SetRect(&vt_one_char, vt_pen.h, vt_pen.v - vt_above, \
  78.                   vt_pen.h + vt_font.widMax, vt_pen.v + vt_below); \
  79.                   PenMode(patXor); \
  80.                   PaintRect(&vt_one_char); \
  81.                   PenMode(patCopy)
  82.  
  83. #define SAVE    vt_saverow = vt_row; vt_savecol = vt_col
  84.  
  85. #define RESTORE    vt_row = vt_saverow; vt_col = vt_savecol
  86.  
  87. WindowPtr    vt;
  88. FontInfo    vt_font;
  89. int         vt_line, vt_above, vt_below;
  90. int            vt_col, vt_savecol;
  91. int            vt_row, vt_saverow;
  92. Rect        vt_one_char;
  93. Rect        vt_rect;
  94. Rect        screenRect;
  95. Point        vt_pen;
  96. int            vt_rawf;
  97. int            vt_esc;
  98. int            vt_inprog;        /* number in progress */
  99. int            vt_x, vt_y;        /* for motion escape code */
  100.  
  101. static int    firsttime = 0;
  102. static int    linesize = 0;
  103. static char    *lineptr;
  104. static char    linebuf[256];
  105.  
  106. /* initialize the world.  We call this based on the "firsttime" flag - not an
  107.  * every faccess call! - we only want to do it once...
  108.  */
  109. vt_open()
  110. {
  111.     char *vt_title;
  112.     int i;
  113.  
  114.     InitGraf(&qd.thePort);
  115.     InitFonts();
  116.     FlushEvents(everyEvent, 0);
  117.     InitWindows();
  118.     InitMenus();
  119.     TEInit();
  120.     InitDialogs(nil);
  121.     InitCursor();
  122.     
  123.     vt_title = "";
  124.     screenRect = qd.screenBits.bounds;
  125.     SetRect(&vt_rect, 4, 20 + 4, screenRect.right - 4, screenRect.bottom - 4);
  126.     vt = NewWindow(nil, &vt_rect, vt_title, true, plainDBox, -1, false, 0);
  127.     SetPort(vt);
  128.     vt_rect.left -= 4; /* make vt_rect local - only used for scrolls hereafter */
  129.     vt_rect.right -= 4;
  130.     vt_rect.top -= (20 + 4);
  131.     vt_rect.bottom -= (20 + 4);
  132.     
  133.     TextFont(monaco); /* this driver only supports constant-width */
  134.     TextSize(9);
  135.     GetFontInfo(&vt_font);
  136.     PenMode(patCopy);
  137.     vt_line = vt_font.ascent + vt_font.descent + vt_font.leading;
  138.     vt_above = vt_font.ascent; /* dereference structure for efficiency */
  139.     vt_below = vt_font.descent;
  140.     vt_rawf = 0;            /* start out cooked */
  141.     vt_esc = ENONE;            /* no escape sequence yet */
  142.     
  143.     vt_row = vt_col = 0;    /* start out at home */
  144.     HOP;                    /* actually move there */
  145.     CURSOR;                    /* put up a cursor (XOR) */
  146.  
  147.     return;
  148. }
  149.  
  150. /* scroll the whole screen up one line-height */
  151. vt_scroll()
  152. {
  153.     RgnHandle scroll_rgn;
  154.     
  155.     scroll_rgn = NewRgn();
  156.     ScrollRect(&vt_rect, 0, -vt_line, scroll_rgn);
  157.     DisposeRgn(scroll_rgn);
  158.     
  159.     return;
  160. }
  161.  
  162. /* put a character on the screen.  Set state flags so we can process sequences
  163.  * of characters (to do escape sequences.)
  164.  * Assume we are sitting on the cursor and vt_pen is valid
  165.  */
  166. vt_putch(c)
  167.     int c;
  168. {
  169.     if(vt_esc > ENONE) { /* we are in the middle of an escape sequence */
  170.         escape_code(c);
  171.     } else if(c >= ' ' && c <= '~') {    /* it is printable */
  172.         printable_code(c);
  173.     } else {                    /* it is control */
  174.         control_code(c);
  175.     }
  176.     
  177.     return;
  178. }
  179.  
  180. /* it is a simple character */
  181. printable_code(c)
  182.     int c;
  183. {
  184.     BLANK(1, 1);            /* take away the cursor */
  185.     DrawChar(c);            /* paint in the character */
  186.     if(++vt_col >= MAXCOL) {    /* time to auto-linefeed */
  187.         vt_col = 0;
  188.         if(++vt_row >= MAXROW) {/* scroll it */
  189.             vt_row = MAXROW - 1; /* not so far please... */
  190.             vt_scroll();
  191.         }
  192.     }
  193.     HOP;                    /* move to the cell */
  194.     CURSOR;                    /* paint in the cursor */
  195.     
  196.     return;
  197. }
  198.  
  199. /* process a control code - all are exactly 1 character in length */
  200. control_code(c)
  201.     int c;
  202. {
  203.     int i, j;
  204.     
  205.     switch(c) {
  206.       case '\007':            /* bell */
  207.         SysBeep(20);        /* beep for 20/60 seconds */
  208.         break;
  209.       case '\010':            /* backspace */
  210.         if(vt_col > 0) {    /* can't backspace past left margin */
  211.             CURSOR;            /* exor it again to remove */
  212.             vt_col--;
  213.             HOP;            /* jump back one */
  214.             CURSOR;            /* and a new cursor */
  215.         } else {
  216.             SysBeep(20);    /* be a pain */
  217.         }
  218.         break;
  219.       case '\011':            /* tab */
  220.         j = vt_col;            /* stack this for re-entrancy */
  221.         for(i = 0; i < (TABVAL - (j % TABVAL)); i++) {
  222.             vt_putch(' ');    /* just do some spaces */
  223.         }
  224.         break;
  225.       case '\012':            /* line feed */
  226.         CURSOR;                /* kill the old cursor */
  227.         if(!vt_rawf) {        /* do both cr and lf */
  228.             vt_col = 0;        /* the cr part is easy */
  229.         }
  230.         if(++vt_row >= MAXROW) {/* scroll it */
  231.             vt_row = MAXROW - 1; /* not so far please... */
  232.             vt_scroll();
  233.         }
  234.         HOP;
  235.         CURSOR;
  236.         break;
  237.       case '\015':            /* carriage return */
  238.         CURSOR;                /* kill the old cursor */
  239.         vt_col = 0;            /* the cr part is easy */
  240.         if(!vt_rawf) {        /* do both cr and lf */
  241.             if(++vt_row >= MAXROW) {/* scroll it */
  242.                 vt_row = MAXROW - 1; /* not so far please... */
  243.                 vt_scroll();
  244.             }
  245.         }
  246.         HOP;
  247.         CURSOR;
  248.         break;
  249.       case '\033':            /* escape */
  250.         vt_esc = EFIRST;        /* ok - start an escape sequence */
  251.         break;
  252.       /* the ones we don't handle come next */
  253.       case '\013':            /* vertical tab */
  254.       case '\014':            /* form feed */
  255.       default:
  256.         break;
  257.     } /* end of switch */
  258.     
  259.     return;
  260. }
  261.  
  262. escape_code(c)
  263.     int c;
  264. {
  265.     switch(vt_esc) {
  266.       case EFIRST:
  267.         switch(c) {
  268.           case '[':
  269.               vt_esc = EBRACKET; /* remember we saw it */
  270.             vt_inprog = vt_x = vt_y = 0; /* clear these */
  271.               break;
  272.             
  273.           default:
  274.               vt_esc = ENONE; /* blew it */
  275.               break;
  276.         }
  277.         break;
  278.       
  279.       case EBRACKET:
  280.         switch(c) {
  281.           case 'H': /* home (or motion) */
  282.               vt_x = vt_inprog; /* column number */
  283.             vt_inprog = 0;
  284.             /* adjust for brain damaged notion of screen starting at (1,1) */
  285.             if(--vt_x < 0) {
  286.                 vt_x = 0;
  287.             }
  288.             if(--vt_y < 0) {
  289.                 vt_y = 0;
  290.             }
  291.             CURSOR; /* take it away */
  292.             vt_row = vt_y;
  293.             vt_col = vt_x;
  294.             HOP;
  295.             CURSOR;
  296.             vt_esc = ENONE; /* code is complete */
  297.             break;
  298.             
  299.           case 'J': /* clear to end of screen */
  300.               if(vt_row + 1 < MAXROW) { /* something below us */
  301.                 SAVE;
  302.                 vt_row++;     /* drop down a row */
  303.                 vt_col = 0;    /* and over to the beginning */
  304.                 HOP;        /* actually move there */
  305.                 BLANK(MAXCOL, MAXROW - vt_row);
  306.                 RESTORE;
  307.                 HOP;
  308.             }
  309.               /* fall through to clear the fractional part */
  310.           case 'K': /* clear to end of line */
  311.               BLANK(MAXCOL - vt_col, 1); /* erase all on the row */
  312.             CURSOR;    /* replace the cursor */
  313.             vt_esc = ENONE;
  314.               break;
  315.           
  316.           case '0': /* a row or column number */
  317.           case '1':
  318.           case '2':
  319.           case '3':
  320.           case '4':
  321.           case '5':
  322.           case '6':
  323.           case '7':
  324.           case '8':
  325.           case '9':
  326.               vt_inprog *= 10;         /* make room */
  327.             vt_inprog += c - '0';    /* add in the new digit */
  328.               break;
  329.             
  330.           case ';': /* end of row number */
  331.               vt_y = vt_inprog;
  332.             vt_inprog = 0;
  333.               break;
  334.             
  335.           default:
  336.               vt_esc = ENONE; /* blew it */
  337.               break;
  338.         }
  339.         break;
  340.         
  341.       default:
  342.           vt_esc = ENONE; /* blew it */
  343.           break;
  344.     }
  345.     
  346.     return;
  347. }
  348.  
  349. /* low level reader - call this directly if you also want to use peek - that
  350.  * way you get raw-mode and avoid all character buffers.  But note - this code
  351.  * does NOT initialize the world first.  You must call vt_open() manually!
  352.  */
  353. vt_getch()
  354. {
  355.     EventRecord x;
  356.     int rc;
  357.     
  358.     SystemTask();
  359.     
  360.     /* GetNextEvent returns a boolean enum - make it an integer */
  361.     while(GetNextEvent(autoKeyMask | keyDownMask, &x) == false) {
  362.         SystemTask(); /* wait for it */
  363.     }
  364.     rc = x.message & 0xff;
  365.     if(x.modifiers & cmdKey) {    /* it is a control character */
  366.         rc &= 0x1f;                /* so fold it */
  367.     }
  368.     if(!vt_rawf && rc == '\004') { /* cooked mode and a ^D spells EOF */
  369.         return(EOF);
  370.     }
  371.     return(rc);
  372. }
  373.  
  374. /* return a character but don't pull it off the queue!  Don't block if nothing is
  375.  * available - just return a null.
  376.  */
  377. vt_peekch()
  378. {
  379.     EventRecord x;
  380.     int rc;
  381.     
  382.     SystemTask();
  383.     
  384.     /* EventAvail returns a boolean enum - make it an integer */
  385.     if(EventAvail(autoKeyMask | keyDownMask, &x) == true) { /* something */
  386.         rc = x.message & 0xff;
  387.         if(x.modifiers & cmdKey) {    /* it is a control character */
  388.             rc &= 0x1f;                /* so fold it */
  389.         }
  390.         if(!vt_rawf && rc == '\004') { /* cooked mode and a ^D spells EOF */
  391.             return(EOF);
  392.         } else {    /* normal character */
  393.             return(rc);
  394.         }
  395.         /*NOTREACHED*/
  396.     } else {
  397.         return(0);    /* nothing - call it a null */
  398.     }
  399.     /*NOTREACHED*/
  400. }
  401.  
  402. /* handle system requests for open, rename, and delete.  Only open is legal.
  403.  */
  404. vt_faccess(fname, mode, perm)
  405.     char *fname;
  406.     int mode;
  407.     int perm;
  408. {
  409.     /* if we are not the correct driver, return and let the system try
  410.      * another driver.
  411.      */
  412.     if(EqualString(fname, "dev:console", false, true) == false) {
  413.         return(-1);
  414.     }
  415.     
  416.     /* this driver only handles opens */
  417.     if(mode == F_OPEN) {
  418.         if(firsttime == 0) { /* only do it once */
  419.             vt_open();
  420.             firsttime++;
  421.         }
  422.         return(0); /* but always claim success */
  423.     }
  424.     
  425.     /* tell them the request is bogus */
  426.     return(0x40000016);
  427. }
  428.  
  429. /* not much to do */
  430. vt_close()
  431. {
  432.     return(0);
  433. }
  434.  
  435. /* return as many characters as asked for, up to a carriage return.  Someday
  436.  * we need to add raw mode here.
  437.  */
  438. vt_read(ap)
  439.     IOSTR *ap;
  440. {
  441.     /* fill the buffer if it is empty */
  442.     if(linesize <= 0) {
  443.         linesize = vt_readline(linebuf, 256);
  444.         lineptr = linebuf;
  445.     }
  446.     
  447.     /* copy till either user is satisfied or we hit the end of the line.
  448.      * We must leave the count field set in the ap structure to show how
  449.      * much more is to be done.
  450.      */
  451.     for( ; (ap->count > 0) && (linesize > 0); ap->count--, linesize--) {
  452.         *(ap->buffer)++ = *lineptr++;
  453.     }
  454.     
  455.     return(0);
  456. }
  457.  
  458. /* read until a carriage return (or we fill the buffer). Return how much we
  459.  * got.
  460.  */
  461. vt_readline(bp, size)
  462.     char *bp;
  463.     int size;
  464. {
  465.     int i;
  466.     
  467.     for(i = size; i; bp++, i--) {
  468.         *bp = vt_getch();
  469.         
  470.         if(*bp == '\010' && i < size) {
  471.             bp -= 2;
  472.             i += 2;
  473.         }
  474.         
  475.         if(*bp == '\004' || *bp == '\n') {
  476.             i--;
  477.             break;
  478.         }
  479.     }
  480.     
  481.     return(size - i);
  482. }
  483.  
  484. /* loop characters to the screen */
  485. vt_write(ap)
  486.     IOSTR *ap;
  487. {
  488.     for( ; ap->count; ap->count--) { /* must leave count at 0 on exit */
  489.         vt_putch(*(ap->buffer)++);
  490.     }
  491.     
  492.     return(0);
  493. }
  494.  
  495. /* this routine turns out to be essential because the system intends to ask us
  496.  * for the optimum buffer size.  We return -1 to tell it to choose for us.
  497.  */
  498. vt_ioctl(fd, op, arg)
  499.     int fd;
  500.     int op;
  501.     int *arg;
  502. {
  503.     switch(op) {
  504.       case FIOINTERACTIVE:
  505.           return(0);
  506.         
  507.       case TIOFLUSH:
  508.           return(0);
  509.         
  510.       /* I don't trust this!  We would have to clear screen and reset
  511.        * point sizes for it to be safe.
  512.        */
  513.       case TIOSPORT:
  514.           /* vt = (WindowPtr) *arg; */
  515.           return(0);
  516.         
  517.       case TIOGPORT:
  518.           *arg = (int) vt;
  519.         return(0);
  520.         
  521.       default:
  522.           return(-1);
  523.     }
  524.     /*NOTREACHED*/
  525. }
  526.  
  527. /* this stuff should be via ioctl but why make it so hard? */
  528. vt_raw()
  529. {
  530.     vt_rawf = 1;
  531.     
  532.     return;
  533. }
  534.  
  535. vt_cooked()
  536. {
  537.     vt_rawf = 0;
  538.     
  539.     return;
  540. }
  541.  
  542. /* this code is a reverse compile of the cruntime.o module. */
  543. /*
  544. write(fd, buf, cnt)
  545.     int fd;
  546.     char *buf;
  547.     int cnt;
  548. {
  549.     IOSTR *ind;
  550.     int foo;
  551.     
  552.     if(fd < 0) {
  553.         _uerror(0x16, 0);
  554.         return(-1);
  555.     }
  556.     
  557.     ind = _getIOPort(&fd);
  558.     
  559.     if(!ind) {
  560.         return(-1);
  561.     }
  562.     
  563.     if(!(ind->flags & 2)) {
  564.         _uerror(0x09, 0);
  565.         return(-1);
  566.     }
  567.     
  568.     ind->count = cnt;
  569.     ind->buffer = buf;
  570.     foo = (*(ind->handler->l_write))(ind);
  571.     
  572.     if(foo) {
  573.         _uerror(foo, ind->errcode);
  574.         return(-1);
  575.     } else {
  576.         return(cnt - (ind->count));
  577.     }
  578. }
  579. */
  580.  
  581. /* this bypasses printf and is useful for debugging to avoid recursion.
  582.  * Prints a string.
  583.  */
  584. /*
  585. lpr(s)
  586.     char *s;
  587. {
  588.     while(*s != 0) {
  589.         vt_putch(*s++);
  590.     }
  591.     
  592.     return;
  593. }
  594. */
  595.  
  596. /* this one prints an integer in hex with leading zeros. */
  597. /*
  598. lpx(x)
  599.     unsigned int x;
  600. {
  601.     int i, j;
  602.     
  603.     for(i = 0; i < 8; i++) {
  604.         j = (x >> (28 - (i * 4))) & 0xf;
  605.         if(j <= 9) {
  606.             vt_putch(j + '0');
  607.         } else {
  608.             vt_putch(j - 10 + 'a');
  609.         }
  610.     }
  611.     
  612.     return;
  613. }
  614. */
  615.  
  616. /* Start of code for da support.  We use these for a gp text editor among
  617.  * other things.  Note - there is no way to pass the file name in.  Oh
  618.  * well.  Most of this code is stolen from the sample application which
  619.  * Apple distributes with MPW and hence is copyright Apple Computer Corp.
  620.  */
  621.  
  622. /*
  623.  * Resource ID constants.
  624.  */
  625. # define appleID        128
  626. # define fileID         129
  627. # define editID         130
  628.  
  629. # define appleMenu        0
  630.  
  631. # define fileMenu        1
  632. # define    quitCommand     1
  633.  
  634. # define editMenu        2
  635. # define    undoCommand     1
  636. # define    cutCommand        3
  637. # define    copyCommand     4
  638. # define    pasteCommand    5
  639. # define    clearCommand    6
  640.  
  641. # define menuCount     3
  642.  
  643. /*
  644.  * HIWORD and LOWORD macros, for readability.
  645.  */
  646. # define HIWORD(aLong)        (((aLong) >> 16) & 0xFFFF)
  647. # define LOWORD(aLong)        ((aLong) & 0xFFFF)
  648.  
  649. /*
  650.  * Global Data objects, used by routines external to main().
  651.  */
  652. MenuHandle        MyMenus[menuCount];     /* The menu handles */
  653. int                Doneflag;                /* Becomes TRUE when File/Quit chosen */
  654.  
  655. da_mode(fname)
  656.     char *fname;
  657. {
  658.     EventRecord     myEvent;
  659.     WindowPtr        theActiveWindow, whichWindow;
  660.     GrafPtr         savePort;
  661.     char            forcedDA[256];
  662.  
  663.     setupMenus();
  664.  
  665.     for (Doneflag = 0; !Doneflag; ) {
  666.         /*
  667.          * Main Event tasks:
  668.          */
  669.         SystemTask();
  670.         
  671.         /* if a name was passed in, assume it is a DA - we fake an open
  672.          * of it.  DA's are funny in that the name contains a leading
  673.          * NULL character.  So we stick one in 'cause they are hard to
  674.          * type.  This results in a bizzare C string but the Desk Manager
  675.          * is happy...
  676.          */
  677.         if(fname[0] != '\0') {
  678.             forcedDA[0] = '\0'; /* DA names (usually) have this */
  679.             strcpy(forcedDA + 1, fname); /* don't step on the null */
  680.             fname[0] = '\0';     /* open it only once */
  681.             GetPort(&savePort);
  682.             (void) OpenDeskAcc(forcedDA);
  683.             SetPort(savePort);
  684.             continue;
  685.         }
  686.                 
  687.         theActiveWindow = FrontWindow();        /* Used often, avoid repeated calls */
  688.         /*
  689.          * Handle the next event.
  690.          */
  691.         if ( ! GetNextEvent(everyEvent, &myEvent)) {
  692.             continue;    /* not for us */
  693.         }
  694.         /*
  695.          * In the unlikely case that the active desk accessory does not
  696.          * handle mouseDown, keyDown, or other events, GetNextEvent() will
  697.          * give them to us!  So before we perform actions on some events,
  698.          * we check to see that the affected window in question is really
  699.          * our window.
  700.          */
  701.         switch (myEvent.what) {
  702.             case mouseDown:
  703.                 switch (FindWindow(&myEvent.where, &whichWindow)) {
  704.                     case inSysWindow:
  705.                         SystemClick(&myEvent, whichWindow);
  706.                         break;
  707.                     case inMenuBar:
  708.                         doCommand(MenuSelect(&myEvent.where));
  709.                         break;
  710.                     case inDrag:
  711.                     case inGrow:
  712.                         /* No such - Fall through */
  713.                     case inContent:
  714.                         if (whichWindow != theActiveWindow) {
  715.                             SelectWindow(whichWindow);
  716.                         }
  717.                         break;
  718.                     default:
  719.                         break;
  720.                 }/*endsw FindWindow*/
  721.                 break;
  722.  
  723.             case keyDown:
  724.             case autoKey:
  725.                 if (vt == theActiveWindow) {
  726.                     if (myEvent.modifiers & cmdKey) {
  727.                         doCommand(MenuKey(myEvent.message & charCodeMask));
  728.                     }
  729.                 }
  730.                 break;
  731.  
  732.             case activateEvt:
  733.                 if ((WindowPtr) myEvent.message == vt) {
  734.                     if (myEvent.modifiers & activeFlag) {
  735.                         DisableItem(MyMenus[editMenu], 0);
  736.                     } else {
  737.                         EnableItem(MyMenus[editMenu], 0);
  738.                     }
  739.                     DrawMenuBar();
  740.                 }
  741.                 break;
  742.  
  743.             default:
  744.                 break;
  745.  
  746.         }/*endsw myEvent.what*/
  747.  
  748.     }/*endfor Main Event loop*/
  749.  
  750.     trashMenus();
  751.     return;
  752. }
  753.  
  754. setupMenus()
  755. {
  756.     register MenuHandle *pMenu;
  757.     /*
  758.      * Set up the desk accessories menu.
  759.      *  We install the desk accessory names from the 'DRVR' resources.
  760.      */
  761.     MyMenus[appleMenu] = GetMenu(appleID);
  762.     AddResMenu(MyMenus[appleMenu], (ResType) 'DRVR');
  763.     /*
  764.      * Now the File and Edit menus.
  765.      */
  766.     MyMenus[fileMenu] = GetMenu(fileID);
  767.     MyMenus[editMenu] = GetMenu(editID);
  768.     /*
  769.      * Now insert all of the application menus in the menu bar.
  770.      *
  771.      * "Real" C programmers never use array indexes
  772.      * unless they're constants :-)
  773.      */
  774.     for (pMenu = &MyMenus[0]; pMenu < &MyMenus[menuCount]; ++pMenu) {
  775.         InsertMenu(*pMenu, 0);
  776.     }
  777.     DisableItem(MyMenus[editMenu], 0);
  778.  
  779.     DrawMenuBar();
  780.  
  781.     return;
  782. }
  783.  
  784. trashMenus()
  785. {
  786.     ClearMenuBar();        /* remove menus */
  787.     DrawMenuBar();        /* show it */
  788.     
  789.     ReleaseResource(MyMenus[appleMenu]);
  790.     ReleaseResource(MyMenus[fileMenu]);
  791.     ReleaseResource(MyMenus[editMenu]);
  792.  
  793.     return;
  794. }
  795.  
  796. /*
  797.  * Process mouse clicks in menu bar
  798.  */
  799. doCommand(mResult)
  800. long mResult;
  801. {    
  802.     int                 theMenu, theItem;
  803.     char                daName[256];
  804.     GrafPtr             savePort;
  805.  
  806.     theItem = LOWORD(mResult);
  807.     theMenu = HIWORD(mResult);        /* This is the resource ID */
  808.  
  809.     switch (theMenu) {
  810.         case appleID:
  811.             GetItem(MyMenus[appleMenu], theItem, daName);
  812.             GetPort(&savePort);
  813.             (void) OpenDeskAcc(daName);
  814.             SetPort(savePort);
  815.             break;
  816.  
  817.         case fileID:
  818.             switch (theItem) {
  819.                 case quitCommand:
  820.                     Doneflag++;            /* Request exit */
  821.                     break;
  822.                 default:
  823.                     break;
  824.             }
  825.             break;
  826.         case editID:
  827.             /*
  828.              * If this is for a 'standard' edit item,
  829.              * run it through SystemEdit.
  830.              */
  831.             if (theItem <= clearCommand) {
  832.                 SystemEdit(theItem-1);
  833.             }
  834.             break;
  835.  
  836.         default:
  837.             break;
  838.  
  839.     }/*endsw theMenu*/
  840.  
  841.     HiliteMenu(0);
  842.  
  843.     return;
  844. }
  845.