home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 300-399 / ff386.lzh / XLispStat / src3.lzh / Mac / TransSkel1.c < prev    next >
C/C++ Source or Header  |  1990-10-11  |  33KB  |  1,432 lines

  1. /*
  2.     TransSkel version 1.02 - Transportable application skeleton
  3.     
  4.     TransSkel is public domain and is written by:
  5.  
  6.             Paul DuBois
  7.             Wisconsin Regional Primate Research Center
  8.             1220 Capital Court
  9.             Madison WI  53706  USA
  10.  
  11.     UUCP:    allegra,ihnp4,seismo}!uwvax!uwmacc!dubois
  12.     ARPA:    dubois@unix.macc.wisc.edu
  13.             dubois@rhesus.primate.wisc.edu
  14.  
  15.     This version of TransSkel written for LightspeedC.  LightspeedC is a
  16.     trademark of:
  17.             THINK Technologies, Inc
  18.             420 Bedford Street  Suite 350
  19.             Lexington, MA  02173  USA
  20.  
  21.   History
  22.   06/13/86    Beta version.
  23.   08/27/86    Version number changed to 1.01.
  24.               v1.0 DoGrow bug fixed - the port at the point of the
  25.               InvalRect could have been anything; the fix is to set
  26.               the port to the grown window first.  This also explains
  27.               why the kludge to DoActivate in v1.0 worked.
  28.   10/02/86    Version number changed to 1.02, as a result of adding
  29.             modifications by David W. Berry (well!dwb@lll-lcc.arpa)
  30.             for supporting window zooming.  Also used his modifications
  31.             for supporting modeless dialogs (though not in the same
  32.             form).  Dialogs can be #define'd on or off.
  33. */
  34.  
  35.  
  36. /*
  37.     The following symbol controls support for dialogs.
  38.     Changing #define to #undef disables the support.
  39. */
  40.  
  41. # define    supportDialogs
  42.  
  43.  
  44. #ifdef MPWC
  45. # ifdef        supportDialogs
  46. #    include    <Dialogs.h>
  47. # else
  48. #    include    <Windows.h>
  49. # endif
  50.  
  51. # include    <Events.h>
  52. # include    <OSEvents.h>
  53. # include    <Menus.h>
  54. # include    <Memory.h>
  55. # include    <DiskInit.h>
  56. # include    <ToolUtils.h>
  57. # include    <Fonts.h>
  58. # include    <Desk.h>
  59. #else
  60. # ifdef        supportDialogs
  61. #    include    <DialogMgr.h>
  62. # else
  63. #    include    <WindowMgr.h>
  64. # endif
  65.  
  66. # include    <EventMgr.h>
  67. # include    <MenuMgr.h>
  68. #endif MPWC
  69.  
  70.  
  71. # define    nil            0L
  72. # define    mBarHeight    20    /* menu bar height.  All window sizing
  73.                                code takes this into account */
  74.  
  75.  
  76. /*
  77.     This window zooming stuff may need to be removed if/when Think
  78.     supports it in the compiler.
  79. */
  80.  
  81. #ifdef DODO
  82. pascal short    TrackBox() = 0xa83b;    /* declare traps */
  83. pascal void        ZoomWindow() = 0xa83a;
  84. #endif DODO
  85.  
  86. /* enum */                                    /* declare part codes */
  87. /* {
  88.     inZoomIn = 7,
  89.     inZoomOut
  90. }; */
  91.  
  92.  
  93.  
  94. /*
  95.     New(TypeName) returns handle to new object, for any TypeName.
  96.     If there is insufficient memory, the result is nil.
  97. */
  98.  
  99. # define    New(x)    (x **) NewHandle ((Size) sizeof (x))
  100.  
  101.  
  102. /*
  103.     Window and Menu handler types, constants, variables.
  104.  
  105.     whList and mhList are the lists of window and menu handlers.
  106.     whClobOnRmve and mhClobOnRmve are true if the handler disposal proc
  107.     is to be called when a handler is removed.  They are temporarily set
  108.     false when handlers are installed for windows or menus that already
  109.     have handlers - the old handler is removed WITHOUT calling the
  110.     disposal proc.
  111.  
  112.     Default lower limits on window sizing of 80 pixels both directions is
  113.     sufficient to allow text windows room to draw a grow box and scroll
  114.     bars without having the thumb and arrows overlap.  These values may
  115.     be changed if such a constraint is undesirable with SkelGrowBounds.
  116.     Default upper limits are for the Macintosh, not the Lisa, but are set
  117.     per machine in SkelInit.
  118. */
  119.  
  120. typedef struct WHandler
  121. {
  122.     WindowPtr    whWind;            /* window/dialog to be handled  */
  123.     ProcPtr        whClobber;        /* data structure disposal proc */
  124.     ProcPtr        whMouse;        /* mouse-click handler proc     */
  125.     ProcPtr        whKey;            /* key-click handler proc       */
  126.     ProcPtr        whUpdate;        /* update handler proc          */
  127.     ProcPtr        whActivate;        /* activate event handler proc  */
  128.     ProcPtr        whClose;        /* close "event" handler proc   */
  129.     ProcPtr        whIdle;            /* main loop proc               */
  130. # ifdef    supportDialogs
  131.     ProcPtr        whEvent;        /* event proc                   */
  132. # endif
  133.     Rect        whGrow;            /* limits on window sizing      */
  134.     Boolean        whSized;        /* true = window was resized    */
  135.     Boolean        whFrontOnly;    /* true = idle only when active */
  136.     struct WHandler    **whNext;    /* next window handler          */
  137. } WHandler;
  138.  
  139. static WHandler    **whList = nil;
  140. static Boolean    whClobOnRmve = true;
  141. static Rect        growRect = { 80, 80, 512, 342 - mBarHeight };
  142.  
  143.  
  144. typedef struct MHandler
  145. {
  146.     int                mhID;            /* menu id                     */
  147.     ProcPtr            mhSelect;        /* item selection handler proc */
  148.     ProcPtr            mhClobber;        /* menu disposal handler proc  */
  149.     ProcPtr            mhUpdate;        /* menu update handler, L. Tierney */
  150.     struct MHandler    **mhNext;        /* next menu handler           */
  151. } MHandler;
  152.  
  153.  
  154. static MHandler    **mhList = nil;            /* list of menu handlers */
  155. static Boolean    mhClobOnRmve = true;
  156.  
  157.  
  158. /*
  159.     Variables for default Apple menu handler.  appleID is set to 1 if
  160.     SkelApple is called and is the id of the Apple menu, appleAboutProc
  161.     is the procedure to execute if there is an About... item and it's
  162.     chosen from the Apple menu.  If doAbout is true, then the menu
  163.     contains the About... item, otherwise it's just desk accessories.
  164. */
  165.  
  166. static MenuHandle    appleMenu;
  167. static int            appleID = 0;
  168. static ProcPtr        appleAboutProc = nil;
  169. static Boolean        doAbout = false;
  170.  
  171.  
  172. /*
  173.     Miscellaneous
  174.  
  175.     screenPort points to the window manager port.
  176.     
  177.     doneFlag determines when SkelMain returns.  It is set by calling
  178.     SkelWhoa(), which the host does to request a halt.
  179.  
  180.     pBkgnd points to a background procedure, to be run during event
  181.     processing.  Set it with SkelBackground.  If nil, there's no
  182.     procedure.
  183.  
  184.     pEvent points to an event-inspecting hook, to be run whenever an
  185.     event occurs.  Set it with SkelEventHook.  If nil, there's no
  186.     procedure.
  187.  
  188.     eventMask controls the event types requested in the GetNextEvent
  189.     call in SkelMain.
  190.  
  191.     diskInitPt is the location at which the disk initialization dialog
  192.     appears, if an uninitialized disk is inserted.
  193. */
  194.  
  195. static GrafPtr    screenPort;
  196. static int        doneFlag = false;
  197. static ProcPtr    pBkgnd = nil;
  198. static Boolean    (*pEvent)() = nil;
  199. static int        eventMask = everyEvent;
  200. static Point    diskInitPt = { /* v = */ 120, /* h = */ 100 };
  201.  
  202. # ifdef    supportDialogs
  203.  
  204. /*
  205.     Events that are passed to dialogs.  Others are ignored.
  206.     Standard mask passes , mousedown, keydown, autokey, update,
  207.     activate and null events.  Null events are controlled by bit 0.
  208. */
  209.  
  210. static int    dlogEventMask = 0x16b;
  211.  
  212. # endif
  213.  
  214.  
  215. /* -------------------------------------------------------------------- */
  216. /*                        Internal (private) Routines                        */
  217. /* -------------------------------------------------------------------- */
  218.  
  219.  
  220. /*
  221.     Get handler associated with user or dialog window.
  222.     Return nil if window doesn't belong to any known handler.
  223.     This routine is absolutely fundamental to TransSkel.
  224. */
  225.  
  226.  
  227. static WHandler **GetWDHandler (theWind)
  228. WindowPtr    theWind;
  229. {
  230. register WHandler    **h;
  231.  
  232.     for (h = whList; h != nil; h = (**h).whNext)
  233.     {
  234.         if ((**h).whWind == theWind)
  235.             return (h);
  236.     }
  237.     return (nil);
  238. }
  239.  
  240.  
  241. /*
  242.     Get handler associated with user window.
  243.     Return nil if window doesn't belong to any known handler.
  244.     The order of the two tests is critical:  theWind might be nil.
  245. */
  246.  
  247. static WHandler **GetWHandler (theWind)
  248. WindowPtr    theWind;
  249. {
  250. register WHandler    **h;
  251.  
  252.     if ((h = GetWDHandler (theWind)) != nil
  253.         && ((WindowPeek) theWind)->windowKind != dialogKind)
  254.     {
  255.             return (h);
  256.     }
  257.     return (nil);
  258. }
  259.  
  260.  
  261. # ifdef    supportDialogs
  262.  
  263. /*
  264.     Get handler associated with dialog window.
  265.     Return nil if window doesn't belong to any known handler.
  266.     The order of the two tests is critical:  theDialog might be nil.
  267. */
  268.  
  269. static WHandler **GetDHandler (theDialog)
  270. DialogPtr    theDialog;
  271. {
  272. register WHandler    **h;
  273.  
  274.     if ((h = GetWDHandler (theDialog)) != nil
  275.         && ((WindowPeek) theDialog)->windowKind == dialogKind)
  276.     {
  277.             return (h);
  278.     }
  279.     return (nil);
  280. }
  281.  
  282. # endif
  283.  
  284.  
  285. /*
  286.     General menu-handler.  Just passes selection to the handler's
  287.     select routine.  If the select routine is nil, selecting items from
  288.     the menu is a nop.
  289. */
  290.  
  291. static DoMenuCommand (command)
  292. long        command;
  293. {
  294. register int        menu;
  295. register int        item;
  296. register MHandler    **mh;
  297. register ProcPtr    p;
  298.  
  299.     menu = HiWord (command);
  300.     item = LoWord (command);
  301.     for (mh = mhList; mh != nil; mh = (**mh).mhNext)
  302.     {
  303.         if ((menu == (**mh).mhID) && ((p = (**mh).mhSelect) != nil))
  304.         {
  305.             (*p) (item, menu);/* menu argument added, L. Tierney */
  306.             break;
  307.         }
  308.     }
  309.     HiliteMenu (0);        /* command done, turn off menu hiliting */
  310. }
  311.  
  312.  
  313. /*
  314.     Apple menu handler
  315.     
  316.     DoAppleItem:  If the first item was chosen, and there's an "About..."
  317.     item, call the procedure associated with it (if not nil).  If there
  318.     is no "About..." item or the item was not the first one, then open
  319.     the associated desk accessory.  The port is saved and restored
  320.     because OpenDeskAcc does not always preserve it correctly.
  321.     
  322.     DoAppleClobber disposes of the Apple menu.
  323. */
  324.  
  325.  
  326. static DoAppleItem (item)
  327. int        item;
  328. {
  329. GrafPtr        curPort;
  330. Str255        str;
  331.  
  332.     if (doAbout && item == 1)
  333.     {
  334.         if (appleAboutProc != nil)
  335.             (*appleAboutProc) ();
  336.     }
  337.     else
  338.     {
  339.         GetPort (&curPort);
  340.         GetItem (appleMenu, item, str);        /* get DA name */
  341.         (void) OpenDeskAcc (str);            /* open it */
  342.         SetPort (curPort);
  343.     }
  344. }
  345.  
  346. static DoAppleClobber () { DisposeMenu (appleMenu); }
  347.  
  348.  
  349. /* -------------------------------------------------------------------- */
  350. /*                        Window-handler routing routines                    */
  351. /*                                                                        */
  352. /*    Each routine sets the port to the handler's window before executing    */
  353. /*    the handler procedure.                                                */
  354. /* -------------------------------------------------------------------- */
  355.  
  356.  
  357. /*
  358.     Pass local mouse coordinates, click time, and the modifiers flag
  359.     word to the handler.
  360. */
  361.  
  362. static DoMouse (h, theEvent)
  363. WHandler    **h;
  364. EventRecord    *theEvent;
  365.  
  366. {
  367. register ProcPtr    p;
  368. Point                thePt;
  369.  
  370.     if (h != nil)
  371.     {
  372.         SetPort ((**h).whWind);
  373.         if ((p = (**h).whMouse) != nil)
  374.         {
  375.             thePt = theEvent->where;    /* make local copy */
  376.             GlobalToLocal (&thePt);
  377.             (*p) (thePt, theEvent->when, theEvent->modifiers);
  378.         }
  379.     }
  380. }
  381.  
  382.  
  383. /*
  384.     Pass the character and the modifiers flag word to the handler.
  385. */
  386.  
  387. static DoKey (h, ch, mods)
  388. WHandler    **h;
  389. char        ch;
  390. int            mods;
  391. {
  392. register ProcPtr    p;
  393.  
  394.     if (h != nil)
  395.     {
  396.         SetPort ((**h).whWind);
  397.         if ((p = (**h).whKey) != nil)
  398.             (*p) (ch, mods);
  399.     }
  400. }
  401.  
  402.  
  403. /*
  404.     Call the window updating procedure, passing to it an indicator whether
  405.     the window has been resized or not.  Then clear the flag, assuming
  406.     the update proc took whatever action was necessary to respond to
  407.     resizing.
  408.  
  409.     If the handler doesn't have any update proc, the Begin/EndUpdate
  410.     stuff is still done, to clear the update region.  Otherwise the
  411.     Window Manager will keep generating update events for the window,
  412.     stalling updates of other windows.
  413.  
  414.     Make sure to save and restore the port, as it's not always the
  415.     active window that is updated.
  416. */
  417.  
  418. static DoUpdate (h)
  419. WHandler    **h;
  420.  
  421. {
  422. register WHandler    **rh;
  423. register ProcPtr    p;
  424. register GrafPtr    updPort;
  425. GrafPtr                tmpPort;
  426.  
  427.     if ((rh = h) != nil)
  428.     {
  429.         GetPort (&tmpPort);
  430.         SetPort (updPort = (**rh).whWind);
  431.         BeginUpdate (updPort);
  432.         if ((p = (**rh).whUpdate) != nil)
  433.         {
  434.             (*p) ((**rh).whSized);
  435.             (**rh).whSized = false;
  436.         }
  437.         EndUpdate (updPort);
  438.         SetPort (tmpPort);
  439.     }
  440. }
  441.  
  442.  
  443. /*
  444.     Pass activate/deactivate notification to handler.
  445. */
  446.  
  447. static DoActivate (h, active)
  448. WHandler    **h;
  449. Boolean        active;
  450.  
  451. {
  452. register ProcPtr    p;
  453.  
  454.     if ((h != nil) && ((p = (**h).whActivate) != nil))
  455.     {
  456.         SetPort ((**h).whWind);
  457.         (*p) (active);
  458.     }
  459. }
  460.  
  461.  
  462. /*
  463.     Execute a window handler's close proc.  This may be used by handlers
  464.     for temp windows that want to remove themselves when the window
  465.     is closed:  they can call SkelRmveWind to dispose of the window
  466.     and remove the handler from the window handler list.  Thus, windows
  467.     may be dynamically created and destroyed without filling up the
  468.     handler list with a bunch of invalid handlers.
  469.     
  470.     If the handler doesn't have a close proc, just hide the window.
  471.     The host should provide some way of reopening the window (perhaps
  472.     a menu selection).  Otherwise the window will be lost from user
  473.     control if it is hidden, since it won't receive user events.
  474.  
  475.     The port is set to the window manager port after calling the
  476.     handler proc, to avoid a dangling port.
  477.  
  478.     This is called both for regular and dialog windows.
  479. */
  480.  
  481. static DoClose (h)
  482. WHandler    **h;
  483. {
  484. register WHandler    **rh;
  485. register ProcPtr    p;
  486.  
  487.     if ((rh = h) != nil)
  488.     {
  489.         SetPort ((**rh).whWind);
  490.         if ((p = (**rh).whClose) != nil)
  491.             (*p) ();
  492.         else
  493.             HideWindow ((**rh).whWind);
  494.         SetPort (screenPort);
  495.     }
  496. }
  497.  
  498.  
  499. /*
  500.     Execute a window handler's clobber proc.
  501.  
  502.     The port is set to the window manager port after calling the
  503.     handler proc, to avoid a dangling port.
  504.  
  505.     This is called both for regular and dialog windows.
  506. */
  507.  
  508. static DoClobber (h)
  509. WHandler    **h;
  510. {
  511. register ProcPtr    p;
  512.  
  513.     if (h != nil)
  514.     {
  515.         SetPort ((**h).whWind);
  516.         if ((p = (**h).whClobber) != nil)
  517.             (*p) ();
  518.         SetPort (screenPort);
  519.     }
  520. }
  521.  
  522.  
  523. /*
  524.     Execute handler's idle proc.
  525.  
  526.     Make sure to save and restore the port, since idle procs may be
  527.     called for any window, not just the active one.
  528. */
  529.  
  530. static DoIdle (h)
  531. WHandler    **h;
  532. {
  533. register ProcPtr    p;
  534. GrafPtr                tmpPort;
  535.  
  536.     if (h != nil)
  537.     {
  538.         GetPort (&tmpPort);
  539.         SetPort ((**h).whWind);
  540.         if ((p = (**h).whIdle) != nil)
  541.             (*p) ();
  542.         SetPort (tmpPort);
  543.     }
  544. }
  545.  
  546.  
  547. # ifdef    supportDialogs
  548.  
  549. /* -------------------------------------------------------------------- */
  550. /*                            Dialog-handling routines                    */
  551. /* -------------------------------------------------------------------- */
  552.  
  553.  
  554. /*
  555.     Handle event if it's for a dialog.  The event must be one of
  556.     those that is passed to dialogs according to dlogEventMask.
  557.     This mask can be set so that disk-inserts, for instance, don't
  558.     get eaten up.
  559. */
  560.  
  561. static DoDialog (theEvent)
  562. EventRecord        *theEvent;
  563. {
  564. register WHandler    **dh;
  565. DialogPtr            theDialog;
  566. register int        what;
  567. short                item;
  568. GrafPtr                tmpPort;
  569.  
  570. /*
  571.     handle command keys before they get to IsDialogEvent
  572. */
  573.  
  574.     what = theEvent->what;
  575.     if((what == keyDown || what == autoKey) && (theEvent->modifiers & cmdKey))
  576.     {
  577.            DoMenuCommand (MenuKey (theEvent->message & charCodeMask));
  578.            return (true);
  579.     }
  580.     
  581.     if(((1 << what) & dlogEventMask) && IsDialogEvent (theEvent))
  582.     {
  583.         
  584.         if (DialogSelect (theEvent, &theDialog, &item)
  585.            && (dh = GetDHandler (theDialog)) != nil
  586.            && (**dh).whEvent != nil)
  587.         {
  588.             GetPort (&tmpPort);
  589.             SetPort (theDialog);
  590.             (*(**dh).whEvent) (item, theEvent);
  591.             SetPort (tmpPort);
  592.         }
  593.         else if (theEvent->what == activateEvt) { /* L. Tierney */
  594.           GetPort (&tmpPort);
  595.           SetPort (theDialog);
  596.           activateDialog((theEvent->modifiers & activeFlag) != 0);
  597.           SetPort (tmpPort);
  598.         }
  599.         return (true);
  600.     }
  601.     return (false);
  602. }
  603.  
  604. # endif
  605.  
  606.  
  607. /* -------------------------------------------------------------------- */
  608. /*                            Event-handling routines                        */
  609. /* -------------------------------------------------------------------- */
  610.  
  611.  
  612. /*
  613.     Have either sized or zoomed the window.  Invalidate it to force
  614.     an update and set the 'resized' flag in the window handler true.
  615. */
  616.  
  617. static TriggerUpdate (h, thePort)
  618. WHandler    **h;
  619. GrafPtr        thePort;
  620. {
  621.     SetPort (thePort);
  622.     InvalRect (&thePort->portRect);
  623.     if (h != nil)
  624.         (**h).whSized = true;
  625. }
  626.  
  627.  
  628. /*
  629.     Size a window.  If the window has a handler, use the grow limits
  630.     in the handler record, otherwise use the defaults.
  631.  
  632.     The portRect is invalidated to force an update event.  (The port
  633.     must be set first, as it could be pointing anywhere.)  The handler's
  634.     update procedure should check the parameter passed to it to check
  635.     whether the window has changed size, if it needs to adjust itself to
  636.     the new size.  THIS IS A CONVENTION.  Update procs must notice grow
  637.     "events", there is no procedure specifically for such events.
  638.     
  639.     The clipping rectangle is not reset.  If the host application
  640.     keeps the clipping set equal to the portRect or something similar,
  641.     then it will have to arrange to treat window growing with more
  642.     care.
  643. */
  644.  
  645. static DoGrow (h, thePort, startPt)
  646. WHandler    **h;
  647. GrafPtr        thePort;
  648. Point        startPt;
  649. {
  650. Rect                r;
  651. register long        growRes;
  652.  
  653.     if (h != nil)
  654.         r = (**h).whGrow;
  655.     else
  656.         r = growRect;    /* use default */
  657.  
  658.     /* grow result non-zero if size change    */
  659.  
  660.     if (growRes = GrowWindow (thePort, startPt, &r))
  661.     {
  662.         SizeWindow (thePort, LoWord (growRes), HiWord (growRes), false);
  663.         TriggerUpdate (h, thePort);
  664.     }
  665. }
  666.  
  667.  
  668. /*
  669.     Zoom the current window.  Very similar to DoGrow
  670. */
  671.  
  672. DoZoom (h, thePort, partCode)
  673. register WHandler    **h;
  674. GrafPtr                thePort;
  675. short                partCode;
  676. {
  677.     ZoomWindow (thePort, partCode, 0);
  678.     TriggerUpdate (h, thePort);
  679. }
  680.  
  681.  
  682. /*
  683.     General event handler
  684. */
  685.  
  686. static DoEvent (theEvt)
  687. EventRecord    *theEvt;
  688.  
  689. {
  690. register EventRecord    *theEvent;
  691. Point                    evtPt;
  692. GrafPtr                    evtPort;
  693. register int            evtPart;
  694. register char            evtChar;
  695. register int            evtMods;
  696. register WHandler        **h;
  697. Rect                    r;
  698.  
  699.     theEvent = theEvt;
  700.  
  701. # ifdef    supportDialogs
  702.  
  703.     if(DoDialog (theEvent))
  704.         return;
  705.  
  706. # endif
  707.  
  708.     evtPt = theEvent->where;
  709.     switch (theEvent->what)
  710.     {
  711.  
  712.         case nullEvent:
  713.             break;
  714. /*
  715.     Mouse click.  Get the window that the click occurred in, and the
  716.     part of the window.
  717. */
  718.         case mouseDown:
  719.         {
  720.             evtPart = FindWindow (evtPt, &evtPort);
  721.             h = GetWHandler (evtPort);
  722.  
  723.             switch (evtPart)
  724.             {
  725. /*
  726.     Click in a desk accessory window.  Pass back to the system.
  727. */
  728.                 case inSysWindow:
  729.                 {
  730.                     SystemClick (theEvent, evtPort);
  731.                     break;
  732.                 }
  733. /*
  734.     Click in menu bar.  Track the mouse and execute selected command,
  735.     if any.
  736. */
  737.                 case inMenuBar:
  738.                 {
  739.                     UpdateMenus(); /* Menu update; L. Tierney */
  740.                     DoMenuCommand (MenuSelect (evtPt));
  741.                     break;
  742.                 }
  743. /*
  744.     Click in grow box.  Resize window.
  745. */
  746.                 case inGrow:
  747.                 {
  748.                     DoGrow (h, evtPort, evtPt);
  749.                     break;
  750.                 }
  751. /*
  752.     Click in title bar.  Drag the window around.  Leave at least
  753.     4 pixels visible in both directions.
  754. */
  755.                 case inDrag:
  756.                 {
  757.                     r = screenPort->portRect;
  758.                     r.top += mBarHeight;            /* skip down past menu bar */
  759.                     InsetRect (&r, 4, 4);
  760.                     DragWindow (evtPort, evtPt, &r);
  761.                     break;
  762.                 }
  763. /*
  764.     Click in close box.  Call the close proc if the window has one.
  765. */
  766.                 case inGoAway:
  767.                 {
  768.                     if (TrackGoAway (evtPort, evtPt))
  769.                         DoClose (GetWDHandler (evtPort));
  770.                     break;
  771.                 }
  772. /*
  773.     Click in content region.  If the window wasn't frontmost (active),
  774.     just select it, otherwise pass the click to the window's mouse
  775.     click handler.
  776. */
  777.                 case inContent:
  778.                 {
  779.                     if (evtPort != FrontWindow ())
  780.                         SelectWindow (evtPort);
  781.                     else
  782.                         DoMouse (h, theEvent);
  783.                     break;
  784.                 }
  785.  
  786. /*
  787.     Click in zoom box.  Track the click and then zoom the window if
  788.     necessary
  789. */
  790.                 case inZoomIn:
  791.                 case inZoomOut:
  792.                 {
  793.                     if(TrackBox(evtPort, evtPt, evtPart))
  794.                         DoZoom (h, evtPort, evtPart);
  795.                     break;
  796.                 }
  797.  
  798.             }
  799.             break;    /* mouseDown */
  800.         }
  801. /*
  802.     Key event.  If the command key was down, process as menu item
  803.     selection, otherwise pass the character and the modifiers flags
  804.     to the active window's key handler.
  805.  
  806.     If dialogs are supported, there's no check for command-key
  807.     equivalents, since that would have been checked in DoDialog.
  808. */
  809.         case keyDown:
  810.         case autoKey:
  811.         {
  812.             evtChar = theEvent->message & charCodeMask;
  813.             evtMods = theEvent->modifiers;
  814.  
  815. # ifndef    supportDialogs
  816.             if (evtMods & cmdKey)        /* try menu equivalent */
  817.             {
  818.                 DoMenuCommand (MenuKey (evtChar));
  819.                 break;
  820.             }
  821.  
  822. # endif
  823.  
  824.             DoKey (GetWHandler (FrontWindow ()), evtChar, evtMods);
  825.             break;
  826.         }
  827. /*
  828.     Update a window.
  829. */
  830.         case updateEvt:
  831.         {
  832.             DoUpdate (GetWHandler ((WindowPtr) theEvent->message));
  833.             break;
  834.         }
  835. /*
  836.     Activate or deactivate a window.
  837. */
  838.         case activateEvt:
  839.         {
  840.             DoActivate (GetWHandler ((WindowPtr) theEvent->message),
  841.                         ((theEvent->modifiers & activeFlag) != 0));
  842.             break;
  843.         }
  844. /*
  845.     handle inserts of uninitialized disks
  846. */
  847.         case diskEvt:
  848.         {
  849.             if (HiWord (theEvent->message) != noErr)
  850.             {
  851.                 DILoad ();
  852.                 (void) DIBadMount (diskInitPt, theEvent->message);
  853.                 DIUnload ();
  854.             }
  855.             break;
  856.         }
  857.     }
  858. }
  859.  
  860. /* menu updating on click in menu bar, added L. Tierney */
  861. static UpdateMenus()
  862.   MHandler **mh;
  863.   ProcPtr p;
  864.   
  865.   for (mh = mhList; mh != nil; mh = (*mh)->mhNext)
  866.     if ((p = (*mh)->mhUpdate) != nil) (*p)((*mh)->mhID);
  867. }
  868.  
  869. /* -------------------------------------------------------------------- */
  870. /*                        Interface (public) Routines                        */
  871. /* -------------------------------------------------------------------- */
  872.  
  873.  
  874. /*
  875.     Initialize the various Macintosh Managers.
  876.     Set default upper limits on window sizing.
  877.     FlushEvents does NOT toss disk insert events, so that disks
  878.     inserted while the application is starting up don't result
  879.     in dead drives.
  880. */
  881.  
  882. SkelInit ()
  883. {
  884.     MaxApplZone ();
  885.     FlushEvents (everyEvent - diskMask, 0 );
  886. #ifdef MPWC
  887.     InitGraf (&(qd.thePort));
  888. #else
  889.     InitGraf (&thePort);
  890. #endif MPWC    
  891.     InitFonts ();
  892.     InitWindows ();
  893.     InitMenus ();
  894.     TEInit ();
  895.     InitDialogs (nil);        /* no restart proc */
  896.     InitCursor ();
  897. /*
  898.     Set upper limits of window sizing to machine screen size.  Allow
  899.     for the menu bar.
  900. */
  901.     GetWMgrPort (&screenPort);
  902.     growRect.right = screenPort->portRect.right;
  903.     growRect.bottom = screenPort->portRect.bottom - mBarHeight;
  904. }
  905.  
  906.  
  907. /*
  908.     Main loop.
  909.  
  910.     Task care of DA's with SystemTask.
  911.     Run background task if there is one.
  912.     If there is an event, check for an event hook.  If there isn't
  913.     one defined, or if there is but it returns false, call the
  914.     general event handler.  (Hook returns true if TransSkel should
  915.     ignore the event.)
  916.     If no event, call the "no-event" handler for the front window and for
  917.     any other windows with idle procedures that are always supposed
  918.     to run.  This is done in such a way that it is safe for idle procs
  919.     to remove the handler for their own window if they want (unlikely,
  920.     but...)  This loop doesn't check whether the window is really
  921.     a dialog window or not, but it doesn't have to, because such
  922.     things always have a nil idle proc.
  923.     
  924.     doneFlag is reset upon exit.  This allows it to be called
  925.     repeatedly, or recursively.
  926.  
  927.     If dialogs are supported, null events are looked at (in SkelMain)
  928.     and passed to the event handler.  This is necessary to make sure
  929.     DialogSelect gets called repeatedly, or the caret won't blink if
  930.     a dialog has any editText items.
  931.  
  932.     If an event-inspecting hook is installed, null events are not passed
  933.     to it.
  934. */
  935.  
  936. SkelMain ()
  937. {
  938. EventRecord            theEvent;
  939. register WHandler    **wh, **wh2;
  940. register WindowPtr    w;
  941. Boolean                haveEvent;
  942.  
  943.     while (!doneFlag)
  944.     {    
  945.         SystemTask ();
  946.         if (pBkgnd != nil)
  947.             (*pBkgnd) ();
  948.  
  949.         haveEvent = GetNextEvent (eventMask, &theEvent);
  950.  
  951. /*        if (pEvent == nil || (haveEvent && (*pEvent) (&theEvent) == false))
  952.             DoEvent(&theEvent);*/
  953.         if (haveEvent
  954.             && (pEvent == nil || (*pEvent) (&theEvent) == false))
  955.             DoEvent(&theEvent);
  956.  
  957.         if (!haveEvent)
  958.         {
  959.             for (wh = whList; wh != nil; wh = wh2)
  960.             {
  961.                 wh2 = (**wh).whNext;
  962.                 w = (**wh).whWind;
  963.                 if ( (w == FrontWindow () || !(**wh).whFrontOnly ) )
  964.                 {
  965.                     SystemTask ();
  966.                     DoIdle (wh);
  967.                 }
  968.             }
  969.         }
  970.     }
  971.     doneFlag = false;
  972. }
  973.  
  974.  
  975. /*
  976.     Tell SkelMain to stop
  977. */
  978.  
  979. SkelWhoa () { doneFlag = true; }
  980.  
  981.  
  982. /*
  983.     Clobber all the menu, window and dialog handlers
  984. */
  985.  
  986. SkelClobber ()
  987. {
  988.     while (whList != nil)
  989.         SkelRmveWind ((**whList).whWind);
  990.  
  991.     while (mhList != nil)
  992.         SkelRmveMenu (GetMHandle((**mhList).mhID));
  993. }
  994.  
  995.  
  996. /* -------------------------------------------------------------------- */
  997. /*                        Menu-handler interface routines                    */
  998. /* -------------------------------------------------------------------- */
  999.  
  1000.  
  1001. /*
  1002.     Install handler for a menu.  Remove any previous handler for it.
  1003.     Pass the following parameters:
  1004.  
  1005.     theMenu    Handle to the menu to be handled.  Must be created by host.
  1006.     pSelect    Proc that handles selection of items from menu.  If this is
  1007.             nil, the menu is installed, but nothing happens when items
  1008.             are selected from it.
  1009.     pClobber Proc for disposal of handler's data structures.  Usually
  1010.             nil for menus that remain in menu bar until program
  1011.             termination.
  1012.     
  1013.     The menu is installed and drawn in the menu bar.
  1014. */
  1015. /* update added, L. TIerney */
  1016. SkelMenu (theMenu, pSelect, pClobber)
  1017. MenuHandle    theMenu;
  1018. ProcPtr        pSelect;
  1019. ProcPtr        pClobber;
  1020. {
  1021. register MHandler    **mh;
  1022.  
  1023.     mhClobOnRmve = false;
  1024.     SkelRmveMenu (theMenu);
  1025.     mhClobOnRmve = true;
  1026.  
  1027.     mh = New (MHandler);
  1028.     (**mh).mhNext = mhList;
  1029.     mhList = mh;
  1030.     (**mh).mhID = (**theMenu).menuID;    /* get menu id number */
  1031.     (**mh).mhSelect = pSelect;            /* install selection handler */
  1032.     (**mh).mhClobber = pClobber;        /* install disposal handler */
  1033.     (**mh).mhUpdate = nil;
  1034.     InsertMenu (theMenu, 0);            /* put menu at end of menu bar */
  1035.     DrawMenuBar ();
  1036. }
  1037.  
  1038. /* install menu update handler; L. Tierney */
  1039. SkelMenuUpdateProc(theMenu, pUpdate)
  1040.     MenuHandle theMenu;
  1041.     ProcPtr pUpdate;
  1042. {
  1043.   MHandler **mh;
  1044.   
  1045.   for (mh = mhList; mh != nil; mh = (**mh).mhNext)
  1046.     if ((**mh).mhID == (**theMenu).menuID) {
  1047.       (**mh).mhUpdate = pUpdate;
  1048.       break;
  1049.     }
  1050. }
  1051.     
  1052. /*
  1053.     Remove a menu handler.  This calls the handler's disposal routine
  1054.     and then takes the handler out of the handler list and disposes
  1055.     of it.
  1056.  
  1057.     Note that the menu MUST be deleted from the menu bar before calling
  1058.     the clobber proc, because the menu bar will end up filled with
  1059.     garbage if the menu was allocated with NewMenu (see discussion of
  1060.     DisposeMenu in Menu Manager section of Inside Macintosh).
  1061. */
  1062.  
  1063. SkelRmveMenu (theMenu)
  1064. MenuHandle    theMenu;
  1065. {
  1066. register int        mID;
  1067. register MHandler    **h, **h2;
  1068. register ProcPtr    p;
  1069.  
  1070.     mID = (**theMenu).menuID;
  1071.     if (mhList != nil)                /* if list empty, ignore */
  1072.     {
  1073.         if ((**mhList).mhID == mID)    /* is it the first element? */
  1074.         {
  1075.             h2 = mhList;
  1076.             mhList = (**mhList).mhNext;
  1077.         }
  1078.         else
  1079.         {
  1080.             for (h = mhList; h != nil; h = h2)
  1081.             {
  1082.                 h2 = (**h).mhNext;
  1083.                 if (h2 == nil)
  1084.                     return;                        /* menu not in list! */
  1085.                 if ((**h2).mhID == mID)            /* found it */
  1086.                 {
  1087.                     (**h).mhNext = (**h2).mhNext;
  1088.                     break;
  1089.                 }
  1090.             }
  1091.         }
  1092.         DeleteMenu (mID);
  1093.         DrawMenuBar ();
  1094.         if (mhClobOnRmve && (p = (**h2).mhClobber) != nil)
  1095.             (*p) (theMenu);                /* call disposal routine */
  1096.         DisposHandle ((Handle) h2);                /* get rid of handler record */
  1097.     }
  1098. }
  1099.  
  1100.  
  1101. /*
  1102.     Install a handler for the Apple menu.
  1103.     
  1104.     SkelApple is called if TransSkel is supposed to handle the apple
  1105.     menu itself.  The title is the title of the first item.  If nil,
  1106.     then only desk accessories are put into the menu.  If not nil, then
  1107.     the title is entered as the first item, followed by a gray line,
  1108.     then the desk accessories.
  1109. */
  1110.  
  1111. SkelApple (aboutTitle, aboutProc)
  1112. StringPtr    aboutTitle;
  1113. ProcPtr        aboutProc;
  1114. {
  1115. Str255    appleTitle;
  1116.  
  1117.     appleTitle[0] = 1;        /* build apple menu title */
  1118.     appleTitle[1] = 0x14;    /* "apple" character */
  1119.     appleID = 1;
  1120.     appleMenu = NewMenu (appleID, appleTitle);
  1121.     if (aboutTitle != nil)
  1122.     {
  1123.         doAbout = true;
  1124.         AppendMenu (appleMenu, aboutTitle);    /* add About... item title */
  1125.         AppendMenu (appleMenu, "\p(-");        /* add gray line */
  1126.         appleAboutProc = aboutProc;
  1127.     }
  1128.     AddResMenu (appleMenu, 'DRVR');        /* add desk accessories */
  1129.     SkelMenu (appleMenu, DoAppleItem, DoAppleClobber);
  1130. }
  1131.  
  1132.  
  1133. /* -------------------------------------------------------------------- */
  1134. /*                    Window-handler interface routines                    */
  1135. /* -------------------------------------------------------------------- */
  1136.  
  1137.  
  1138. /*
  1139.     Install handler for a window.  Remove any previous handler for it.
  1140.     Pass the following parameters:
  1141.  
  1142.     theWind    Pointer to the window to be handled.  Must be created by host.
  1143.     pMouse    Proc to handle mouse clicks in window.  The proc will be
  1144.             passed the point (in local coordinates), the time of the
  1145.             click, and the modifier flags word.
  1146.     pKey    Proc to handle key clicks in window.  The proc will be passed
  1147.             the character and the modifier flags word.
  1148.     pUpdate    Proc for updating window.  TransSkel brackets calls to update
  1149.             procs with calls to BeginUpdate and EndUpdate, so the visRgn
  1150.             is set up correctly.  A flag is passed indicating whether the
  1151.             window was resized or not.  BY CONVENTION, the entire portRect
  1152.             is invalidated when the window is resized.  That way, the
  1153.             handler's update proc can redraw the entire content region
  1154.             without interference from BeginUpdate/EndUpdate.  The flag
  1155.             is set to false after the update proc is called; the
  1156.             assumption is made that it will notice the resizing and
  1157.             respond appropriately.
  1158.     pActivate Proc to execute when window is activated or deactivated.
  1159.             A boolean is passed to it which is true if the window is
  1160.             coming active, false if it's going inactive.
  1161.     pClose    Proc to execute when mouse clicked in close box.  Useful
  1162.             mainly to temp window handlers that want to know when to
  1163.             self-destruct (with SkelRmveWind).
  1164.     pClobber Proc for disposal of handler's data structures
  1165.     pIdle    Proc to execute when no events are pending.
  1166.     frontOnly True if pIdle should execute on no events only when
  1167.             theWind is frontmost, false if executes all the time.  Note
  1168.             that if it always goes, everything else may be slowed down!
  1169.  
  1170.     If a particular procedure is not needed (e.g., key events are
  1171.     not processed by a handler), pass nil in place of the appropriate
  1172.     procedure address.
  1173.  
  1174.     All handler procedures may assume that the port is set correctly
  1175.     at the time they are called.
  1176. */
  1177.  
  1178. SkelWindow (theWind, pMouse, pKey, pUpdate, pActivate, pClose,
  1179.                 pClobber, pIdle, frontOnly)
  1180.  
  1181. WindowPtr    theWind;
  1182. ProcPtr        pMouse, pKey, pUpdate, pActivate, pClose, pClobber, pIdle;
  1183. Boolean        frontOnly;
  1184. {
  1185. register WHandler    **hHand, *hPtr;
  1186.  
  1187.     whClobOnRmve = false;
  1188.     SkelRmveWind (theWind);
  1189.     whClobOnRmve = true;
  1190. /*
  1191.     Get new handler, attach to list of handlers.  It is attached to the
  1192.     beginning of the list, which is simpler; the order is presumably
  1193.     irrelevant to the host, anyway.
  1194. */
  1195.     hHand = New (WHandler);
  1196.     (**hHand).whNext = whList;
  1197.     whList = hHand;
  1198. /*
  1199.     Fill in handler fields
  1200. */
  1201.     hPtr = *hHand;
  1202.     hPtr->whWind = theWind;
  1203.     hPtr->whMouse = pMouse;
  1204.     hPtr->whKey = pKey;
  1205.     hPtr->whUpdate = pUpdate;
  1206.     hPtr->whActivate = pActivate;
  1207.     hPtr->whClose = pClose;
  1208.     hPtr->whClobber = pClobber;
  1209.     hPtr->whIdle = pIdle;
  1210.     hPtr->whFrontOnly = frontOnly;
  1211.     hPtr->whSized = false;
  1212.     hPtr->whGrow = growRect;
  1213.     SetPort (theWind);
  1214. }
  1215.  
  1216.  
  1217. /*
  1218.     Remove a window handler.  This calls the handler's disposal routine
  1219.     and then takes the handler out of the handler list and disposes
  1220.     of it.
  1221.  
  1222.     SkelRmveWind is also called by SkelRmveDlog.
  1223. */
  1224.  
  1225. SkelRmveWind (theWind)
  1226. WindowPtr    theWind;
  1227. {
  1228. register WHandler    **h, **h2;
  1229.  
  1230.     if (whList != nil)        /* if list empty, ignore */
  1231.     {
  1232.         if ((**whList).whWind == theWind)    /* is it the first element? */
  1233.         {
  1234.             h2 = whList;
  1235.             whList = (**whList).whNext;
  1236.         }
  1237.         else
  1238.         {
  1239.             for (h = whList; h != nil; h = h2)
  1240.             {
  1241.                 h2 = (**h).whNext;
  1242.                 if (h2 == nil)
  1243.                     return;                        /* theWind not in list! */
  1244.                 if ((**h2).whWind == theWind)    /* found it */
  1245.                 {
  1246.                     (**h).whNext = (**h2).whNext;
  1247.                     break;
  1248.                 }
  1249.             }
  1250.         }
  1251.         if (whClobOnRmve)
  1252.             DoClobber (h2);        /* call disposal routine */
  1253.         DisposHandle ((Handle) h2);        /* get rid of handler record */
  1254.     }
  1255. }
  1256.  
  1257.  
  1258. # ifdef    supportDialogs
  1259.  
  1260. /* -------------------------------------------------------------------- */
  1261. /*                    Dialog-handler interface routines                    */
  1262. /* -------------------------------------------------------------------- */
  1263.  
  1264.  
  1265. /*
  1266.     Install a dialog handler.  Remove any previous handler for it.
  1267.     SkelDialog calls SkelWindow as a subsidiary to install a window
  1268.     handler, then sets the event procedure on return.
  1269.  
  1270.     Pass the following parameters:
  1271.  
  1272.     theDialog    Pointer to the dialog to be handled.  Must be created
  1273.             by host.
  1274.     pEvent    Event-handling proc for dialog events.
  1275.     pClose    Proc to execute when mouse clicked in close box.  Useful
  1276.             mainly to dialog handlers that want to know when to
  1277.             self-destruct (with SkelRmveDlog).
  1278.     pClobber Proc for disposal of handler's data structures
  1279.  
  1280.     If a particular procedure is not needed, pass nil in place of
  1281.     the appropriate procedure address.
  1282.  
  1283.     All handler procedures may assume that the port is set correctly
  1284.     at the time they are called.
  1285. */
  1286.  
  1287. SkelDialog (theDialog, pEvent, pClose, pClobber)
  1288. DialogPtr    theDialog;
  1289. ProcPtr        pEvent;
  1290. ProcPtr        pClose;
  1291. ProcPtr        pClobber;
  1292. {
  1293.     SkelWindow (theDialog, nil, nil, nil, nil, pClose, pClobber, nil, false);
  1294.     (**GetWDHandler (theDialog)).whEvent = pEvent;
  1295. }
  1296.  
  1297.  
  1298. /*
  1299.     Remove a dialog and its handler
  1300. */
  1301.  
  1302. SkelRmveDlog (theDialog)
  1303. DialogPtr    theDialog;
  1304. {
  1305.     SkelRmveWind (theDialog);
  1306. }
  1307.  
  1308. # endif
  1309.  
  1310.  
  1311. /* -------------------------------------------------------------------- */
  1312. /*                    Miscellaneous interface routines                    */
  1313. /* -------------------------------------------------------------------- */
  1314.  
  1315.  
  1316. /*
  1317.     Override the default sizing limits for a window, or, if theWind
  1318.     is nil, reset the default limits used by SkelWindow.
  1319. */
  1320.  
  1321. SkelGrowBounds (theWind, hLo, vLo, hHi, vHi)
  1322. WindowPtr    theWind;
  1323. int            hLo, vLo, hHi, vHi;
  1324. {
  1325. register WHandler    **h;
  1326. Rect                r;
  1327.  
  1328.     if (theWind == nil)
  1329.         SetRect (&growRect, hLo, vLo, hHi, vHi);
  1330.     else if ((h = GetWHandler (theWind)) != nil)
  1331.     {
  1332.         SetRect (&r, hLo, vLo, hHi, vHi);
  1333.         (**h).whGrow = r;
  1334.     }
  1335. }
  1336.  
  1337.  
  1338. /*
  1339.     Set the event mask.
  1340. */
  1341.  
  1342. SkelEventMask (mask)
  1343. int        mask;
  1344. {
  1345.     eventMask = mask;
  1346. }
  1347.  
  1348.  
  1349. /*
  1350.     Return the event mask.
  1351. */
  1352.  
  1353. SkelGetEventMask (mask)
  1354. int        *mask;
  1355. {
  1356.     *mask = eventMask;
  1357. }
  1358.  
  1359.  
  1360. /*
  1361.     Install a background task.  If p is nil, the current task is
  1362.     disabled.
  1363. */
  1364.  
  1365. SkelBackground (p)
  1366. ProcPtr    p;
  1367. {
  1368.     pBkgnd = p;
  1369. }
  1370.  
  1371.  
  1372. /*
  1373.     Return the current background task.  Return nil if none.
  1374. */
  1375.  
  1376. SkelGetBackground (p)
  1377. ProcPtr    *p;
  1378. {
  1379.     *p = pBkgnd;
  1380. }
  1381.  
  1382.  
  1383. /*
  1384.     Install an event-inspecting hook.  If p is nil, the hook is
  1385.     disabled.
  1386. */
  1387.  
  1388. SkelEventHook (p)
  1389. Boolean    (*p)();
  1390. {
  1391.     pEvent = p;
  1392. }
  1393.  
  1394.  
  1395. /*
  1396.     Return the current event-inspecting hook.  Return nil if none.
  1397. */
  1398.  
  1399. SkelGetEventHook (p)
  1400. Boolean    (**p)();
  1401. {
  1402.     *p = pEvent;
  1403. }
  1404.  
  1405.  
  1406. # ifdef    supportDialogs
  1407.  
  1408. /*
  1409.     Set the mask for event types that will be passed to dialogs.
  1410.     Bit 1 is always set, so that null events will be passed.
  1411. */
  1412.  
  1413. SkelDlogMask (mask)
  1414. int        mask;
  1415. {
  1416.     dlogEventMask = mask | 1;
  1417. }
  1418.  
  1419.  
  1420. /*
  1421.     Return the current dialog event mask.
  1422. */
  1423.  
  1424. SkelGetDlogMask (mask)
  1425. int        *mask;
  1426. {
  1427.     *mask = dlogEventMask;
  1428. }
  1429.  
  1430. # endif
  1431.