Add ProcessPendingEvents to wxApp::Yield which makes the code almost identical
[wxWidgets.git] / src / cocoa / app.mm
1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/cocoa/app.mm
3 // Purpose:     wxApp
4 // Author:      David Elliott
5 // Modified by:
6 // Created:     2002/11/27
7 // RCS-ID:      $Id$
8 // Copyright:   (c) David Elliott
9 //              Software 2000 Ltd.
10 // Licence:     wxWidgets licence
11 /////////////////////////////////////////////////////////////////////////////
12
13 #include "wx/wxprec.h"
14
15 #include "wx/app.h"
16
17 #ifndef WX_PRECOMP
18     #include "wx/dc.h"
19     #include "wx/intl.h"
20     #include "wx/log.h"
21     #include "wx/module.h"
22 #endif
23
24 #include "wx/cocoa/ObjcRef.h"
25 #include "wx/cocoa/autorelease.h"
26 #include "wx/cocoa/mbarman.h"
27 #include "wx/cocoa/NSApplication.h"
28
29 #import <AppKit/NSApplication.h>
30 #import <Foundation/NSRunLoop.h>
31 #import <Foundation/NSThread.h>
32 #import <AppKit/NSEvent.h>
33 #import <Foundation/NSString.h>
34 #import <Foundation/NSNotification.h>
35 #import <AppKit/NSCell.h>
36
37 bool      wxApp::sm_isEmbedded = false; // Normally we're not a plugin
38
39 // wxNSApplicationObserver singleton.
40 static wxObjcAutoRefFromAlloc<wxNSApplicationObserver*> sg_cocoaAppObserver = [[WX_GET_OBJC_CLASS(wxNSApplicationObserver) alloc] init];
41
42 // ========================================================================
43 // wxNSApplicationDelegate
44 // ========================================================================
45 @implementation wxNSApplicationDelegate : NSObject
46
47 // NOTE: Terminate means that the event loop does NOT return and thus
48 // cleanup code doesn't properly execute.  Furthermore, wxWidgets has its
49 // own exit on frame delete mechanism.
50 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
51 {
52     return NO;
53 }
54
55 @end // implementation wxNSApplicationDelegate : NSObject
56 WX_IMPLEMENT_GET_OBJC_CLASS(wxNSApplicationDelegate,NSObject)
57
58 // ========================================================================
59 // wxNSApplicationObserver
60 // ========================================================================
61 @implementation wxNSApplicationObserver : NSObject
62
63 - (void)applicationWillBecomeActive:(NSNotification *)notification
64 {
65     wxTheApp->CocoaDelegate_applicationWillBecomeActive();
66 }
67
68 - (void)applicationDidBecomeActive:(NSNotification *)notification
69 {
70     wxTheApp->CocoaDelegate_applicationDidBecomeActive();
71 }
72
73 - (void)applicationWillResignActive:(NSNotification *)notification
74 {
75     wxTheApp->CocoaDelegate_applicationWillResignActive();
76 }
77
78 - (void)applicationDidResignActive:(NSNotification *)notification
79 {
80     wxTheApp->CocoaDelegate_applicationDidResignActive();
81 }
82
83 - (void)applicationWillUpdate:(NSNotification *)notification;
84 {
85     wxTheApp->CocoaDelegate_applicationWillUpdate();
86 }
87
88 - (void)controlTintChanged:(NSNotification *)notification
89 {
90     wxLogDebug(wxT("TODO: send EVT_SYS_COLOUR_CHANGED as appropriate"));
91 }
92
93 @end // implementation wxNSApplicationObserver : NSObject
94 WX_IMPLEMENT_GET_OBJC_CLASS(wxNSApplicationObserver,NSObject)
95
96 // ========================================================================
97 // wxApp
98 // ========================================================================
99
100 // ----------------------------------------------------------------------------
101 // wxApp Static member initialization
102 // ----------------------------------------------------------------------------
103 IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
104
105 // ----------------------------------------------------------------------------
106 // wxApp initialization/cleanup
107 // ----------------------------------------------------------------------------
108 bool wxApp::Initialize(int& argc, wxChar **argv)
109 {
110     wxAutoNSAutoreleasePool pool;
111     m_cocoaMainThread = [NSThread currentThread];
112     // Mac OS X passes a process serial number command line argument when
113     // the application is launched from the Finder. This argument must be
114     // removed from the command line arguments before being handled by the
115     // application (otherwise applications would need to handle it)
116     if ( argc > 1 )
117     {
118         static const wxChar *ARG_PSN = _T("-psn_");
119         if ( wxStrncmp(argv[1], ARG_PSN, wxStrlen(ARG_PSN)) == 0 )
120         {
121             // remove this argument
122             --argc;
123             memmove(argv + 1, argv + 2, argc * sizeof(wxChar *));
124         }
125     }
126
127     return wxAppBase::Initialize(argc, argv);
128 }
129
130 void wxApp::CleanUp()
131 {
132     wxAutoNSAutoreleasePool pool;
133
134     wxDC::CocoaShutdownTextSystem();
135     wxMenuBarManager::DestroyInstance();
136
137     [[NSNotificationCenter defaultCenter] removeObserver:sg_cocoaAppObserver];
138     if(!sm_isEmbedded)
139     {
140         [m_cocoaApp setDelegate:nil];
141         [m_cocoaAppDelegate release];
142         m_cocoaAppDelegate = NULL;
143     }
144
145     wxAppBase::CleanUp();
146 }
147
148 // ----------------------------------------------------------------------------
149 // wxApp creation
150 // ----------------------------------------------------------------------------
151 wxApp::wxApp()
152 {
153     m_topWindow = NULL;
154
155 #ifdef __WXDEBUG__
156     m_isInAssert = false;
157 #endif // __WXDEBUG__
158
159     argc = 0;
160     argv = NULL;
161     m_cocoaApp = NULL;
162     m_cocoaAppDelegate = NULL;
163 }
164
165 void wxApp::CocoaDelegate_applicationWillBecomeActive()
166 {
167 }
168
169 void wxApp::CocoaDelegate_applicationDidBecomeActive()
170 {
171 }
172
173 void wxApp::CocoaDelegate_applicationWillResignActive()
174 {
175     wxTopLevelWindowCocoa::DeactivatePendingWindow();
176 }
177
178 void wxApp::CocoaDelegate_applicationDidResignActive()
179 {
180 }
181
182 bool wxApp::OnInitGui()
183 {
184     wxAutoNSAutoreleasePool pool;
185     if(!wxAppBase::OnInitGui())
186         return false;
187
188     // Create the app using the sharedApplication method
189     m_cocoaApp = [NSApplication sharedApplication];
190
191     if(!sm_isEmbedded)
192     {
193         // Enable response to application delegate messages
194         m_cocoaAppDelegate = [[WX_GET_OBJC_CLASS(wxNSApplicationDelegate) alloc] init];
195         [m_cocoaApp setDelegate:m_cocoaAppDelegate];
196     }
197
198     // Enable response to "delegate" messages on the notification observer
199     [[NSNotificationCenter defaultCenter] addObserver:sg_cocoaAppObserver
200         selector:@selector(applicationWillBecomeActive:)
201         name:NSApplicationWillBecomeActiveNotification object:nil];
202
203     [[NSNotificationCenter defaultCenter] addObserver:sg_cocoaAppObserver
204         selector:@selector(applicationDidBecomeActive:)
205         name:NSApplicationDidBecomeActiveNotification object:nil];
206
207     [[NSNotificationCenter defaultCenter] addObserver:sg_cocoaAppObserver
208         selector:@selector(applicationWillResignActive:)
209         name:NSApplicationWillResignActiveNotification object:nil];
210
211     [[NSNotificationCenter defaultCenter] addObserver:sg_cocoaAppObserver
212         selector:@selector(applicationDidResignActive:)
213         name:NSApplicationDidResignActiveNotification object:nil];
214
215     [[NSNotificationCenter defaultCenter] addObserver:sg_cocoaAppObserver
216         selector:@selector(applicationWillUpdate:)
217         name:NSApplicationWillUpdateNotification object:nil];
218
219     // Enable response to system notifications
220     [[NSNotificationCenter defaultCenter] addObserver:sg_cocoaAppObserver
221         selector:@selector(controlTintChanged:)
222         name:NSControlTintDidChangeNotification object:nil];
223
224     if(!sm_isEmbedded)
225         wxMenuBarManager::CreateInstance();
226
227     wxDC::CocoaInitializeTextSystem();
228     return true;
229 }
230
231 wxApp::~wxApp()
232 {
233     if(m_cfRunLoopIdleObserver != NULL)
234     {
235         // Invalidate the observer which also removes it from the run loop.
236         CFRunLoopObserverInvalidate(m_cfRunLoopIdleObserver);
237         // Release the ref as we don't need it anymore.
238         m_cfRunLoopIdleObserver.reset();
239     }
240 }
241
242 bool wxApp::CallOnInit()
243 {
244 //    wxAutoNSAutoreleasePool pool;
245     return OnInit();
246 }
247
248 bool wxApp::OnInit()
249 {
250     if(!wxAppBase::OnInit())
251         return false;
252
253     return true;
254 }
255
256 void wxApp::Exit()
257 {
258     wxApp::CleanUp();
259
260     wxAppConsole::Exit();
261 }
262
263 // Yield to other processes
264 bool wxApp::Yield(bool onlyIfNeeded)
265 {
266     // MT-FIXME
267     static bool s_inYield = false;
268
269 #if wxUSE_LOG
270     // disable log flushing from here because a call to wxYield() shouldn't
271     // normally result in message boxes popping up &c
272     wxLog::Suspend();
273 #endif // wxUSE_LOG
274
275     if (s_inYield)
276     {
277         if ( !onlyIfNeeded )
278         {
279             wxFAIL_MSG( wxT("wxYield called recursively" ) );
280         }
281
282         return false;
283     }
284
285     s_inYield = true;
286
287     // Run the event loop until it is out of events
288     while(1)
289     {
290         wxAutoNSAutoreleasePool pool;
291         /*  NOTE: It may be better to use something like
292             NSEventTrackingRunLoopMode since we don't necessarily want all
293             timers/sources/observers to run, only those which would
294             run while tracking events.  However, it should be noted that
295             NSEventTrackingRunLoopMode is in the common set of modes
296             so it may not effectively make much of a difference.
297          */
298         NSEvent *event = [GetNSApplication()
299                 nextEventMatchingMask:NSAnyEventMask
300                 untilDate:[NSDate distantPast]
301                 inMode:NSDefaultRunLoopMode
302                 dequeue: YES];
303         if(!event)
304             break;
305         [GetNSApplication() sendEvent: event];
306     }
307
308     /*
309         Because we just told NSApplication to avoid blocking it will in turn
310         run the CFRunLoop with a timeout of 0 seconds.  In that case, our
311         run loop observer on kCFRunLoopBeforeWaiting never fires because
312         no waiting occurs.  Therefore, no idle events are sent.
313
314         Believe it or not, this is actually desirable because we do not want
315         to process idle from here.  However, we do want to process pending
316         events because some user code expects to do work in a thread while
317         the main thread waits and then notify the main thread by posting
318         an event.
319      */
320     ProcessPendingEvents();
321
322 #if wxUSE_LOG
323     // let the logs be flashed again
324     wxLog::Resume();
325 #endif // wxUSE_LOG
326
327     s_inYield = false;
328
329     return true;
330 }
331
332 void wxApp::WakeUpIdle()
333 {
334     /*  When called from the main thread the NSAutoreleasePool managed by
335         the [NSApplication run] method would ordinarily be in place and so
336         one would think a pool here would be unnecessary.
337
338         However, when called from a different thread there is usually no
339         NSAutoreleasePool in place because wxThread has no knowledge of
340         wxCocoa.  The pool here is generally only ever going to contain
341         the NSEvent we create with the factory method.  As soon as we add
342         it to the main event queue with postEvent:atStart: it is retained
343         and so safe for our pool to release.
344      */
345     wxAutoNSAutoreleasePool pool;
346     /*  NOTE: This is a little heavy handed.  What this does is cause an
347         AppKit NSEvent to be added to NSApplication's queue (which is always
348         on the main thread).  This will cause the main thread runloop to
349         exit which returns control to nextEventMatchingMask which returns
350         the event which is then sent with sendEvent: and essentially dropped
351         since it's not for a window (windowNumber 0) and NSApplication
352         certainly doesn't understand it.
353
354         With the exception of wxEventLoop::Exit which uses us to cause the
355         runloop to exit and return to the NSApplication event loop, most
356         callers only need wx idle to happen, or more specifically only really
357         need to ensure that ProcessPendingEvents is called which is currently
358         done without exiting the runloop.
359
360         Be careful if you decide to change the implementation of this method
361         as wxEventLoop::Exit depends on the current behavior.
362      */
363     [m_cocoaApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined
364             location:NSZeroPoint modifierFlags:NSAnyEventMask
365             timestamp:0 windowNumber:0 context:nil
366             subtype:0 data1:0 data2:0] atStart:NO];
367 }
368
369 extern "C" static void ObserveMainRunLoopBeforeWaiting(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info);
370 extern "C" static void ObserveMainRunLoopBeforeWaiting(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info)
371 {
372     static_cast<wxApp*>(info)->CF_ObserveMainRunLoopBeforeWaiting(observer, activity);
373 }
374
375 #if 0
376 static int sg_cApplicationWillUpdate = 0;
377 #endif
378
379 /*!
380     Invoked from the applicationWillUpdate notification observer.  See the
381     NSApplication documentation for the official statement on when this
382     will be called.  Since it can be hard to understand for a Cocoa newbie
383     I'll try to explain it here as it relates to wxCocoa.
384
385     Basically, we get called from within nextEventMatchingMask if and only
386     if any user code told the application to send the update notification
387     (sort of like a request for idle events).  However, unlike wx idle events,
388     this notification is sent quite often, nearly every time through the loop
389     because nearly every control tells the application to send it.
390
391     Because wx idle events are only supposed to be sent when the event loop
392     is about to block we instead schedule a function to be called just
393     before the run loop waits and send the idle events from there.
394
395     It also has the desirable effect of only sending the wx idle events when
396     the event loop is actualy going to block.  If the event loop is being
397     pumped manualy (e.g. like a PeekMessage) then the kCFRunLoopBeforeWaiting
398     observer never fires.  Our Yield() method depends on this because sending
399     idle events from within Yield would be bad.
400
401     Normally you might think that we could just set the observer up once and
402     leave it attached.  However, this is problematic because our run loop
403     observer calls user code (the idle handlers) which can actually display
404     modal dialogs.  Displaying a modal dialog causes reentry of the event
405     loop, usually in a different run loop mode than the main loop (e.g. in
406     modal-dialog mode instead of default mode).  Because we only register the
407     observer with the run loop mode at the time of this call, it won't be
408     called from a modal loop.
409
410     We want it to be called and thus we need a new observer.
411  */
412 void wxApp::CocoaDelegate_applicationWillUpdate()
413 {
414     wxLogTrace(wxTRACE_COCOA,wxT("applicationWillUpdate"));
415
416 //    CFRunLoopRef cfRunLoop = [[NSRunLoop currentRunLoop] getCFRunLoop];
417     CFRunLoopRef cfRunLoop = CFRunLoopGetCurrent();
418     wxCFRef<CFStringRef> cfRunLoopMode(CFRunLoopCopyCurrentMode(cfRunLoop));
419
420     /*  If we have an observer and that observer is for the wrong run loop
421         mode then invalidate it and release it.
422      */
423     if(m_cfRunLoopIdleObserver != NULL && m_cfObservedRunLoopMode != cfRunLoopMode)
424     {
425         CFRunLoopObserverInvalidate(m_cfRunLoopIdleObserver);
426         m_cfRunLoopIdleObserver.reset();
427     }
428 #if 0
429     ++sg_cApplicationWillUpdate;
430 #endif
431     /*  This will be true either on the first call or when the above code has
432         invalidated and released the exisiting observer.
433      */
434     if(m_cfRunLoopIdleObserver == NULL)
435     {
436         // Enable idle event handling
437         CFRunLoopObserverContext observerContext =
438         {   0
439         ,   this
440         ,   NULL
441         ,   NULL
442         ,   NULL
443         };
444         /*  NOTE: I can't recall why we don't just let the observer repeat
445             instead of invalidating itself each time it fires thus requiring
446             it to be recreated for each shot but there was if I remember
447             some good (but very obscure) reason for it.
448
449             On the other hand, I could be wrong so don't take that as gospel.
450          */
451         m_cfRunLoopIdleObserver.reset(CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopBeforeWaiting, /*repeats*/FALSE, /*priority*/0, ObserveMainRunLoopBeforeWaiting, &observerContext));
452         m_cfObservedRunLoopMode = cfRunLoopMode;
453         CFRunLoopAddObserver(cfRunLoop, m_cfRunLoopIdleObserver, m_cfObservedRunLoopMode);
454     }
455 }
456
457 static inline bool FakeNeedMoreIdle()
458 {
459 #if 0
460 // Return true on every 10th call.
461     static int idleCount = 0;
462     return ++idleCount % 10;
463 #else
464     return false;
465 #endif
466 }
467
468 /*!
469     Called by CFRunLoop just before waiting.  This is the appropriate time to
470     send idle events.  Unlike other ports, we don't peek the queue for events
471     and stop idling if there is one.  Instead, if the user requests more idle
472     events we tell Cocoa to send us an applicationWillUpdate notification
473     which will cause our observer of that notification to tell CFRunLoop to
474     call us before waiting which will cause us to be fired again but only
475     after exhausting the event queue.
476
477     The reason we do it this way is that peeking for an event causes CFRunLoop
478     to reenter and fire off its timers, observers, and sources which we're
479     better off avoiding.  Doing it this way, we basically let CFRunLoop do the
480     work of peeking for the next event which is much nicer.
481  */
482 void wxApp::CF_ObserveMainRunLoopBeforeWaiting(CFRunLoopObserverRef observer, int activity)
483 {
484     // Ensure that CocoaDelegate_applicationWillUpdate will recreate us.
485     // We've already been invalidated by CFRunLoop because we are one-shot.
486     m_cfRunLoopIdleObserver.reset();
487 #if 0
488     wxLogTrace(wxTRACE_COCOA,wxT("Idle BEGIN (%d)"), sg_cApplicationWillUpdate);
489     sg_cApplicationWillUpdate = 0;
490 #else
491     wxLogTrace(wxTRACE_COCOA,wxT("Idle BEGIN"));
492 #endif
493     if( ProcessIdle() || FakeNeedMoreIdle() )
494     {
495         wxLogTrace(wxTRACE_COCOA, wxT("Idle REQUEST MORE"));
496         [NSApp setWindowsNeedUpdate:YES];
497     }
498     else
499     {
500         wxLogTrace(wxTRACE_COCOA, wxT("Idle END"));
501     }
502 }
503
504 #ifdef __WXDEBUG__
505 void wxApp::OnAssert(const wxChar *file, int line, const wxChar* cond, const wxChar *msg)
506 {
507     m_isInAssert = true;
508     wxAppBase::OnAssert(file, line, cond, msg);
509     m_isInAssert = false;
510 }
511 #endif // __WXDEBUG__
512
513 /*  A note about Cocoa's event loops vs. run loops:
514
515     It's important to understand that Cocoa has a two-level event loop.  The
516     outer level is run by NSApplication and can only ever happen on the main
517     thread. The nextEventMatchingMask:untilDate:inMode:dequeue: method returns
518     the next event which is then given to sendEvent: to send it.  These
519     methods are defined in NSApplication and are thus part of AppKit.
520
521     Events (NSEvent) are only sent due to actual user actions like clicking
522     the mouse or moving the mouse or pressing a key and so on.  There are no
523     paint events; there are no timer events; there are no socket events; there
524     are no idle events.
525
526     All of those types of "events" have nothing to do with the GUI at all.
527     That is why Cocoa's AppKit doesn't implement them.  Instead, they are
528     implemented in Foundation's NSRunLoop which on OS X uses CFRunLoop
529     to do the actual work.
530
531     How NSApplication uses NSRunLoop is rather interesting.  Basically, it
532     interacts with NSRunLoop only from within the nextEventMatchingMask
533     method.  It passes its inMode: argument almost directly to NSRunLoop
534     and thus CFRunLoop.  The run loop then runs (e.g. loops) until it
535     is told to exit.  The run loop calls the callout functions directly.
536     From within those callout functions the run loop is considered to
537     be running.  Presumably, the AppKit installs a run loop source to
538     receive messages from the window server over the mach port (like a
539     socket).  For some messages (e.g. need to paint) the AppKit will
540     call application code like drawRect: without exiting the run loop.
541     For other messages (ones that can be encapsulated in an NSEvent)
542     the AppKit tells the run loop to exit which returns control to
543     the nextEventMatchingMask method which then returns the NSEvent
544     object.  It's important to note that once the runloop has exited
545     it is no longer considered running and thus if you ask it which
546     mode it is running in it will return nil.
547
548     When manually pumping the event loop care should be taken to
549     tell it to run in the correct mode.  For instance, if you are
550     using it to run a modal dialog then you want to run it in
551     the modal panel run loop mode.  AppKit presumably has sources
552     or timers or observers that specifically don't listen on this
553     mode.  Another interesting mode is the connection reply mode.
554     This allows Cocoa to wait for a response from a distributed
555     objects message without firing off user code that may result
556     in a DO call being made thus recursing.  So basically, the
557     mode is a way for Cocoa to attempt to avoid run loop recursion
558     but to allow it under certain circumstances.
559  */
560