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