]> git.saurik.com Git - wxWidgets.git/blob - src/osx/cocoa/evtloop.mm
Add support for custom scheme handling and virtual file systems to the OSX WebKit...
[wxWidgets.git] / src / osx / cocoa / evtloop.mm
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
7 // RCS-ID: $Id$
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
27 #include "wx/evtloop.h"
28
29 #ifndef WX_PRECOMP
30 #include "wx/app.h"
31 #include "wx/nonownedwnd.h"
32 #endif // WX_PRECOMP
33
34 #include "wx/log.h"
35
36 #include "wx/osx/private.h"
37
38 // ============================================================================
39 // wxEventLoop implementation
40 // ============================================================================
41
42 #if 0
43
44 // in case we want to integrate this
45
46 static 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;
55
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 }
103
104 #endif
105
106 wxGUIEventLoop::wxGUIEventLoop()
107 {
108 m_modalSession = nil;
109 m_dummyWindow = nil;
110 m_modalNestedLevel = 0;
111 m_modalWindow = NULL;
112 }
113
114 wxGUIEventLoop::~wxGUIEventLoop()
115 {
116 wxASSERT( m_modalSession == nil );
117 wxASSERT( m_dummyWindow == nil );
118 wxASSERT( m_modalNestedLevel == 0 );
119 }
120
121 //-----------------------------------------------------------------------------
122 // events dispatch and loop handling
123 //-----------------------------------------------------------------------------
124
125 #if 0
126
127 bool wxGUIEventLoop::Pending() const
128 {
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)
134 wxMacAutoreleasePool autoreleasepool;
135
136 return [[NSApplication sharedApplication]
137 nextEventMatchingMask: NSAnyEventMask
138 untilDate: nil
139 inMode: NSDefaultRunLoopMode
140 dequeue: NO] != nil;
141 #else
142 return true;
143 #endif
144 }
145
146 bool wxGUIEventLoop::Dispatch()
147 {
148 if ( !wxTheApp )
149 return false;
150
151 wxMacAutoreleasePool autoreleasepool;
152
153 if(NSEvent *event = [NSApp
154 nextEventMatchingMask:NSAnyEventMask
155 untilDate:[NSDate dateWithTimeIntervalSinceNow: m_sleepTime]
156 inMode:NSDefaultRunLoopMode
157 dequeue: YES])
158 {
159 WXEVENTREF formerEvent = wxTheApp == NULL ? NULL : wxTheApp->MacGetCurrentEvent();
160 WXEVENTHANDLERCALLREF formerHandler = wxTheApp == NULL ? NULL : wxTheApp->MacGetCurrentEventHandlerCallRef();
161
162 if (wxTheApp)
163 wxTheApp->MacSetCurrentEvent(event, NULL);
164 m_sleepTime = 0.0;
165 [NSApp sendEvent: event];
166
167 if (wxTheApp)
168 wxTheApp->MacSetCurrentEvent(formerEvent , formerHandler);
169 }
170 else
171 {
172 if (wxTheApp)
173 wxTheApp->ProcessPendingEvents();
174
175 if ( wxTheApp->ProcessIdle() )
176 m_sleepTime = 0.0 ;
177 else
178 {
179 m_sleepTime = 1.0;
180 #if wxUSE_THREADS
181 wxMutexGuiLeave();
182 wxMilliSleep(20);
183 wxMutexGuiEnter();
184 #endif
185 }
186 }
187
188 return true;
189 }
190
191 #endif
192
193 int wxGUIEventLoop::DoDispatchTimeout(unsigned long timeout)
194 {
195 wxMacAutoreleasePool autoreleasepool;
196
197 if ( m_modalSession )
198 {
199 NSInteger response = [NSApp runModalSession:(NSModalSession)m_modalSession];
200
201 switch (response)
202 {
203 case NSRunContinuesResponse:
204 {
205 if ( [[NSApplication sharedApplication]
206 nextEventMatchingMask: NSAnyEventMask
207 untilDate: nil
208 inMode: NSDefaultRunLoopMode
209 dequeue: NO] != nil )
210 return 1;
211
212 return -1;
213 }
214
215 case NSRunStoppedResponse:
216 case NSRunAbortedResponse:
217 return -1;
218 default:
219 wxFAIL_MSG("unknown response code");
220 break;
221 }
222 return -1;
223 }
224 else
225 {
226 NSEvent *event = [NSApp
227 nextEventMatchingMask:NSAnyEventMask
228 untilDate:[NSDate dateWithTimeIntervalSinceNow: timeout/1000]
229 inMode:NSDefaultRunLoopMode
230 dequeue: YES];
231
232 if ( event == nil )
233 return -1;
234
235 [NSApp sendEvent: event];
236
237 return 1;
238 }
239 }
240
241 void wxGUIEventLoop::DoRun()
242 {
243 wxMacAutoreleasePool autoreleasepool;
244 [NSApp run];
245 }
246
247 void wxGUIEventLoop::DoStop()
248 {
249 // only calling stop: is not enough when called from a runloop-observer,
250 // therefore add a dummy event, to make sure the runloop gets another round
251 [NSApp stop:0];
252 WakeUp();
253 }
254
255 void wxGUIEventLoop::WakeUp()
256 {
257 NSEvent *event = [NSEvent otherEventWithType:NSApplicationDefined
258 location:NSMakePoint(0.0, 0.0)
259 modifierFlags:0
260 timestamp:0
261 windowNumber:0
262 context:nil
263 subtype:0 data1:0 data2:0];
264 [NSApp postEvent:event atStart:FALSE];
265 }
266
267 CFRunLoopRef wxGUIEventLoop::CFGetCurrentRunLoop() const
268 {
269 NSRunLoop* nsloop = [NSRunLoop currentRunLoop];
270 return [nsloop getCFRunLoop];
271 }
272
273
274 // TODO move into a evtloop_osx.cpp
275
276 wxModalEventLoop::wxModalEventLoop(wxWindow *modalWindow)
277 {
278 m_modalWindow = dynamic_cast<wxNonOwnedWindow*> (modalWindow);
279 wxASSERT_MSG( m_modalWindow != NULL, "must pass in a toplevel window for modal event loop" );
280 m_modalNativeWindow = m_modalWindow->GetWXWindow();
281 }
282
283 wxModalEventLoop::wxModalEventLoop(WXWindow modalNativeWindow)
284 {
285 m_modalWindow = NULL;
286 wxASSERT_MSG( modalNativeWindow != NULL, "must pass in a toplevel window for modal event loop" );
287 m_modalNativeWindow = modalNativeWindow;
288 }
289
290 // END move into a evtloop_osx.cpp
291
292 void wxModalEventLoop::DoRun()
293 {
294 wxMacAutoreleasePool pool;
295
296 // If the app hasn't started, flush the event queue
297 // If we don't do this, the Dock doesn't get the message that
298 // the app has started so will refuse to activate it.
299 [NSApplication sharedApplication];
300 if (![NSApp isRunning])
301 {
302 while(NSEvent *event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:nil inMode:NSDefaultRunLoopMode dequeue:YES])
303 {
304 [NSApp sendEvent:event];
305 }
306 }
307
308 [NSApp runModalForWindow:m_modalNativeWindow];
309 }
310
311 void wxModalEventLoop::DoStop()
312 {
313 [NSApp stopModal];
314 }
315
316 void wxGUIEventLoop::BeginModalSession( wxWindow* modalWindow )
317 {
318 WXWindow nsnow = nil;
319
320 if ( m_modalNestedLevel > 0 )
321 {
322 wxASSERT_MSG( m_modalWindow == modalWindow, "Nested Modal Sessions must be based on same window");
323 m_modalNestedLevel++;
324 return;
325 }
326
327 m_modalWindow = modalWindow;
328 m_modalNestedLevel = 1;
329
330 if ( modalWindow )
331 {
332 // we must show now, otherwise beginModalSessionForWindow does it but it
333 // also would do a centering of the window before overriding all our position
334 if ( !modalWindow->IsShownOnScreen() )
335 modalWindow->Show();
336
337 wxNonOwnedWindow* now = dynamic_cast<wxNonOwnedWindow*> (modalWindow);
338 wxASSERT_MSG( now != NULL, "must pass in a toplevel window for modal event loop" );
339 nsnow = now ? now->GetWXWindow() : nil;
340 }
341 else
342 {
343 NSRect r = NSMakeRect(10, 10, 0, 0);
344 nsnow = [NSPanel alloc];
345 [nsnow initWithContentRect:r
346 styleMask:NSBorderlessWindowMask
347 backing:NSBackingStoreBuffered
348 defer:YES
349 ];
350 [nsnow orderOut:nil];
351 m_dummyWindow = nsnow;
352 }
353 m_modalSession = [NSApp beginModalSessionForWindow:nsnow];
354 wxASSERT_MSG(m_modalSession != NULL, "modal session couldn't be started");
355 }
356
357 void wxGUIEventLoop::EndModalSession()
358 {
359 wxASSERT_MSG(m_modalSession != NULL, "no modal session active");
360
361 wxASSERT_MSG(m_modalNestedLevel > 0, "incorrect modal nesting level");
362
363 if ( --m_modalNestedLevel == 0 )
364 {
365 [NSApp endModalSession:(NSModalSession)m_modalSession];
366 m_modalSession = nil;
367 if ( m_dummyWindow )
368 {
369 [m_dummyWindow release];
370 m_dummyWindow = nil;
371 }
372 }
373 }
374
375 //
376 //
377 //
378
379 wxWindowDisabler::wxWindowDisabler(bool disable)
380 {
381 m_modalEventLoop = NULL;
382 m_disabled = disable;
383 if ( disable )
384 DoDisable();
385 }
386
387 wxWindowDisabler::wxWindowDisabler(wxWindow *winToSkip)
388 {
389 m_disabled = true;
390 DoDisable(winToSkip);
391 }
392
393 void wxWindowDisabler::DoDisable(wxWindow *winToSkip)
394 {
395 // remember the top level windows which were already disabled, so that we
396 // don't reenable them later
397 m_winDisabled = NULL;
398
399 wxWindowList::compatibility_iterator node;
400 for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() )
401 {
402 wxWindow *winTop = node->GetData();
403 if ( winTop == winToSkip )
404 continue;
405
406 // we don't need to disable the hidden or already disabled windows
407 if ( winTop->IsEnabled() && winTop->IsShown() )
408 {
409 winTop->Disable();
410 }
411 else
412 {
413 if ( !m_winDisabled )
414 {
415 m_winDisabled = new wxWindowList;
416 }
417
418 m_winDisabled->Append(winTop);
419 }
420 }
421
422 m_modalEventLoop = (wxEventLoop*)wxEventLoopBase::GetActive();
423 m_modalEventLoop->BeginModalSession(winToSkip);
424 }
425
426 wxWindowDisabler::~wxWindowDisabler()
427 {
428 if ( !m_disabled )
429 return;
430
431 m_modalEventLoop->EndModalSession();
432
433 wxWindowList::compatibility_iterator node;
434 for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() )
435 {
436 wxWindow *winTop = node->GetData();
437 if ( !m_winDisabled || !m_winDisabled->Find(winTop) )
438 {
439 winTop->Enable();
440 }
441 //else: had been already disabled, don't reenable
442 }
443
444 delete m_winDisabled;
445 }
446