]> git.saurik.com Git - wxWidgets.git/blame - src/osx/cocoa/evtloop.mm
no 10.4 support anymore
[wxWidgets.git] / src / osx / cocoa / evtloop.mm
CommitLineData
b503b036
SC
1///////////////////////////////////////////////////////////////////////////////
2// Name: src/osx/cocoa/evtloop.mm
3// Purpose: implementation of wxEventLoop for OS X
4// Author: Vadim Zeitlin, Stefan Csomor
5// Modified by:
6// Created: 2006-01-12
a9a4f229 7// RCS-ID: $Id$
b503b036
SC
8// Copyright: (c) 2006 Vadim Zeitlin <vadim@wxwindows.org>
9// Licence: wxWindows licence
10///////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20// for compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24 #pragma hdrstop
25#endif
26
1e04d2bf 27#include "wx/evtloop.h"
b503b036
SC
28
29#ifndef WX_PRECOMP
30 #include "wx/app.h"
bf06fbce 31 #include "wx/nonownedwnd.h"
b503b036
SC
32#endif // WX_PRECOMP
33
f965a844
RR
34#include "wx/log.h"
35
b503b036
SC
36#include "wx/osx/private.h"
37
38// ============================================================================
39// wxEventLoop implementation
40// ============================================================================
41
e9e8b381
SC
42#if 0
43
44// in case we want to integrate this
11fed901 45
902ddbfd
SC
46static NSUInteger CalculateNSEventMaskFromEventCategory(wxEventCategory cat)
47{
48 // the masking system doesn't really help, as only the lowlevel UI events
49 // are split in a useful way, all others are way to broad
50
51 if ( (cat | wxEVT_CATEGORY_USER_INPUT) && (cat | (~wxEVT_CATEGORY_USER_INPUT) ) )
52 return NSAnyEventMask;
53
54 NSUInteger mask = 0;
11fed901 55
902ddbfd
SC
56 if ( cat | wxEVT_CATEGORY_USER_INPUT )
57 {
58 mask |=
59 NSLeftMouseDownMask |
60 NSLeftMouseUpMask |
61 NSRightMouseDownMask |
62 NSRightMouseUpMask |
63 NSMouseMovedMask |
64 NSLeftMouseDraggedMask |
65 NSRightMouseDraggedMask |
66 NSMouseEnteredMask |
67 NSMouseExitedMask |
68 NSScrollWheelMask |
69#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
70 NSTabletPointMask |
71 NSTabletProximityMask |
72#endif
73 NSOtherMouseDownMask |
74 NSOtherMouseUpMask |
75 NSOtherMouseDraggedMask |
76
77 NSKeyDownMask |
78 NSKeyUpMask |
79 NSFlagsChangedMask |
80#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
81 NSEventMaskGesture |
82 NSEventMaskMagnify |
83 NSEventMaskSwipe |
84 NSEventMaskRotate |
85 NSEventMaskBeginGesture |
86 NSEventMaskEndGesture |
87#endif
88 0;
89 }
90
91 if ( cat | (~wxEVT_CATEGORY_USER_INPUT) )
92 {
93 mask |=
94 NSAppKitDefinedMask |
95 NSSystemDefinedMask |
96 NSApplicationDefinedMask |
97 NSPeriodicMask |
98 NSCursorUpdateMask;
99 }
100
101 return mask;
102}
11fed901 103
e9e8b381 104#endif
11fed901 105
902ddbfd
SC
106wxGUIEventLoop::wxGUIEventLoop()
107{
108 m_modalSession = nil;
109 m_dummyWindow = nil;
0aff141c
SC
110 m_modalNestedLevel = 0;
111 m_modalWindow = NULL;
11fed901 112}
11fed901 113
902ddbfd 114wxGUIEventLoop::~wxGUIEventLoop()
b503b036 115{
902ddbfd
SC
116 wxASSERT( m_modalSession == nil );
117 wxASSERT( m_dummyWindow == nil );
0aff141c 118 wxASSERT( m_modalNestedLevel == 0 );
6b8ef0b3
VZ
119}
120
121//-----------------------------------------------------------------------------
122// events dispatch and loop handling
123//-----------------------------------------------------------------------------
124
0056673c
SC
125#if 0
126
b503b036
SC
127bool wxGUIEventLoop::Pending() const
128{
a765eef3
SC
129#if 0
130 // this code doesn't reliably detect pending events
131 // so better return true and have the dispatch deal with it
132 // as otherwise we end up in a tight loop when idle events are responded
133 // to by RequestMore(true)
dbeddfb9 134 wxMacAutoreleasePool autoreleasepool;
a765eef3 135
b503b036
SC
136 return [[NSApplication sharedApplication]
137 nextEventMatchingMask: NSAnyEventMask
138 untilDate: nil
139 inMode: NSDefaultRunLoopMode
a765eef3
SC
140 dequeue: NO] != nil;
141#else
142 return true;
143#endif
b503b036
SC
144}
145
50d4763f 146
b503b036
SC
147bool wxGUIEventLoop::Dispatch()
148{
149 if ( !wxTheApp )
150 return false;
151
152 wxMacAutoreleasePool autoreleasepool;
153
154 if(NSEvent *event = [NSApp
155 nextEventMatchingMask:NSAnyEventMask
156 untilDate:[NSDate dateWithTimeIntervalSinceNow: m_sleepTime]
157 inMode:NSDefaultRunLoopMode
158 dequeue: YES])
159 {
0b6f851f
SC
160 WXEVENTREF formerEvent = wxTheApp == NULL ? NULL : wxTheApp->MacGetCurrentEvent();
161 WXEVENTHANDLERCALLREF formerHandler = wxTheApp == NULL ? NULL : wxTheApp->MacGetCurrentEventHandlerCallRef();
162
7dab9892
KO
163 if (wxTheApp)
164 wxTheApp->MacSetCurrentEvent(event, NULL);
b503b036
SC
165 m_sleepTime = 0.0;
166 [NSApp sendEvent: event];
0b6f851f
SC
167
168 if (wxTheApp)
169 wxTheApp->MacSetCurrentEvent(formerEvent , formerHandler);
b503b036
SC
170 }
171 else
172 {
b0a9bfc8
SC
173 if (wxTheApp)
174 wxTheApp->ProcessPendingEvents();
175
b503b036
SC
176 if ( wxTheApp->ProcessIdle() )
177 m_sleepTime = 0.0 ;
178 else
179 {
180 m_sleepTime = 1.0;
181#if wxUSE_THREADS
182 wxMutexGuiLeave();
183 wxMilliSleep(20);
184 wxMutexGuiEnter();
185#endif
186 }
187 }
188
189 return true;
190}
91407318 191
0056673c 192#endif
f965a844 193
0056673c 194int wxGUIEventLoop::DoDispatchTimeout(unsigned long timeout)
91407318
VZ
195{
196 wxMacAutoreleasePool autoreleasepool;
197
902ddbfd
SC
198 if ( m_modalSession )
199 {
200 NSInteger response = [NSApp runModalSession:(NSModalSession)m_modalSession];
201
202 switch (response)
203 {
204 case NSRunContinuesResponse:
205 {
206 if ( [[NSApplication sharedApplication]
207 nextEventMatchingMask: NSAnyEventMask
208 untilDate: nil
209 inMode: NSDefaultRunLoopMode
210 dequeue: NO] != nil )
211 return 1;
212
213 return -1;
214 }
215
216 case NSRunStoppedResponse:
217 case NSRunAbortedResponse:
218 return -1;
219 default:
220 wxFAIL_MSG("unknown response code");
902ddbfd
SC
221 break;
222 }
a624c97f 223 return -1;
902ddbfd
SC
224 }
225 else
226 {
227 NSEvent *event = [NSApp
228 nextEventMatchingMask:NSAnyEventMask
229 untilDate:[NSDate dateWithTimeIntervalSinceNow: timeout/1000]
230 inMode:NSDefaultRunLoopMode
231 dequeue: YES];
232
233 if ( event == nil )
234 return -1;
91407318 235
902ddbfd 236 [NSApp sendEvent: event];
91407318 237
902ddbfd
SC
238 return 1;
239 }
91407318 240}
80eee837
SC
241
242void wxGUIEventLoop::DoRun()
243{
244 wxMacAutoreleasePool autoreleasepool;
245 [NSApp run];
246}
247
248void wxGUIEventLoop::DoStop()
249{
2e5f9929
SC
250 // only calling stop: is not enough when called from a runloop-observer,
251 // therefore add a dummy event, to make sure the runloop gets another round
85a74f93
SC
252 [NSApp stop:0];
253 WakeUp();
254}
255
256void wxGUIEventLoop::WakeUp()
257{
50d4763f
SC
258 NSEvent* cevent = [NSApp currentEvent];
259
260 // when already in a mouse event handler, don't add higher level event
261 if ( cevent != nil && [cevent type] < NSKeyDown )
262 {
263 wxCFEventLoop::WakeUp();
264 }
265 else
266 {
267 wxMacAutoreleasePool autoreleasepool;
268 NSEvent *event = [NSEvent otherEventWithType:NSApplicationDefined
2e5f9929
SC
269 location:NSMakePoint(0.0, 0.0)
270 modifierFlags:0
271 timestamp:0
272 windowNumber:0
273 context:nil
274 subtype:0 data1:0 data2:0];
50d4763f
SC
275 [NSApp postEvent:event atStart:FALSE];
276 }
80eee837
SC
277}
278
7934e447
SC
279CFRunLoopRef wxGUIEventLoop::CFGetCurrentRunLoop() const
280{
281 NSRunLoop* nsloop = [NSRunLoop currentRunLoop];
282 return [nsloop getCFRunLoop];
283}
284
285
cfb0ef70
SC
286// TODO move into a evtloop_osx.cpp
287
288wxModalEventLoop::wxModalEventLoop(wxWindow *modalWindow)
2439f1d9 289{
cfb0ef70 290 m_modalWindow = dynamic_cast<wxNonOwnedWindow*> (modalWindow);
2439f1d9 291 wxASSERT_MSG( m_modalWindow != NULL, "must pass in a toplevel window for modal event loop" );
cfb0ef70 292 m_modalNativeWindow = m_modalWindow->GetWXWindow();
2439f1d9
SC
293}
294
cfb0ef70
SC
295wxModalEventLoop::wxModalEventLoop(WXWindow modalNativeWindow)
296{
297 m_modalWindow = NULL;
298 wxASSERT_MSG( modalNativeWindow != NULL, "must pass in a toplevel window for modal event loop" );
299 m_modalNativeWindow = modalNativeWindow;
300}
301
302// END move into a evtloop_osx.cpp
303
80eee837
SC
304void wxModalEventLoop::DoRun()
305{
306 wxMacAutoreleasePool pool;
307
308 // If the app hasn't started, flush the event queue
309 // If we don't do this, the Dock doesn't get the message that
310 // the app has started so will refuse to activate it.
311 [NSApplication sharedApplication];
312 if (![NSApp isRunning])
313 {
314 while(NSEvent *event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:nil inMode:NSDefaultRunLoopMode dequeue:YES])
315 {
316 [NSApp sendEvent:event];
317 }
318 }
319
cfb0ef70 320 [NSApp runModalForWindow:m_modalNativeWindow];
80eee837
SC
321}
322
323void wxModalEventLoop::DoStop()
324{
f834239f 325 [NSApp abortModal];
80eee837
SC
326}
327
902ddbfd
SC
328void wxGUIEventLoop::BeginModalSession( wxWindow* modalWindow )
329{
330 WXWindow nsnow = nil;
0aff141c
SC
331
332 if ( m_modalNestedLevel > 0 )
333 {
334 wxASSERT_MSG( m_modalWindow == modalWindow, "Nested Modal Sessions must be based on same window");
335 m_modalNestedLevel++;
336 return;
337 }
338
339 m_modalWindow = modalWindow;
340 m_modalNestedLevel = 1;
902ddbfd
SC
341
342 if ( modalWindow )
343 {
b64af07b
SC
344 // we must show now, otherwise beginModalSessionForWindow does it but it
345 // also would do a centering of the window before overriding all our position
346 if ( !modalWindow->IsShownOnScreen() )
347 modalWindow->Show();
348
902ddbfd
SC
349 wxNonOwnedWindow* now = dynamic_cast<wxNonOwnedWindow*> (modalWindow);
350 wxASSERT_MSG( now != NULL, "must pass in a toplevel window for modal event loop" );
351 nsnow = now ? now->GetWXWindow() : nil;
352 }
353 else
354 {
355 NSRect r = NSMakeRect(10, 10, 0, 0);
356 nsnow = [NSPanel alloc];
357 [nsnow initWithContentRect:r
358 styleMask:NSBorderlessWindowMask
359 backing:NSBackingStoreBuffered
360 defer:YES
361 ];
362 [nsnow orderOut:nil];
363 m_dummyWindow = nsnow;
364 }
365 m_modalSession = [NSApp beginModalSessionForWindow:nsnow];
203ec424 366 wxASSERT_MSG(m_modalSession != NULL, "modal session couldn't be started");
902ddbfd
SC
367}
368
369void wxGUIEventLoop::EndModalSession()
370{
371 wxASSERT_MSG(m_modalSession != NULL, "no modal session active");
0aff141c
SC
372
373 wxASSERT_MSG(m_modalNestedLevel > 0, "incorrect modal nesting level");
374
375 if ( --m_modalNestedLevel == 0 )
902ddbfd 376 {
0aff141c
SC
377 [NSApp endModalSession:(NSModalSession)m_modalSession];
378 m_modalSession = nil;
379 if ( m_dummyWindow )
380 {
381 [m_dummyWindow release];
382 m_dummyWindow = nil;
383 }
902ddbfd
SC
384 }
385}
386
387//
388//
389//
390
391wxWindowDisabler::wxWindowDisabler(bool disable)
392{
393 m_modalEventLoop = NULL;
394 m_disabled = disable;
395 if ( disable )
396 DoDisable();
397}
398
399wxWindowDisabler::wxWindowDisabler(wxWindow *winToSkip)
400{
401 m_disabled = true;
402 DoDisable(winToSkip);
403}
404
405void wxWindowDisabler::DoDisable(wxWindow *winToSkip)
406{
407 // remember the top level windows which were already disabled, so that we
408 // don't reenable them later
409 m_winDisabled = NULL;
410
411 wxWindowList::compatibility_iterator node;
412 for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() )
413 {
414 wxWindow *winTop = node->GetData();
415 if ( winTop == winToSkip )
416 continue;
417
418 // we don't need to disable the hidden or already disabled windows
419 if ( winTop->IsEnabled() && winTop->IsShown() )
420 {
421 winTop->Disable();
422 }
423 else
424 {
425 if ( !m_winDisabled )
426 {
427 m_winDisabled = new wxWindowList;
428 }
429
430 m_winDisabled->Append(winTop);
431 }
432 }
433
434 m_modalEventLoop = (wxEventLoop*)wxEventLoopBase::GetActive();
85fb0a0a
RD
435 if (m_modalEventLoop)
436 m_modalEventLoop->BeginModalSession(winToSkip);
902ddbfd
SC
437}
438
439wxWindowDisabler::~wxWindowDisabler()
440{
441 if ( !m_disabled )
442 return;
443
85fb0a0a
RD
444 if (m_modalEventLoop)
445 m_modalEventLoop->EndModalSession();
902ddbfd
SC
446
447 wxWindowList::compatibility_iterator node;
448 for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() )
449 {
450 wxWindow *winTop = node->GetData();
451 if ( !m_winDisabled || !m_winDisabled->Find(winTop) )
452 {
453 winTop->Enable();
454 }
455 //else: had been already disabled, don't reenable
456 }
457
458 delete m_winDisabled;
459}
460