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