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