tkMacOSXCarbonEvents.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:21k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /*
  2.  * tkMacOSXCarbonEvents.c --
  3.  *
  4.  * This file implements functions that register for and handle
  5.  * various Carbon Events and Timers. Most carbon events of interest
  6.  * to TkAqua are processed in a handler registered on the dispatcher
  7.  * event target so that we get first crack at them before HIToolbox
  8.  * dispatchers/processes them further.
  9.  * As some events are sent directly to the focus or app event target
  10.  * and not dispatched normally, we also register a handler on the
  11.  * application event target.
  12.  *
  13.  * Copyright 2001, Apple Computer, Inc.
  14.  * Copyright (c) 2005-2007 Daniel A. Steffen <das@users.sourceforge.net>
  15.  *
  16.  * See the file "license.terms" for information on usage and redistribution of
  17.  * this file, and for a DISCLAIMER OF ALL WARRANTIES.
  18.  *
  19.  * The following terms apply to all files originating from Apple
  20.  * Computer, Inc. ("Apple") and associated with the software
  21.  * unless explicitly disclaimed in individual files.
  22.  *
  23.  *
  24.  * Apple hereby grants permission to use, copy, modify,
  25.  * distribute, and license this software and its documentation
  26.  * for any purpose, provided that existing copyright notices are
  27.  * retained in all copies and that this notice is included
  28.  * verbatim in any distributions. No written agreement, license,
  29.  * or royalty fee is required for any of the authorized
  30.  * uses. Modifications to this software may be copyrighted by
  31.  * their authors and need not follow the licensing terms
  32.  * described here, provided that the new terms are clearly
  33.  * indicated on the first page of each file where they apply.
  34.  *
  35.  *
  36.  * IN NO EVENT SHALL APPLE, THE AUTHORS OR DISTRIBUTORS OF THE
  37.  * SOFTWARE BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
  38.  * INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF
  39.  * THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
  40.  * EVEN IF APPLE OR THE AUTHORS HAVE BEEN ADVISED OF THE
  41.  * POSSIBILITY OF SUCH DAMAGE.  APPLE, THE AUTHORS AND
  42.  * DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
  43.  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
  44.  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS
  45.  * SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND APPLE,THE
  46.  * AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
  47.  * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  48.  *
  49.  * GOVERNMENT USE: If you are acquiring this software on behalf
  50.  * of the U.S. government, the Government shall have only
  51.  * "Restricted Rights" in the software and related documentation
  52.  * as defined in the Federal Acquisition Regulations (FARs) in
  53.  * Clause 52.227.19 (c) (2).  If you are acquiring the software
  54.  * on behalf of the Department of Defense, the software shall be
  55.  * classified as "Commercial Computer Software" and the
  56.  * Government shall have only "Restricted Rights" as defined in
  57.  * Clause 252.227-7013 (c) (1) of DFARs.  Notwithstanding the
  58.  * foregoing, the authors grant the U.S. Government and others
  59.  * acting in its behalf permission to use and distribute the
  60.  * software in accordance with the terms specified in this
  61.  * license.
  62.  *
  63.  * RCS: @(#) $Id: tkMacOSXCarbonEvents.c,v 1.3.2.18 2007/11/09 06:26:54 das Exp $
  64.  */
  65. #include "tkMacOSXPrivate.h"
  66. #include "tkMacOSXEvent.h"
  67. #include "tkMacOSXDebug.h"
  68. /*
  69. #ifdef TK_MAC_DEBUG
  70. #define TK_MAC_DEBUG_CARBON_EVENTS
  71. #endif
  72. */
  73. /*
  74.  * Declarations of functions used only in this file:
  75.  */
  76. static OSStatus CarbonEventHandlerProc(EventHandlerCallRef callRef,
  77. EventRef event, void *userData);
  78. static OSStatus InstallStandardApplicationEventHandler(void);
  79. static void CarbonTimerProc(EventLoopTimerRef timer, void *userData);
  80. /*
  81.  * Static data used by several functions in this file:
  82.  */
  83. static EventLoopTimerRef carbonTimer = NULL;
  84. static int carbonTimerEnabled = 0;
  85. static EventHandlerUPP carbonEventHandlerUPP = NULL;
  86. static Tcl_Interp *carbonEventInterp = NULL;
  87. static int inTrackingLoop = 0;
  88. #if MAC_OS_X_VERSION_MIN_REQUIRED < 1050
  89. /*
  90.  * For InstallStandardApplicationEventHandler():
  91.  */
  92. static jmp_buf exitRaelJmpBuf;
  93. static void ExitRaelEventHandlerProc(EventHandlerCallRef callRef,
  94. EventRef event, void *userData) __attribute__ ((__noreturn__));
  95. #endif
  96. /*
  97.  *----------------------------------------------------------------------
  98.  *
  99.  * CarbonEventHandlerProc --
  100.  *
  101.  * This procedure is the handler for all registered CarbonEvents.
  102.  *
  103.  * Results:
  104.  * OS status code.
  105.  *
  106.  * Side effects:
  107.  * Dispatches CarbonEvents.
  108.  *
  109.  *----------------------------------------------------------------------
  110.  */
  111. static OSStatus
  112. CarbonEventHandlerProc(
  113.     EventHandlerCallRef callRef,
  114.     EventRef event,
  115.     void *userData)
  116. {
  117.     OSStatus err = eventNotHandledErr;
  118.     TkMacOSXEvent macEvent;
  119.     MacEventStatus eventStatus;
  120.     macEvent.eventRef = event;
  121.     macEvent.eClass = GetEventClass(event);
  122.     macEvent.eKind = GetEventKind(event);
  123.     macEvent.interp = (Tcl_Interp *) userData;
  124.     macEvent.callRef = callRef;
  125.     bzero(&eventStatus, sizeof(eventStatus));
  126. #ifdef TK_MAC_DEBUG_CARBON_EVENTS
  127.     if (!(macEvent.eClass == kEventClassMouse && (
  128.     macEvent.eKind == kEventMouseMoved ||
  129.     macEvent.eKind == kEventMouseDragged))) {
  130. TkMacOSXDbgMsg("Started handling %s",
  131. TkMacOSXCarbonEventToAscii(event));
  132. TkMacOSXInitNamedDebugSymbol(HIToolbox, void, _DebugPrintEvent,
  133. EventRef inEvent);
  134. if (_DebugPrintEvent) {
  135.     /*
  136.      * Carbon-internal event debugging (c.f. Technote 2124)
  137.      */
  138.     _DebugPrintEvent(event);
  139. }
  140.     }
  141. #endif /* TK_MAC_DEBUG_CARBON_EVENTS */
  142.     TkMacOSXProcessEvent(&macEvent,&eventStatus);
  143.     if (eventStatus.stopProcessing) {
  144. err = noErr;
  145.     }
  146. #ifdef TK_MAC_DEBUG_CARBON_EVENTS
  147.     if (macEvent.eKind != kEventMouseMoved &&
  148.     macEvent.eKind != kEventMouseDragged) {
  149. TkMacOSXDbgMsg("Finished handling %s: %s handled",
  150. TkMacOSXCarbonEventToAscii(event),
  151. eventStatus.stopProcessing ? "   " : "not");
  152.     }
  153. #endif /* TK_MAC_DEBUG_CARBON_EVENTS */
  154.     return err;
  155. }
  156. /*
  157.  *----------------------------------------------------------------------
  158.  *
  159.  * TkMacOSXInitCarbonEvents --
  160.  *
  161.  * This procedure initializes all CarbonEvent handlers.
  162.  *
  163.  * Results:
  164.  * None.
  165.  *
  166.  * Side effects:
  167.  * Handlers for Carbon Events are registered.
  168.  *
  169.  *----------------------------------------------------------------------
  170.  */
  171. MODULE_SCOPE void
  172. TkMacOSXInitCarbonEvents(
  173.     Tcl_Interp *interp)
  174. {
  175.     const EventTypeSpec dispatcherEventTypes[] = {
  176. {kEventClassKeyboard,  kEventRawKeyDown},
  177. {kEventClassKeyboard,  kEventRawKeyRepeat},
  178. {kEventClassKeyboard,  kEventRawKeyUp},
  179. {kEventClassKeyboard,  kEventRawKeyModifiersChanged},
  180. {kEventClassKeyboard,  kEventRawKeyRepeat},
  181.     };
  182.     const EventTypeSpec applicationEventTypes[] = {
  183. {kEventClassMenu,  kEventMenuBeginTracking},
  184. {kEventClassMenu,  kEventMenuEndTracking},
  185. {kEventClassMenu,  kEventMenuOpening},
  186. {kEventClassMenu,  kEventMenuTargetItem},
  187. {kEventClassCommand,  kEventCommandProcess},
  188. {kEventClassCommand,  kEventCommandUpdateStatus},
  189. {kEventClassApplication, kEventAppActivated},
  190. {kEventClassApplication, kEventAppDeactivated},
  191. {kEventClassApplication, kEventAppQuit},
  192. {kEventClassApplication, kEventAppHidden},
  193. {kEventClassApplication, kEventAppShown},
  194. {kEventClassApplication, kEventAppAvailableWindowBoundsChanged},
  195. {kEventClassAppearance,  kEventAppearanceScrollBarVariantChanged},
  196.     };
  197.     carbonEventHandlerUPP = NewEventHandlerUPP(CarbonEventHandlerProc);
  198.     carbonEventInterp = interp;
  199.     ChkErr(InstallStandardApplicationEventHandler);
  200.     ChkErr(InstallEventHandler, GetEventDispatcherTarget(),
  201.     carbonEventHandlerUPP, GetEventTypeCount(dispatcherEventTypes),
  202.     dispatcherEventTypes, (void *) carbonEventInterp, NULL);
  203.     ChkErr(InstallEventHandler, GetApplicationEventTarget(),
  204.     carbonEventHandlerUPP, GetEventTypeCount(applicationEventTypes),
  205.     applicationEventTypes, (void *) carbonEventInterp, NULL);
  206. #ifdef TK_MAC_DEBUG_CARBON_EVENTS
  207.     TkMacOSXInitNamedDebugSymbol(HIToolbox, void, _TraceEventByName,
  208.     CFStringRef);
  209.     if (_TraceEventByName) {
  210. /* Carbon-internal event debugging (c.f. Technote 2124) */
  211. _TraceEventByName(CFSTR("kEventRawKeyDown"));
  212. _TraceEventByName(CFSTR("kEventRawKeyRepeat"));
  213. _TraceEventByName(CFSTR("kEventRawKeyUp"));
  214. _TraceEventByName(CFSTR("kEventRawKeyModifiersChanged"));
  215. _TraceEventByName(CFSTR("kEventRawKeyRepeat"));
  216. _TraceEventByName(CFSTR("kEventMenuBeginTracking"));
  217. _TraceEventByName(CFSTR("kEventMenuEndTracking"));
  218. _TraceEventByName(CFSTR("kEventMenuOpening"));
  219. _TraceEventByName(CFSTR("kEventMenuTargetItem"));
  220. _TraceEventByName(CFSTR("kEventCommandProcess"));
  221. _TraceEventByName(CFSTR("kEventCommandUpdateStatus"));
  222. _TraceEventByName(CFSTR("kEventAppActivated"));
  223. _TraceEventByName(CFSTR("kEventAppDeactivated"));
  224. _TraceEventByName(CFSTR("kEventAppQuit"));
  225. _TraceEventByName(CFSTR("kEventAppHidden"));
  226. _TraceEventByName(CFSTR("kEventAppShown"));
  227. _TraceEventByName(CFSTR("kEventAppAvailableWindowBoundsChanged"));
  228. _TraceEventByName(CFSTR("kEventAppearanceScrollBarVariantChanged"));
  229. _TraceEventByName(CFSTR("kEventMouseDown"));
  230. _TraceEventByName(CFSTR("kEventMouseUp"));
  231. #if 0
  232. _TraceEventByName(CFSTR("kEventMouseMoved"));
  233. _TraceEventByName(CFSTR("kEventMouseDragged"));
  234. #endif
  235. _TraceEventByName(CFSTR("kEventMouseWheelMoved"));
  236. _TraceEventByName(CFSTR("kEventMouseScroll"));
  237. _TraceEventByName(CFSTR("kEventWindowActivated"));
  238. _TraceEventByName(CFSTR("kEventWindowDeactivated"));
  239. _TraceEventByName(CFSTR("kEventWindowUpdate"));
  240. _TraceEventByName(CFSTR("kEventWindowExpanding"));
  241. _TraceEventByName(CFSTR("kEventWindowBoundsChanged"));
  242. _TraceEventByName(CFSTR("kEventWindowDragStarted"));
  243. _TraceEventByName(CFSTR("kEventWindowDragCompleted"));
  244. _TraceEventByName(CFSTR("kEventWindowConstrain"));
  245. _TraceEventByName(CFSTR("kEventWindowGetRegion"));
  246. _TraceEventByName(CFSTR("kEventWindowDrawContent"));
  247.     }
  248. #endif /* TK_MAC_DEBUG_CARBON_EVENTS */
  249. }
  250. /*
  251.  *----------------------------------------------------------------------
  252.  *
  253.  * TkMacOSXInstallWindowCarbonEventHandler --
  254.  *
  255.  * This procedure installs our window CarbonEvent handler.
  256.  *
  257.  * Results:
  258.  * None.
  259.  *
  260.  * Side effects:
  261.  * Handler for Carbon Events is registered.
  262.  *
  263.  *----------------------------------------------------------------------
  264.  */
  265. MODULE_SCOPE void
  266. TkMacOSXInstallWindowCarbonEventHandler(
  267. Tcl_Interp *interp, WindowRef window)
  268. {
  269.     const EventTypeSpec windowEventTypes[] = {
  270. {kEventClassMouse,  kEventMouseDown},
  271. {kEventClassMouse,  kEventMouseUp},
  272. {kEventClassMouse,  kEventMouseMoved},
  273. {kEventClassMouse,  kEventMouseDragged},
  274. {kEventClassMouse,  kEventMouseWheelMoved},
  275. {kEventClassWindow,  kEventWindowActivated},
  276. {kEventClassWindow,  kEventWindowDeactivated},
  277. {kEventClassWindow,  kEventWindowUpdate},
  278. {kEventClassWindow,  kEventWindowExpanding},
  279. {kEventClassWindow,  kEventWindowBoundsChanged},
  280. {kEventClassWindow,  kEventWindowDragStarted},
  281. {kEventClassWindow,  kEventWindowDragCompleted},
  282. {kEventClassWindow,  kEventWindowConstrain},
  283. {kEventClassWindow,  kEventWindowGetRegion},
  284. {kEventClassWindow,  kEventWindowDrawContent},
  285.     };
  286.     ChkErr(InstallEventHandler, GetWindowEventTarget(window),
  287.     carbonEventHandlerUPP, GetEventTypeCount(windowEventTypes),
  288.     windowEventTypes, (void *) (interp ? interp : carbonEventInterp),
  289.     NULL);
  290. }
  291. /*
  292.  *----------------------------------------------------------------------
  293.  *
  294.  * InstallStandardApplicationEventHandler --
  295.  *
  296.  * This procedure installs the carbon standard application event
  297.  * handler.
  298.  *
  299.  * Results:
  300.  * OS status code.
  301.  *
  302.  * Side effects:
  303.  * Standard handlers for application Carbon Events are registered.
  304.  *
  305.  *----------------------------------------------------------------------
  306.  */
  307. static OSStatus
  308. InstallStandardApplicationEventHandler(void)
  309. {
  310.     OSStatus err = memFullErr;
  311.     TK_IF_HI_TOOLBOX(5,
  312.        /*
  313. * The approach below does not work correctly in Leopard, it leads to
  314. * crashes in [NSView unlockFocus] whenever HIToolbox uses Cocoa (Help
  315. * menu, Nav Services, Color Picker). While it is now possible to
  316. * install the standard app handler with InstallStandardEventHandler(),
  317. * to fully replicate RAEL the standard menubar event handler also needs
  318. * to be installed. Unfortunately there appears to be no public API to
  319. * obtain the menubar event target. As a workaround, for now we resort
  320. * to calling the HIToolbox-internal GetMenuBarEventTarget() directly
  321. * (symbol acquired via TkMacOSXInitNamedDebugSymbol() from HIToolbox
  322. * version 343, may not exist in later versions).
  323. */
  324. err = ChkErr(InstallStandardEventHandler, GetApplicationEventTarget());
  325. TkMacOSXInitNamedDebugSymbol(HIToolbox, EventTargetRef,
  326. GetMenuBarEventTarget, void);
  327. if (GetMenuBarEventTarget) {
  328.     ChkErr(InstallStandardEventHandler, GetMenuBarEventTarget());
  329. } else {
  330.     TkMacOSXDbgMsg("Unable to install standard menubar event handler");
  331. }
  332.     ) TK_ELSE_HI_TOOLBOX (5,
  333.        /*
  334. * This is a hack to workaround missing Carbon API to install the
  335. * standard application event handler (InstallStandardEventHandler()
  336. * does not work on the application target). The only way to install the
  337. * standard app handler is to call RunApplicationEventLoop(), but since
  338. * we are running our own event loop, we'll immediately need to break
  339. * out of RAEL again: we do this via longjmp out of the
  340. * ExitRaelEventHandlerProc event handler called first off from RAEL by
  341. * posting a high priority dummy event. This workaround is derived from
  342. * a similar approach in Technical Q&A 1061.
  343. */
  344. enum {
  345.     kExitRaelEvent = 'ExiT'
  346. };
  347. const EventTypeSpec exitRaelEventType = {
  348.     kExitRaelEvent, kExitRaelEvent
  349. };
  350. EventHandlerUPP exitRaelEventHandler;
  351. EventHandlerRef exitRaelEventHandlerRef = NULL;
  352. EventRef exitRaelEvent = NULL;
  353. exitRaelEventHandler = NewEventHandlerUPP(
  354. (EventHandlerProcPtr) ExitRaelEventHandlerProc);
  355. if (exitRaelEventHandler) {
  356.     err = ChkErr(InstallEventHandler, GetEventDispatcherTarget(),
  357.     exitRaelEventHandler, 1, &exitRaelEventType, NULL,
  358.     &exitRaelEventHandlerRef);
  359. }
  360. if (err == noErr) {
  361.     err = ChkErr(CreateEvent, NULL, kExitRaelEvent, kExitRaelEvent,
  362.     GetCurrentEventTime(), kEventAttributeNone,
  363.     &exitRaelEvent);
  364. }
  365. if (err == noErr) {
  366.     err = ChkErr(PostEventToQueue, GetMainEventQueue(), exitRaelEvent,
  367.     kEventPriorityHigh);
  368. }
  369. if (err == noErr) {
  370.     if (!setjmp(exitRaelJmpBuf)) {
  371. RunApplicationEventLoop();
  372. /*
  373.  * This point should never be reached!
  374.  */
  375. Tcl_Panic("RunApplicationEventLoop exited !");
  376.     }
  377. }
  378. if (exitRaelEvent) {
  379.     ReleaseEvent(exitRaelEvent);
  380. }
  381. if (exitRaelEventHandlerRef) {
  382.     RemoveEventHandler(exitRaelEventHandlerRef);
  383. }
  384. if (exitRaelEventHandler) {
  385.     DisposeEventHandlerUPP(exitRaelEventHandler);
  386. }
  387.     ) TK_ENDIF
  388.     return err;
  389. }
  390. #if MAC_OS_X_VERSION_MIN_REQUIRED < 1050
  391. /*
  392.  *----------------------------------------------------------------------
  393.  *
  394.  * ExitRaelEventHandlerProc --
  395.  *
  396.  * This procedure is the dummy event handler used to break out of
  397.  * RAEL via longjmp, it is called as the first ever event handler
  398.  * in RAEL by posting a high priority dummy event.
  399.  *
  400.  * Results:
  401.  * None. Never returns !
  402.  *
  403.  * Side effects:
  404.  * longjmp back to InstallStandardApplicationEventHandler().
  405.  *
  406.  *----------------------------------------------------------------------
  407.  */
  408. static void
  409. ExitRaelEventHandlerProc(
  410.     EventHandlerCallRef callRef,
  411.     EventRef event,
  412.     void *userData)
  413. {
  414.     longjmp(exitRaelJmpBuf, 1);
  415. }
  416. #endif
  417. /*
  418.  *----------------------------------------------------------------------
  419.  *
  420.  * TkMacOSXRunTclEventLoop --
  421.  *
  422.  * Process a limited number of tcl events.
  423.  *
  424.  * Results:
  425.  * Returns 1 if events were handled and 0 otherwise.
  426.  *
  427.  * Side effects:
  428.  * Runs the Tcl event loop.
  429.  *
  430.  *----------------------------------------------------------------------
  431.  */
  432. MODULE_SCOPE int
  433. TkMacOSXRunTclEventLoop(void)
  434. {
  435.     int i = 4, result = 0;
  436.     /* Avoid starving main event loop: process at most 4 events. */
  437.     while(--i && Tcl_ServiceAll()) {
  438. result = 1;
  439.     }
  440.     return result;
  441. }
  442. /*
  443.  *----------------------------------------------------------------------
  444.  *
  445.  * CarbonTimerProc --
  446.  *
  447.  * This procedure is the carbon timer handler that runs the tcl
  448.  * event loop periodically.
  449.  *
  450.  * Results:
  451.  * None.
  452.  *
  453.  * Side effects:
  454.  * Runs the Tcl event loop.
  455.  *
  456.  *----------------------------------------------------------------------
  457.  */
  458. static void
  459. CarbonTimerProc(
  460.     EventLoopTimerRef timer,
  461.     void *userData)
  462. {
  463.     if(carbonTimerEnabled > 0 && TkMacOSXRunTclEventLoop()) {
  464. #ifdef TK_MAC_DEBUG_CARBON_EVENTS
  465. TkMacOSXDbgMsg("Processed tcl events from carbon timer");
  466. #endif /* TK_MAC_DEBUG_CARBON_EVENTS */
  467.     }
  468. }
  469. /*
  470.  *----------------------------------------------------------------------
  471.  *
  472.  * TkMacOSXStartTclEventLoopCarbonTimer --
  473.  *
  474.  * This procedure installs (if necessary) and starts a carbon
  475.  * event timer that runs the tcl event loop periodically.
  476.  * It should be called whenever a nested carbon event loop might
  477.  * run by HIToolbox (e.g. during mouse tracking) to ensure that
  478.  * tcl events continue to be processed.
  479.  *
  480.  * Results:
  481.  * OS status code.
  482.  *
  483.  * Side effects:
  484.  * Carbon event timer is installed and started.
  485.  *
  486.  *----------------------------------------------------------------------
  487.  */
  488. MODULE_SCOPE OSStatus
  489. TkMacOSXStartTclEventLoopCarbonTimer(void)
  490. {
  491.     OSStatus err = noErr;
  492.     if (++carbonTimerEnabled > 0) {
  493. if(!carbonTimer) {
  494.     EventLoopTimerUPP timerUPP = NewEventLoopTimerUPP(CarbonTimerProc);
  495.     err = ChkErr(InstallEventLoopTimer, GetMainEventLoop(),
  496.     5 * kEventDurationMillisecond,
  497.     5 * kEventDurationMillisecond,
  498.     timerUPP, NULL, &carbonTimer);
  499. } else {
  500.     err = ChkErr(SetEventLoopTimerNextFireTime, carbonTimer,
  501.     5 * kEventDurationMillisecond);
  502. }
  503.     }
  504.     return err;
  505. }
  506. /*
  507.  *----------------------------------------------------------------------
  508.  *
  509.  * TkMacOSXStopTclEventLoopCarbonTimer --
  510.  *
  511.  * This procedure stops the carbon event timer started by
  512.  * TkMacOSXStartTclEventLoopCarbonTimer().
  513.  *
  514.  * Results:
  515.  * OS status code.
  516.  *
  517.  * Side effects:
  518.  * Carbon event timer is stopped.
  519.  *
  520.  *----------------------------------------------------------------------
  521.  */
  522. MODULE_SCOPE OSStatus
  523. TkMacOSXStopTclEventLoopCarbonTimer(void)
  524. {
  525.     OSStatus err = noErr;
  526.     if (--carbonTimerEnabled == 0) {
  527. if(carbonTimer) {
  528.     err = ChkErr(SetEventLoopTimerNextFireTime, carbonTimer,
  529.     kEventDurationForever);
  530. }
  531.     }
  532.     return err;
  533. }
  534. /*
  535.  *----------------------------------------------------------------------
  536.  *
  537.  * TkMacOSXTrackingLoop --
  538.  *
  539.  * Call with 1 before entering a mouse tracking loop (e.g. window
  540.  * resizing or menu tracking) to enable tcl event processing but
  541.  * disable  carbon event processing (except for update events)
  542.  * during the loop, and with 0 after exiting the loop to reset.
  543.  *
  544.  * Results:
  545.  * None.
  546.  *
  547.  * Side effects:
  548.  * None.
  549.  *
  550.  *----------------------------------------------------------------------
  551.  */
  552. MODULE_SCOPE void
  553. TkMacOSXTrackingLoop(int tracking)
  554. {
  555.     static int previousServiceMode = TCL_SERVICE_NONE;
  556.     if (tracking) {
  557. inTrackingLoop++;
  558. previousServiceMode = Tcl_SetServiceMode(TCL_SERVICE_ALL);
  559. TkMacOSXStartTclEventLoopCarbonTimer();
  560. #ifdef TK_MAC_DEBUG_CARBON_EVENTS
  561. TkMacOSXDbgMsg("Entering tracking loop");
  562. #endif /* TK_MAC_DEBUG_CARBON_EVENTS */
  563.     } else {
  564. TkMacOSXStopTclEventLoopCarbonTimer();
  565. previousServiceMode = Tcl_SetServiceMode(previousServiceMode);
  566. inTrackingLoop--;
  567. #ifdef TK_MAC_DEBUG_CARBON_EVENTS
  568. TkMacOSXDbgMsg("Exiting tracking loop");
  569. #endif /* TK_MAC_DEBUG_CARBON_EVENTS */
  570.     }
  571. }
  572. /*
  573.  *----------------------------------------------------------------------
  574.  *
  575.  * TkMacOSXReceiveAndDispatchEvent --
  576.  *
  577.  * This receives a carbon event and sends it to the carbon event
  578.  * dispatcher.
  579.  *
  580.  * Results:
  581.  * Mac OS status
  582.  *
  583.  * Side effects:
  584.  * This receives and dispatches the next Carbon event.
  585.  *
  586.  *----------------------------------------------------------------------
  587.  */
  588. MODULE_SCOPE OSStatus
  589. TkMacOSXReceiveAndDispatchEvent(void)
  590. {
  591.     static EventTargetRef targetRef = NULL;
  592.     int numEventTypes = 0;
  593.     const EventTypeSpec *eventTypes = NULL;
  594.     EventRef eventRef;
  595.     OSStatus err;
  596.     const EventTypeSpec trackingEventTypes[] = {
  597. {'dniw',  kEventWindowUpdate},
  598. {kEventClassWindow,  kEventWindowUpdate},
  599.     };
  600.     if (inTrackingLoop > 0) {
  601. eventTypes = trackingEventTypes;
  602. numEventTypes = GetEventTypeCount(trackingEventTypes);
  603.     }
  604.     /*
  605.      * This is a poll, since we have already counted the events coming
  606.      * into this routine, and are guaranteed to have one waiting.
  607.      */
  608.     err = ReceiveNextEvent(numEventTypes, eventTypes,
  609.     kEventDurationNoWait, true, &eventRef);
  610.     if (err == noErr) {
  611. #ifdef TK_MAC_DEBUG_CARBON_EVENTS
  612. UInt32 kind = GetEventKind(eventRef);
  613. if (kind != kEventMouseMoved && kind != kEventMouseDragged) {
  614.     TkMacOSXDbgMsg("Dispatching %s", TkMacOSXCarbonEventToAscii(eventRef));
  615.     TkMacOSXInitNamedDebugSymbol(HIToolbox, void, _DebugPrintEvent,
  616.     EventRef inEvent);
  617.     if (_DebugPrintEvent) {
  618. /* Carbon-internal event debugging (c.f. Technote 2124) */
  619. _DebugPrintEvent(eventRef);
  620.     }
  621. }
  622. #endif /* TK_MAC_DEBUG_CARBON_EVENTS */
  623. if (!targetRef) {
  624.     targetRef = GetEventDispatcherTarget();
  625. }
  626. TkMacOSXStartTclEventLoopCarbonTimer();
  627. err = SendEventToEventTarget(eventRef, targetRef);
  628. TkMacOSXStopTclEventLoopCarbonTimer();
  629. if (err != noErr && err != eventLoopTimedOutErr
  630. && err != eventNotHandledErr) {
  631.     TkMacOSXDbgMsg("SendEventToEventTarget(%s) failed: %ld",
  632.     TkMacOSXCarbonEventToAscii(eventRef), err);
  633. }
  634. ReleaseEvent(eventRef);
  635.     } else if (err != eventLoopTimedOutErr) {
  636. TkMacOSXDbgMsg("ReceiveNextEvent failed: %ld", err);
  637.     }
  638.     return err;
  639. }