home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / developm / scnote / gzonelst.011 / GetZoneList.c < prev    next >
Text File  |  1989-10-01  |  22KB  |  811 lines

  1. /* ------------------------------------------------------------------------------
  2. #
  3. #    Apple Macintosh Developer Technical Support
  4. #
  5. #    AppleTalk GetZoneList Sample Application
  6. #
  7. #    GetZoneList
  8. #
  9. #    GetZoneList.c    -    C Source
  10. #
  11. #    Copyright ⌐ 1989 Apple Computer, Inc.
  12. #    All rights reserved.
  13. #
  14. #    Versions:    1.0                    11/88
  15. #                1.1                    10/89
  16. #
  17. #    Components:    GetZoneList.p        October 1, 1989
  18. #                GetZoneList.c        October 1, 1989
  19. #                GetZoneList.r        October 1, 1989
  20. #                PGetZoneList.make    October 1, 1989
  21. #                CGetZoneList.make    October 1, 1989
  22. #
  23. #    Requirements:
  24. #                UFailure.p            November 1, 1988
  25. #                UFailure.inc1.p        November 1, 1988
  26. #                UFailure.a            November 1, 1988
  27. #
  28. #    GetZoneList is a sample application that uses
  29. #    AppleTalk ATP and ZIP to obtain a list of zones
  30. #    on an AppleTalk internet.
  31. #
  32. #    GetZoneList also demonstrates using a signal, or
  33. #    failure-catching mechanism to recover from error
  34. #    situations.  Since C does not allow nested procedures
  35. #    a la Pascal, a few modifications were made to incorporate
  36. #    the failure handling and keep this sample fairly close in
  37. #    design to the Pascal sample.  
  38. #    (Gee, thanks a lot M2 for using nested procs. - pvh)
  39. #
  40. #    GetZoneList is based on MACDTS Sample.c. For more
  41. #    description and explanation of the non-example
  42. #    specific areas of this application, please refer to
  43. #    either Sample.p or TESample.c.
  44. #
  45. ------------------------------------------------------------------------------ */
  46.  
  47. #include <Values.h>
  48. #include <Types.h>
  49. #include <QuickDraw.h>
  50. #include <Fonts.h>
  51. #include <Events.h>
  52. #include <Controls.h>
  53. #include <Windows.h>
  54. #include <Menus.h>
  55. #include <TextEdit.h>
  56. #include <Dialogs.h>
  57. #include <Packages.h>
  58. #include <Desk.h>
  59. #include <Scrap.h>
  60. #include <Lists.h>
  61. #include <ToolUtils.h>
  62. #include <Memory.h>
  63. #include <SegLoad.h>
  64. #include <Errors.h>
  65. #include <Files.h>
  66. #include <OSUtils.h>
  67. #include <AppleTalk.h>
  68. #include <Traps.h>        
  69. #include <DiskInit.h>
  70. #include <Script.h>
  71. #include <UFailure.h>
  72.  
  73.  
  74. #define        kSysEnvironsVersion        1
  75. #define        kOSEvent                app4Evt        /* event used by Multifinder */
  76. #define        kSuspendResumeMessage    1            /* high byte of suspend/resume event message */
  77. #define        kResumeMask                1            /* bit of message field for resume vs. suspend */
  78.     
  79. #define        kCR                        13            /* carriage return character */
  80. #define        kENTER                    3            /* enter character */
  81. #define        kScrollBarWidth            15            /* the width of the scrollbar in the list */
  82. #define        kListInset                -1            /* adjustment for list frame */
  83. #define        kATPTimeOutVal            3            /* re-try ATP SendRequest every 3 seconds */
  84. #define        kATPRetryCount            5            /* for five times */
  85. #define        kZonesSize                578            /* size of buffer for zone names */
  86. #define        kGZLCall                0x08000000    /* GetZoneList indicator */
  87. #define        kZIPSocket                6            /* the Zone Information Protocol socket */
  88. #define        kMoreZones                0xFF000000     /* mask to see if more zones to come */
  89. #define        kZoneCount                0x0000FFFF     /* mask to count zones in buffer */
  90. #define        kHilite                    1            /* hilite value for button control */
  91. #define        kDeHilite                0            /* dehilite value for button control */
  92. #define        kHiliteDelay            5            /* time in ticks to leave button hilited */
  93.     
  94. #define        kMinHeap                0
  95. #define        kMinSpace                0
  96.     
  97. #define        sErrStrings                128            /* error string STR# */
  98. #define        eStandardErr            1
  99. #define        eWrongMachine            2
  100. #define        eSmallSize                3
  101. #define        eNoMemory                4
  102. #define        eAppleTalk                5
  103. #define        eNoZones                6
  104.     
  105. #define        rAboutAlert                128            /* about alert */
  106. #define        rZoneDialog                129            /* zone list dialog */
  107. #define        dZoneList                2            /* user item that is zone list */
  108. #define        dDefault                3            /* user item that is default indicator */
  109. #define        rUserAlert                130            /* error alert */
  110.  
  111. #define        rMenuBar                128            /* application's menu bar */
  112.  
  113. #define        mApple                    128            /* Apple menu */
  114. #define        iAbout                    1
  115.  
  116. #define        mFile                    129            /* File menu */
  117. #define        iNew                    1
  118. #define        iClose                    4
  119. #define        iQuit                    12
  120.  
  121. #define        mEdit                    130            /* Edit menu */
  122. #define        iUndo                    1
  123. #define        iCut                    3
  124. #define        iCopy                    4
  125. #define        iPaste                    5
  126. #define        iClear                    6
  127.  
  128. /* kDITop and kDILeft are used to locate the Disk Initialization dialogs. */
  129. #define        kDITop                    0x0050
  130. #define        kDILeft                    0x0070
  131.  
  132.  
  133. /* Globs */
  134. SysEnvRec    gMac;                    /* set up by Initialize */
  135. Boolean        gHasWaitNextEvent;        /* set up by Initialize */
  136. Boolean        gInBackground;            /* maintained by Initialize and DoEvent */
  137.     
  138. ListHandle    gList;                    /* the list to be filled with zone names */
  139.  
  140. extern void _DataInit(); 
  141.  
  142. /*     globals added for C sample use as the Pascal 
  143.     example used those horrid :-) nested procedures! */
  144. ATPPBPtr    gATPPBPtr;    /* the parameter block for GetZoneList call */
  145. Ptr            gZones;     /* the data buffer for GetZoneList call */
  146. DialogPtr    gErrDlg;    /* Dialog used for displaying zone list */ 
  147.  
  148.  
  149. #pragma segment Initialize
  150. Boolean TrapAvailable(tNumber, tType)
  151.     short        tNumber;
  152.     TrapType    tType;
  153. {
  154.     return( NGetTrapAddress(tNumber, tType) != GetTrapAddress(_Unimplemented) );
  155. }  /* TrapAvailable */
  156.  
  157.  
  158. #pragma segment Main
  159. void FailOSErrMsg(result, message)
  160.     short    result;
  161.     short    message;
  162. {
  163.     if (result != noErr)
  164.         Failure(result, message);
  165. } /* SignalOSErrMsg */
  166.  
  167.  
  168. #pragma segment Main
  169. void FailnilMsg(p, message)
  170.     Ptr        p;
  171.     short    message;
  172. {
  173.     if (p == nil)
  174.         Failure(memFullErr, message);
  175. } /* FailNILMsg */
  176.  
  177.  
  178. #pragma segment Main
  179. void AlertUser(error, message)
  180.  
  181. /* Display an alert to inform the user of an error. Message acts as an 
  182.  index into a STR# resource of error messages. if no message is given,
  183.  i.e. = 0, then use a standard message. if error is not noErr then
  184.  display it as well. */
  185.  
  186.     short    error;
  187.     long    message;
  188. {
  189.     Str255    msg1, msg2;
  190.     short    itemHit;
  191.  
  192.     if (message == 0L)  message = eStandardErr;
  193.     GetIndString(msg1, sErrStrings, message);
  194.     if (error == noErr) 
  195.         msg2[0] = '';
  196.     else
  197.         NumToString(error, msg2);
  198.     ParamText(msg1, msg2, "\p", "\p");
  199.     itemHit = Alert(rUserAlert, nil);
  200. } /* AlertUser */
  201.  
  202.  
  203. #pragma segment Main
  204. Boolean IsDAWindow(window)
  205.     WindowPtr    window;
  206. {
  207.     if (window == nil)
  208.         return (false);
  209.     else    /* DA windows have negative windowKinds */
  210.         return ((WindowPeek) window)->windowKind < 0;
  211. } /* IsDAWindow */
  212.  
  213.  
  214. #pragma segment Main
  215. Boolean IsAppWindow(window)
  216.     WindowPtr    window;
  217. {
  218.     short        windowKind;
  219.  
  220.     if ( window == nil )
  221.         return false;
  222.     else {    /* application windows have windowKinds >= userKind (8) or dialogKind (2) */
  223.         windowKind = ((WindowPeek) window)->windowKind;
  224.         return (windowKind >= userKind) || (windowKind == dialogKind);
  225.     }
  226. } /* IsAppWindow */
  227.  
  228.  
  229. #pragma segment Main
  230. void ZoneListCleanUp()
  231. {
  232.     if (gATPPBPtr != nil)
  233.         DisposPtr((Ptr)gATPPBPtr);            /* get rid of pb block */
  234.     if (gZones != nil)
  235.         DisposPtr(gZones);                    /* and buffer */
  236. } /* ZoneListCleanUp */
  237.  
  238.  
  239. #pragma segment Main
  240. pascal void HandleZoneListErr(short error, long message)
  241. {
  242.     #pragma    unused (error, message)
  243.  
  244.     ZoneListCleanUp();                        /* get rid of allocated junk */
  245. } /* HandleZoneListErr */
  246.  
  247.  
  248. #pragma segment Main
  249. void BuildZoneList()
  250.  
  251. /*     Create the list of zones on the network. Find a bridge to talk to , if one is
  252.      present, then ask it for zone names. Add the names to the list in the dialog.    */
  253.  
  254. {
  255.     BDSElement    dBDS;                /* the BDS for GetZoneList call */
  256.     Ptr            dCurr;                /* the data buffer for GetZoneList call */
  257.     short        dIndex, dCount;
  258.     short        ignore;
  259.     Cell        cSize;
  260.     FailInfo    fi;
  261.  
  262.     gATPPBPtr = nil;                                            /* init some important variables*/
  263.     gZones = nil;
  264.  
  265.     CatchCFailures(&fi, HandleZoneListErr);
  266.     
  267.     gATPPBPtr = (ATPPBPtr)NewPtr(sizeof(ATPParamBlock));
  268.     FailnilMsg(gATPPBPtr, eNoMemory);
  269.     gZones = NewPtr(kZonesSize);
  270.     FailnilMsg(gZones, eNoMemory);
  271.     dBDS.buffSize = kZonesSize;                                    /* set up BDS */
  272.     dBDS.buffPtr = gZones;
  273.         
  274.     gATPPBPtr->ATPatpFlags = 0;
  275.         
  276.     FailOSErrMsg(GetNodeAddress(&ignore, &gATPPBPtr->ATPaddrBlock.aNet), eAppleTalk);    /* get net of bridge */
  277.         
  278.     if (gATPPBPtr->ATPaddrBlock.aNet == 0) 
  279.         Failure(0, eNoZones);                                    /* bail if no zones present */
  280.     gATPPBPtr->ATPaddrBlock.aNode = GetBridgeAddress();            /* get node of bridge */
  281.     gATPPBPtr->ATPaddrBlock.aSocket = kZIPSocket;                /* the socket we want */
  282.     gATPPBPtr->ATPreqLength = 0;
  283.     gATPPBPtr->ATPreqPointer = nil;
  284.     gATPPBPtr->ATPbdsPointer = (Ptr) &dBDS;
  285.     gATPPBPtr->ATPnumOfBuffs = 1;
  286.     gATPPBPtr->ATPtimeOutVal = kATPTimeOutVal;
  287.     gATPPBPtr->ATPretryCount = kATPRetryCount;
  288.  
  289.     dIndex = 1;
  290.     dCount = 0;
  291.     SetPt(&cSize, 0, 0);                                                /* we always stuff into first */
  292.     
  293.     do {
  294.         gATPPBPtr->ATPuserData = kGZLCall + dIndex;                        /* indicate GetZoneList request */
  295.         FailOSErrMsg(PSendRequest(gATPPBPtr, false), eAppleTalk);        /* send sync request */
  296.         
  297.         dCount = dCount + dBDS.userBytes & kZoneCount;                    /* find out how many returned */
  298.         dCurr = gZones;                                                    /* put current pointer at start */
  299.         do {                                                            /* get each zone */
  300.             ignore = LAddRow(1, 0, gList);                                /* create new cell at start */
  301.             LSetCell((Ptr)dCurr + 1L, (short) *dCurr, cSize, gList);    /* stuff in zone */
  302.             dCurr = (Ptr)(dCurr + *dCurr + 1 );                            /* bump up current pointer */
  303.             dIndex = dIndex + 1;                                        /* increment which zone */
  304.         } while(! (dIndex > dCount));
  305.         
  306.     } while ((dBDS.userBytes & kMoreZones) == 0);                /*     keep going until none left */
  307.     
  308.     ZoneListCleanUp();
  309.     
  310.     Success(&fi);
  311. } /* BuildZoneList */
  312.  
  313.  
  314. #pragma segment Main
  315. pascal void ZoneListDraw(dlg, item)
  316.     DialogPtr    dlg;
  317.     short        item;
  318. {
  319.  
  320. /* The user item void for the zone list user item and default
  321.  box user item in the dialog. Draw the list and the frame that goes with it.
  322.  Draw the default box around the OK button */
  323.  
  324.     GrafPtr     port;
  325.     short        kind;
  326.     Handle        h;
  327.     Rect        r;
  328.     PenState    ps;
  329.  
  330.     GetPort(&port);                                        /* save old port */
  331.     SetPort(dlg);                                        /* make dialog port */
  332.     switch (item) {
  333.         case dZoneList: 
  334.             LUpdate(dlg->visRgn, gList);                /* re-draw list */
  335.             GetDItem(dlg, dZoneList, &kind, &h, &r);
  336.             InsetRect(&r, kListInset, kListInset);
  337.             FrameRect(&r);                                /* re-draw frame */
  338.             break;
  339.         case dDefault:
  340.             GetDItem(dlg, dDefault, &kind, &h, &r);
  341.             GetPenState(&ps);
  342.             PenSize(3, 3);
  343.             InsetRect(&r, -4, -4);
  344.             FrameRoundRect(&r, 16, 16);                    /* draw default box */
  345.             SetPenState(&ps);
  346.             break;
  347.         }
  348.     SetPort(port);                                        /* restore old port */
  349. } /* ZoneListDraw */
  350.  
  351.  
  352. #pragma segment Main
  353. pascal Boolean ListFilter (dlg, event, item)
  354.     DialogPtr    dlg;
  355.     EventRecord    *event;
  356.     short        *item;
  357. {
  358.  
  359. /*    Passed as parameter to ModalDialog. Handle key presses and mouse clicks
  360.        from the user. Do all the right default actions since we override them
  361.      by virtue of our existence.    */
  362.  
  363.     GrafPtr        port;
  364.     Point        loc;
  365.     short        kind;
  366.     Handle        h;
  367.     Rect        r;
  368.     Boolean        ignore;
  369.     char        key;
  370.     long         finalTicks;
  371.  
  372.     Boolean        returnValue;
  373.     
  374.     returnValue = false;                                            /*    always default false */
  375.  
  376.     switch (event->what) {
  377.         case keyDown:                                                 /*    check for <cr> or <enter> */
  378.         case autoKey:
  379.             key = (char) event->message;
  380.             if (key == kCR || key == kENTER) {                        /*    it was a <cr> or <enter> */
  381.                 GetDItem(dlg, ok, &kind, &h, &r);
  382.                 HiliteControl((ControlHandle)h, kHilite);
  383.                 Delay(kHiliteDelay, &finalTicks);
  384.                 HiliteControl((ControlHandle)h, kDeHilite);
  385.                 returnValue = true;                                    /*    so we handle it */
  386.                 *item = 1;                                            /*    and make the first item hit */
  387.                 }
  388.             break;
  389.         case mouseDown:                                             /*    we want mouseDowns */
  390.             GetPort(&port);
  391.             SetPort(dlg);
  392.             loc = event->where;
  393.             GlobalToLocal(&loc);                                    /*    find where clicked */
  394.             GetDItem(dlg, dZoneList, &kind, &h, &r);                /*    get rect for list */
  395.             if (PtInRect(loc, &r)) {                                /*    if clicked inside╔ */
  396.                 returnValue = true;                                    /*    we take care of it */
  397.                 ignore = LClick(loc, event->modifiers, gList);        /*    by passing click to list */
  398.                 }
  399.             SetPort(port);
  400.             break;
  401.         }
  402.     return (returnValue);
  403. } /* ListFilter */
  404.  
  405.  
  406. #pragma segment Main
  407. void CleanUp_DoZoneList()
  408. {
  409.     if (gList != nil)
  410.         LDispose(gList);                                    /*    get rid of list */
  411.     if (gErrDlg != nil)
  412.         DisposDialog(gErrDlg);                                /*    get rid of dialog */
  413. } /* CleanUp_DoZoneList */
  414.  
  415.  
  416. #pragma segment Main
  417. pascal void HandleErr_DoZoneList(short error, long message)
  418. {
  419.     #pragma    unused (error, message)
  420.  
  421.     CleanUp_DoZoneList();                                /*    release junk */
  422. } /* HandleErr_DoZoneList */
  423.  
  424.  
  425. #pragma segment Main
  426. void DoZoneList()
  427.  
  428. /*    Put up a modal dialog that shows a list of the zones on the net. Create the dialog
  429.  and list, call BuildZoneList to fill it, then wait for the user to click OK. */
  430.  
  431. {
  432.     DialogPtr    dlg;
  433.     short        item, kind;
  434.     Handle        h;
  435.     Rect        r, rView, dataBounds;
  436.     Cell        cSize;
  437.     FailInfo    fi;
  438.     short        hor, ver;
  439.     
  440.     gList = nil;                                            /*    init some important variables */
  441.     dlg = nil;
  442.  
  443.     CatchCFailures(&fi, HandleErr_DoZoneList);
  444.  
  445.     
  446.     dlg = GetNewDialog(rZoneDialog, nil, (WindowPtr)-1);            /*    create dialog */
  447.     
  448.     gErrDlg = dlg;
  449.     
  450.     FailnilMsg(dlg, eNoMemory);
  451.     
  452.     /*    We center the dialog horizontally and position it vertically one-third the
  453.      distance from the menu bar to the bottom of the main device. We do not
  454.      check for the dialog extending past the bottom of the device because we
  455.      know the dialog is not that big. You may wish to make that check. */
  456.         
  457.     hor = dlg->portRect.right - dlg->portRect.left;
  458.  
  459.     hor = ((qd.screenBits.bounds.right - qd.screenBits.bounds.left) - hor) / 2;
  460.     ver = ((qd.screenBits.bounds.bottom - qd.screenBits.bounds.top) - GetMBarHeight()) / 3;
  461.  
  462.     MoveWindow(dlg, hor, ver, false);
  463.     
  464.     GetDItem(dlg, dDefault, &kind, &h, &r);
  465.     SetDItem(dlg, dDefault, kind, (Handle) ZoneListDraw, &r);
  466.     GetDItem(dlg, dZoneList, &kind, &h, &r);
  467.     SetDItem(dlg, dZoneList, kind, (Handle) ZoneListDraw, &r);        /*    connect drawing void */
  468.     rView = r;
  469.     rView.right -= kScrollBarWidth;                            /*    adjust rectangle for scroll */
  470.     SetRect(&dataBounds, 0, 0, 1, 0);                        /*    init to one-wide list */
  471.     SetPt(&cSize, 0, 0);
  472.     gList = LNew(&rView, &dataBounds, cSize, 0, (WindowPtr)dlg,
  473.                     false, false, false, true);                /*    create with vertical scroll */
  474.     FailnilMsg(gList, eNoMemory);
  475.     BuildZoneList();                                        /*    put the stuff into the list */
  476.     SetPt(&cSize, 0, 0);
  477.     LSetSelect(true, cSize, gList);                            /*    select the first guy */
  478.     LDoDraw(true, gList);                                    /*    turn on the list */
  479.     ShowWindow(dlg);                                        /*    turn on the dialog */
  480.     
  481.     do {
  482.         ModalDialog((ModalFilterProcPtr) ListFilter, &item);    /*    accept events */
  483.         } while (item != ok);                                    /*    until he presses 'ok' */
  484.     
  485.     CleanUp_DoZoneList();
  486.     
  487.     Success(&fi);
  488. } /* DoZoneList */
  489.  
  490.  
  491. #pragma segment Main
  492. Boolean DoCloseWindow(window)
  493.     WindowPtr    window;
  494. {
  495.     Boolean     functionValue = true;
  496.     
  497.     if (IsDAWindow(window)) 
  498.         CloseDeskAcc((short) ((WindowPeek)window)->windowKind);
  499.     else
  500.     if (IsAppWindow(window))
  501.         CloseWindow(window);
  502.  
  503.     return(functionValue);
  504. } /* DoCloseWindow */
  505.  
  506.  
  507. #pragma segment Initialize
  508. pascal void HandleErr_Initialize(error, message)
  509.     short    error;
  510.     long    message;
  511. {
  512.         if (error > 0)
  513.             AlertUser(0, error);
  514.         else
  515.             AlertUser(error, message);
  516.         ExitToShell();    
  517. } /* HandleErr_Initialize */
  518.  
  519.  
  520. #pragma segment Initialize
  521. void Initialize()
  522. {
  523.     Handle            menuBar;
  524.     OSErr            ignoreError;
  525.     long            total, contig;
  526.     Boolean            ignoreResult;
  527.     EventRecord        event;
  528.     short            count;
  529.     FailInfo        fi;
  530.  
  531.     gHasWaitNextEvent = TrapAvailable(_WaitNextEvent, ToolTrap);
  532.     gInBackground = false;
  533.  
  534.     InitGraf(&qd.thePort);
  535.     InitFonts();
  536.     InitWindows();
  537.     InitMenus();
  538.     TEInit();
  539.     InitDialogs(nil);
  540.     InitCursor();
  541.  
  542.     /* get MultiFinder started */
  543.     for (count=1;count<3;count++)
  544.         ignoreResult = EventAvail(everyEvent, &event);
  545.  
  546.     CatchCFailures(&fi, HandleErr_Initialize);
  547.  
  548.     FailOSErrMsg(MPPOpen(), eAppleTalk);
  549.     FailOSErrMsg(ATPLoad(), eAppleTalk);
  550.  
  551.     ignoreError = SysEnvirons(kSysEnvironsVersion, &gMac);
  552.     if (gMac.machineType < 0)
  553.         Failure(0, eWrongMachine);
  554.     
  555.     if (GetApplLimit() - ApplicZone() < kMinHeap)
  556.         Failure(0, eSmallSize);
  557.  
  558.     PurgeSpace(&total, &contig);
  559.     if (total < kMinSpace)
  560.         Failure(0, eNoMemory);
  561.  
  562.     menuBar = GetNewMBar(rMenuBar);                /*    read menus into menu bar */
  563.     FailnilMsg(menuBar, eNoMemory);
  564.     
  565.     SetMenuBar(menuBar);                        /*    install menus */
  566.     DisposHandle(menuBar);
  567.     AddResMenu(GetMHandle(mApple), 'DRVR');        /*    add DA names to Apple menu */
  568.     DrawMenuBar();
  569.     
  570.     Success(&fi);
  571. } /* Initialize */
  572.  
  573.  
  574. #pragma segment Main
  575. void Terminate()
  576. {
  577.     WindowPtr    aWindow;
  578.     Boolean        closed;
  579.  
  580.     closed = true;
  581.     do {
  582.         aWindow = FrontWindow();                /*    get the current front window */
  583.         if (aWindow != nil)
  584.             closed = DoCloseWindow(aWindow);    /*    close this window */
  585.     } while ((closed) && (aWindow != nil));        /*    do all windows */
  586.     if (closed)
  587.         ExitToShell();                            /*    exit if no cancellation */
  588. } /* Terminate */
  589.  
  590.  
  591. #pragma segment Main
  592. void AdjustMenus()
  593. {
  594.     WindowPtr    window;
  595.     MenuHandle    menu;
  596.  
  597.     window = FrontWindow();
  598.  
  599.     menu = GetMHandle(mFile);
  600.     if (IsDAWindow(window))                        /*    we can allow desk accessories to be closed from the menu */
  601.         EnableItem(menu, iClose);
  602.     else
  603.         DisableItem(menu, iClose);                /*    but not our traffic light window */
  604.  
  605.     menu = GetMHandle(mEdit);
  606.     if (IsDAWindow(window)) {                    /*    a desk accessory might need the edit menu */
  607.         EnableItem(menu, iUndo);
  608.         EnableItem(menu, iCut);
  609.         EnableItem(menu, iCopy);
  610.         EnableItem(menu, iPaste);
  611.         EnableItem(menu, iClear);
  612.         }
  613.     else {                                        /*    but we know we do not */
  614.         DisableItem(menu, iUndo);
  615.         DisableItem(menu, iCut);
  616.         DisableItem(menu, iCopy);
  617.         DisableItem(menu, iClear);
  618.         DisableItem(menu, iPaste);
  619.         }
  620. } /* AdjustMenus */
  621.  
  622.  
  623. pascal void HandleMenu(short error, long message)
  624. {
  625.     #pragma    unused (error, message)
  626.  
  627.     HiliteMenu(0);                                /*    unhighlight what MenuSelect (or MenuKey) hilited */
  628. } /* HandleMenu */
  629.  
  630.  
  631. #pragma segment Main
  632. void DoMenuCommand(menuResult)
  633.     long    menuResult;
  634. {
  635.     short        menuID;                            /*    the resource ID of the selected menu */
  636.     short        menuItem;                        /*    the item number of the selected menu */
  637.     short        itemHit;
  638.     Str255        daName;
  639.     short        daRefNum;
  640.     Boolean        handledByDA    ;
  641.     Boolean        ignore;
  642.     FailInfo    fi;
  643.  
  644.     CatchCFailures(&fi, (HandlerFuncPtr) HandleMenu);
  645.     
  646.     menuID = HiWord(menuResult);                            /*    use built-ins (for efficiency)... */
  647.     menuItem = LoWord(menuResult);                        /*    to get menu item number and menu number */
  648.     switch (menuID) {
  649.         case mApple:
  650.             switch (menuItem) {
  651.                 case iAbout:                            /*    bring up alert for About */
  652.                     itemHit = Alert(rAboutAlert, nil);
  653.                     break;
  654.                 default:                                /*    all non-About items in this menu are DAs */
  655.                     GetItem(GetMHandle(mApple), menuItem, daName);
  656.                     daRefNum = OpenDeskAcc(daName);
  657.                     break;
  658.                 }
  659.             break;
  660.         case mFile:
  661.             switch (menuItem) {
  662.                 case iNew:
  663.                     DoZoneList();
  664.                     break;
  665.                 case iClose:
  666.                     ignore = DoCloseWindow(FrontWindow());
  667.                     break;
  668.                 case iQuit:
  669.                     Terminate();
  670.                     break;
  671.                 }
  672.             break;
  673.         case mEdit:                                    /*    call SystemEdit for DA editing & Multifinder */
  674.             handledByDA = SystemEdit(menuItem-1);    /*    since we don't do any editing */
  675.             break;
  676.         }
  677.  
  678.     HiliteMenu(0);                                    /*    cleanup */
  679.  
  680.     Success(&fi);
  681. } /* DoMenuCommand */
  682.  
  683.  
  684. #pragma segment Main
  685. void AdjustCursor(Point mouse, RgnHandle region)
  686. {
  687.     #pragma    unused (mouse, region)
  688. } /* AdjustCursor */
  689.  
  690.  
  691. #pragma segment Main
  692. pascal void HandleErr_DoEvent(error, message)
  693.     short    error;
  694.     long    message;
  695. {
  696.     if (error > 0)
  697.         AlertUser(0, error);
  698.     else
  699.         AlertUser(error, message);
  700.     ExitToShell();
  701. } /* HandleErr_DoEvent */
  702.  
  703.  
  704. #pragma segment Main
  705. void DoEvent(event)
  706.     EventRecord    event;
  707. {
  708.     short        part;
  709.     WindowPtr    window;
  710.     char        key;
  711.     FailInfo    fi;
  712.     Point        aPoint;
  713.     OSErr        err;
  714.     
  715.     CatchCFailures(&fi, (HandlerFuncPtr) HandleErr_DoEvent);
  716.     
  717.     switch (event.what) {
  718.         case mouseDown: 
  719.             part = FindWindow(event.where, &window);
  720.             switch (part) {
  721.                 case inMenuBar:                            /*    process the menu command */
  722.                     AdjustMenus();
  723.                     DoMenuCommand(MenuSelect(event.where));
  724.                     break;
  725.                 case inSysWindow:                        /*    let the system handle the mouseDown */
  726.                     SystemClick(&event, window);
  727.                     break;
  728.                 case inContent:
  729.                     break;
  730.                 case inDrag:
  731.                     break;
  732.                 case inGrow:
  733.                     break;
  734.                 case inZoomIn: 
  735.                 case inZoomOut:
  736.                     break;
  737.                 }
  738.             break;
  739.         case keyDown:                                     /*    check for menukey equivalents */
  740.         case autoKey:
  741.             key = event.message & charCodeMask;
  742.             if (event.modifiers & cmdKey) {                /*    Command key down */
  743.                 if (event.what == keyDown) {
  744.                     AdjustMenus();                        /*    enable/disable/check menu items properly */
  745.                     DoMenuCommand(MenuKey(key));
  746.                     }
  747.                 }
  748.             break;
  749.         /*    call DoActivate with the window and... */
  750.         case activateEvt:
  751.             break;
  752.         case updateEvt:
  753.             break;
  754.         /* It is not a bad idea to at least call DIBadMount in response
  755.          to a diskEvt, so that the user can format a floppy. */
  756.         case diskEvt:
  757.             if (HiWord(event.message) != noErr) {
  758.                 SetPt(&aPoint, kDILeft, kDITop);
  759.                 err = DIBadMount(aPoint, event.message);
  760.             }
  761.         case kOSEvent:
  762.             switch ((event.message >> 24) & 0x0FF) {     /* high byte of message */
  763.                 case kSuspendResumeMessage:
  764.                     gInBackground = event.message & kResumeMask;
  765.                     break;
  766.                 }
  767.             break;
  768.         }    
  769.     Success(&fi);
  770. } /* DoEvent */
  771.  
  772.  
  773. #pragma segment Main
  774. void EventLoop()
  775. {
  776.     RgnHandle    cursorRgn;
  777.     Boolean        gotEvent;
  778.     EventRecord    event;
  779.     
  780.     cursorRgn = NewRgn();            /*    we╒ll pass WNE an empty region the 1st time thru */
  781.  
  782.     do {
  783.         if (gHasWaitNextEvent)        /*    put us 'asleep' forever under Multifinder */
  784.             gotEvent = WaitNextEvent(everyEvent, &event, MAXLONG, cursorRgn);
  785.         else {
  786.             SystemTask();            /*    must be called if using GetNextEvent */
  787.             gotEvent = GetNextEvent(everyEvent, &event);
  788.             }
  789.         if (gotEvent) {
  790.             AdjustCursor(event.where, cursorRgn); /*    make sure we have the right cursor */
  791.             DoEvent(event);
  792.             }
  793.         AdjustCursor(event.where, cursorRgn);
  794.     } while (true);                    /*    loop forever; we quit through an ExitToShell */
  795. } /* EventLoop */
  796.  
  797.  
  798. #pragma segment Main
  799. void main()
  800. {    
  801.     UnloadSeg(_DataInit);            /*    note that _DataInit must not be in Main! */
  802.     MaxApplZone();                    /*    expand the heap so code segments load at the top */
  803.  
  804.     InitUFailure();    
  805.  
  806.     Initialize();                    /* initialize the program */
  807.     UnloadSeg(Initialize);            /* note that Initialize must not be in Main! */
  808.  
  809.     EventLoop();                    /* call the main event loop */
  810. } /* main */
  811.