1/*
2 * tkMacOSXEvent.c --
3 *
4 *	This file contains the basic Mac OS X Event handling routines.
5 *
6 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
7 * Copyright 2001, Apple Computer, Inc.
8 * Copyright (c) 2005-2007 Daniel A. Steffen <das@users.sourceforge.net>
9 *
10 * See the file "license.terms" for information on usage and redistribution
11 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12 *
13 * RCS: @(#) $Id: tkMacOSXEvent.c,v 1.3.2.16 2007/11/09 06:26:55 das Exp $
14 */
15
16#include "tkMacOSXPrivate.h"
17#include "tkMacOSXEvent.h"
18#include "tkMacOSXDebug.h"
19
20
21/*
22 *----------------------------------------------------------------------
23 *
24 * TkMacOSXFlushWindows --
25 *
26 *	This routine flushes all the Carbon windows of the application. It
27 *	is called by XSync().
28 *
29 * Results:
30 *	None.
31 *
32 * Side effects:
33 *	Flushes all Carbon windows
34 *
35 *----------------------------------------------------------------------
36 */
37
38MODULE_SCOPE void
39TkMacOSXFlushWindows(void)
40{
41    WindowRef wRef = GetWindowList();
42
43    while (wRef) {
44	TK_IF_MAC_OS_X_API (3, HIWindowFlush,
45	    ChkErr(HIWindowFlush, wRef);
46	) TK_ELSE_MAC_OS_X (3,
47	    CGrafPtr portPtr = GetWindowPort(wRef);
48
49	    if (QDIsPortBuffered(portPtr)) {
50		QDFlushPortBuffer(portPtr, NULL);
51	    }
52	) TK_ENDIF
53	wRef = GetNextWindow(wRef);
54    }
55}
56
57/*
58 *----------------------------------------------------------------------
59 *
60 * TkMacOSXProcessEvent --
61 *
62 *	This dispatches a filtered Carbon event to the appropriate handler
63 *
64 *	Note on MacEventStatus.stopProcessing: Please be conservative in the
65 *	individual handlers and don't assume the event is fully handled
66 *	unless you *really* need to ensure that other handlers don't see the
67 *	event anymore. Some OS manager or library might be interested in
68 *	events even after they are already handled on the Tk level.
69 *
70 * Results:
71 *	0 on success
72 *	-1 on failure
73 *
74 * Side effects:
75 *	Converts a Carbon event to a Tk event
76 *
77 *----------------------------------------------------------------------
78 */
79
80MODULE_SCOPE int
81TkMacOSXProcessEvent(
82    TkMacOSXEvent *eventPtr,
83    MacEventStatus *statusPtr)
84{
85    switch (eventPtr->eClass) {
86	case kEventClassMouse:
87	    TkMacOSXProcessMouseEvent(eventPtr, statusPtr);
88	    break;
89	case kEventClassWindow:
90	    TkMacOSXProcessWindowEvent(eventPtr, statusPtr);
91	    break;
92	case kEventClassKeyboard:
93	    TkMacOSXProcessKeyboardEvent(eventPtr, statusPtr);
94	    break;
95	case kEventClassApplication:
96	    TkMacOSXProcessApplicationEvent(eventPtr, statusPtr);
97	    break;
98	case kEventClassAppearance:
99	    TkMacOSXProcessAppearanceEvent(eventPtr, statusPtr);
100	    break;
101	case kEventClassMenu:
102	    TkMacOSXProcessMenuEvent(eventPtr, statusPtr);
103	    break;
104	case kEventClassCommand:
105	    TkMacOSXProcessCommandEvent(eventPtr, statusPtr);
106	    break;
107	default: {
108	    TkMacOSXDbgMsg("Unrecognised event: %s",
109		    TkMacOSXCarbonEventToAscii(eventPtr->eventRef));
110	    break;
111	}
112    }
113    return 0;
114}
115
116/*
117 *----------------------------------------------------------------------
118 *
119 * TkMacOSXProcessMenuEvent --
120 *
121 *	This routine processes the event in eventPtr, and
122 *	generates the appropriate Tk events from it.
123 *
124 * Results:
125 *	True if event(s) are generated - false otherwise.
126 *
127 * Side effects:
128 *	Additional events may be place on the Tk event queue.
129 *
130 *----------------------------------------------------------------------
131 */
132
133MODULE_SCOPE int
134TkMacOSXProcessMenuEvent(
135    TkMacOSXEvent *eventPtr,
136    MacEventStatus *statusPtr)
137{
138    int menuContext;
139    OSStatus err;
140
141    switch (eventPtr->eKind) {
142	case kEventMenuBeginTracking:
143	case kEventMenuEndTracking:
144	case kEventMenuOpening:
145	case kEventMenuTargetItem:
146	    break;
147	default:
148	    return 0;
149	    break;
150    }
151    err = ChkErr(GetEventParameter, eventPtr->eventRef, kEventParamMenuContext,
152	    typeUInt32, NULL, sizeof(menuContext), NULL, &menuContext);
153    if (err == noErr && ((menuContext & kMenuContextMenuBarTracking) ||
154	    (menuContext & kMenuContextPopUpTracking))) {
155	switch (eventPtr->eKind) {
156	    MenuRef menu;
157
158	    case kEventMenuBeginTracking:
159		TkMacOSXClearMenubarActive();
160
161		/*
162		 * Handle -postcommand
163		 */
164
165		TkMacOSXPreprocessMenu();
166		TkMacOSXTrackingLoop(1);
167		break;
168	    case kEventMenuEndTracking:
169		TkMacOSXTrackingLoop(0);
170		break;
171	    case kEventMenuOpening:
172		err = ChkErr(GetEventParameter, eventPtr->eventRef,
173			kEventParamDirectObject, typeMenuRef, NULL,
174			sizeof(menu), NULL, &menu);
175		if (err == noErr) {
176		    TkMacOSXClearActiveMenu(menu);
177		    return TkMacOSXGenerateParentMenuSelectEvent(menu);
178		}
179		break;
180	    case kEventMenuTargetItem:
181		err = ChkErr(GetEventParameter, eventPtr->eventRef,
182			kEventParamDirectObject, typeMenuRef, NULL,
183			sizeof(menu), NULL, &menu);
184		if (err == noErr) {
185		    MenuItemIndex index;
186
187		    err = ChkErr(GetEventParameter, eventPtr->eventRef,
188			    kEventParamMenuItemIndex, typeMenuItemIndex, NULL,
189			    sizeof(index), NULL, &index);
190		    if (err == noErr) {
191			return TkMacOSXGenerateMenuSelectEvent(menu, index);
192		    }
193		}
194		break;
195	}
196    }
197    return 0;
198}
199
200/*
201 *----------------------------------------------------------------------
202 *
203 * TkMacOSXProcessCommandEvent --
204 *
205 *	This routine processes the event in eventPtr, and
206 *	generates the appropriate Tk events from it.
207 *
208 * Results:
209 *	True if event(s) are generated - false otherwise.
210 *
211 * Side effects:
212 *	Additional events may be place on the Tk event queue.
213 *
214 *----------------------------------------------------------------------
215 */
216
217MODULE_SCOPE int
218TkMacOSXProcessCommandEvent(
219    TkMacOSXEvent *eventPtr,
220    MacEventStatus * statusPtr)
221{
222    HICommand command;
223    int menuContext;
224    OSStatus err;
225
226    switch (eventPtr->eKind) {
227	case kEventCommandProcess:
228	case kEventCommandUpdateStatus:
229	    break;
230	default:
231	    return 0;
232	    break;
233    }
234    err = ChkErr(GetEventParameter, eventPtr->eventRef,
235	    kEventParamDirectObject, typeHICommand, NULL, sizeof(command),
236	    NULL, &command);
237    if (err == noErr && (command.attributes & kHICommandFromMenu)) {
238	if (eventPtr->eKind == kEventCommandProcess) {
239	    err = ChkErr(GetEventParameter, eventPtr->eventRef,
240		    kEventParamMenuContext, typeUInt32, NULL,
241		    sizeof(menuContext), NULL, &menuContext);
242	    if (err == noErr && (menuContext & kMenuContextMenuBar) &&
243		    (menuContext & kMenuContextMenuBarTracking)) {
244		TkMacOSXHandleMenuSelect(GetMenuID(command.menu.menuRef),
245			command.menu.menuItemIndex,
246			(GetCurrentEventKeyModifiers() & optionKey) != 0);
247		return 1;
248	    }
249	} else {
250	    Tcl_CmdInfo dummy;
251	    if (command.commandID == kHICommandPreferences && eventPtr->interp) {
252		if (Tcl_GetCommandInfo(eventPtr->interp,
253			"::tk::mac::ShowPreferences", &dummy)) {
254		    if (!IsMenuItemEnabled(command.menu.menuRef,
255			    command.menu.menuItemIndex)) {
256			EnableMenuItem(command.menu.menuRef,
257				command.menu.menuItemIndex);
258		    }
259		} else {
260		    if (IsMenuItemEnabled(command.menu.menuRef,
261			    command.menu.menuItemIndex)) {
262			DisableMenuItem(command.menu.menuRef,
263				command.menu.menuItemIndex);
264		    }
265		}
266		statusPtr->stopProcessing = 1;
267		return 1;
268	    }
269	}
270    }
271    return 0;
272}
273