home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1989 …il & Dave's Excellent CD / Excellent CD HFS.raw / Moof / Goodies / DTS Goodies / Events Source / Events.p < prev    next >
Encoding:
Text File  |  1987-09-08  |  35.0 KB  |  1,008 lines  |  [TEXT/MPS ]

  1. {[j=20-/40/80!,o=95,a-]}               { PasMat formatting options }
  2.  
  3. {$SETC AppleShareFriendly = FALSE}       {set this to TRUE to save configuration to a resource
  4.                                         file, FALSE saves it to the application's resources}
  5.  
  6. PROGRAM Events;                        {a program to demonstrate how an application receives
  7.                                         events under Juggler 6/30/87}
  8.  
  9.  {
  10.    modified 8/1/87(v1.0B4):   Just call SystemTask iff GNE is being called
  11.    Saves window positions (like a real "Juggler-friendly" app)
  12.    modified 9/1/87 to fix bugs -- thanks CK!
  13.  }
  14.  
  15.     USES
  16.         {$PUSH}
  17.  
  18.         {$LOAD PasDump.dump}
  19.         Memtypes,QuickDraw,OSIntf,ToolIntf,PackIntf,WLW {WritelnWindow};
  20.         {$LOAD}
  21.         {$POP}
  22.  
  23.         {$D+}
  24.         {$R-}
  25.         
  26.     CONST
  27.         TheAngle            = 15;       {angle to paint in each time in dial-drawing routine}
  28.         MaxChunk            = 360 DIV TheAngle;
  29.         WNETrapNum            = $60;       {trap number of WaitNextEvent}
  30.         UnImplTrapNum        = $9F;       {trap number of "unimplemented trap"}
  31.  
  32.         {Window IDs}
  33.         FugitID             = 128;
  34.         InfoID                = 129;       {resource IDs of our two windowettes}
  35.         DebugID             = 130;       {resource ID of WIND template for debug window}
  36.         AboutMeDLOG         = 128;       {resource ID of our about dialog}
  37.  
  38.         DebugWNum            = 1;       {array indices to our windows}
  39.         FugitWNum            = 2;
  40.         InfoWNum            = 3;
  41.  
  42.         NumWindows            = InfoWNum; {FugitWind,InfoWind,DebugWind}
  43.  
  44.         {Menu IDs}
  45.         MenuCount            = 3;       {total number of menus}
  46.         AppleID             = 128;       {resource IDs/menu IDs for Apple,File and Options menus}
  47.         FileID                = 129;
  48.         OptionID            = 130;
  49.  
  50.         AppleM                = 1;       {index for each menu in myMenus (array of menu handles)}
  51.         FileM                = 2;
  52.         OptionM             = 3;
  53.  
  54.         AboutMeItem         = 1;       {menu item number of about me}
  55.         QuitItem            = 1;       {menu item number of "quit" in file menu}
  56.         ShowMouseItem        = 1;       {menu item number of ShowMouseItem in options menu}
  57.  
  58.         ConfCreator         = 'EVNT';  {creator bytes for this application}
  59.         ConfResType         = 'CnFG';  {resource type of configuration data in configuration
  60.                                         file, registered with tech support}
  61.         ConfResID            = 128;       {resource ID... " " "}
  62.         ConfigFNameStrID    = 128;       {resource ID of configuration file name string}
  63.  
  64.         {low-memory globals that we MUST use}
  65.         GrayRgnLowMemGlobal = $9EE;    {location of low-memory global for gray region -- this
  66.                                         is the only way to get the correct region for multiple
  67.                                         screens on the Mac II}
  68.         MBarHeight            = $BAA;    {low-memory global location for mBarHeight}
  69.  
  70.     TYPE
  71.         ELongPtr = ^Longint;
  72.         EWordPtr = ^Integer;
  73.         LongStuffType        = RECORD   {For type conversions}
  74.                                   CASE Integer OF
  75.                                       1:
  76.                                           (long: longint);
  77.                                       2:
  78.                                           (HiWrd,LoWrd: Integer);
  79.                                       3:
  80.                                           (HiByte,HiMidByte,LoMidByte,LoByte: SignedByte);
  81.                               END;       {LongStuffType}
  82.  
  83.         ConfigWindInfo        = RECORD
  84.                                   windTopLeft: Point;
  85.                                   height: Integer;
  86.                                   width: Integer;
  87.                               END;       {ConfigWindInfo}
  88.  
  89.         ConfigResType        = RECORD   {to write to configuration file}
  90.                                   grayRgnRect: Rect; {so we can keep track of the GrayRgn's
  91.                                                       bbox}
  92.                                   configWindArray: ARRAY [1..NumWindows] OF ConfigWindInfo;
  93.                               END;
  94.         pConfigResType        = ^ConfigResType;
  95.         hConfigResType        = ^pConfigResType;
  96.  
  97.     VAR
  98.         MyMenus            : ARRAY [1..MenuCount] OF MenuHandle;
  99.         MyEvent            : EventRecord;
  100.         FugitWind           : WindowPtr; {our window that will show the rotating dial}
  101.         InfoWind           : WindowPtr; {the window that will show status information}
  102.         YieldTime           : Integer;  {number of ticks to pass to WNE}
  103.         SysEnv               : SysEnvRec; {for SysEnvirons}
  104.         WNEIsImplemented   : BOOLEAN;  {is WaitNextEvent implemented}
  105.         Suspended           : BOOLEAN;  {are we in the background?}
  106.         Done               : BOOLEAN;
  107.         ThePat               : Pattern;  {used for drawing the rotating dial}
  108.         ArcRect            : Rect;       { " " }
  109.         Chunk               : Integer;  { " " }
  110.         PatIsBlack           : BOOLEAN;  {we need this to flip patterns}
  111.         WNERgn               : RgnHandle; {cursor region to pass to WNE}
  112.         InfoWindRgn        : RgnHandle; {rgn containing rect of InfoWind in global coords}
  113.         AllButInfoWindRgn  : RgnHandle; {rgn containing everything but InfoWind rgn}
  114.         ShowMouseMoved       : BOOLEAN;  {whether to report on mouse moved events or not}
  115.         MouseMovedMessage  : SignedByte; {we need this to check for mouse-moved events}
  116.         PlusCursH           : CursHandle; {cursor handle for the plus cursor}
  117.         Err                : OSErr;    {general purpose error checker}
  118.         WChanged           : BOOLEAN;  {have any of our windows changed -- not used in this
  119.                                         version}
  120. SusPendCount: Integer;
  121. {------------------------------------------------------------------------------------}
  122.  
  123. (* FUNCTION WaitNextEvent(eventMask: Integer; VAR theEvent: EventRecord; sleep: longint;
  124.    mouseRgn: RgnHandle): BOOLEAN;
  125.   INLINE $A860;
  126. *)
  127.         {the above is now in the MPW 2.0 interfaces}
  128.  
  129.         {------------------------------------------------------------------------------------}
  130.  
  131. PROCEDURE EvInitWW(r: Rect; wName: Str255);
  132.  
  133. CONST
  134.     EvNewCentury = 34; {font Family of New Century SchoolBook}
  135.  
  136.     VAR
  137.         WWFamily,WWSize: Integer;
  138.  
  139.     BEGIN {InitWW}
  140.         WWInit(50,80);
  141.  
  142.         IF RealFont(EvNewCentury,10) THEN BEGIN
  143.             WWFamily := EvNewCentury;
  144.             WWSize := 10
  145.         END
  146.         ELSE BEGIN
  147.             WWFamily := monaco;
  148.             WWSize := 9
  149.         END;
  150.         WWNew(r,wName,false,true,WWFamily,WWSize);
  151.         SetWRefCon(gDebugWindowPtr,0);    {clear out the refcon to show no change in configuration}
  152.     END; {InitWW}
  153.  
  154.         {------------------------------------------------------------------------------------}
  155.  
  156.     PROCEDURE SetUpMenus;
  157.     {set up menus and menu bar}
  158.  
  159.         VAR
  160.             i                   : Integer;
  161.  
  162.         BEGIN
  163.             MyMenus[AppleM] := GetMenu(AppleID); {read Apple menu from resource file}
  164.             AddResMenu(MyMenus[AppleM],'DRVR'); {add desk accessory names to Apple menu}
  165.             MyMenus[FileM] := GetMenu(FileID); {read file menu from resource file}
  166.             MyMenus[OptionM] := GetMenu(OptionID); {read file menu from resource file}
  167.  
  168.             FOR i := 1 TO MenuCount DO InsertMenu(MyMenus[i],0); {install menus in menu bar}
  169.             DrawMenuBar;               {and draw menu bar}
  170.         END;                           {of SetUpMenus}
  171.  
  172.     {------------------------------------------------------------------------------------}
  173.  
  174.     FUNCTION MenuBarHeight: Integer;   {returns the menu height, independent of ROM}
  175.  
  176.         CONST
  177.             MHt64KROM            = 20;  {menu-bar height for 64K ROMs}
  178.  
  179.         BEGIN                           {MenuBarHeight}
  180.             IF SysEnv.machineType < 0 THEN {64K ROM machine}
  181.                 MenuBarHeight := MHt64KROM
  182.             ELSE
  183.                 MenuBarHeight := EWordPtr(MBarHeight)^; {get it from low-memory}
  184.         END;                           {MenuBarHeight}
  185.  
  186.     {------------------------------------------------------------------------------------}
  187.  
  188.     PROCEDURE DoAbout;                   {display the About box}
  189.  
  190.         VAR
  191.             aboutMeDialog       : DialogPtr; {our dialog}
  192.             screenWidth        : Integer;
  193.             screenHeight       : Integer;
  194.             theItem            : Integer;
  195.  
  196.         BEGIN                           {DoAbout}
  197.             {now we'll get our INVISIBLE dialog -- invisible so we can center it}
  198.             aboutMeDialog := GetNewDialog(AboutMeDLOG,NIL,WindowPtr( - 1));
  199.  
  200.             {we'll need these for centering}
  201.             screenWidth := ScreenBits.bounds.right - ScreenBits.bounds.left;
  202.             screenHeight := ScreenBits.bounds.bottom - ScreenBits.bounds.top-MenuBarHeight;
  203.  
  204.             {let's center it (it's still invisible)}
  205.             WITH aboutMeDialog^.portRect DO
  206.                 MoveWindow(aboutMeDialog,(screenWidth - (right - left)) DIV 2,(screenHeight -
  207.                            (bottom - top)) DIV 2,TRUE); {center it}
  208.  
  209.             ShowWindow(aboutMeDialog); {make it visible}
  210.             REPEAT
  211.                 ModalDialog(NIL,theItem); {this'll stop those pesky background tasks}
  212.             UNTIL theItem = OK;
  213.             DisposDialog(aboutMeDialog); {get rid of the about box dialog}
  214.         END;                           {DoAbout}
  215.  
  216.  
  217.     {------------------------------------------------------------------------------------}
  218.  
  219.     PROCEDURE FlipCursor;
  220.     {we got a mouse-moved event, flip the cursor and assign the new region}
  221.     {we only get mouse-moved events if we are the foreground app!}
  222.     {WritelnWindow slows the cursor change in this example}
  223.  
  224.         BEGIN                           {FlipCursor}
  225.             IF WNERgn = InfoWindRgn THEN BEGIN
  226.                 SetCursor(Arrow);       {the cursor was in the InfoWind, it has moved out, set
  227.                                         cursor to arrow}
  228.                 WNERgn := AllButInfoWindRgn; {flip the region}
  229.             END
  230.             ELSE BEGIN                   {the region was AllButInfoWindRgn}
  231.                 SetCursor(PlusCursH^^); {the cursor was not in the InfoWind, it moved in, set
  232.                                          cursor to plu}
  233.                 WNERgn := InfoWindRgn; {flip the region}
  234.             END
  235.         END;                           {FlipCursor}
  236.  
  237.     {------------------------------------------------------------------------------------}
  238.  
  239.     PROCEDURE GetMouseCursor;           {this is called when we get a menu command to turn
  240.                                         ShowMouseMoved on}
  241.  
  242.         VAR
  243.             mousePt            : Point;
  244.  
  245.         BEGIN                           {GetMouseCursor}
  246.             SetPort(InfoWind);
  247.             GetMouse(mousePt);           {we need to get the mouse here to see where we are when
  248.                                         the command was issued}
  249.  
  250.             IF (PtInRect(mousePt,thePort^.portRect)) & (PlusCursH <> NIL) THEN BEGIN {we're in
  251.                     the InfoWind}
  252.                 SetCursor(PlusCursH^^); {set to plus cursor}
  253.                 WNERgn := InfoWindRgn; {we want to know when we move outside of InfoWind}
  254.             END
  255.             ELSE BEGIN                   {we're not in the InfoWind}
  256.                 SetCursor(Arrow);       {set to arrow}
  257.                 WNERgn := AllButInfoWindRgn; {we want to know when we move into InfoWind}
  258.             END;                       {ELSE}
  259.         END;                           {GetMouseCursor}
  260.  
  261.     {------------------------------------------------------------------------------------}
  262.  
  263.     PROCEDURE DoCommand(mResult: longint; byKey: BOOLEAN);
  264.  
  265.         CONST
  266.             menuTicks            = 5;   {number of ticks to Delay when a MenuKey is hit: 1/12
  267.                                         sec.}
  268.  
  269.         VAR
  270.             theItem,theMenu    : Integer;
  271.             daName               : Str255; {name of DA to launch}
  272.             temp               : Integer;
  273.             svPort               : GrafPtr;
  274.             longStuff           : LongStuffType;
  275.  
  276.         BEGIN                           {DoCommand}
  277.             longStuff.long := mResult; {Oh how I HATE calling HiWord and LoWord! -- you could
  278.                                         call it, though}
  279.             theItem := longStuff.LoWrd; {extract the menu and item numbers}
  280.             theMenu := longStuff.HiWrd;
  281.             CASE theMenu OF            {which menu?}
  282.                 AppleID:
  283.                     IF theItem = AboutMeItem THEN
  284.                         DoAbout
  285.                     ELSE BEGIN           {it's a DA - get its name and open it}
  286.                         GetPort(svPort); {save the port}
  287.                         GetItem(MyMenus[AppleM],theItem,daName);
  288.                         temp := OpenDeskAcc(daName);
  289.                         SetPort(svPort); {put us back in our port}
  290.                     END;               {ELSE}
  291.                 FileID:                {only one item in the File menu}
  292.                     CASE theItem OF
  293.                         QuitItem:
  294.                             Done := TRUE;
  295.                     END;               {mini-case statement}
  296.                 OptionID:               {for now, only one item in the Options menu}
  297.                     CASE theItem OF
  298.                         ShowMouseItem: BEGIN {this item will be disabled if we don't have
  299.                                               WaitNextEvent}
  300.                             ShowMouseMoved := NOT (ShowMouseMoved); {this menu item toggles}
  301.                             CheckItem(MyMenus[OptionM],theItem,ShowMouseMoved); {check it
  302.                                 accordingly}
  303.                             IF ShowMouseMoved THEN
  304.                                 GetMouseCursor {find out which cursor and which region we need}
  305.                             ELSE BEGIN
  306.                                 WNERgn := NIL; {pass NIL to WNE for no mouse tracking}
  307.                                 SetCursor(Arrow); {no mouse tracking, set cursor to arrow}
  308.                             END;
  309.                         END;           {CASE ShowMouseItem}
  310.                     END;               {CASE}
  311.             END;                       {menu case}
  312.             IF byKey THEN Delay(menuTicks,longStuff.long); {Delay to show item was hit}
  313.             HiliteMenu(0);
  314.         END;                           {DoCommand}
  315.  
  316.     {------------------------------------------------------------------------------------}
  317.  
  318.     PROCEDURE UpdateWindow(theWindow: WindowPtr; theStr: Str255); {the port is set correctly by
  319.                                                                    the main event loop}
  320.  
  321.         VAR
  322.             myStr               : Str255;
  323.             r                   : Rect;
  324.  
  325.         BEGIN                           {UpdateWindow}
  326.             BeginUpdate(theWindow);
  327.             IF theWindow = InfoWind THEN BEGIN
  328.                 SetRect(r,5,0,theWindow^.portRect.right,40); {Erase just the two info items}
  329.                 EraseRect(r);
  330.                 MoveTo(5,20);
  331.                 IF WNEIsImplemented THEN BEGIN {display yieldtime}
  332.                     NumToString(YieldTime,myStr);
  333.                     DrawString(myStr);
  334.                     DrawString(' ticks');
  335.                 END
  336.                 ELSE
  337.                     DrawString('no WNE'); {this is easy}
  338.  
  339.                 MoveTo(5,40);           {to show information about 4Gnd/BackGnd}
  340.                 IF Suspended THEN
  341.                     DrawString('BackGnd')
  342.                 ELSE
  343.                     DrawString('4Gnd')
  344.             END
  345.             ELSE IF theWindow = FugitWind THEN
  346.                 IF PatIsBlack THEN
  347.                     FillArc(ArcRect,0,Chunk * TheAngle,Black) {fill in from 0 with black}
  348.                 ELSE
  349.                     FillArc(ArcRect,0,(Chunk * TheAngle) - 360,Black); {fill back from 0 with
  350.                 black}
  351.  
  352.             EndUpdate(theWindow);
  353.             writeln(theStr);           {to debug window}
  354.         END;                           {UpdateWindow}
  355.  
  356.     {------------------------------------------------------------------------------------}
  357.  
  358.     PROCEDURE CalculateWNECursRgns;    {called at startup time and whenever the InfoWind is
  359.                                         dragged}
  360.  
  361.         VAR
  362.             totalScreenRgn       : RgnHandle; {used to figure out AllButInfoWindRgn}
  363.             r                   : Rect; {utility rectangle}
  364.  
  365.         BEGIN                           {CalculateWNECursRgns}
  366.             r := InfoWind^.portRect;
  367.             WITH r DO BEGIN
  368.                 LocalToGlobal(TopLeft);
  369.                 LocalToGlobal(botRight);
  370.             END;
  371.             RectRgn(InfoWindRgn,r);    {this needs to be in global coords}
  372.  
  373.             {now we'll make a region that combines the gray region and screenBits.bounds}
  374.             {so we are sure to get the menu bar (then we won't get mouse-moveds when}
  375.             {we're in the menu bar)}
  376.  
  377.            {there's probably a faster way of doing this, but this way will work with a variety}
  378.             {of menu bar heights and multiple screens}
  379.  
  380.             totalScreenRgn := NewRgn;  {we'll need this for a short time, get rid of it when
  381.                                         done}
  382.             {union GrayRgn's bbox with screenBits.bounds}
  383.             UnionRect(ScreenBits.bounds,(RgnHandle(ELongPtr(GrayRgnLowMemGlobal)^)^^.rgnBBox),
  384.                       r);
  385.             InsetRect(r, - 20, - 20);  {to handle single screen Macs}
  386.             RectRgn(totalScreenRgn,r); {convert to a region}
  387.  
  388.             DiffRgn(totalScreenRgn,InfoWindRgn,AllButInfoWindRgn); {diff of (gray+screenBits)
  389.                                                                     and InfoWind}
  390.             DisposeRgn(totalScreenRgn); {we're all done with this}
  391.         END;                           {CalculateWNECursRgns}
  392.  
  393.     {------------------------------------------------------------------------------------}
  394.  
  395.     {$IFC AppleShareFriendly=TRUE}
  396.  
  397.     FUNCTION OpenConfigFile: Integer;  {opens the configuration file, returns 0 if the open
  398.                                         fails}
  399. {
  400.  
  401. In order to keep track of our windows' positions, so that the user can put them where
  402. he/she wants them and they will come up that way the next time the app is run, we will
  403. use a configuration file.  We do this in order to be server (AppleShare) friendly. We
  404. could keep a resource in our application's resource fork, but that would cause problems if
  405. the application were shared.  So, we call SysEnvirons to see where we should put the file
  406. (SysEnv.sysVRefNum) and away we go -- both Juggler- and AppleShare-friendly
  407.  
  408. }
  409.  
  410.         VAR
  411.             oldVol               : Integer;
  412.             myStrH               : StringHandle;
  413.  
  414.         BEGIN                           {OpenConfigFile}
  415.             OpenConfigFile := 0;       {default to error}
  416.             Err := GetVol(NIL,oldVol); {save off the old volume}
  417.             Err := SetVol(NIL,SysEnv.sysVRefNum); {set to the folder containing currently open
  418.                                                    system file}
  419.             IF Err = noErr THEN BEGIN  {if we get an error here, OpenConfigFile is set to fail
  420.                                         (0) at this point}
  421.                 myStrH := GetString(ConfigFNameStrID); {from our application's resource file}
  422.                 OpenConfigFile := OpenResFile(myStrH^^); {if someone's ResEdited our resource
  423.                                                           away, tough!!}
  424.                 ReleaseResource(Handle(myStrH)); {all done with it}
  425.             END;                       {IF err = noErr}
  426.             Err := SetVol(NIL,oldVol); {restore default directory}
  427.         END;                           {OpenConfigFile}
  428.  
  429.     {$ENDC}
  430.     {------------------------------------------------------------------------------------}
  431.  
  432.     PROCEDURE WriteConfigInfo;           {writes configuration info (window positions) to the
  433.                                         configuration file}
  434.  
  435.         VAR
  436.             configFileRef       : Integer;
  437.             myStrH               : StringHandle;
  438.             oldVol               : Integer;
  439.             myFndrInfo           : FInfo;
  440.  
  441.          {------------------------------------------------------------------------------------}
  442.  
  443.         PROCEDURE WriteConfigData(whichResFile: Integer); {routine to write the data out}
  444.  
  445.             VAR
  446.                 myConfig           : ConfigResType;
  447.                 hResConfig           : Handle;
  448.  
  449.          {------------------------------------------------------------------------------------}
  450.  
  451.             PROCEDURE FillInWInfo(whichWind: WindowPtr; arrElem: Integer;
  452.                                   VAR Data: ConfigResType); {gets window coordinates}
  453.  
  454.                 VAR
  455.                     oldPort            : GrafPtr;
  456.                     p                   : Point;
  457.  
  458.                 BEGIN                   {FillInWInfo}
  459.                     GetPort(oldPort);
  460.                     SetPort(whichWind); {set port for the LocalToGlobal to follow}
  461.                     p := whichWind^.portRect.TopLeft;
  462.                     LocalToGlobal(p);  {change to global coordinates}
  463.                     WITH Data.configWindArray[arrElem],whichWind^.portRect DO BEGIN
  464.                         windTopLeft := p;
  465.                         width := right - left;
  466.                         height := bottom - top;
  467.                     END;               {WITH}
  468.                     SetPort(oldPort);  {restore port}
  469.                 END;                   {FillInWInfo}
  470.  
  471.          {------------------------------------------------------------------------------------}
  472.  
  473.             BEGIN                       {WriteConfigData}
  474.                 {at this point, we know the appropriate resource file exists and is open}
  475.                 hResConfig := GetResource(ConfResType,ConfResID); {get the CNFG resource}
  476.                 IF (hResConfig = NIL) | (HomeResFile(hResConfig) <> whichResFile) THEN BEGIN
  477.                     IF hResConfig <> NIL THEN ReleaseResource(hResConfig); {It's not ours}
  478.                     hResConfig := NewHandle(sizeOf(myConfig)); {we'll make one}
  479.                     AddResource(hResConfig,ConfResType,ConfResID,''); {make a new one}
  480.                 END;                   {IF}
  481.  
  482.                 {fill in the record with the appropriate information}
  483.                 FillInWInfo(gDebugWindowPtr,DebugWNum,hConfigResType(hResConfig)^^);
  484.                 FillInWInfo(FugitWind,FugitWNum,hConfigResType(hResConfig)^^);
  485.                 FillInWInfo(InfoWind,InfoWNum,hConfigResType(hResConfig)^^);
  486.                 hConfigResType(hResConfig)^^.grayRgnRect := (RgnHandle(ELongPtr(
  487.                                                                        GrayRgnLowMemGlobal)^)^^
  488.                                                             .rgnBBox);
  489.                 ChangedResource(hResConfig); {we want it changed!} {no reason to
  490.                                                                     ReleaseResource this guy}
  491.             END;                       {WriteConfigData}
  492.  
  493.         {------------------------------------------------------------------------------------}
  494.  
  495.         BEGIN                           {WriteConfigInfo}
  496.             {$IFC AppleShareFriendly = TRUE}
  497.             writeln('writing config info to file');
  498.             Err := GetVol(NIL,oldVol); {save default volume}
  499.             Err := SetVol(NIL,SysEnv.sysVRefNum); {set to system folder}
  500.  
  501.             {strategy: create a resfile, if we get an error, just skip ahead to the open}
  502.  
  503.             myStrH := GetString(ConfigFNameStrID); {from our application's resource file}
  504.             CreateResFile(myStrH^^);   {ignore the error, just check for errors on the open
  505.                                         call below}
  506.  
  507.             {IF we created the file, we need to set up the Finder Info}
  508.             IF ResError = noErr THEN BEGIN
  509.                 {GetFInfo won't move memory, so no need to lock myStrH}
  510.                 Err := GetFInfo(myStrH^^,SysEnv.sysVRefNum,myFndrInfo);
  511.                 IF Err = noErr THEN BEGIN
  512.                     WITH myFndrInfo DO BEGIN
  513.                         fdType := ConfResType;
  514.                         fdCreator := ConfCreator;
  515.                     END;               {WITH}
  516.                     Err := SetFInfo(myStrH^^,SysEnv.sysVRefNum,myFndrInfo);
  517.                 END;                   {IF}
  518.             END;                       {IF ResError...}
  519.             ReleaseResource(Handle(myStrH)); {all done with this string}
  520.             configFileRef := OpenConfigFile; {go ahead and try to open it}
  521.  
  522.             {$ENDC}
  523.             {$IFC AppleShareFriendly=TRUE}
  524.             IF configFileRef <> 0 THEN BEGIN {the file exists, write configuration data}
  525.                 WriteConfigData(configFileRef); {write the actual data}
  526.                 CloseResFile(configFileRef); {and close the resource file}
  527.                 Err := FlushVol(NIL,SysEnv.sysVRefNum); {flush the volume the config file's on}
  528.             END                        {IF configFileRef <> 0}
  529.             ELSE;                       {do nothing, we just couldn't write it}
  530.             Err := SetVol(NIL,oldVol); {restore default volume}
  531.             {$ELSEC}                   {Duplicated code below}
  532.             writeln('writing config info to resource');
  533.             WriteConfigData(CurResFile);
  534.             {$ENDC}
  535.         END;                           {WriteConfigInfo}
  536.  
  537.     {------------------------------------------------------------------------------------}
  538.  
  539.     FUNCTION ReadConfigInfo(VAR wConfig: ConfigResType): BOOLEAN; {reads the info in the
  540.                                                                    configuration file}
  541.  
  542.         VAR
  543.             configFileRef       : Integer;
  544.             myConf               : hConfigResType;
  545.  
  546.         BEGIN                           {ReadConfigInfo}
  547.             {$IFC AppleShareFriendly=TRUE}
  548.             ReadConfigInfo := FALSE;   {start with this as a default}
  549.  
  550.             configFileRef := OpenConfigFile; {try to open it}
  551.             IF configFileRef <> 0 THEN BEGIN {we got the file}
  552.                 {$ENDC}
  553.                 myConf := hConfigResType(GetResource(ConfResType,ConfResID));
  554.                 IF myConf <> NIL THEN BEGIN
  555.                     ReadConfigInfo := TRUE; {This is true}
  556.                     wConfig := myConf^^;
  557.                     {$IFC AppleShareFriendly=TRUE}
  558.                     CloseResFile(configFileRef); {all done, close the ResFile}
  559.                     {$ENDC}
  560.                 END;                   {IF}
  561.                 {$IFC AppleShareFriendly=TRUE}
  562.             END;                       {IF configFileRef...}
  563.             {$ENDC}
  564.         END;                           {ReadConfigInfo}
  565.  
  566.     {------------------------------------------------------------------------------------}
  567.  
  568.     PROCEDURE Initialize;
  569.  
  570.         PROCEDURE SetUpWindows;        {Gets windows and puts them in the right places}
  571.  
  572. {
  573. NOTE:  I use a very simplistic method to see if I can use the saved window positions.
  574. This is just an example, so you shouldn't use this code.  All I check is to see if the
  575. GrayRgn's BBox has changed, and if it has, I assume that the world has changed, so I revert
  576. to the default window positions.  This is to handle the multiple screens on the Macintosh II.
  577. Real programs, such as the Finder, save window positions in a much more intelligent fashion.
  578. The next version of Events, will include a better technique for handling this.
  579. }
  580.  
  581.             TYPE
  582.                 WindRSRC            = RECORD
  583.                                           bounds: Rect;
  584.                                           procID: Integer;
  585.                                           visible: BOOLEAN;
  586.                                           Filler: BOOLEAN; {otherwise Pascal will pack Visible
  587.                                                             and goAwayFlag}
  588.                                           goAwayFlag: BOOLEAN;
  589.                                           filler2: BOOLEAN;
  590.                                           refCon: longint;
  591.                                           wTitle: Str255;
  592.                                       END;
  593.                 pWindRSRC            = ^WindRSRC;
  594.                 hWindRSRC            = ^pWindRSRC;
  595.  
  596.             VAR
  597.                 hWIND               : hWindRSRC;
  598.                 myConfig           : ConfigResType;
  599.                 r                   : Rect;
  600.                 windTitle           : Str255;
  601.  
  602.             BEGIN                       {SetUpWindows}
  603.  
  604.                 {get our two invisible windows}
  605.                 FugitWind := GetNewWindow(FugitID,NIL,WindowPtr( - 1));
  606.                 InfoWind := GetNewWindow(InfoID,NIL,WindowPtr( - 1));
  607.                 hWIND := hWindRSRC(GetResource('WIND',DebugID)); {we'll need this to get the
  608.                                                                   title string from}
  609.                 {or, if no configuration data is around, we'll get the bounds from this}
  610.  
  611.                 IF ReadConfigInfo(myConfig) & EqualRect(myConfig.grayRgnRect,
  612.                                                         (RgnHandle(ELongPtr(GrayRgnLowMemGlobal)
  613.                                                         ^)^^.rgnBBox)) THEN BEGIN {we have a
  614.                         saved window configuration}
  615.                     WITH myConfig DO BEGIN
  616.                         {first, set up FugitWind}
  617.                         WITH configWindArray[FugitWNum] DO BEGIN
  618.                             MoveWindow(FugitWind,windTopLeft.h,windTopLeft.v,FALSE);
  619.                             SizeWindow(FugitWind,width,height,FALSE);
  620.                         END;
  621.                         {Now, the InfoWind}
  622.                         WITH configWindArray[InfoWNum] DO BEGIN
  623.                             MoveWindow(InfoWind,windTopLeft.h,windTopLeft.v,FALSE);
  624.                             SizeWindow(InfoWind,width,height,FALSE);
  625.                         END;           {WITH}
  626.                         {now, set up the rectangle for the debug window}
  627.  
  628.                         WITH configWindArray[DebugWNum] DO
  629.                             SetRect(r,windTopLeft.h,windTopLeft.v,windTopLeft.h + width,
  630.                                     windTopLeft.v + height);
  631.                     END;               {WITH MyConfig}
  632.                 END                    {IF}
  633.                 ELSE BEGIN               {we don't have the configuration details...}
  634.                     {or the grayRgn's bbox changed, use defaults}
  635.                     {set up WritelnWindow stuff}
  636.                     r := hWIND^^.bounds;
  637.                     r.bottom := ScreenBits.bounds.bottom - 60;
  638.                 END;
  639.  
  640.                 windTitle := hWIND^^.wTitle; {get the title}
  641.                 ReleaseResource(Handle(hWIND)); {all done}
  642.                 EvInitWW(r,windTitle); {we assume that no one's mucked with our resources}
  643.  
  644.                 UnloadSeg(@WWInit);    {unload this segment as well}
  645.  
  646.                 ShowWindow(FugitWind); {show our two invisible windows}
  647.                 ShowWindow(InfoWind);
  648.                 SelectWindow(InfoWind); {bring this window to the front}
  649.             END;                       {SetUpWindows}
  650.  
  651.         {------------------------------------------------------------------------------------}
  652.  
  653.         PROCEDURE _DataInit;
  654.             EXTERNAL;                   {so we can unload it}
  655.  
  656.         {------------------------------------------------------------------------------------}
  657.  
  658.         BEGIN                           {Initialize}
  659.             UnloadSeg(@_DataInit);       {unload data initialization code before any allocations}
  660.             MoreMasters; MoreMasters;  {get some master pointer blocks}
  661.             MaxApplZone;               {grow the heap}
  662.             InitGraf(@thePort);        {standard Macintosh inits}
  663.             InitFonts;
  664.             FlushEvents(everyEvent,0);
  665.             InitWindows;
  666.             InitMenus;
  667.             TEInit;
  668.             InitDialogs(NIL);
  669.             InitCursor;
  670.  
  671.             Err := SysEnvirons(1,SysEnv); {first version of SysEnvirons, we don't care about
  672.                                            the error}
  673.  
  674.             SetUpMenus;                {get our menus}
  675.             SetUpWindows;               {configure our windows}
  676.             FlushEvents(everyEvent,0);
  677.  
  678.             {initialize variables for drawing routines}
  679.             ThePat := Black;           {draw with this to start}
  680.             PatIsBlack := TRUE;        {start with a black pattern for drawing}
  681.             SetRect(ArcRect,10,10,90,90);
  682.             Chunk := 0;
  683.  
  684.             ShowMouseMoved := FALSE;   {don't show these initially}
  685.             {Is WaitNextEvent implemented?}
  686.             WNEIsImplemented := (SysEnv.machineType >= 0) & {>= 128K ROMs}
  687.                 (NGetTrapAddress(WNETrapNum,ToolTrap) <> NGetTrapAddress(UnImplTrapNum,ToolTrap));
  688.             IF NOT WNEIsImplemented THEN {disable showmousemoved menu item}
  689.                 DisableItem(MyMenus[OptionM],ShowMouseItem);
  690.  
  691.             {now let's calculate all of our cursor regions}
  692.             SetPort(InfoWind);
  693.             InfoWindRgn := NewRgn;       {we'll need this for the WNE cursor stuff}
  694.             AllButInfoWindRgn := NewRgn; {we'll need this for the WNE cursor stuff}
  695.             CalculateWNECursRgns;       {calculate the cursor regions}
  696.             WNERgn := NIL;               {default to ShowMouseMoved = FALSE}
  697.  
  698.             MouseMovedMessage := $FA;  {high byte of event record message for mouse moved
  699.                                         events}
  700.             PlusCursH := GetCursor(plusCursor);
  701.             IF PlusCursH <> NIL THEN HNoPurge(Handle(PlusCursH));
  702.  
  703.             YieldTime := 0;            {don't yield any time (Juggler 1.0B3 and later)}
  704.             WChanged := FALSE;           {nobody's changed yet}
  705.             SusPendCount:= 0;
  706.         END;                           {Initialize}
  707.  
  708.     {------------------------------------------------------------------------------------}
  709.  
  710.     PROCEDURE MainEventLoop;
  711.  
  712.         CONST
  713.             quantum             = 2;   {run for 2 ticks before yielding}
  714.             cleanUpTime         = 300; {clean up once every 5 seconds}
  715.  
  716.         VAR
  717.             hasEvent           : BOOLEAN;
  718.             whichWindow        : WindowPtr;
  719.             whichPart           : Integer;
  720.             theChar            : char;
  721.             longStuff           : LongStuffType; {for conversions}
  722.             dragRect           : Rect;
  723.             cleanUpTicks       : longint; {so we know when to call CompactMem}
  724.             timerTicks,ourTime : longint; {this is all for the percentage stuff -- thanks JM}
  725.             runTime,elapsedTime: longint;
  726.             lastTickCount       : longint;
  727.             lastPercent        : longint;
  728.  
  729.          {------------------------------------------------------------------------------------}
  730.  
  731.         PROCEDURE DrawRotatingDial(VAR currentPat: Pattern);
  732.  
  733.             VAR
  734.                 myTicks            : longint;
  735.  
  736.             BEGIN                       {DrawRotatingDial}
  737.                 {Now draw the rotating dial}
  738.                 SetPort(FugitWind);    {set to correct port}
  739.  
  740.                 myTicks := TickCount;  {synch to VBL the poor man's way}
  741.                 REPEAT
  742.                 UNTIL TickCount <> myTicks;
  743.  
  744.                 FillArc(ArcRect,Chunk * TheAngle,TheAngle,currentPat); {draw a chunk}
  745.                 Chunk := Chunk + 1;    {go to next chunk}
  746.                 IF Chunk >= MaxChunk THEN BEGIN {we're done, flip color, reset Chunk}
  747.                     Chunk := 0;
  748.                     IF PatIsBlack THEN
  749.                         currentPat := white
  750.                     ELSE
  751.                         currentPat := Black;
  752.                     PatIsBlack := NOT (PatIsBlack);
  753.                 END;                   {IF}
  754.             END;                       {DrawRotatingDial}
  755.  
  756.         {------------------------------------------------------------------------------------}
  757.  
  758.         PROCEDURE DrawPercentage(runTim,eTime: longint; VAR lastPerct: longint);
  759.  
  760.             VAR
  761.                 percent            : longint;
  762.                 drawRect           : Rect;
  763.                 myStr               : Str255;
  764.  
  765.             BEGIN                       {DrawPercentage}
  766.                 {now draw the percentage information}
  767.                 SetPort(InfoWind);       {in this window}
  768.  
  769.                 percent := ((runTim * 100) DIV eTime);
  770.                 IF percent >= 100 THEN percent := 99; {just in case}
  771.                 IF percent <> lastPerct THEN BEGIN
  772.                     SetRect(drawRect,5,60 - 19 {poor man's} ,thePort^.portRect.right,60);
  773.                     EraseRect(drawRect);
  774.                     MoveTo(5,60);
  775.                     NumToString(percent,myStr);
  776.                     DrawString(myStr);
  777.                     DrawChar('%');
  778.                     lastPerct := percent;
  779.                 END;                   {IF}
  780.             END;                       {DrawPercentage}
  781.  
  782.         {------------------------------------------------------------------------------------}
  783.  
  784.         BEGIN                           {MainEventLoop}
  785.  
  786.             {first initialize some globals}
  787.             Done := FALSE;               {we just started!}
  788.             Suspended := FALSE;        {as far as we know, we're not suspended}
  789.  
  790.             WITH ScreenBits.bounds DO
  791.                 SetRect(dragRect,4,MenuBarHeight + 4,right - 4,bottom - 4);
  792.  
  793.             {get initial values for the percentage stuff}
  794.             lastTickCount := TickCount;
  795.             ourTime := lastTickCount;  {prime our lastTime}
  796.             runTime := 0;               {our total time running}
  797.             elapsedTime := 100;        {total time, avoid divide by zero}
  798.             lastPercent := 0;           {make sure this is drawn}
  799.  
  800.             cleanUpTicks := lastTickCount; {get the ticks so we know when to compact}
  801.  
  802.             REPEAT
  803.  
  804.                 DrawRotatingDial(ThePat); {draw a chunk of the dial}
  805.  
  806.                 {now calculate the percent of processor time -- stolen from John Meier}
  807.                 WHILE (TickCount - ourTime) < quantum DO; {use up rest of quantum}
  808.                 timerTicks := TickCount;
  809.                 runTime := runTime + timerTicks - ourTime;
  810.                 elapsedTime := elapsedTime + timerTicks - lastTickCount;
  811.                 lastTickCount := timerTicks;
  812.                 IF elapsedTime > 1000 THEN BEGIN
  813.                     runTime := 0;
  814.                     elapsedTime := 1;
  815.                 END;
  816.  
  817.                 {see if we should compact the heap to get rid of all the free blocks that}
  818.                 {writelnWindow creates -- time to be anal ytical?}
  819.                 IF NOT Suspended THEN  {only do this if we're in the 4Gnd}
  820.                     IF lastTickCount - cleanUpTicks > cleanUpTime THEN BEGIN
  821.                         longStuff.long := CompactMem(FreeMem); {coalesce free blocks-- won't
  822.                                                                 purge}
  823.                         cleanUpTicks := lastTickCount; {reset this guy}
  824.                     END;               {IF}
  825.  
  826.                 {ask for events}
  827.                 IF WNEIsImplemented THEN
  828.                     hasEvent := WaitNextEvent(everyEvent,MyEvent,YieldTime,WNERgn)
  829.                 ELSE BEGIN
  830.                     SystemTask;        {for drivers}
  831.                     hasEvent := GetNextEvent(everyEvent,MyEvent);
  832.                 END;                   {ELSE}
  833.  
  834.                 ourTime := TickCount;  {ourTime starts after GetNextEvent}
  835.                 DrawPercentage(runTime,elapsedTime,lastPercent); {show the current percentage}
  836.  
  837.                 IF hasEvent THEN
  838.                     CASE MyEvent.what OF {which event?}
  839.  
  840.                         mouseDown: BEGIN
  841.                             whichPart := FindWindow(MyEvent.where,whichWindow);
  842.                            {the events window gets its own mouseDown events, so let's check...}
  843.                             IF whichWindow = gDebugWindowPtr THEN BEGIN
  844.                                 WWMouseDown(whichPart,MyEvent.where,MyEvent.modifiers);
  845.                                 WChanged := TRUE; {since WW is a "black box" assume that a
  846.                                                    mouse-down means that it's grown or moved}
  847.                                 writeln('mouseDown: Events window');
  848.                             END
  849.                             ELSE
  850.                                 CASE whichPart OF
  851.  
  852.                                     inDesk:
  853.                                         writeln('mouseDown: inDesk');
  854.  
  855.                                     inMenuBar: BEGIN
  856.                                         writeln('mouseDown: inMenuBar');
  857.                                         DoCommand(MenuSelect(MyEvent.where),FALSE);
  858.                                     END; {inMenuBar}
  859.  
  860.                                     inSysWindow: BEGIN
  861.                                         SystemClick(MyEvent,whichWindow);
  862.                                         writeln('mouseDown: inSysWindow');
  863.                                     END; {inSysWindow}
  864.                                     inContent: BEGIN
  865.                                         IF whichWindow <> FrontWindow THEN
  866.                                             SelectWindow(whichWindow);
  867.                                         writeln('mouseDown: inContent');
  868.                                     END; {inContent}
  869.                                     inDrag: BEGIN
  870.                                         DragWindow(whichWindow,MyEvent.where,dragRect);
  871.                                         WChanged := TRUE; {to show the configuration needs
  872.                                                            updating}
  873.                                         IF whichWindow = InfoWind THEN CalculateWNECursRgns;
  874.                                         {recalculate the regions if we move InfoWind}
  875.                                         writeln('mouseDown: inDrag');
  876.                                     END; {inDrag}
  877.                                     inGrow:
  878.                                         writeln('mouseDown: inGrow');
  879.                                     inGoAway:
  880.                                         writeln('mouseDown: inGoAway');
  881.  
  882.                                 END;   {CASE}
  883.                         END;           {mouseDown}
  884.  
  885.                         keyDown,autoKey: BEGIN
  886.                             IF MyEvent.what = keyDown THEN
  887.                                 writeln('keyDown')
  888.                             ELSE
  889.                                 writeln('autoKey');
  890.                             theChar := CHR(BitAnd(MyEvent.message,charCodeMask)); {get the
  891.                                 char}
  892.                             IF BitAnd(MyEvent.modifiers,cmdKey) <> 0 THEN
  893.                                 DoCommand(MenuKey(theChar),TRUE) {pass it to the command
  894.                                                                   handler}
  895.                             ELSE IF WNEIsImplemented THEN BEGIN
  896.                                 YieldTime := Ord(theChar) - Ord('0'); {so that 0 thru 9 work}
  897.                                 IF YieldTime < 0 THEN YieldTime := 0; {don't want negatives}
  898.                                 SetPort(InfoWind);
  899.                                 InvalRect(InfoWind^.portRect); {generate update event}
  900.                             END;       {IF}
  901.                         END;           {keyDown}
  902.  
  903.                         updateEvt: BEGIN
  904.                             SetPort(WindowPtr(MyEvent.message));
  905.                             write('update: ');
  906.                             IF WindowPtr(MyEvent.message) = InfoWind THEN
  907.                                 UpdateWindow(WindowPtr(MyEvent.message),'InfoWind')
  908.                             ELSE IF WindowPtr(MyEvent.message) = FugitWind THEN
  909.                                 UpdateWindow(WindowPtr(MyEvent.message),'FugitWind')
  910.                             ELSE IF WindowPtr(MyEvent.message) = gDebugWindowPtr THEN BEGIN
  911.                                 WWUpdateEvent;
  912.                                 writeln('Events window');
  913.                             END        {ELSE = gDebugWindowPtr}
  914.                             ELSE
  915.                                 writeln('Unknown window');
  916.                         END;           {updateEvt}
  917.  
  918.                         diskEvt: BEGIN
  919.                             longStuff.long := MyEvent.message;
  920.                             IF longStuff.HiWrd < 0 THEN {got a bad mount}
  921.                                 Err := DIBadMount(MyEvent.where,MyEvent.message);
  922.                             {we can't really do anything else here that BadMount couldn't do}
  923.                             writeln('Disk insert event');
  924.                         END;           {diskEvt}
  925.  
  926.                         activateEvt: BEGIN
  927.                             IF BitAnd(MyEvent.modifiers,activeFlag) <> 0 THEN
  928.                                 write('activate: ')
  929.                             ELSE
  930.                                 write('deactivate: ');
  931.                             IF WindowPtr(MyEvent.message) = FugitWind THEN
  932.                                 writeln('FugitWind')
  933.                             ELSE IF WindowPtr(MyEvent.message) = InfoWind THEN
  934.                                 writeln('InfoWind')
  935.                             ELSE IF WindowPtr(MyEvent.message) = gDebugWindowPtr THEN BEGIN
  936.                                 writeln('Events window');
  937.                                 WWActivateEvent(MyEvent.modifiers);
  938.                             END        {ELSE IF}
  939.                             ELSE
  940.                                 writeln('Unknown window');
  941.                         END;           {Activate Event}
  942.  
  943.                         networkEvt:
  944.                             writeln('Network Event'); {Juggler doesn't support these}
  945.  
  946.                         driverEvt:
  947.                             writeln('Driver Event');
  948.  
  949.                         app1Evt:
  950.                             writeln('App1Event');
  951.  
  952.                         app2Evt:
  953.                             writeln('App2Event');
  954.  
  955.                         app3Evt:
  956.                             writeln('App3Event');
  957.  
  958.                         app4Evt: BEGIN {Juggler uses this for SUSPEND/RESUME and mouse-moved
  959.                                         events}
  960.                             longStuff.long := MyEvent.message;
  961.                             IF longStuff.HiByte = MouseMovedMessage THEN BEGIN
  962.                                 {mouse moved event}
  963.                                 writeln('MouseMoved');
  964.                                 FlipCursor; {we got a mouse-moved, flip the cursor}
  965.                             END        {IF}
  966.                             ELSE IF Odd(MyEvent.message) THEN BEGIN
  967.                                 writeln('RESUME');
  968.                                 Suspended := FALSE;
  969.                                 SetPort(InfoWind);
  970.                                 InvalRect(thePort^.portRect); {force update of the info window}
  971.                                 IF FrontWindow = gDebugWindowPtr then
  972.                                     WWActivateEvent(1);
  973.  
  974.                             END        {ELSE IF}
  975.                             ELSE BEGIN
  976.                                 writeln('SUSPEND');
  977.                                 SusPendCount:= 1;
  978.                                 Suspended := TRUE;
  979.                                 {we need to deactivate this window, since we are Juggler smart}
  980.                                 IF FrontWindow = gDebugWindowPtr THEN WWActivateEvent(0);
  981.                                 SetPort(InfoWind);
  982.                                 InvalRect(thePort^.portRect); {force update of the info window}
  983.                             END;       {ELSE}
  984.                         END;           {app4Evt}
  985.                     END;               {event.what case}
  986.             UNTIL Done;
  987.         END;                           {MainEventLoop}
  988.  
  989.     {------------------------------------------------------------------------------------}
  990.  
  991.     BEGIN                               {PROGRAM}
  992.         Initialize;
  993.         MainEventLoop;
  994.         DisposeRgn(InfoWindRgn);       {we're all done with it}
  995.         DisposeRgn(AllButInfoWindRgn); {we're all done with it}
  996.  
  997.   {here we could check to see if any of our windows have been changed, but, since
  998.   this may be running under Juggler, and someone could go into the Finder and
  999.   delete our configuration file while we are running, we'll just always write
  1000.   the configuration data}
  1001.  
  1002.         {IF WChanged THEN}
  1003.         WriteConfigInfo;
  1004.  
  1005.         writeln;
  1006.         writeln('Bye bye');
  1007.     END.
  1008.