home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / developm / scnote / cplussmp.014 / TApplication.cp < prev    next >
Encoding:
Text File  |  1989-10-01  |  11.1 KB  |  440 lines

  1. /*------------------------------------------------------------------------------
  2. #
  3. #    Apple Macintosh Developer Technical Support
  4. #
  5. #    MultiFinder-Aware Simple TextEdit Sample Application
  6. #
  7. #    CPlusTESample
  8. #
  9. #    TApplication.cp        -    C++ source
  10. #
  11. #    Copyright ⌐ 1989 Apple Computer, Inc.
  12. #    All rights reserved.
  13. #
  14. #    Versions:    
  15. #            1.20                    10/89
  16. #            1.10                     07/89
  17. #            1.00                     04/89
  18. #    
  19. #    Components:
  20. #            CPlusTESample.make        October 1, 1989
  21. #            TApplicationCommon.h    October 1, 1989
  22. #            TApplication.h            October 1, 1989
  23. #            TDocument.h                October 1, 1989
  24. #            TECommon.h                October 1, 1989
  25. #            TESample.h                October 1, 1989
  26. #            TEDocument.h            October 1, 1989
  27. #            TApplication.cp            October 1, 1989
  28. #            TDocument.cp            October 1, 1989
  29. #            TESample.cp                October 1, 1989
  30. #            TEDocument.cp            October 1, 1989
  31. #            TESampleGlue.a            October 1, 1989
  32. #            TApplication.r            October 1, 1989
  33. #            TESample.r                October 1, 1989
  34. #
  35. #    CPlusTESample is an example application that demonstrates
  36. #    how to initialize the commonly used toolbox managers,
  37. #    operate successfully under MultiFinder, handle desk
  38. #    accessories and create, grow, and zoom windows. The
  39. #    fundamental TextEdit toolbox calls and TextEdit autoscroll
  40. #    are demonstrated. It also shows how to create and maintain
  41. #    scrollbar controls. 
  42. #
  43. #    This version of TESample has been substantially reworked in
  44. #    C++ to show how a "typical" object oriented program could
  45. #    be written. To this end, what was once a single source code
  46. #    file has been restructured into a set of classes which
  47. #    demonstrate the advantages of object-oriented programming.
  48. #
  49. ------------------------------------------------------------------------------*/
  50.  
  51.  
  52. /*
  53. Segmentation strategy:
  54.  
  55.     This program has only one segment, since the issues
  56.     surrounding segmentation within a class's methods have
  57.     not been investigated yet. We DO unload the data
  58.     initialization segment at startup time, which frees up
  59.     some memory 
  60.  
  61. SetPort strategy:
  62.  
  63.     Toolbox routines do not change the current port. In
  64.     spite of this, in this program we use a strategy of
  65.     calling SetPort whenever we want to draw or make calls
  66.     which depend on the current port. This makes us less
  67.     vulnerable to bugs in other software which might alter
  68.     the current port (such as the bug (feature?) in many
  69.     desk accessories which change the port on OpenDeskAcc).
  70.     Hopefully, this also makes the routines from this
  71.     program more self-contained, since they don't depend on
  72.     the current port setting. 
  73.  
  74. Clipboard strategy:
  75.  
  76.     This program does not maintain a private scrap.
  77.     Whenever a cut, copy, or paste occurs, we import/export
  78.     from the public scrap to TextEdit's scrap right away,
  79.     using the TEToScrap and TEFromScrap routines. If we did
  80.     use a private scrap, the import/export would be in the
  81.     activate/deactivate event and suspend/resume event
  82.     routines. 
  83. */
  84.  
  85. // Mac Includes
  86. #include <Types.h>
  87. #include <QuickDraw.h>
  88. #include <Fonts.h>
  89. #include <Events.h>
  90. #include <Controls.h>
  91. #include <Windows.h>
  92. #include <Menus.h>
  93. #include <TextEdit.h>
  94. #include <Dialogs.h>
  95. #include <Desk.h>
  96. #include <Scrap.h>
  97. #include <ToolUtils.h>
  98. #include <Memory.h>
  99. #include <SegLoad.h>
  100. #include <Files.h>
  101. #include <OSUtils.h>
  102. #include <Traps.h>
  103.  
  104. #ifndef __TAPPLICATION__
  105. #include "TApplication.h"
  106. #endif __TAPPLICATION__
  107.  
  108. // OSEvent is the event number of the suspend/resume and mouse-moved events sent
  109. // by MultiFinder. Once we determine that an event is an osEvent, we look at the
  110. // high byte of the message sent to determine which kind it is. To differentiate
  111. // suspend and resume events we check the resumeMask bit.
  112. const short kOsEvent = app4Evt;                // event used by MultiFinder
  113. const short kSuspendResumeMessage = 0x01;    // high byte of suspend/resume event message
  114. const short kClipConvertMask = 0x02;        // bit of message field clip conversion
  115. const short kResumeMask = 0x01;                // bit of message field for resume vs. suspend
  116. const short kMouseMovedMessage = 0xFA;        // high byte of mouse-moved event message
  117.  
  118. extern "C" { 
  119.     // from MPW standard library
  120.     void _DataInit();                // sets up A5 globals
  121. };
  122.  
  123. TApplication::TApplication()
  124. {
  125.     SysEnvRec envRec;
  126.     long stkNeeded;
  127.     long heapSize;
  128.  
  129.     // initialize Mac Toolbox components
  130.     InitGraf((Ptr) &qd.thePort);
  131.     InitFonts();
  132.     InitWindows();
  133.     InitMenus();
  134.     TEInit();
  135.     InitDialogs((ResumeProcPtr) nil);
  136.     InitCursor();
  137.  
  138.     // Unload data segment: note that _DataInit must not be in Main!
  139.     UnloadSeg((ProcPtr) _DataInit);
  140.  
  141.     // ignore the error returned from SysEnvirons; even if an error occurred,
  142.     // the SysEnvirons glue will fill in the SysEnvRec
  143.     (void) SysEnvirons(curSysEnvVers, &envRec);
  144.  
  145.     // Are we running on a 128K ROM machine or better???
  146.     if (envRec.machineType < 0)
  147.       BigBadError(kErrStrings,eWrongMachine);        // if not, alert & quit
  148.  
  149.     // if we need more stack space, get it now
  150.     stkNeeded = StackNeeded();
  151.     if (stkNeeded > StackSpace())
  152.       {
  153.         // new address is heap size + current stack - needed stack
  154.         SetApplLimit((Ptr) ((long) GetApplLimit() - stkNeeded + StackSpace()));
  155.       }
  156.  
  157.     // Check for minimum heap size
  158.     heapSize = (long) GetApplLimit() - (long) ApplicZone();
  159.     if (heapSize < HeapNeeded())
  160.       BigBadError(kErrStrings,eSmallSize);
  161.  
  162.     // expand the heap so new code segments load at the top
  163.     MaxApplZone();
  164.  
  165.     // allocate an empty document list
  166.     fDocList = new TDocumentList;
  167.  
  168.     // check to see if WaitNextEvent is implemented
  169.     fHaveWaitNextEvent = TrapAvailable(_WaitNextEvent, ToolTrap);
  170.  
  171.     // initialize our class variables
  172.     fCurDoc = nil;
  173.     fDone = false;
  174.     fInBackground = false;
  175.     fMouseRgn = nil;
  176.     fWhichWindow = nil;
  177. }
  178.  
  179. void TApplication::ExitLoop()
  180. {
  181.     fDone = true;
  182. }
  183.  
  184. void TApplication::EventLoop()
  185. {
  186.     int gotEvent;
  187.     EventRecord tEvt;
  188.  
  189.     SetUp();                    // call setup routine
  190.     DoIdle();                    // do idle once
  191.  
  192.     while (fDone == false)
  193.       {
  194.         // always set up fWhichWindow before doing anything
  195.         fWhichWindow = FrontWindow();
  196.         if (fWhichWindow != nil)
  197.           {
  198.             // see if window belongs to a document
  199.             fCurDoc = fDocList->FindDoc(fWhichWindow);
  200.             // make sure we always draw into correct window
  201.             SetPort(fWhichWindow);
  202.           }
  203.         else fCurDoc = nil;
  204.  
  205.         DoIdle();            // call idle time handler
  206.         
  207.         if (fHaveWaitNextEvent)
  208.           {
  209.             gotEvent = WaitNextEvent(everyEvent, &tEvt, SleepVal(), fMouseRgn);
  210.           }
  211.         else
  212.           {
  213.             SystemTask();
  214.             gotEvent = GetNextEvent(everyEvent, &tEvt);
  215.           }
  216.         fTheEvent = tEvt;
  217.  
  218.         // make sure we got a real event
  219.         if ( gotEvent )
  220.           {
  221.             AdjustCursor();
  222.             switch (fTheEvent.what)
  223.               {
  224.                 case mouseDown :
  225.                     DoMouseDown();
  226.                     break;
  227.                 case mouseUp :
  228.                     DoMouseUp();
  229.                     break;
  230.                 case keyDown :
  231.                 case autoKey :
  232.                     DoKeyDown();
  233.                     break;
  234.                 case updateEvt :
  235.                     DoUpdateEvt();                
  236.                     break;
  237.                 case diskEvt :
  238.                     DoDiskEvt();
  239.                     break;
  240.                 case activateEvt :
  241.                     DoActivateEvt();
  242.                     break;
  243.                 case kOsEvent :
  244.                     DoOSEvent();
  245.                     break;
  246.                 default :
  247.                     break;
  248.               } // end switch (fTheEvent.what)
  249.           }
  250.         AdjustCursor();
  251.       }
  252.     // call cleanup handler
  253.     CleanUp();
  254. }
  255.  
  256. void TApplication::DoKeyDown()
  257. {
  258.     char key;
  259.     long mResult;
  260.  
  261.     key = (char) (fTheEvent.message & charCodeMask);
  262.     if ((fTheEvent.modifiers & cmdKey) && (fTheEvent.what == keyDown))
  263.       {
  264.         // only do command keys if we are not autokeying
  265.         AdjustMenus();                    // make sure menus are up to date
  266.         mResult = MenuKey(key);
  267.         if (mResult != 0)                // if it wasn't a menu key, pass it through
  268.           {
  269.             DoMenuCommand(HiWrd(mResult), LoWrd(mResult));
  270.             return;
  271.           }
  272.       }
  273.     if (fCurDoc != nil)
  274.       {
  275.         EventRecord tEvt;
  276.  
  277.         // we copy event record so that we don't pass reference to object field 
  278.         tEvt = fTheEvent;
  279.         fCurDoc->DoKeyDown(&tEvt);
  280.       }
  281. }
  282.  
  283. void TApplication::DoActivateEvt()
  284. {
  285.     // event record contains window ptr
  286.     fWhichWindow = (WindowPtr) fTheEvent.message;
  287.     // see if window belongs to a document
  288.     fCurDoc = fDocList->FindDoc(fWhichWindow);
  289.     SetPort(fWhichWindow);
  290.  
  291.     if (fCurDoc != nil)
  292.       fCurDoc->DoActivate((fTheEvent.modifiers & activeFlag) != 0);
  293. }
  294.  
  295. void TApplication::DoUpdateEvt()
  296. {
  297.     // event record contains window ptr
  298.     fWhichWindow = (WindowPtr) fTheEvent.message;
  299.     // see if window belongs to a document
  300.     fCurDoc = fDocList->FindDoc(fWhichWindow);
  301.     SetPort(fWhichWindow);
  302.  
  303.     if (fCurDoc != nil)
  304.       fCurDoc->DoUpdate();
  305. }
  306.  
  307. // NOTE: we use an anonymous parameter here so that the compiler
  308. // doesn't warn us about it being unused. Since we give it a name
  309. // in the class definition, we still know what its used for.
  310. void TApplication::DoSuspend(Boolean)
  311. {
  312.     if (fCurDoc != nil)
  313.       fCurDoc->DoActivate(!fInBackground);
  314. }
  315.  
  316. void TApplication::DoResume(Boolean)
  317. {
  318.     if (fCurDoc != nil)
  319.       fCurDoc->DoActivate(!fInBackground);
  320. }
  321.  
  322. void TApplication::DoOSEvent()
  323. {
  324.     Boolean doConvert;
  325.     unsigned char evType;
  326.  
  327.     // is it a multifinder event?
  328.     evType = (unsigned char) (fTheEvent.message >> 24) & 0x00ff;
  329.     switch (evType) {     // high byte of message is type of event
  330.         case kMouseMovedMessage :
  331.             DoIdle();                    // mouse-moved is also an idle event
  332.             break;
  333.         case kSuspendResumeMessage :
  334.             doConvert = (fTheEvent.message & kClipConvertMask) != 0;
  335.             fInBackground = (fTheEvent.message & kResumeMask) == 0;
  336.             if (fInBackground)
  337.               DoSuspend(doConvert);
  338.             else DoResume(doConvert);
  339.             break;
  340.     }
  341. }
  342.  
  343. void TApplication::DoMouseDown()
  344. {
  345.     long mResult;
  346.     short partCode;
  347.     WindowPtr tWind;
  348.     EventRecord tEvt;
  349.  
  350.     // gotta watch those object field dereferences
  351.     partCode = FindWindow(fTheEvent.where, &tWind);
  352.     fWhichWindow = tWind;
  353.     tEvt = fTheEvent;
  354.     switch (partCode)
  355.       {
  356.         case inSysWindow :
  357.             DoMouseInSysWindow();
  358.             break;
  359.         case inMenuBar :
  360.             AdjustMenus();
  361.             mResult = MenuSelect(tEvt.where);
  362.             if (mResult != 0)
  363.               DoMenuCommand(HiWrd(mResult),LoWrd(mResult));
  364.             break;
  365.         case inGoAway :
  366.             DoGoAway();                    
  367.             break;
  368.         case inDrag :
  369.             DoDrag();
  370.             break;
  371.         case inGrow :
  372.             if (fCurDoc != nil)
  373.               fCurDoc->DoGrow(&tEvt);                    
  374.             break;
  375.         case inZoomIn :
  376.         case inZoomOut :
  377.             if ((TrackBox(fWhichWindow, tEvt.where, partCode)) &&
  378.                 (fCurDoc != nil))
  379.               fCurDoc->DoZoom(partCode);
  380.             break;
  381.         case inContent :
  382.             // If window is not in front, make it so
  383.             if ( fWhichWindow != FrontWindow() )
  384.               SelectWindow(fWhichWindow);
  385.             else if (fCurDoc != nil)
  386.               fCurDoc->DoContent(&tEvt);                    
  387.             break;
  388.       }
  389. }
  390.  
  391. void TApplication::DoDrag()
  392. {
  393.     DragWindow(fWhichWindow, fTheEvent.where, &qd.screenBits.bounds);
  394. }
  395.  
  396. void TApplication::DoGoAway()
  397. {
  398.     if (TrackGoAway(fWhichWindow, fTheEvent.where))
  399.       {
  400.         if (fCurDoc != nil)
  401.           {
  402.             fDocList->RemoveDoc(fCurDoc);
  403.             fCurDoc->DoClose();
  404.           }
  405.         else CloseDeskAcc(((WindowPeek) fWhichWindow)->windowKind);
  406.         // make sure our current document/window references are valid
  407.         fWhichWindow = FrontWindow();
  408.         if (fWhichWindow != nil)
  409.           {
  410.             fCurDoc = fDocList->FindDoc(fWhichWindow);
  411.             SetPort(fWhichWindow);
  412.           }
  413.         else fCurDoc = nil;
  414.       }
  415. }
  416.  
  417. Boolean TApplication::TrapAvailable(short tNumber,TrapType tType)
  418. {
  419.     // Check and see if the trap exists. On 64K ROM machines, tType will be ignored.
  420.     return NGetTrapAddress(tNumber, tType) != GetTrapAddress(_Unimplemented);
  421. } /*TrapAvailable*/
  422.  
  423. void AlertUser(short errResID, short errCode)
  424. {
  425.     Str255 message;
  426.  
  427.     SetCursor(&qd.arrow);
  428.     GetIndString(message, errResID, errCode);
  429.     ParamText(message, "\p", "\p", "\p");
  430.     (void) Alert(rUserAlert, (ModalFilterProcPtr) nil);
  431. } // AlertUser
  432.  
  433. void BigBadError(short errResID, short errCode)
  434. {
  435.     AlertUser(errResID,errCode);
  436.     ExitToShell();
  437. }
  438.  
  439. // That's all, folks...
  440.