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

  1. {------------------------------------------------------------------------------
  2. #
  3. #    Apple Macintosh Developer Technical Support
  4. #
  5. #    AppleTalk GetZoneList Sample Application
  6. #
  7. #    GetZoneList
  8. #
  9. #    GetZoneList.p    -    Pascal Source
  10. #
  11. #    Copyright ⌐ 1988 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.
  35. #
  36. #    GetZoneList is based on MACDTS Sample.p. For more
  37. #    description and explanantion of the non-example
  38. #    specific areas of this application, please refer to
  39. #    either Sample.p or TESample.p.
  40. #
  41. ------------------------------------------------------------------------------}
  42.  
  43. PROGRAM GetZoneList;
  44.  
  45. USES
  46.     MemTypes, QuickDraw, OSIntf, ToolIntf, AppleTalk, PackIntf, FixMath, Script, UFailure, Traps;
  47.  
  48. CONST
  49.     kSysEnvironsVersion        = 1;
  50.     kOSEvent                = app4Evt;    {event used by MultiFinder}
  51.     kSuspendResumeMessage    = 1;        {high byte of suspend/resume event message}
  52.     kResumeMask                = 1;        {bit of message field for resume vs. suspend}
  53.     
  54.     kCR                = 13;                {carriage return character}
  55.     kENTER            = 3;                {enter character}
  56.     kScrollBarWidth    = 15;                {the width of the scrollbar in the list}
  57.     kListInset        = -1;                {adjustment for list frame}
  58.     kATPTimeOutVal    = 3;                {re-try ATP SendRequest every 3 seconds}
  59.     kATPRetryCount    = 5;                {for five times}
  60.     kZonesSize        = 578;                {size of buffer for zone names}
  61.     kGZLCall        = $08000000;        {GetZoneList indicator}
  62.     kZIPSocket        = 6;                {the Zone Information Protocol socket}
  63.     kMoreZones        = $FF000000;        {mask to see if more zones to come}
  64.     kZoneCount        = $0000FFFF;        {mask to count zones in buffer}
  65.     kHilite            = 1;                {hilite value for button control}
  66.     kDeHilite        = 0;                {dehilite value for button control}
  67.     kHiliteDelay    = 5;                {time in ticks to leave button hilited}
  68.     
  69.     kMinHeap        = 0;
  70.     kMinSpace        = 0;
  71.     
  72.     sErrStrings        = 128;                {error string STR#}
  73.     eStandardErr    = 1;
  74.     eWrongMachine    = 2;
  75.     eSmallSize        = 3;
  76.     eNoMemory        = 4;
  77.     eAppleTalk        = 5;
  78.     eNoZones        = 6;
  79.     
  80.     rAboutAlert        = 128;                {about alert}
  81.     rZoneDialog        = 129;                {zone list dialog}
  82.     dZoneList        = 2;                {user item that is zone list}
  83.     dDefault        = 3;                {user item that is default indicator}
  84.     rUserAlert        = 130;                {error alert}
  85.  
  86.     rMenuBar        = 128;                {application's menu bar}
  87.  
  88.     mApple            = 128;                {Apple menu}
  89.     iAbout            = 1;
  90.  
  91.     mFile            = 129;                {File menu}
  92.     iNew            = 1;
  93.     iClose            = 4;
  94.     iQuit            = 12;
  95.  
  96.     mEdit            = 130;                {Edit menu}
  97.     iUndo            = 1;
  98.     iCut            = 3;
  99.     iCopy            = 4;
  100.     iPaste            = 5;
  101.     iClear            = 6;
  102.     
  103.     {1.01 - kDITop and kDILeft are used to locate the Disk Initialization dialogs.}
  104.     kDITop        = $0050;
  105.     kDILeft        = $0070;
  106.  
  107.  
  108. VAR
  109.     gMac                : SysEnvRec;    {set up by Initialize}
  110.     gHasWaitNextEvent    : BOOLEAN;        {set up by Initialize}
  111.     gInBackground        : BOOLEAN;        {maintained by Initialize and DoEvent}
  112.     
  113.     gList                : ListHandle;    {the list to be filled with zone names}
  114.  
  115. {$S Initialize}
  116. FUNCTION TrapAvailable(tNumber: INTEGER; tType: TrapType): BOOLEAN;
  117. BEGIN
  118.     TrapAvailable := NGetTrapAddress(tNumber, tType) <> GetTrapAddress(_Unimplemented);
  119. END; {TrapAvailable}
  120.  
  121.  
  122. {$S Main}
  123. PROCEDURE FailOSErrMsg(result, message: INTEGER);
  124. BEGIN
  125.     IF result <> noErr THEN
  126.         Failure(result, message);
  127. END; {SignalOSErrMsg}
  128.  
  129.  
  130. {$S Main}
  131. PROCEDURE FailNILMsg(p: UNIV Ptr; message: INTEGER);
  132. BEGIN
  133.     IF p = NIL THEN
  134.         Failure(memFullErr, message);
  135. END; {FailNILMsg}
  136.  
  137.  
  138. {$S Main}
  139. PROCEDURE AlertUser(error: INTEGER; message: LongInt);
  140.  
  141. {Display an alert to inform the user of an error. Message acts as an 
  142.  index into a STR# resource of error messages. If no message is given,
  143.  i.e. = 0, then use a standard message. If error is not noErr then
  144.  display it as well.}
  145.  
  146. VAR
  147.     msg1, msg2    : Str255;
  148.     itemHit        : INTEGER;
  149. BEGIN
  150.     IF message = 0 THEN message := eStandardErr;
  151.     GetIndString(msg1, sErrStrings, message);
  152.     IF error = noErr THEN
  153.         msg2 := ''
  154.     ELSE
  155.         NumToString(error, msg2);
  156.     ParamText(msg1, msg2, '', '');
  157.     itemHit := Alert(rUserAlert, NIL);
  158. END; {AlertUser}
  159.  
  160.  
  161. {$S Main}
  162. FUNCTION IsDAWindow(window: WindowPtr): BOOLEAN;
  163. BEGIN
  164.     IF window = NIL THEN
  165.         IsDAWindow := FALSE
  166.     ELSE    {DA windows have negative windowKinds}
  167.         IsDAWindow := WindowPeek(window)^.windowKind < 0;
  168. END; {IsDAWindow}
  169.  
  170.  
  171. {$S Main}
  172. FUNCTION IsAppWindow(window: WindowPtr): BOOLEAN;
  173. BEGIN
  174.     IF window = NIL THEN
  175.         IsAppWindow := FALSE
  176.     ELSE    {application windows have windowKinds >= userKind (8) or dialogKind (2)}
  177.         WITH WindowPeek(window)^ DO
  178.             IsAppWindow := (windowKind >= userKind) | (windowKind = dialogKind);
  179. END; {IsAppWindow}
  180.  
  181.  
  182. {$S Main}
  183. PROCEDURE BuildZoneList;
  184.  
  185. {Create the list of zones on the network. Find a bridge to talk to , if one is
  186.  present, then ask it for zone names. Add the names to the list in the dialog.}
  187.  
  188. VAR
  189.     dATPPBptr                    : ATPPBptr;        {the parameter block for GetZoneList call}
  190.     dBDS                        : BDSElement;    {the BDS for GetZoneList call}
  191.     dZones, dCurr                : Ptr;            {the data buffer for GetZoneList call}
  192.     dIndex, dCount, dNode, dNet    : INTEGER;
  193.     ignore                        : INTEGER;
  194.     cSize                        : Point;
  195.     fi                            : FailInfo;
  196.     
  197.     PROCEDURE CleanUp;
  198.     BEGIN
  199.         IF dATPPBptr <> NIL THEN
  200.             DisposPtr(Ptr(dATPPBptr));                    {get rid of pb block}
  201.         IF dZones <> NIL THEN
  202.             DisposPtr(dZones);                            {and buffer}
  203.     END; {CleanUp}
  204.     
  205.     PROCEDURE HandleErr(error: INTEGER; message: LongInt);
  206.     BEGIN
  207.         CleanUp;                                        {get rid of allocated junk}
  208.     END;
  209.     
  210. BEGIN
  211.     dATPPBptr := NIL;                                    {init some important variables}
  212.     dZones := NIL;
  213.     CatchFailures(fi, HandleErr);
  214.     
  215.     dATPPBptr := ATPPBptr(NewPtr(SIZEOF(ATPParamBlock)));
  216.     FailNILMsg(dATPPBptr, eNoMemory);
  217.     dZones := NewPtr(kZonesSize);
  218.     FailNILMsg(dZones, eNoMemory);
  219.     WITH dBDS DO BEGIN                                    {set up BDS}
  220.         buffSize := kZonesSize;
  221.         buffPtr := dZones;
  222.         END;
  223.     WITH dATPPBptr^ DO BEGIN                            {set up pb block}
  224.         atpFlags := 0;
  225.         FailOSErrMsg(GetNodeAddress(ignore,
  226.             addrBlock.aNet), eAppleTalk);                {get net of bridge}
  227.         IF addrBlock.aNet = 0 THEN
  228.             Failure(0, eNoZones);                        {bail if no zones present}
  229.         addrBlock.aNode := GetBridgeAddress;            {get node of bridge}
  230.         addrBlock.aSocket := kZIPSocket;                {the socket we want}
  231.         reqLength := 0;
  232.         reqPointer := NIL;
  233.         bdsPointer := @dBDS;
  234.         numOfBuffs := 1;
  235.         timeOutVal := kATPTimeOutVal;
  236.         retryCount := kATPRetryCount;
  237.         END;
  238.     dIndex := 1;
  239.     dCount := 0;
  240.     SetPt(cSize, 0, 0);                                    {we always stuff into first}
  241.     REPEAT
  242.         dATPPBptr^.userData := kGZLCall + dIndex;        {indicate GetZoneList request}
  243.         FailOSErrMsg(PSendRequest(dATPPBptr,
  244.             FALSE), eAppleTalk);                        {send sync request}
  245.         dCount := dCount + BAND(dBDS.userBytes,
  246.                     kZoneCount);                        {find out how many returned}
  247.         dCurr := dZones;                                {put current pointer at start}
  248.         REPEAT                                            {get each zone}
  249.             ignore := LAddRow(1, 0, gList);                {create new cell at start}
  250.             LSetCell(POINTER(ORD4(dCurr) + 1), dCurr^,
  251.                         cSize, gList);                    {stuff in zone}
  252.             dCurr := POINTER(ORD4(dCurr) + dCurr^+1);    {bump up current pointer}
  253.             dIndex := dIndex + 1;                        {increment which zone}
  254.         UNTIL dIndex > dCount;
  255.     UNTIL (BAND(dBDS.userBytes, kMoreZones) <> 0);        {keep going until none left}
  256.     CleanUp;
  257.     
  258.     Success(fi);
  259. END; {BuildZoneList}
  260.  
  261.  
  262. {$S Main}
  263. PROCEDURE ZoneListDraw(dlg: DialogPtr; item: INTEGER);
  264.  
  265. {The user item procedure for the zone list user item and default
  266.  box user item in the dialog. Draw the list and the frame that goes with it.
  267.  Draw the default box around the OK button.}
  268.  
  269. VAR
  270.     port    : GrafPtr;
  271.     kind    : INTEGER;
  272.     h        : Handle;
  273.     r        : Rect;
  274.     ps        : PenState;
  275.     
  276. BEGIN
  277.     GetPort(port);                                    {save old port}
  278.     SetPort(dlg);                                    {make dialog port}
  279.     CASE item OF
  280.     dZoneList: BEGIN
  281.             LUpdate(dlg^.visRgn, gList);            {re-draw list}
  282.             GetDItem(dlg, dZoneList, kind, h, r);
  283.             InsetRect(r, kListInset, kListInset);
  284.             FrameRect(r);                            {re-draw frame}
  285.         END;
  286.     dDefault: BEGIN
  287.             GetDItem(dlg, dDefault, kind, h, r);
  288.             GetPenState(ps);
  289.             PenSize(3, 3);
  290.             InsetRect(r, -4, -4);
  291.             FrameRoundRect(r, 16, 16);                {draw default box}
  292.             SetPenState(ps);
  293.         END;
  294.     END;
  295.     SetPort(port);                                    {restore old port}
  296. END; {ZoneListDraw}
  297.  
  298.  
  299. {$S Main}
  300. FUNCTION ListFilter (dlg: DialogPtr; VAR event: EventRecord;
  301.                                             VAR item: INTEGER) : BOOLEAN;
  302.  
  303. {Passed as parameter to ModalDialog. Handle key presses and mouse clicks
  304.  from the user. Do all the right default actions since we override them
  305.  by virtue of our existence.}
  306.  
  307. VAR
  308.     port        : GrafPtr;
  309.     loc            : Point;
  310.     kind        : INTEGER;
  311.     h            : Handle;
  312.     r            : Rect;
  313.     ignore        : BOOLEAN;
  314.     key            : SignedByte;
  315.     finalTicks    : LongInt;
  316. BEGIN
  317.     ListFilter := FALSE;                                {always default FALSE}
  318.     CASE event.what OF
  319.         keyDown, autoKey: BEGIN                            {check for <cr> or <enter>}
  320.             key := SignedByte(event.message);
  321.             IF key IN [kCR, kENTER] THEN BEGIN            {it was a <cr> or <enter>}
  322.                 GetDItem(dlg, ok, kind, h, r);
  323.                 HiliteControl(ControlHandle(h), kHilite);
  324.                 Delay(kHiliteDelay, finalTicks);
  325.                 HiliteControl(ControlHandle(h), kDeHilite);
  326.                 ListFilter := TRUE;                        {so we handle it}
  327.                 item := 1;                                {and make the first item hit}
  328.             END;
  329.         END;
  330.         mouseDown: BEGIN                                {we want mouseDowns}
  331.             GetPort(port);
  332.             SetPort(dlg);
  333.             loc := event.where;
  334.             GlobalToLocal(loc);                            {find where clicked}
  335.             GetDItem(dlg, dZoneList, kind, h, r);        {get rect for list}
  336.             IF PtInRect(loc, r) THEN BEGIN                {if clicked inside╔}
  337.                 ListFilter := TRUE;                        {we take care of it}
  338.                 ignore := LClick(loc, event.modifiers, 
  339.                                     gList);                {by passing click to list}
  340.             END;
  341.             SetPort(port);
  342.         END;
  343.     END;
  344. END; {ListFilter}
  345.  
  346.  
  347. {$S Main}
  348. PROCEDURE DoZoneList;
  349.  
  350. {Put up a modal dialog that shows a list of the zones on the net. Create the dialog
  351.  and list, call BuildZoneList to fill it, then wait for the user to click OK.}
  352.  
  353. VAR
  354.     dlg                        : DialogPtr;
  355.     item, kind                : INTEGER;
  356.     h                        : Handle;
  357.     r, rView, dataBounds    : Rect;
  358.     cSize                    : Point;
  359.     fi                        : FailInfo;
  360.     hor, ver                : INTEGER;
  361.     
  362.     PROCEDURE CleanUp;
  363.     BEGIN
  364.         IF gList <> NIL THEN
  365.             LDispose(gList);                                {get rid of list}
  366.         IF dlg <> NIL THEN
  367.             DisposDialog(dlg);                                {get rid of dialog}
  368.     END; {CleanUp}
  369.  
  370.     PROCEDURE HandleErr(error: INTEGER; message: LongInt);
  371.     BEGIN
  372.         CleanUp;                                            {release junk}
  373.     END;
  374.     
  375. BEGIN
  376.     gList := NIL;                                            {init some important variables}
  377.     dlg := NIL;
  378.     CatchFailures(fi, HandleErr);
  379.     
  380.     dlg := GetNewDialog(rZoneDialog, NIL, POINTER(-1));        {create dialog}
  381.     FailNILMsg(dlg, eNoMemory);
  382.     
  383.     {We center the dialog horizontally and position it vertically one-third the
  384.      distance from the menu bar to the bottom of the main device. We do not
  385.      check for the dialog extending past the bottom of the device because we
  386.      know the dialog is not that big. You may wish to make that check.}
  387.     WITH dlg^.portRect DO
  388.         hor := right - left;
  389.     WITH screenBits.bounds DO BEGIN
  390.         hor := ((right - left) - hor) DIV 2;
  391.         ver := ((bottom - top) - GetMBarHeight) DIV 3;
  392.     END;
  393.     MoveWindow(dlg, hor, ver, FALSE);
  394.     
  395.     GetDItem(dlg, dDefault, kind, h, r);
  396.     h := @ZoneListDraw;                                        {connect drawing procedure}
  397.     SetDItem(dlg, dDefault, kind, h, r);
  398.     GetDItem(dlg, dZoneList, kind, h, r);
  399.     h := @ZoneListDraw;                                        {connect drawing procedure}
  400.     SetDItem(dlg, dZoneList, kind, h, r);
  401.     rView := r;
  402.     WITH rView DO
  403.         right := right - kScrollBarWidth;                    {adjust rectangle for scroll}
  404.     SetRect(dataBounds, 0, 0, 1, 0);                        {init to one-wide list}
  405.     SetPt(cSize, 0, 0);
  406.     gList := LNew(rView, dataBounds, cSize, 0, WindowPtr(dlg),
  407.                     FALSE, FALSE, FALSE, TRUE);                {create with vertical scroll}
  408.     FailNILMsg(gList, eNoMemory);
  409.     BuildZoneList;                                            {put the stuff into the list}
  410.     SetPt(cSize, 0, 0);
  411.     LSetSelect(TRUE, cSize, gList);                            {select the first guy}
  412.     LDoDraw(TRUE, gList);                                    {turn on the list}
  413.     ShowWindow(dlg);                                        {turn on the dialog}
  414.     REPEAT
  415.         ModalDialog(@ListFilter, item);                        {accept events}
  416.     UNTIL item = ok;                                        {until he presses 'ok'}
  417.     CleanUp;
  418.     
  419.     Success(fi);
  420. END; {DoZoneList}
  421.  
  422.  
  423. {$S Main}
  424. FUNCTION DoCloseWindow(window: WindowPtr) : BOOLEAN;
  425. BEGIN
  426.     DoCloseWindow := TRUE;
  427.     IF IsDAWindow(window) THEN
  428.         CloseDeskAcc(WindowPeek(window)^.windowKind)
  429.     ELSE 
  430.     IF IsAppWindow(window) THEN
  431.         CloseWindow(window);
  432. END; {DoCloseWindow}
  433.  
  434.  
  435. {$S Initialize}
  436. PROCEDURE Initialize;
  437. VAR
  438.     menuBar            : Handle;
  439.     window            : WindowPtr;
  440.     ignoreError        : OSErr;
  441.     total, contig    : LongInt;
  442.     ignoreResult    : BOOLEAN;
  443.     event            : EventRecord;
  444.     count            : INTEGER;
  445.     fi                : FailInfo;
  446.  
  447.     PROCEDURE HandleErr(error: INTEGER; message: LongInt);
  448.     BEGIN
  449.         IF error > 0 THEN
  450.             AlertUser(0, error)
  451.         ELSE
  452.             AlertUser(error, message);
  453.         ExitToShell;
  454.     END; {HandleErr}
  455.  
  456. BEGIN
  457.     gHasWaitNextEvent := TrapAvailable(_WaitNextEvent, ToolTrap);
  458.     gInBackground := FALSE;
  459.  
  460.     InitGraf(@thePort);
  461.     InitFonts;
  462.     InitWindows;
  463.     InitMenus;
  464.     TEInit;
  465.     InitDialogs(NIL);
  466.     InitCursor;
  467.  
  468.     FOR count := 1 TO 3 DO
  469.         ignoreResult := EventAvail(everyEvent, event);
  470.  
  471.     CatchFailures(fi, HandleErr);
  472.  
  473.     FailOSErrMsg(MPPOpen, eAppleTalk);
  474.     FailOSErrMsg(ATPLoad, eAppleTalk);
  475.  
  476.     ignoreError := SysEnvirons(kSysEnvironsVersion, gMac);
  477.     IF gMac.machineType < 0 THEN
  478.         Failure(0, eWrongMachine);
  479.     
  480.     IF ORD(GetApplLimit) - ORD(ApplicZone) < kMinHeap THEN
  481.         Failure(0, eSmallSize);
  482.  
  483.     PurgeSpace(total, contig);
  484.     IF total < kMinSpace THEN
  485.         Failure(0, eNoMemory);
  486.  
  487.     menuBar := GetNewMBar(rMenuBar);        {read menus into menu bar}
  488.     FailNILMsg(menuBar, eNoMemory);
  489.     SetMenuBar(menuBar);                    {install menus}
  490.     DisposHandle(menuBar);
  491.     AddResMenu(GetMHandle(mApple), 'DRVR');    {add DA names to Apple menu}
  492.     DrawMenuBar;
  493.     
  494.     Success(fi);
  495. END; {Initialize}
  496.  
  497.  
  498. {$S Main}
  499. PROCEDURE Terminate;
  500. VAR
  501.     aWindow    : WindowPtr;
  502.     closed    : BOOLEAN;
  503.  
  504. BEGIN
  505.     closed := TRUE;
  506.     REPEAT
  507.         aWindow := FrontWindow;                    {get the current front window}
  508.         IF aWindow <> NIL THEN
  509.             closed := DoCloseWindow(aWindow);    {close this window}
  510.     UNTIL (NOT closed) | (aWindow = NIL);        {do all windows}
  511.     IF closed THEN
  512.         ExitToShell;                            {exit if no cancellation}
  513. END; {Terminate}
  514.  
  515.  
  516. {$S Main}
  517. PROCEDURE AdjustMenus;
  518. VAR
  519.     window            : WindowPtr;
  520.     menu            : MenuHandle;
  521.  
  522. BEGIN
  523.     window := FrontWindow;
  524.  
  525.     menu := GetMHandle(mFile);
  526.     IF IsDAWindow(window) THEN                {we can allow desk accessories to be closed from the menu}
  527.         EnableItem(menu, iClose)
  528.     ELSE
  529.         DisableItem(menu, iClose);            {but not our traffic light window}
  530.  
  531.     menu := GetMHandle(mEdit);
  532.     IF IsDAWindow(window) THEN BEGIN        {a desk accessory might need the edit menu}
  533.         EnableItem(menu, iUndo);
  534.         EnableItem(menu, iCut);
  535.         EnableItem(menu, iCopy);
  536.         EnableItem(menu, iPaste);
  537.         EnableItem(menu, iClear);
  538.     END ELSE BEGIN                            {but we know we do not}
  539.         DisableItem(menu, iUndo);
  540.         DisableItem(menu, iCut);
  541.         DisableItem(menu, iCopy);
  542.         DisableItem(menu, iClear);
  543.         DisableItem(menu, iPaste);
  544.     END;
  545.  
  546. END; {AdjustMenus}
  547.  
  548.  
  549. {$S Main}
  550. PROCEDURE DoMenuCommand(menuResult: LONGINT);
  551. VAR
  552.     menuID            : INTEGER;        {the resource ID of the selected menu}
  553.     menuItem        : INTEGER;        {the item number of the selected menu}
  554.     itemHit            : INTEGER;
  555.     daName            : Str255;
  556.     daRefNum        : INTEGER;
  557.     handledByDA        : BOOLEAN;
  558.     ignore            : BOOLEAN;
  559.     fi                : FailInfo;
  560.     
  561.     PROCEDURE HandleMenu(error: INTEGER; message: LongInt);
  562.     BEGIN
  563.         HiliteMenu(0);                {unhighlight what MenuSelect (or MenuKey) hilited}
  564.     END;
  565.  
  566. BEGIN
  567.     CatchFailures(fi, HandleMenu);
  568.     menuID := HiWrd(menuResult);    {use built-ins (for efficiency)...}
  569.     menuItem := LoWrd(menuResult);    {to get menu item number and menu number}
  570.     CASE menuID OF
  571.         mApple:
  572.             CASE menuItem OF
  573.                 iAbout:                {bring up alert for About}
  574.                     itemHit := Alert(rAboutAlert, NIL);
  575.                 OTHERWISE BEGIN        {all non-About items in this menu are DAs}
  576.                     GetItem(GetMHandle(mApple), menuItem, daName);
  577.                     daRefNum := OpenDeskAcc(daName);
  578.                 END;
  579.             END;
  580.         mFile:
  581.             CASE menuItem OF
  582.                 iNew:
  583.                     DoZoneList;
  584.                 iClose:
  585.                     ignore := DoCloseWindow(FrontWindow);
  586.                 iQuit:
  587.                     Terminate;
  588.             END;
  589.         mEdit:                        {call SystemEdit for DA editing & MultiFinder}
  590.             handledByDA := SystemEdit(menuItem-1);    {since we don't do any editing}
  591.     END;
  592.     Success(fi);
  593.     HiliteMenu(0);                    {cleanup}
  594. END; {DoMenuCommand}
  595.  
  596.  
  597. {$S Main}
  598. PROCEDURE AdjustCursor(mouse: Point; region: RgnHandle);
  599. BEGIN
  600. END; {AdjustCursor}
  601.  
  602.  
  603. {$S Main}
  604. PROCEDURE DoEvent(event: EventRecord);
  605. VAR
  606.     part, err    : INTEGER;
  607.     window        : WindowPtr;
  608.     hit            : BOOLEAN;
  609.     key            : CHAR;
  610.     fi            : FailInfo;
  611.     aPoint        : Point;
  612.     
  613.     PROCEDURE HandleErr(error: INTEGER; message: LongInt);
  614.     BEGIN
  615.         IF error > 0 THEN
  616.             AlertUser(0, error)
  617.         ELSE
  618.             AlertUser(error, message);
  619.         EXIT(DoEvent);
  620.     END; {HandleErr}
  621.  
  622. BEGIN
  623.     CatchFailures(fi, HandleErr);
  624.         
  625.     CASE event.what OF
  626.         mouseDown: BEGIN
  627.             part := FindWindow(event.where, window);
  628.             CASE part OF
  629.                 inMenuBar: BEGIN            {process the menu command}
  630.                     AdjustMenus;
  631.                     DoMenuCommand(MenuSelect(event.where));
  632.                 END;
  633.                 inSysWindow:                {let the system handle the mouseDown}
  634.                     SystemClick(event, window);
  635.                 inContent:;
  636.                 inDrag:;
  637.                 inGrow:;
  638.                 inZoomIn, inZoomOut:;
  639.             END;
  640.         END;
  641.         keyDown, autoKey: BEGIN                {check for menukey equivalents}
  642.             key := CHR(BAnd(event.message, charCodeMask));
  643.             IF BAnd(event.modifiers, cmdKey) <> 0 THEN    {Command key down}
  644.                 IF event.what = keyDown THEN BEGIN
  645.                     AdjustMenus;            {enable/disable/check menu items properly}
  646.                     DoMenuCommand(MenuKey(key));
  647.                 END;
  648.         END;                                {call DoActivate with the window and...}
  649.         activateEvt:;
  650.         updateEvt:;
  651.         {1.01 - It is not a bad idea to at least call DIBadMount in response
  652.          to a diskEvt, so that the user can format a floppy.}
  653.         diskEvt:
  654.             IF HiWrd(event.message) <> noErr THEN BEGIN
  655.                 SetPt(aPoint, kDILeft, kDITop);
  656.                 err := DIBadMount(aPoint, event.message);
  657.             END;
  658.         kOSEvent:
  659.             CASE BAnd(BRotL(event.message, 8), 255) OF    {high byte of message}
  660.                 kSuspendResumeMessage: BEGIN
  661.                     gInBackground := BAnd(event.message, kResumeMask) = 0;
  662.                 END;
  663.             END;
  664.     END;
  665.     
  666.     Success(fi);
  667. END; {DoEvent}
  668.  
  669.  
  670. {$S Main}
  671. PROCEDURE EventLoop;
  672. VAR
  673.     cursorRgn    : RgnHandle;
  674.     gotEvent    : BOOLEAN;
  675.     event        : EventRecord;
  676.  
  677. BEGIN
  678.     cursorRgn := NewRgn;            {we╒ll pass WNE an empty region the 1st time thru}
  679.  
  680.     REPEAT
  681.         IF gHasWaitNextEvent THEN    {put us 'asleep' forever under MultiFinder}
  682.             gotEvent := WaitNextEvent(everyEvent, event, MAXLONGINT, cursorRgn)
  683.         ELSE BEGIN
  684.             SystemTask;                {must be called if using GetNextEvent}
  685.             gotEvent := GetNextEvent(everyEvent, event);
  686.         END;
  687.         IF gotEvent THEN BEGIN
  688.             AdjustCursor(event.where, cursorRgn); {make sure we have the right cursor}
  689.             DoEvent(event);
  690.         END;
  691.         AdjustCursor(event.where, cursorRgn);
  692.     UNTIL FALSE;                    {loop forever; we quit through an ExitToShell}
  693. END; {EventLoop}
  694.  
  695.  
  696. PROCEDURE _DataInit; EXTERNAL;
  697.  
  698.  
  699. {$S Main}
  700. BEGIN
  701.     UnloadSeg(@_DataInit);        {note that _DataInit must not be in Main!}
  702.     MaxApplZone;                {expand the heap so code segments load at the top}
  703.  
  704.     InitSignals;
  705.     Initialize;                    {initialize the program}
  706.     UnloadSeg(@Initialize);        {note that Initialize must not be in Main!}
  707.  
  708.     EventLoop;                    {call the main event loop}
  709. END.
  710.