summaryrefslogtreecommitdiffstats
path: root/macosx/tkMacOSXNotify.c
blob: d36829249c56a5aecdd02f3dbb27c8e0410becb2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
/*
 * tkMacOSXNotify.c --
 *
 *	This file contains the implementation of a tcl event source
 *	for the Carbon event loop.
 *
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
 * Copyright 2001, Apple Computer, Inc.
 * Copyright (c) 2005-2007 Daniel A. Steffen <das@users.sourceforge.net>
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#include "tkMacOSXPrivate.h"
#include "tkMacOSXEvent.h"
#include <pthread.h>

/*
 * The following static indicates whether this module has been initialized
 * in the current thread.
 */

typedef struct ThreadSpecificData {
    int initialized;
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;

static void TkMacOSXNotifyExitHandler(ClientData clientData);
static void CarbonEventsSetupProc(ClientData clientData, int flags);
static void CarbonEventsCheckProc(ClientData clientData, int flags);

/*
 *----------------------------------------------------------------------
 *
 * Tk_MacOSXSetupTkNotifier --
 *
 *	This procedure is called during Tk initialization to create
 *	the event source for Carbon events.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	A new event source is created.
 *
 *----------------------------------------------------------------------
 */

void
Tk_MacOSXSetupTkNotifier(void)
{
    ThreadSpecificData *tsdPtr = Tcl_GetThreadData(&dataKey,
	    sizeof(ThreadSpecificData));

    if (!tsdPtr->initialized) {
	/* HACK ALERT: There is a bug in Jaguar where when it goes to make
	 * the event queue for the Main Event Loop, it stores the Current
	 * event loop rather than the Main Event Loop in the Queue structure.
	 * So we have to make sure that the Main Event Queue gets set up on
	 * the main thread. Calling GetMainEventQueue will force this to
	 * happen.
	 */
	GetMainEventQueue();

	tsdPtr->initialized = 1;
	/* Install Carbon events event source in main event loop thread. */
	if (GetCurrentEventLoop() == GetMainEventLoop()) {
	    if (!pthread_main_np()) {
		/*
		 * Panic if the Carbon main event loop thread (i.e. the
		 * thread  where HIToolbox was first loaded) is not the
		 * main application thread, as Carbon does not support
		 * this properly.
		 */
		Tcl_Panic("Tk_MacOSXSetupTkNotifier: %s",
		    "first [load] of TkAqua has to occur in the main thread!");
	    }
	    Tcl_CreateEventSource(CarbonEventsSetupProc,
		    CarbonEventsCheckProc, GetMainEventQueue());
	    TkCreateExitHandler(TkMacOSXNotifyExitHandler, NULL);
	}
    }
}

/*
 *----------------------------------------------------------------------
 *
 * TkMacOSXNotifyExitHandler --
 *
 *	This function is called during finalization to clean up the
 *	TkMacOSXNotify module.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

static void
TkMacOSXNotifyExitHandler(clientData)
    ClientData clientData;	/* Not used. */
{
    ThreadSpecificData *tsdPtr = Tcl_GetThreadData(&dataKey,
	    sizeof(ThreadSpecificData));

    Tcl_DeleteEventSource(CarbonEventsSetupProc,
	    CarbonEventsCheckProc, GetMainEventQueue());
    tsdPtr->initialized = 0;
}

/*
 *----------------------------------------------------------------------
 *
 * CarbonEventsSetupProc --
 *
 *	This procedure implements the setup part of the Carbon Events
 *	event source. It is invoked by Tcl_DoOneEvent before entering
 *	the notifier to check for events.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	If Carbon events are queued, then the maximum block time will be
 *	set to 0 to ensure that the notifier returns control to Tcl.
 *
 *----------------------------------------------------------------------
 */

static void
CarbonEventsSetupProc(clientData, flags)
    ClientData clientData;
    int flags;
{
    static Tcl_Time blockTime = { 0, 0 };

    if (!(flags & TCL_WINDOW_EVENTS)) {
	return;
    }

    if (GetNumEventsInQueue((EventQueueRef)clientData)) {
	Tcl_SetMaxBlockTime(&blockTime);
    }
}

/*
 *----------------------------------------------------------------------
 *
 * CarbonEventsCheckProc --
 *
 *	This procedure processes events sitting in the Carbon event
 *	queue.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Moves applicable queued Carbon events onto the Tcl event queue.
 *
 *----------------------------------------------------------------------
 */

static void
CarbonEventsCheckProc(clientData, flags)
    ClientData clientData;
    int flags;
{
    int numFound;
    OSStatus err = noErr;

    if (!(flags & TCL_WINDOW_EVENTS)) {
	return;
    }

    numFound = GetNumEventsInQueue((EventQueueRef)clientData);

    /* Avoid starving other event sources: */
    if (numFound > 4) {
	numFound = 4;
    }
    while (numFound > 0 && err == noErr) {
	err = TkMacOSXReceiveAndDispatchEvent();
	numFound--;
    }
}