1/* 2 * tkMacOSXNotify.c -- 3 * 4 * This file contains the implementation of a tcl event source 5 * for the Carbon event loop. 6 * 7 * Copyright (c) 1995-1997 Sun Microsystems, Inc. 8 * Copyright 2001, Apple Computer, Inc. 9 * Copyright (c) 2005-2007 Daniel A. Steffen <das@users.sourceforge.net> 10 * 11 * See the file "license.terms" for information on usage and redistribution 12 * of this file, and for a DISCLAIMER OF ALL WARRANTIES. 13 * 14 * RCS: @(#) $Id: tkMacOSXNotify.c,v 1.5.2.12 2007/06/29 03:22:02 das Exp $ 15 */ 16 17#include "tkMacOSXPrivate.h" 18#include "tkMacOSXEvent.h" 19#include <pthread.h> 20 21/* 22 * The following static indicates whether this module has been initialized 23 * in the current thread. 24 */ 25 26typedef struct ThreadSpecificData { 27 int initialized; 28} ThreadSpecificData; 29static Tcl_ThreadDataKey dataKey; 30 31static void TkMacOSXNotifyExitHandler(ClientData clientData); 32static void CarbonEventsSetupProc(ClientData clientData, int flags); 33static void CarbonEventsCheckProc(ClientData clientData, int flags); 34 35/* 36 *---------------------------------------------------------------------- 37 * 38 * Tk_MacOSXSetupTkNotifier -- 39 * 40 * This procedure is called during Tk initialization to create 41 * the event source for Carbon events. 42 * 43 * Results: 44 * None. 45 * 46 * Side effects: 47 * A new event source is created. 48 * 49 *---------------------------------------------------------------------- 50 */ 51 52void 53Tk_MacOSXSetupTkNotifier(void) 54{ 55 ThreadSpecificData *tsdPtr = Tcl_GetThreadData(&dataKey, 56 sizeof(ThreadSpecificData)); 57 58 if (!tsdPtr->initialized) { 59 /* HACK ALERT: There is a bug in Jaguar where when it goes to make 60 * the event queue for the Main Event Loop, it stores the Current 61 * event loop rather than the Main Event Loop in the Queue structure. 62 * So we have to make sure that the Main Event Queue gets set up on 63 * the main thread. Calling GetMainEventQueue will force this to 64 * happen. 65 */ 66 GetMainEventQueue(); 67 68 tsdPtr->initialized = 1; 69 /* Install Carbon events event source in main event loop thread. */ 70 if (GetCurrentEventLoop() == GetMainEventLoop()) { 71 if (!pthread_main_np()) { 72 /* 73 * Panic if the Carbon main event loop thread (i.e. the 74 * thread where HIToolbox was first loaded) is not the 75 * main application thread, as Carbon does not support 76 * this properly. 77 */ 78 Tcl_Panic("Tk_MacOSXSetupTkNotifier: %s", 79 "first [load] of TkAqua has to occur in the main thread!"); 80 } 81 Tcl_CreateEventSource(CarbonEventsSetupProc, 82 CarbonEventsCheckProc, GetMainEventQueue()); 83 TkCreateExitHandler(TkMacOSXNotifyExitHandler, NULL); 84 } 85 } 86} 87 88/* 89 *---------------------------------------------------------------------- 90 * 91 * TkMacOSXNotifyExitHandler -- 92 * 93 * This function is called during finalization to clean up the 94 * TkMacOSXNotify module. 95 * 96 * Results: 97 * None. 98 * 99 * Side effects: 100 * None. 101 * 102 *---------------------------------------------------------------------- 103 */ 104 105static void 106TkMacOSXNotifyExitHandler(clientData) 107 ClientData clientData; /* Not used. */ 108{ 109 ThreadSpecificData *tsdPtr = Tcl_GetThreadData(&dataKey, 110 sizeof(ThreadSpecificData)); 111 112 Tcl_DeleteEventSource(CarbonEventsSetupProc, 113 CarbonEventsCheckProc, GetMainEventQueue()); 114 tsdPtr->initialized = 0; 115} 116 117/* 118 *---------------------------------------------------------------------- 119 * 120 * CarbonEventsSetupProc -- 121 * 122 * This procedure implements the setup part of the Carbon Events 123 * event source. It is invoked by Tcl_DoOneEvent before entering 124 * the notifier to check for events. 125 * 126 * Results: 127 * None. 128 * 129 * Side effects: 130 * If Carbon events are queued, then the maximum block time will be 131 * set to 0 to ensure that the notifier returns control to Tcl. 132 * 133 *---------------------------------------------------------------------- 134 */ 135 136static void 137CarbonEventsSetupProc(clientData, flags) 138 ClientData clientData; 139 int flags; 140{ 141 static Tcl_Time blockTime = { 0, 0 }; 142 143 if (!(flags & TCL_WINDOW_EVENTS)) { 144 return; 145 } 146 147 if (GetNumEventsInQueue((EventQueueRef)clientData)) { 148 Tcl_SetMaxBlockTime(&blockTime); 149 } 150} 151 152/* 153 *---------------------------------------------------------------------- 154 * 155 * CarbonEventsCheckProc -- 156 * 157 * This procedure processes events sitting in the Carbon event 158 * queue. 159 * 160 * Results: 161 * None. 162 * 163 * Side effects: 164 * Moves applicable queued Carbon events onto the Tcl event queue. 165 * 166 *---------------------------------------------------------------------- 167 */ 168 169static void 170CarbonEventsCheckProc(clientData, flags) 171 ClientData clientData; 172 int flags; 173{ 174 int numFound; 175 OSStatus err = noErr; 176 177 if (!(flags & TCL_WINDOW_EVENTS)) { 178 return; 179 } 180 181 numFound = GetNumEventsInQueue((EventQueueRef)clientData); 182 183 /* Avoid starving other event sources: */ 184 if (numFound > 4) { 185 numFound = 4; 186 } 187 while (numFound > 0 && err == noErr) { 188 err = TkMacOSXReceiveAndDispatchEvent(); 189 numFound--; 190 } 191} 192