home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 15 / BBS in a box XV-2.iso / Files II / Prog / M / MacPerl 4.13 source.sit / Perl Source ƒ / MacPerl / MPMain.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-04  |  21.6 KB  |  1,050 lines  |  [TEXT/MPS ]

  1. /*********************************************************************
  2. Project    :    MacPerl            -    Real Perl Application
  3. File        :    MPMain.c            -    The main event loop
  4. Author    :    Matthias Neeracher
  5.  
  6. A lot of this code is borrowed from 7Edit written by
  7. Apple Developer Support UK
  8.  
  9. Language    :    MPW C
  10.  
  11. $Log: MPMain.c,v $
  12. Revision 1.2  1994/05/04  02:52:40  neeri
  13. Inline Input.
  14.  
  15. Revision 1.1  1994/02/27  23:01:21  neeri
  16. Initial revision
  17.  
  18. Revision 0.9  1993/12/30  00:00:00  neeri
  19. DeferredKeys
  20.  
  21. Revision 0.8  1993/12/20  00:00:00  neeri
  22. Trying to be more subtle about cursors
  23.  
  24. Revision 0.7  1993/12/12  00:00:00  neeri
  25. SacrificialGoat
  26.  
  27. Revision 0.6  1993/10/17  00:00:00  neeri
  28. Mercutio Support
  29.  
  30. Revision 0.5  1993/08/17  00:00:00  neeri
  31. Preferences
  32.  
  33. Revision 0.4  1993/08/16  00:00:00  neeri
  34. Moved scripting to separate file
  35.  
  36. Revision 0.3  1993/07/15  00:00:00  neeri
  37. Beginning to see the light
  38.  
  39. Revision 0.2  1993/05/30  00:00:00  neeri
  40. Support Console Windows
  41.  
  42. Revision 0.1  1993/05/29  00:00:00  neeri
  43. Compiles correctly
  44.  
  45. *********************************************************************/
  46.  
  47. #include <Memory.h>
  48. #include <QuickDraw.h>
  49. #include <Types.h>
  50. #include <Menus.h>
  51. #include <Windows.h>
  52. #include <Dialogs.h>
  53. #include <Traps.h>
  54. #include <Packages.h>
  55. #include <PPCToolbox.h>
  56. #include <Resources.h>
  57. #include <Editions.h>
  58. #include <Printing.h>
  59. #include <ToolUtils.h>
  60. #include <Desk.h>
  61. #include <Scrap.h>
  62. #include <OSEvents.h>
  63. #include <AppleEvents.h>
  64. #include <AEObjects.h>
  65. #include <Errors.h>
  66. #include <StandardFile.h>
  67. #include <Balloons.h>
  68. #include <String.h>
  69. #include <CType.h>
  70. #include <PLStringFuncs.h>
  71. #include <StdLib.h>
  72. #include <CursorCtl.h>
  73. #include <Script.h>
  74.  
  75. #include "MPGlobals.h"
  76. #include "MPUtils.h"
  77. #include "MPEditions.h"
  78. #include "MPAppleEvents.h"
  79. #include "MPWindow.h"
  80. #include "MPFile.h"
  81. #include "MPHelp.h"
  82. #include "MPScript.h"
  83. #include "MPUtils.h"
  84. #include "MPPreferences.h"
  85. #include "Mercutio.h"
  86.  
  87. #define RESOLVE_MAC_CONFLICTS
  88. #include <EXTERN.h>
  89. #include <perl.h>
  90.  
  91. #pragma segment Main
  92.  
  93. pascal void MaintainCursor(Boolean busy)
  94. {
  95.     Point         pt;
  96.     WindowPtr     wPtr;
  97.     GrafPtr       savePort;
  98.     DPtr          theDoc;
  99.     Boolean        inText = false;
  100.  
  101.     if (busy) {
  102.         SpinCursor(1);
  103.         
  104.         return;
  105.     }
  106.     
  107.     wPtr = FrontWindow();
  108.     if (Ours(wPtr)) {
  109.         theDoc = DPtrFromWindowPtr(wPtr);
  110.         GetPort(&savePort);
  111.         SetPort(wPtr);
  112.         GetMouse(&pt);
  113. #ifndef RUNTIME
  114.         if (gTextServicesImplemented && SetTSMCursor(pt))
  115.             return;
  116. #endif
  117.         if (theDoc->theText)
  118.             if (inText = PtInRect(pt, &(**(theDoc->theText)).viewRect))
  119.                 SetCursor(&editCursor);
  120.             else
  121.                 SetCursor(&qd.arrow);
  122.         else
  123.             SetCursor(&qd.arrow);
  124.  
  125.         if (theDoc->theText)
  126.             TEIdle(theDoc->theText);
  127.  
  128. #ifndef RUNTIME
  129.         DoHelp(wPtr, theDoc, pt, inText);
  130. #endif
  131.  
  132.         SetPort(savePort);
  133.     } else if (!wPtr)
  134.         SetCursor(&qd.arrow);
  135. }
  136.  
  137. #pragma segment Main
  138.  
  139. pascal void MaintainMenus(void)
  140. {
  141.     DPtr               theDoc;
  142.     WindowPtr          firstWindow;
  143.     SectHandle         currSection;
  144.     static Boolean    mRunningPerl;
  145.  
  146.     firstWindow = FrontWindow();
  147.     if (!Ours(firstWindow)) {
  148.         EnableItem(myMenus[fileM], fmNew);
  149.         EnableItem(myMenus[fileM], fmOpen);
  150.         DisableItem(myMenus[fileM], fmClose);
  151.         DisableItem(myMenus[fileM], fmSave);
  152.         DisableItem(myMenus[fileM], fmSaveAs);
  153.         DisableItem(myMenus[fileM], fmRevert);
  154.         DisableItem(myMenus[fileM], fmPrint);
  155.         DisableItem(myMenus[fileM], fmPageSetUp);
  156.         EnableItem(myMenus[fileM], fmQuit);
  157.  
  158. #ifndef RUNTIME
  159.         DisableItem(myMenus[editM],  cPublisher);
  160.         DisableItem(myMenus[editM],  cSubscriber);
  161.         DisableItem(myMenus[editM],  cOptions);
  162.         DisableItem(myMenus[editM],  cBorders);
  163.  
  164.         EnableItem(myMenus[helpM], hmExplain);
  165. #endif 
  166.         
  167.         if (gRunningPerl != mRunningPerl)     {
  168.             if (gRunningPerl) 
  169.                 DeleteMenu(perlID);
  170.             else
  171.                 InsertMenu(myMenus[perlM], 0);
  172.             
  173.             mRunningPerl = gRunningPerl;
  174.             
  175.             DrawMenuBar();
  176.         }
  177.  
  178.         if (!mRunningPerl) {
  179.             SetItem(myMenus[perlM], pmRunFront, "\pRun Front Window");
  180.             DisableItem(myMenus[perlM], pmRunFront);
  181.         }
  182.         
  183.         EnableItem(myMenus[editM],  emPreferences);
  184.         
  185.         if (firstWindow) {
  186.             EnableItem(myMenus[editM], undoCommand);
  187.             EnableItem(myMenus[editM], cutCommand);
  188.             EnableItem(myMenus[editM], copyCommand);
  189.             EnableItem(myMenus[editM], pasteCommand);
  190.             EnableItem(myMenus[editM], clearCommand);
  191.         }
  192.     } else {
  193.         theDoc = DPtrFromWindowPtr(firstWindow);
  194.         
  195.         if (theDoc->kind == kDocumentWindow) {
  196.             EnableItem(myMenus[editM], pasteCommand);
  197. #ifndef RUNTIME
  198.             EnableItem(myMenus[editM], cBorders);
  199. #endif
  200.             if (!mRunningPerl) {
  201.                 Str255    title;
  202.                 
  203.                 PLstrcpy(title, "\pRun ");
  204.                 GetWTitle(firstWindow, title+5);
  205.                 title[0]             = title[5] + 6;
  206.                 title[5]              = '"';
  207.                 title[title[0]]    = '"';
  208.                 SetItem(myMenus[perlM], pmRunFront, title);
  209.                 EnableItem(myMenus[perlM], pmRunFront);
  210.             }
  211.         } else {
  212. #ifndef RUNTIME
  213.             DisableItem(myMenus[editM], cBorders);
  214. #endif
  215.             
  216.             if ((*theDoc->theText)->selStart < theDoc->u.cons.fence)
  217.                 DisableItem(myMenus[editM], pasteCommand);
  218.             else
  219.                 EnableItem(myMenus[editM], pasteCommand);
  220.  
  221.             if (!mRunningPerl) {
  222.                 SetItem(myMenus[perlM], pmRunFront, "\pRun Front Window");
  223.                 DisableItem(myMenus[perlM], pmRunFront);
  224.             }
  225.         }
  226.         
  227.         EnableItem(myMenus[fileM], fmClose);
  228.         EnableItem(myMenus[fileM], fmSave);
  229.         EnableItem(myMenus[fileM], fmSaveAs);
  230.         EnableItem(myMenus[fileM], fmPrint);
  231.         EnableItem(myMenus[fileM], fmPageSetUp);
  232.         EnableItem(myMenus[fileM], fmQuit);
  233.  
  234.         if (theDoc->kind == kDocumentWindow && theDoc->dirty)
  235.             EnableItem(myMenus[fileM], fmRevert);
  236.         else
  237.             DisableItem(myMenus[fileM], fmRevert);
  238.  
  239.         DisableItem(myMenus[editM], undoCommand);
  240.  
  241.         if (((**(theDoc->theText)).selEnd - (**(theDoc->theText)).selStart) < 0) {
  242.             DisableItem(myMenus[editM], cutCommand);
  243.             DisableItem(myMenus[editM], copyCommand);
  244.             DisableItem(myMenus[editM], clearCommand);
  245. #ifndef RUNTIME
  246.             DisableItem(myMenus[editM], cPublisher);
  247. #endif
  248.         } else {
  249.             EnableItem(myMenus[editM], cutCommand);
  250.             EnableItem(myMenus[editM], copyCommand);
  251.             EnableItem(myMenus[editM], clearCommand);
  252. #ifndef RUNTIME
  253.             EnableItem(myMenus[editM], cPublisher);
  254. #endif
  255.         }
  256.         
  257.         EnableItem(myMenus[editM],  emPreferences);
  258.  
  259. #ifndef RUNTIME
  260.         currSection =
  261.             GetSection(
  262.                 (**(theDoc->theText)).selStart,
  263.                 (**(theDoc->theText)).selEnd,
  264.                 theDoc);
  265.  
  266.         if (theDoc->kind != kDocumentWindow) {
  267.             DisableItem(myMenus[editM], cPublisher);
  268.             DisableItem(myMenus[editM], cSubscriber);
  269.             DisableItem(myMenus[editM], cOptions);
  270.         } else if (currSection) {
  271.             DisableItem(myMenus[editM], cPublisher);
  272.             DisableItem(myMenus[editM], cSubscriber);
  273.             EnableItem(myMenus[editM],  cOptions);
  274.             if ((**(**currSection).fSectHandle).kind == stPublisher)
  275.                 SetItem(myMenus[editM], cOptions, "\pPublisher Options…");
  276.             else
  277.                 SetItem(myMenus[editM], cOptions, "\pSubscriber Options…");
  278.         } else {
  279.             EnableItem(myMenus[editM],  cPublisher);
  280.             EnableItem(myMenus[editM],  cSubscriber);
  281.             DisableItem(myMenus[editM], cOptions);
  282.         }
  283.         
  284.         EnableItem(myMenus[helpM], hmExplain);
  285. #endif
  286.  
  287.         if (gRunningPerl != mRunningPerl)     {
  288.             if (gRunningPerl) 
  289.                 DeleteMenu(perlID);
  290.             else
  291.                 InsertMenu(myMenus[perlM], 0);
  292.             
  293.             mRunningPerl = gRunningPerl;
  294.             
  295.             DrawMenuBar();
  296.         }
  297.     }
  298. }
  299.  
  300. #pragma segment Main
  301.  
  302. pascal void SetUpCursors(void)
  303. {
  304.     CursHandle  hCurs;
  305.  
  306.     hCurs = GetCursor(1);
  307.     editCursor = **hCurs;
  308.     hCurs = GetCursor(watchCursor);
  309.     waitCursor = **hCurs;
  310. }
  311.  
  312. #pragma segment Main
  313.  
  314. pascal void SetUpMenus(void)
  315. {
  316.     short             i;
  317.     StringHandle    str;
  318.  
  319.     myMenus[appleM] = GetMenu(appleID);
  320.     AddResMenu(myMenus[appleM], 'DRVR');
  321.     myMenus[fileM] = GetMenu(fileID);
  322.     myMenus[editM] = GetMenu(editID);
  323.     myMenus[windowM]    = GetMenu(windowID);
  324.     myMenus[perlM]    = GetMenu(perlID);
  325.  
  326. #ifndef RUNTIME
  327.     for (i = appleM; i < kLastMenu; i++)
  328.         InsertMenu(myMenus[i], 0);
  329.  
  330.     HMGetHelpMenuHandle(&myMenus[helpM]);
  331.     str = GetString(helpID);
  332.     
  333.     HLock((Handle) str);
  334.     AppendMenu(myMenus[helpM], *str);
  335.     ReleaseResource((Handle) str);
  336. #else
  337.     for (i = appleM; i <= kLastMenu; i++)
  338.         InsertMenu(myMenus[i], 0);
  339. #endif
  340.     
  341.     SetShortMenus(); /* Does a DrawMenuBar() */
  342. }
  343.  
  344. pascal void DoFile(short theItem)
  345. {
  346.     short   alertResult;
  347.     DPtr    theDoc;
  348.     FSSpec  theFSSpec;
  349.     OSErr   fileErr;
  350.     TPrint  thePSetup;
  351.  
  352.     switch (theItem){
  353.     case fmNew:
  354.         IssueAENewWindow();
  355.         break;
  356.  
  357.     case fmOpen:
  358.         if (GetFile(&theFSSpec)==noErr)
  359.             fileErr = IssueAEOpenDoc(theFSSpec);
  360.         break;
  361.  
  362.     case fmClose:
  363.         IssueCloseCommand(FrontWindow());
  364.         break;
  365.  
  366.     case fmSave:
  367.     case fmSaveAs:
  368.         theDoc = DPtrFromWindowPtr(FrontWindow());
  369.  
  370.         if (theItem==fmSaveAs || theDoc->kind != kDocumentWindow || !theDoc->u.reg.everSaved) {
  371.             fileErr = GetFileNameToSaveAs(theDoc);
  372.             if (!fileErr)
  373.                 fileErr = IssueSaveCommand(theDoc->theWindow, &theDoc->theFSSpec);
  374.             else if (fileErr != userCanceledErr)    
  375.                 FileError("\perror saving ", theDoc->theFileName);
  376.  
  377.             if (fileErr == noErr)
  378.                 SetWTitle(theDoc->theWindow, theDoc->theFSSpec.name);
  379.         } else
  380.             fileErr = IssueSaveCommand(theDoc->theWindow, nil);
  381.         break;
  382.  
  383.     case fmRevert:
  384.         SetCursor(&qd.arrow);
  385.         theDoc = DPtrFromWindowPtr(FrontWindow());
  386.  
  387.         ParamText(theDoc->theFileName, "", "", "");
  388.         alertResult = Alert(RevertAlert, nil);
  389.         switch (alertResult){
  390.             case aaSave:
  391.                 if (IssueRevertCommand(theDoc->theWindow))
  392.                     FileError("\perror reverting ", theDoc->theFileName);
  393.         }
  394.         break;
  395.  
  396.     case fmPageSetUp:
  397.         theDoc = DPtrFromWindowPtr(FrontWindow());
  398.         if (DoPageSetup(theDoc)) {
  399.              thePSetup = **(theDoc->thePrintSetup);
  400.              IssuePageSetupWindow(theDoc->theWindow, thePSetup);
  401.          }
  402.         break;
  403.  
  404.     case fmPrint:
  405.         IssuePrintWindow(FrontWindow());
  406.          break;
  407.  
  408.     case fmQuit:
  409.         IssueQuitCommand();
  410.         break;
  411.     } /*of switch*/
  412. }
  413.  
  414. #pragma segment Main
  415.  
  416. pascal void DoCommand(long mResult)
  417. {
  418.     short   theItem;
  419.     short   err;
  420.     Str255  name;
  421.     DPtr    theDocument;
  422.  
  423.     if (!mResult)
  424.         return;
  425.  
  426.     theDocument = DPtrFromWindowPtr(FrontWindow());
  427.         
  428. #ifndef RUNTIME
  429.     if (gTextServicesImplemented && TSMMenuSelect(mResult))
  430.         goto done;
  431.     if (theDocument && theDocument->tsmDoc)
  432.         FixTSMDocument(theDocument->tsmDoc);
  433. #endif
  434.  
  435.     theItem = LoWord(mResult);
  436.  
  437.     switch (HiWord(mResult)) {
  438.     case appleID:
  439.         if (theItem == aboutItem) {
  440.             DoAbout();
  441.         } else {
  442.             GetItem(myMenus[appleM], theItem, name);
  443.             err = OpenDeskAcc(name);
  444.             SetPort(FrontWindow());
  445.         }
  446.           break;
  447.  
  448.     case fileID:
  449.         DoFile(theItem);
  450.         break;
  451.  
  452.     case editID:
  453.         SystemEdit(theItem - 1);
  454.  
  455.         switch (theItem) {
  456.         case cutCommand:
  457.             IssueCutCommand(theDocument);
  458.             break;
  459.  
  460.         case copyCommand:
  461.             IssueCopyCommand(theDocument);
  462.             break;
  463.  
  464.         case pasteCommand :
  465.             IssuePasteCommand(theDocument);
  466.             break;
  467.  
  468.         case clearCommand :
  469.             IssueClearCommand(theDocument);
  470.             break;
  471.  
  472.         case selectAllCommand:
  473.             if (theDocument)
  474.                 TESetSelect(0, (**(theDocument->theText)).teLength, theDocument->theText);
  475.             break;
  476.  
  477. #ifndef RUNTIME
  478.         case cPublisher:
  479.             IssueCreatePublisher(theDocument);
  480.             break;
  481.  
  482.         case cSubscriber:
  483.             DoSubscribe(theDocument);
  484.             break;
  485.  
  486.         case cOptions:
  487.             DoSectionOptions(theDocument);
  488.             break;
  489.  
  490.         case cBorders:
  491.             IssueShowBorders(theDocument->theWindow, !theDocument->u.reg.showBorders);
  492.             break;
  493. #endif
  494.  
  495.         case emFormat:
  496.             IssueFormatCommand(theDocument);
  497.             break;
  498.             
  499.         case emPreferences:
  500.             DoPrefDialog();
  501.             break;
  502.         }     /*of switch*/
  503.  
  504.         ShowSelect(theDocument);
  505.          break;
  506.     
  507.     case windowID:
  508.         DoSelectWindow(theItem);
  509.         break;
  510.  
  511.     case perlID:
  512.         DoScriptMenu(theItem);
  513.         break;
  514.  
  515. #ifndef RUNTIME    
  516.     case kHMHelpMenuID:
  517.         Explain(theDocument);
  518.         break;
  519. #endif
  520.     }                 /*of switch*/
  521.  
  522. done:
  523.     HiliteMenu(0);
  524. }
  525.  
  526. #pragma segment Main
  527.  
  528. pascal void DoMouseDown(EventRecord *myEvent)
  529. {
  530.     WindowPtr whichWindow;
  531.     Point     p;
  532.     Rect      dragRect;
  533.  
  534.     p = myEvent->where;
  535.     switch (FindWindow(p, &whichWindow)) {
  536.     case inDesk:
  537.         SysBeep(10);
  538.         break;
  539.  
  540.     case inGoAway:
  541.         if (Ours(whichWindow))
  542.             if (TrackGoAway(whichWindow, p))
  543.                 IssueCloseCommand(whichWindow);
  544.         break;
  545.  
  546.     case inMenuBar:
  547.         SetCursor(&qd.arrow);
  548.         SetupWindowMenu();
  549.         DoCommand(MenuSelect(p));
  550.         HiliteMenu(0);
  551.         break;
  552.  
  553.     case inSysWindow:
  554.         SystemClick(myEvent, whichWindow);
  555.         break;
  556.  
  557.     case inDrag:
  558.         dragRect = qd.screenBits.bounds;
  559.  
  560.         if (Ours(whichWindow)) {
  561.             DragWindow(whichWindow, p, &dragRect);
  562.             /*
  563.                 As rgnBBox may be passed by address
  564.             */
  565.             dragRect = (**((WindowPeek)whichWindow)->strucRgn).rgnBBox;
  566.             /*
  567.                 The windows already there, but still tell
  568.                 the our AppleEvents core about the move in case
  569.                 they want to do anything
  570.             */
  571.             IssueMoveWindow(whichWindow, dragRect);
  572.         }
  573.           break;
  574.  
  575.     case inGrow:
  576.         SetCursor(&qd.arrow);
  577.         if (Ours(whichWindow))
  578.             MyGrowWindow(whichWindow, p);
  579.         break;
  580.  
  581.     case inZoomIn:
  582.         DoZoom(whichWindow, inZoomIn, p);
  583.         break;
  584.  
  585.     case inZoomOut:
  586.         DoZoom(whichWindow, inZoomOut, p);
  587.         break;
  588.  
  589.     case inContent:
  590.         if (whichWindow != FrontWindow())
  591.             SelectWindow(whichWindow);
  592.         else
  593.             if (Ours(whichWindow))
  594.                 DoContent(whichWindow, myEvent);
  595.         break;
  596.     }                 /*of switch*/
  597. }
  598.  
  599. #pragma segment Main
  600.  
  601. pascal long GetSleep(void)
  602. {
  603.     long      sleep;
  604.     WindowPtr theWindow;
  605.     DPtr      theDoc;
  606.  
  607.     sleep = 30;
  608.     if (!gInBackground)
  609.         {
  610.             theWindow = FrontWindow();
  611.             if (theWindow)
  612.                 {
  613.                     theDoc = DPtrFromWindowPtr(theWindow);
  614.                     if ((**(theDoc->theText)).selStart == (**(theDoc->theText)).selEnd)
  615.                         sleep = GetCaretTime();
  616.                 }
  617.         }
  618.     return(sleep);
  619. }                     /*GetSleep*/
  620.  
  621. long FindMenuKey(EventRecord * ev)
  622. {
  623. #ifndef RUNTIME
  624.     /* Work around Help manager bug */
  625.     short    item    =    CountMItems(myMenus[helpM]);
  626.     short    key;
  627.     
  628.     GetItemCmd(myMenus[helpM], item, &key);
  629.     
  630.     if (toupper((char) key) == toupper(ev->message & charCodeMask))
  631.         return (kHMHelpMenuID << 16) | item;
  632.     else
  633. #endif
  634.         return PowerMenuKey(ev->message, ev->modifiers, myMenus[fileM]);
  635. }
  636.  
  637. #pragma segment Main
  638.  
  639. typedef enum {keyOK, keyRetry, keyAbort} KeyStatus;
  640.  
  641. KeyStatus TryKey(DPtr theDoc, char theChar)
  642. {
  643.     switch (theChar) {
  644.     case 0:
  645.     case 1:
  646.     case 2:
  647.     case 4:
  648.     case 5:
  649.     case 6:
  650.     case 7:
  651.     case 10:
  652.     case 11:
  653.     case 12:
  654.     case 14:
  655.     case 15:
  656.     case 16:
  657.     case 17:
  658.     case 18:
  659.     case 19:
  660.     case 20:
  661.     case 21:
  662.     case 22:
  663.     case 23:
  664.     case 24:
  665.     case 25:
  666.     case 26:
  667.     case 27:
  668.         return keyAbort;
  669.         break;
  670.     case ETX:
  671.         theChar = CR;
  672.         
  673.         break;
  674.     default:
  675.         break;
  676.     }
  677.  
  678. #ifndef RUNTIME
  679.     {
  680.         SectHandle  currSection;
  681.         
  682.         /*
  683.             don't allow a subscriber to be changed
  684.         */
  685.         currSection =
  686.             GetSection(
  687.                 (**(theDoc->theText)).selStart,
  688.                 (**(theDoc->theText)).selEnd,
  689.                 theDoc);
  690.     
  691.         if (currSection)
  692.             if ((**(**currSection).fSectHandle).kind == stSubscriber)
  693.                 if (!KeyOKinSubscriber(theChar))
  694.                     return keyAbort;
  695.     }
  696. #endif
  697.  
  698.     if (theDoc->kind == kDocumentWindow) {
  699. #ifndef RUNTIME                    
  700.         DoTEKeySectionRecalc(theDoc, theChar);
  701. #endif
  702.     } else if (theChar == BS) {
  703.         if (AllSelected(theDoc->theText)) {
  704.             if (theDoc->u.cons.fence < 32767)
  705.                 theDoc->u.cons.fence = 0;
  706.         } else if ((*theDoc->theText)->selStart == (*theDoc->theText)->selEnd)
  707.             if ((*theDoc->theText)->selStart-1 < theDoc->u.cons.fence)
  708.                 return keyAbort;
  709.             else if ((*theDoc->theText)->selStart < theDoc->u.cons.fence)
  710.                 return keyAbort;
  711.     } else if (
  712.         (*theDoc->theText)->selStart < theDoc->u.cons.fence &&
  713.         !KeyOKinSubscriber(theChar)
  714.     ) 
  715.         return keyAbort;
  716.     else if (!theDoc->u.cons.selected)
  717.         return keyRetry;
  718.  
  719. #ifndef RUNTIME                    
  720.     AddKeyToTypingBuffer(theDoc, theChar);
  721. #endif
  722.  
  723.     TEKey(theChar, theDoc->theText);
  724.     EnforceMemory(theDoc, theDoc->theText);
  725.     AdjustScrollbars(theDoc, false);
  726.     ShowSelect(theDoc);
  727.  
  728.     theDoc->dirty = true;
  729.     
  730.     return keyOK;
  731. }
  732.  
  733. #ifndef RUNTIME
  734.  
  735. #pragma segment Main
  736.  
  737. static Boolean IntlTSMEvent(EventRecord *event)
  738. {
  739.     short oldFont;
  740.     ScriptCode keyboardScript;
  741.     
  742.     if (qd.thePort != nil)
  743.     {
  744.         oldFont = qd.thePort->txFont;
  745.         keyboardScript = GetSMVariable(smKeyScript);
  746.         if (FontToScript(oldFont) != keyboardScript)
  747.             TextFont(GetScriptVariable(keyboardScript, smScriptAppFond));
  748.     };
  749.     return TSMEvent(event);
  750. }
  751.  
  752. #endif
  753. /* Our cursor/WaitNextEvent strategy */
  754.  
  755. #define BUSY_WAIT            120
  756. #define FRONT_FREQUENCY    30
  757. #define BACK_FREQUENCY  10
  758.  
  759. static long            lastNonBusy = 0;
  760. static long         lastWNE     = 0;
  761. static char            deferredKeys[256];
  762. static short        deferredRd;
  763. static short        deferredWr;
  764. static RgnHandle    mouseRgn;
  765.  
  766. #pragma segment Main
  767.  
  768. pascal void MainEvent(Boolean busy)
  769. {
  770.     DPtr        theDoc;
  771.     char        theChar;
  772.     Boolean     activate;
  773.     Boolean        gotEvent;
  774.     WindowPtr   theWindow;
  775.     long            now;
  776.     EventRecord myEvent;
  777.     Point            mouse;
  778.  
  779.     if (!gSacrificialGoat)        /* Memory trouble */
  780.         if (gRunningPerl)            /* This script has gone too far */
  781.             fatal("Out of memory ! Aborting script for your own good...\n");
  782.         else                            /* We aborted it, now buy a new goat */
  783.             if (!(gSacrificialGoat = NewHandle(SACRIFICE)))
  784.                 exit(0);        /* Save our sorry ass. Shouldn't happen */
  785.     
  786.     now = TickCount();
  787.     if (busy) {
  788.         if (now - lastNonBusy < BUSY_WAIT)
  789.             busy = false;
  790.     } else
  791.         lastNonBusy = now;
  792.     
  793.     if (busy) {
  794.         MaintainCursor(busy);
  795.         
  796.         if (now - lastWNE < (gInBackground ? BACK_FREQUENCY : FRONT_FREQUENCY))
  797.             return;
  798.     } else {
  799.         MaintainCursor(busy);
  800.         MaintainMenus();
  801.     }
  802.     
  803.     lastWNE = now;    
  804.     gGotEof = nil;
  805.     
  806.     if (!gRunningPerl && GetHandleSize((Handle) gWaitingScripts)) {
  807.         AppleEvent * ev    =    (*gWaitingScripts)[0];
  808.         AppleEvent * repl    =    (*gWaitingScripts)[1];
  809.         
  810.         Munger((Handle) gWaitingScripts, 0, nil, 8, (Ptr) -1, 0);
  811.         
  812.         AEResumeTheCurrentEvent(
  813.             ev, repl, (EventHandlerProcPtr) kAEUseStandardDispatch, -1);
  814.     }
  815.     
  816.     if ((theDoc = DPtrFromWindowPtr(FrontWindow())) && theDoc->theText) 
  817.         while (deferredKeys[deferredRd]) {
  818.             switch (TryKey(theDoc, deferredKeys[deferredRd])) {
  819.             case keyOK:
  820.             case keyAbort:
  821.                 deferredKeys[deferredRd] = 0;
  822.                 deferredRd = (deferredRd + 1) & 255;
  823.                 continue;
  824.             }
  825.             break;
  826.         }
  827.  
  828.     if (!(theWindow = FrontWindow()))
  829.         GetWMgrPort(&theWindow);
  830.         
  831.     SetPort(theWindow);
  832.  
  833. #ifndef RUNTIME
  834.     SetSMVariable(smFontForce, gSavedFontForce);
  835. #endif
  836.  
  837.     if (!busy) {
  838.         if (!mouseRgn) 
  839.             mouseRgn    =    NewRgn();
  840.         
  841.         GetMouse(&mouse);
  842.         SetRectRgn(mouseRgn, mouse.h, mouse.v, mouse.h, mouse.v);
  843.         gotEvent = WaitNextEvent(everyEvent, &myEvent, GetSleep(), mouseRgn);
  844.     } else 
  845.         gotEvent = WaitNextEvent(everyEvent, &myEvent, 0, nil);
  846.  
  847. #ifndef RUNTIME
  848.     // clear fontForce again so it doesn't upset our operations
  849.     gSavedFontForce = GetSMVariable(smFontForce);
  850.     (void) SetSMVariable(smFontForce, 0);
  851.         
  852.     if (gotEvent && gTextServicesImplemented && IntlTSMEvent(&myEvent))
  853.         gotEvent = false;        // TSMTE handled it without our help
  854. #endif
  855.  
  856.     if (gotEvent)
  857.         switch (myEvent.what) {
  858.         case mouseDown:
  859. #ifndef RUNTIME
  860.             FlushAndRecordTypingBuffer();
  861. #endif
  862.             DoMouseDown(&myEvent);
  863.             lastNonBusy = now;
  864.             break;
  865.  
  866.         case keyDown:
  867.         case autoKey:
  868.             if (WeirdChar(&myEvent, cmdKey, ETX) 
  869.              || WeirdChar(&myEvent, controlKey, 'd')
  870.             )    {
  871.                  if (theDoc->kind != kDocumentWindow) {
  872.                     gGotEof            =    theDoc;
  873.                     theDoc->dirty     =     true;
  874.                 } 
  875.                 
  876.                 break;
  877.             } 
  878.             
  879.             theChar = myEvent.message & charCodeMask;
  880.  
  881.             if ((myEvent.modifiers & cmdKey) == cmdKey) {
  882.                 DoCommand(FindMenuKey(&myEvent));
  883.                 HiliteMenu(0);
  884.             } else if (theDoc && theDoc->theText)
  885.                 switch (TryKey(theDoc, theChar)) {
  886.                 case keyOK:
  887.                 case keyAbort:
  888.                     break;
  889.                 case keyRetry:
  890.                     deferredKeys[deferredWr] = theChar;
  891.                     deferredWr = (deferredWr + 1) & 255;
  892.                     break;
  893.                 }
  894.               break;
  895.  
  896.         case activateEvt:
  897.             activate = ((myEvent.modifiers & activeFlag) != 0);
  898.             theWindow = (WindowPtr)myEvent.message;
  899.             DoActivate(theWindow, activate);
  900.             break;
  901.  
  902.         case updateEvt:
  903.             theDoc = DPtrFromWindowPtr((WindowPtr)myEvent.message);
  904.             DoUpdate(theDoc);
  905.             break;
  906.  
  907.         case kHighLevelEvent:
  908. #ifndef RUNTIME
  909.             FlushAndRecordTypingBuffer();
  910. #endif
  911.             DoAppleEvent(myEvent);
  912.             break;
  913.  
  914.         case kOSEvent:
  915.             switch (myEvent.message & osEvtMessageMask) { /*high byte of message*/
  916.             case 0x01000000:
  917.                     gInBackground = ((myEvent.message & resumeFlag) == 0);
  918.                     if (!gInBackground)
  919.                         InitCursor();
  920.                     DoActivate(FrontWindow(), !gInBackground);
  921.             }
  922.         }
  923.         
  924.     if (gQuitting && gRunningPerl)
  925.         exit(0);
  926. }
  927.  
  928. pascal long VoodooChile(Size cbNeeded)
  929. {
  930.     long    oldA5 = SetCurrentA5();
  931.     long    res;
  932.     
  933.     if (gSacrificialGoat && (GZSaveHnd() != gSacrificialGoat)) {
  934.         /* Oh Memory Manager, our dark Lord. Take the blood of this animal to
  935.            unwield thy power to crush our enemies.
  936.             
  937.             (Chant 7 times)
  938.         */
  939.         DisposeHandle(gSacrificialGoat);
  940.         
  941.         gSacrificialGoat     =     0;
  942.         res                    =    SACRIFICE;
  943.     } else
  944.         res                     =    0;
  945.         
  946.     SetA5(oldA5);
  947.     
  948.     return res;
  949. }
  950.  
  951. #pragma segment Main
  952.  
  953. void main()
  954. {
  955.     OSErr  err;
  956.     short  result;
  957.  
  958.     InitGraf(&qd.thePort);
  959.     InitFonts();
  960.     FlushEvents(everyEvent, 0);
  961.     InitWindows();
  962.     InitMenus();
  963.     TEInit();
  964.     InitDialogs(nil);
  965.     InitCursor();
  966.  
  967.     MaxApplZone();
  968.     SetGrowZone(&VoodooChile);
  969.     SetUpCursors();
  970.  
  971.     /*check environment checks to see if we are running 7.0*/
  972.     if (!CheckEnvironment()) {
  973.         SetCursor(&qd.arrow);
  974.         /*pose the only 7.0 alert*/
  975.         result = Alert(302, nil);
  976.         return;
  977.     }
  978.  
  979.     gPerlPrefs.version             =     PerlPrefVersion413;
  980.     gPerlPrefs.runFinderOpens    =    false;
  981.     gPerlPrefs.checkType            =    false;
  982.     gPerlPrefs.inlineInput        =     true;
  983.     
  984.     OpenPreferences();
  985.     
  986.     SetUpMenus();
  987.  
  988.     gWCount                = 0;
  989.     gNewDocCount         = 0;
  990.     gQuitting              = false;
  991.     gFontMItem             = 0;
  992.     gConsoleList        = nil;
  993.     gActiveWindow        = nil;
  994.     gAppFile                = CurResFile();
  995.     gScriptFile            = gAppFile;
  996.     gWaitingScripts    = (AppleEvent ***) NewHandle(0);
  997.     gGotEof                = nil;
  998.     gSacrificialGoat    = NewHandle(SACRIFICE);
  999.  
  1000. #ifndef RUNTIME
  1001.     if (err = InitEditionPack()) {
  1002.         ShowError("\pInitEditionPack", err);
  1003.         gQuitting = true;
  1004.     }
  1005.  
  1006.     if (err = AEObjectInit()) {
  1007.         ShowError("\pAEObjectInit", err);
  1008.         gQuitting = true;
  1009.     }
  1010.  
  1011.     InitAppleEvents();
  1012.  
  1013.     if (err = PPCInit()) {
  1014.         ShowError("\pPPCInit", err);
  1015.         gQuitting = true;
  1016.     }
  1017.  
  1018.     if (!(gTSMTEImplemented && !InitTSMAwareApplication())) {
  1019.         gTextServicesImplemented = false;
  1020.         gTSMTEImplemented = false;
  1021.     }
  1022.  
  1023.     gSavedFontForce = GetSMVariable(smFontForce);
  1024.     (void) SetSMVariable(smFontForce, 0);
  1025. #else
  1026.     if (gAppleEventsImplemented) {
  1027.         InitAppleEvents();
  1028.         
  1029.         if (err = PPCInit()) {
  1030.             ShowError("\pPPCInit", err);
  1031.             gQuitting = true;
  1032.         }
  1033.     }
  1034. #endif
  1035.     
  1036.     if (gQuitting)
  1037.         exit(0);
  1038.         
  1039.     InitPerlEnviron();
  1040.     
  1041.     for (gQuitting = DoRuntime(); !gQuitting; )
  1042.         MainEvent(false);
  1043.  
  1044. #ifndef RUNTIME        
  1045.     if (gTextServicesImplemented)
  1046.         CloseTSMAwareApplication();
  1047.     SetSMVariable(smFontForce, gSavedFontForce);
  1048. #endif
  1049. }
  1050.