home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1998 / MacHack 1998.toast / Papers / C++ Exceptions / µShell / Event Handling / EventLoop.cp < prev    next >
Encoding:
Text File  |  1998-06-15  |  13.7 KB  |  666 lines  |  [TEXT/CWIE]

  1. #include "EventLoop.h"
  2. #include "Exceptions.h"
  3. #include "DebugWrite.h"
  4.  
  5. #include <Threads.h>
  6.  
  7. DefineClassSingle(EventLoop);
  8.  
  9. struct AEHandlerInfo
  10. {
  11.     AEEventHandlerProcPtr    proc;
  12.     Size                    size;
  13.     char                    data[1];
  14. };
  15.  
  16. #define sizeofAEHandlerInfo(n)    (offsetof(AEHandlerInfo, data) + (n))
  17.  
  18. //------------------------------------------------------------------------------
  19.  
  20. #if GENERATINGCFM
  21.  
  22.     RoutineDescriptor EventLoop::gProcDescriptors[EventLoop::kNumProcSelectors] =
  23.     {
  24.         BUILD_ROUTINE_DESCRIPTOR(uppAEIdleProcInfo,            EventLoop::xAEIdleProc),
  25.         BUILD_ROUTINE_DESCRIPTOR(uppAEFilterProcInfo,        EventLoop::xAEFilterProc),
  26.         BUILD_ROUTINE_DESCRIPTOR(uppModalFilterProcInfo,     EventLoop::xModalFilterProc),
  27.         BUILD_ROUTINE_DESCRIPTOR(uppAEEventHandlerProcInfo, EventLoop::xAEEventHandlerProc),
  28.         BUILD_ROUTINE_DESCRIPTOR(uppAEEventHandlerProcInfo, EventLoop::xAEEventHandlerProc1)
  29.     };
  30.  
  31. #endif
  32.  
  33. EventLoop* EventLoop::gEventLoop = nil;
  34.  
  35. //------------------------------------------------------------------------------
  36.  
  37. pascal Boolean EventLoop::xAEIdleProc(EventRecord *theEvent, long *sleepTime, RgnHandle *mouseRgn)
  38. {
  39.     OSStatus status = Exception::CatchOSStatus(vAEIdleProc, gEventLoop, theEvent, sleepTime, mouseRgn);
  40.     
  41.     if (status == userCanceledErr)
  42.     {
  43.         return true;
  44.     }
  45.     else
  46.     {
  47.         LogIfErr(status);
  48.     }
  49.  
  50.     return false;
  51. }
  52.  
  53. //------------------------------------------------------------------------------
  54.  
  55. pascal Boolean EventLoop::xAEFilterProc(EventRecord *theEvent, long returnID, long transactionID, const AEAddressDesc *sender)
  56. {
  57.     OSStatus status = Exception::CatchOSStatus(vAEFilterProc, gEventLoop, theEvent, returnID, transactionID, sender);
  58.     
  59.     if (status == 1)
  60.     {
  61.         return true;
  62.     }
  63.     else
  64.     {
  65.         LogIfErr(status);
  66.     }
  67.     
  68.     return false;
  69. }
  70.  
  71. //------------------------------------------------------------------------------
  72.  
  73. pascal Boolean EventLoop::xModalFilterProc(DialogPtr theDialog, EventRecord *theEvent, DialogItemIndex *itemHit)
  74. {
  75.     OSStatus status = Exception::CatchOSStatus(vModalFilterProc, gEventLoop, theDialog, theEvent, itemHit);
  76.     
  77.     if (status == 1)
  78.     {
  79.         return true;
  80.     }
  81.     else
  82.     {
  83.         LogIfErr(status);
  84.     }
  85.     
  86.     return false;
  87. }
  88.  
  89. //------------------------------------------------------------------------------
  90.  
  91. pascal OSErr EventLoop::xAEEventHandlerProc(
  92.     const AppleEvent*    theAppleEvent,
  93.     AppleEvent*            reply,
  94.     UInt32                handlerRefcon)
  95. {
  96.     return Exception::CatchOSErrors(vAEEventHandlerProc, theAppleEvent, reply, (long) 0, handlerRefcon);
  97. }
  98.  
  99. //------------------------------------------------------------------------------
  100.  
  101. pascal OSErr EventLoop::xAEEventHandlerProc1(
  102.     const AppleEvent*    theAppleEvent,
  103.     AppleEvent*            reply,
  104.     UInt32                handlerRefcon)
  105. {
  106.     AEHandlerInfo* info = (AEHandlerInfo*) handlerRefcon;
  107.     
  108.     return Exception::CatchOSErrors(vAEEventHandlerProc, theAppleEvent, reply, &info->data[0], info->proc);
  109. }
  110.  
  111. //------------------------------------------------------------------------------
  112.  
  113. OSStatus EventLoop::vAEIdleProc(va_list args)
  114. {
  115.     VA_ARG(EventRecord*,            theEvent,     args);
  116.     VA_ARG(long*,                    sleepTime,    args);
  117.     VA_ARG(RgnHandle*,                mouseRgn,    args);
  118.     
  119.     return gEventLoop ? gEventLoop->AEIdleProc(*theEvent, *sleepTime, *mouseRgn) : false;
  120. }
  121.  
  122. //------------------------------------------------------------------------------
  123.  
  124. OSStatus EventLoop::vAEFilterProc(va_list args)
  125. {
  126.     VA_ARG(EventRecord*,            theEvent,         args);
  127.     VA_ARG(long,                    returnID,        args);
  128.     VA_ARG(long,                    transactionID,    args);
  129.     VA_ARG(const AEAddressDesc*,    sender,            args);
  130.     
  131.     EventLoop* loop = gEventLoop;
  132.     
  133.     return loop ? loop->AEFilterProc(*theEvent, returnID, transactionID, *sender) : false;
  134. }
  135.  
  136. //------------------------------------------------------------------------------
  137.  
  138. OSStatus EventLoop::vModalFilterProc(va_list args)
  139. {
  140.     VA_ARG(DialogPtr,                theDialog,    args);
  141.     VA_ARG(EventRecord*,            theEvent,     args);
  142.     VA_ARG(DialogItemIndex*,        itemHit,    args);
  143.     
  144.     return gEventLoop ? gEventLoop->ModalFilterProc(theDialog, *theEvent, *itemHit) : false;
  145. }
  146.  
  147. //------------------------------------------------------------------------------
  148.  
  149. OSStatus EventLoop::vAEEventHandlerProc(va_list args)
  150. {
  151.     VA_ARG(const AppleEvent*,        theAppleEvent,    args);
  152.     VA_ARG(AppleEvent*,                reply,            args);
  153.     VA_ARG(UInt32,                     handlerRefcon,    args);
  154.     VA_ARG(AEEventHandlerProcPtr,    handler,        args);
  155.     
  156.     return (*handler)(theAppleEvent, reply, handlerRefcon);
  157. }
  158.  
  159. //------------------------------------------------------------------------------
  160.  
  161. bool EventLoop::HandleEventProc(EventRecord& theEvent, long *sleepTime, RgnHandle *mouseRgn)
  162. {
  163.     WithNewEvent evt(*this, theEvent, sleepTime, mouseRgn);
  164.  
  165.     return HandleEvent(evt);
  166. }
  167.  
  168. //------------------------------------------------------------------------------
  169.  
  170. bool EventLoop::AEIdleProc(EventRecord& theEvent, long& sleepTime, RgnHandle& mouseRgn)
  171. {
  172.     WithNewEvent evt(*this, theEvent, &sleepTime, &mouseRgn);
  173.  
  174.     bool handled = HandleEvent(evt);
  175.  
  176.     return false;
  177. }
  178.  
  179. //------------------------------------------------------------------------------
  180.  
  181. void EventLoop::InteractWithUser(
  182.     long                     timeOutInTicks,
  183.     NMRecPtr                 nmReqPtr)
  184. {
  185.     FailOSErr(AEInteractWithUser(timeOutInTicks, nmReqPtr, GetAEIdleProc()));
  186. }
  187.  
  188. //------------------------------------------------------------------------------
  189.  
  190. void* EventLoop::InstallAEHandler(
  191.     AEEventClass             theAEEventClass,
  192.     AEEventID                 theAEEventID,
  193.     AEEventHandlerProcPtr    handler,
  194.     Size                    dataSize)
  195. {
  196.     long                    refcon;
  197.     AEEventHandlerUPP         upp;
  198.     void*                    result;
  199.     
  200.     if (dataSize > 0)
  201.     {
  202.         AEHandlerInfo* info = (AEHandlerInfo*) NewPtrClear(sizeofAEHandlerInfo(dataSize));
  203.         
  204.         FailNIL(info);
  205.         
  206.         info->proc = handler;
  207.         info->size = dataSize;
  208.         
  209.         upp        = GetAEEventHandlerProc1();
  210.         refcon    = (long) info;
  211.         result    = &info->data[0];
  212.     }
  213.     else
  214.     {
  215.         upp        = GetAEEventHandlerProc();
  216.         refcon    = (long) handler;
  217.         result    = nil;
  218.     }
  219.  
  220.     FailOSErr(AEInstallEventHandler(theAEEventClass, theAEEventID, upp, refcon, false));
  221.  
  222.     return result;
  223. }
  224.  
  225. //------------------------------------------------------------------------------
  226.  
  227. bool EventLoop::AEFilterProc(
  228.     EventRecord&            theEvent,
  229.     long                    /*returnID*/,
  230.     long                    /*transactionID*/,
  231.     const AEAddressDesc&    /*sender*/)
  232. {
  233.     if (!HandleEventProc(theEvent, nil, nil))
  234.     {
  235.         Yield();
  236.     }
  237.     
  238.     return false;
  239. }
  240.  
  241. //------------------------------------------------------------------------------
  242.  
  243. bool EventLoop::ModalFilterProc(
  244.     DialogPtr                /*theDialog*/,
  245.     EventRecord&            theEvent,
  246.     DialogItemIndex&        /*itemHit*/)
  247. {
  248.     if (!HandleEventProc(theEvent, nil, nil))
  249.     {
  250.         Yield();
  251.     }
  252.     
  253.     return false;
  254. }
  255.  
  256. //------------------------------------------------------------------------------
  257.  
  258. bool EventLoop::PollForEvent(EventRecord& theEvent)
  259. {
  260.     long sleep = fLastEvent.IsNullEvent() ? fSleepTime : 0;
  261.  
  262.     return WaitNextEvent(fEventMask, &theEvent, sleep, fMouseRgn);
  263. }
  264.  
  265. //------------------------------------------------------------------------------
  266.  
  267. bool EventLoop::ProcessEvent(
  268.     EventRecord&    theEvent,
  269.     long*            sleepTime,
  270.     RgnHandle*        mouseRgn)
  271. {
  272.     EventLoop*    loop = gEventLoop;
  273.     bool        handled = false;
  274.  
  275.     if (loop != nil)
  276.     {
  277.         WithNewEvent evt(*loop, theEvent, sleepTime, mouseRgn);
  278.     
  279.         handled = loop->FilterEvent(evt);
  280.         
  281.         if (!handled)
  282.         {
  283.             handled = loop->HandleEvent(evt);
  284.         }
  285.         
  286.         Yield();
  287.  
  288.         if (sleepTime != nil)
  289.         {
  290.             *sleepTime = loop->GetSleepTime();
  291.         }
  292.  
  293.         if (mouseRgn != nil)
  294.         {
  295.             *mouseRgn = loop->GetMouseRgn();
  296.         }
  297.     }
  298.  
  299.     return handled;
  300. }
  301.  
  302. //------------------------------------------------------------------------------
  303.  
  304. bool EventLoop::DoIdle()
  305. {
  306.     if (fNestLevel == 0)
  307.     {
  308.         EventRecord theEvent;
  309.     
  310.         PollForEvent(theEvent);
  311.         
  312.         ProcessEvent(theEvent, nil, nil);
  313.     }
  314.     else
  315.     {
  316.         Yield();
  317.     }
  318.  
  319.     return false;
  320. }
  321.  
  322. //------------------------------------------------------------------------------
  323.  
  324. void EventLoop::Yield()
  325. {
  326.     YieldToAnyThread();
  327. }
  328.  
  329. //------------------------------------------------------------------------------
  330.  
  331. void EventLoop::BeginEvent(ToolboxEvent& /*theEvent*/)
  332. {
  333. }
  334.  
  335. //------------------------------------------------------------------------------
  336.  
  337. bool EventLoop::FilterEvent(ToolboxEvent& theEvent)
  338. {
  339.     return fFilterChain.FilterEvent(theEvent);
  340. }
  341.  
  342. //------------------------------------------------------------------------------
  343.  
  344. bool EventLoop::HandleEvent(ToolboxEvent& theEvent)
  345. {
  346.     bool result = FilterEvent(theEvent);
  347.     
  348.     if (!result)
  349.     {
  350.         EventKind what = theEvent.GetEventKind();
  351.         
  352.         switch (what)
  353.         {
  354.         case nullEvent:
  355.             result = HandleNullEvent(theEvent);
  356.             break;
  357.         
  358.         case kHighLevelEvent:
  359.             result = HandleHighLevelEvent(theEvent);
  360.             break;
  361.  
  362.         default:
  363.             break;
  364.         }
  365.     }
  366.     
  367.     return result;
  368. }
  369.  
  370. //------------------------------------------------------------------------------
  371.  
  372. void EventLoop::EndEvent(ToolboxEvent& theEvent)
  373. {
  374.     EventKind what = theEvent.GetEventKind();
  375.     
  376.     if (what != kHighLevelEvent)
  377.     {
  378.         // HLE's don't affect sleep time, etc.
  379.     
  380.         switch (what)
  381.         {
  382.         case mouseDown:
  383.             fLastMouseUp.SetToNullEvent();
  384.             break;
  385.         
  386.         case mouseUp:
  387.             fLastMouseUp = theEvent;
  388.             break;
  389.         }
  390.     
  391.         fLastEvent = theEvent;
  392.     }
  393. }
  394.  
  395. //------------------------------------------------------------------------------
  396.  
  397. bool EventLoop::HandleNullEvent(ToolboxEvent& theEvent)
  398. {
  399.     if (fLastEvent.IsNullEvent())
  400.     {
  401.         do
  402.         {
  403.             Yield();
  404.         }
  405.         while (TickCount() < theEvent.GetEventTime() + fDreamTime);
  406.     }
  407.     else
  408.     {
  409.         // Calc sleep time
  410.     }
  411.  
  412.     return false;
  413. }
  414.  
  415. //------------------------------------------------------------------------------
  416.  
  417. bool EventLoop::HandleHighLevelEvent(ToolboxEvent& theEvent)
  418. {
  419.     OSErr err = AEProcessAppleEvent(theEvent);
  420.     
  421.     LogIfErr(err);
  422.     
  423.     return err == noErr;
  424. }
  425.  
  426. //------------------------------------------------------------------------------
  427.  
  428. EventLoop::~EventLoop()
  429. {
  430.     if (fMouseRgn)
  431.     {
  432.         DisposeRgn(fMouseRgn);
  433.         fMouseRgn = nil;
  434.     }
  435. }
  436.  
  437. //------------------------------------------------------------------------------
  438.  
  439. void EventLoop::Initialize()
  440. {
  441.     TModule::Initialize();
  442.     EventFilterChain::Initialize();
  443.  
  444.     // this initializes fLastEvent and allows the porcess manager to complete
  445.     // switching to our task
  446.  
  447.     for (int i = 3; i > 0; --i)
  448.     {
  449.         WaitNextEvent(0, fLastEvent, 0, nil);
  450.     }
  451. }
  452.  
  453. //--------------------------------------------------------------------------------
  454.  
  455. void EventLoop::Finalize(void)
  456. {
  457.     TModule::Finalize();
  458.     EventFilterChain::Finalize();
  459. }
  460.  
  461. //------------------------------------------------------------------------------
  462.  
  463. void EventLoop::Run()
  464. {
  465.     if (gEventLoop)
  466.     {
  467.         gEventLoop->DoRun();
  468.     }
  469. }
  470.  
  471. //------------------------------------------------------------------------------
  472.  
  473. void EventLoop::Quit()
  474. {
  475.     if (gEventLoop)
  476.     {
  477.         gEventLoop->DoQuit();
  478.     }
  479. }
  480.  
  481. //------------------------------------------------------------------------------
  482.  
  483. void EventLoop::PushEventFilter(EventFilter& filter)
  484. {
  485.     if (gEventLoop)
  486.     {
  487.         gEventLoop->GetFilterList().AddFirst(filter);
  488.     }
  489. }
  490.  
  491. //------------------------------------------------------------------------------
  492.  
  493. void EventLoop::DoRun()
  494. {
  495.     BeforeEventLoop();
  496.  
  497.     while (fAppPhase < kAppDone)
  498.     {
  499.         DoIdle();
  500.     }
  501.     
  502.     AfterEventLoop();
  503. }
  504.  
  505. //------------------------------------------------------------------------------
  506.  
  507. void EventLoop::DoQuit()
  508. {
  509.     fAppPhase = kAppDone;
  510. }
  511.  
  512. //------------------------------------------------------------------------------
  513.  
  514. void EventLoop::BeforeEventLoop()
  515. {
  516. }
  517.  
  518. //------------------------------------------------------------------------------
  519.  
  520. void EventLoop::AfterEventLoop()
  521. {
  522. }
  523.  
  524. //------------------------------------------------------------------------------
  525.  
  526. EventLoop::WithNewEvent::WithNewEvent(
  527.     EventLoop&        loop,
  528.     EventRecord&    theEvent,
  529.     long*            sleepTime,
  530.     RgnHandle*        mouseRgn)
  531. :    ToolboxEvent(theEvent),
  532.     fLoop(loop),
  533.     fSleepTime(sleepTime),
  534.     fMouseRgn(mouseRgn)
  535. {
  536.     fLoop.BeginEvent(*this);
  537. }
  538.  
  539. //------------------------------------------------------------------------------
  540.  
  541. EventLoop::WithNewEvent::~WithNewEvent()
  542. {
  543.     fLoop.EndEvent(*this);
  544.  
  545.     if (fSleepTime != nil)
  546.     {
  547.         *fSleepTime = fLoop.GetSleepTime();
  548.     }
  549.     
  550.     if (fMouseRgn != nil)
  551.     {
  552.         *fMouseRgn = fLoop.GetMouseRgn();
  553.     }
  554. }
  555.  
  556. //------------------------------------------------------------------------------
  557.  
  558. FGEventLoop::~FGEventLoop()
  559. {
  560. }
  561.  
  562. //------------------------------------------------------------------------------
  563.  
  564. bool FGEventLoop::HandleEvent(ToolboxEvent& theEvent)
  565. {
  566.     bool handled = Inherited::HandleEvent(theEvent);
  567.     
  568.     if (!handled)
  569.     {
  570.         EventKind what = theEvent.GetEventKind();
  571.         
  572.         switch (what)
  573.         {
  574.         case nullEvent:
  575.             handled = HandleNullEvent(theEvent);
  576.             break;
  577.         
  578.         case mouseDown:
  579.         case mouseUp:
  580.             handled = HandleMouseEvent(theEvent);
  581.             break;
  582.         
  583.         case keyDown:
  584.         case keyUp:
  585.         case autoKey:
  586.             handled = HandleKeyboardEvent(theEvent);
  587.             break;
  588.         
  589.         case updateEvt:
  590.         case activateEvt:
  591.             handled = HandleWindowEvent(theEvent);
  592.             break;
  593.         
  594.         case kHighLevelEvent:
  595.             handled = HandleHighLevelEvent(theEvent);
  596.             break;
  597.  
  598.         default:
  599.         case diskEvt:
  600.         case osEvt:
  601.             break;
  602.         }
  603.     }
  604.     
  605.     return handled;
  606. }
  607.  
  608. //------------------------------------------------------------------------------
  609.  
  610. bool FGEventLoop::HandleMouseEvent(ToolboxEvent& theEvent)
  611. {
  612.     return HandleWindowEvent(theEvent);
  613. }
  614.  
  615. //------------------------------------------------------------------------------
  616.  
  617. bool FGEventLoop::HandleKeyboardEvent(ToolboxEvent& theEvent)
  618. {
  619.     if (theEvent.GetEventKind() == keyDown)
  620.     {
  621.         if (theEvent.GetModifierBits().cmdKey)
  622. //        if (theEvent.CmdKeyDown())
  623.         {
  624.             return HandleMenuSelection(MenuKey(theEvent.GetCharCode()));
  625.         }
  626.     }
  627.     
  628.     return false;
  629. }
  630.  
  631. //------------------------------------------------------------------------------
  632.  
  633. bool FGEventLoop::HandleWindowEvent(ToolboxEvent& theEvent)
  634. {
  635.     switch (theEvent.GetPartCode())
  636.     {
  637.     case inMenuBar:
  638.         HandleMenuSelection(MenuSelect(theEvent.GetMousePosition()));
  639.         break;
  640.     }
  641.  
  642. /*
  643.     inDesk                        = 0,
  644.     inNoWindow                    = 0,
  645.     inMenuBar                    = 1,
  646.     inSysWindow                    = 2,
  647.     inContent                    = 3,
  648.     inDrag                        = 4,
  649.     inGrow                        = 5,
  650.     inGoAway                    = 6,
  651.     inZoomIn                    = 7,
  652.     inZoomOut                    = 8,
  653.     inCollapseBox                = 11
  654. */
  655.  
  656.     return false;
  657. }
  658.  
  659. //------------------------------------------------------------------------------
  660.  
  661. bool FGEventLoop::HandleMenuSelection(long what)
  662. {
  663.     HiliteMenu(0);
  664.  
  665.     return false;
  666. }