Remove ObjcPose.h since nothing is using it anymore.
[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 // wxNSApplicationObserver singleton.
38 static wxObjcAutoRefFromAlloc<wxNSApplicationObserver*> sg_cocoaAppObserver = [[wxNSApplicationObserver alloc] init];
39
40 // ========================================================================
41 // wxNSApplicationDelegate
42 // ========================================================================
43 @implementation wxNSApplicationDelegate : NSObject
44
45 // NOTE: Terminate means that the event loop does NOT return and thus
46 // cleanup code doesn't properly execute.  Furthermore, wxWidgets has its
47 // own exit on frame delete mechanism.
48 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
49 {
50     return NO;
51 }
52
53 @end // implementation wxNSApplicationDelegate : NSObject
54
55 // ========================================================================
56 // wxNSApplicationObserver
57 // ========================================================================
58 @implementation wxNSApplicationObserver : NSObject
59
60 - (void)applicationWillBecomeActive:(NSNotification *)notification
61 {
62     wxTheApp->CocoaDelegate_applicationWillBecomeActive();
63 }
64
65 - (void)applicationDidBecomeActive:(NSNotification *)notification
66 {
67     wxTheApp->CocoaDelegate_applicationDidBecomeActive();
68 }
69
70 - (void)applicationWillResignActive:(NSNotification *)notification
71 {
72     wxTheApp->CocoaDelegate_applicationWillResignActive();
73 }
74
75 - (void)applicationDidResignActive:(NSNotification *)notification
76 {
77     wxTheApp->CocoaDelegate_applicationDidResignActive();
78 }
79
80 - (void)applicationWillUpdate:(NSNotification *)notification;
81 {
82     wxTheApp->CocoaDelegate_applicationWillUpdate();
83 }
84
85 - (void)controlTintChanged:(NSNotification *)notification
86 {
87     wxLogDebug(wxT("TODO: send EVT_SYS_COLOUR_CHANGED as appropriate"));
88 }
89
90 @end // implementation wxNSApplicationObserver : NSObject
91
92 // ========================================================================
93 // wxApp
94 // ========================================================================
95
96 // ----------------------------------------------------------------------------
97 // wxApp Static member initialization
98 // ----------------------------------------------------------------------------
99 IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
100 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
101     EVT_IDLE(wxAppBase::OnIdle)
102 //    EVT_END_SESSION(wxApp::OnEndSession)
103 //    EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
104 END_EVENT_TABLE()
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     return wxAppBase::Initialize(argc, argv);
129 }
130
131 void wxApp::CleanUp()
132 {
133     wxAutoNSAutoreleasePool pool;
134
135     wxDC::CocoaShutdownTextSystem();
136     wxMenuBarManager::DestroyInstance();
137
138     [m_cocoaApp setDelegate:nil];
139     [[NSNotificationCenter defaultCenter] removeObserver:m_cocoaAppDelegate];
140     [m_cocoaAppDelegate release];
141     m_cocoaAppDelegate = NULL;
142
143     wxAppBase::CleanUp();
144 }
145
146 // ----------------------------------------------------------------------------
147 // wxApp creation
148 // ----------------------------------------------------------------------------
149 wxApp::wxApp()
150 {
151     m_topWindow = NULL;
152
153 #ifdef __WXDEBUG__
154     m_isInAssert = false;
155 #endif // __WXDEBUG__
156
157     argc = 0;
158     argv = NULL;
159     m_cocoaApp = NULL;
160     m_cocoaAppDelegate = NULL;
161 }
162
163 void wxApp::CocoaDelegate_applicationWillBecomeActive()
164 {
165 }
166
167 void wxApp::CocoaDelegate_applicationDidBecomeActive()
168 {
169 }
170
171 void wxApp::CocoaDelegate_applicationWillResignActive()
172 {
173     wxTopLevelWindowCocoa::DeactivatePendingWindow();
174 }
175
176 void wxApp::CocoaDelegate_applicationDidResignActive()
177 {
178 }
179
180 bool wxApp::OnInitGui()
181 {
182     wxAutoNSAutoreleasePool pool;
183     if(!wxAppBase::OnInitGui())
184         return false;
185
186     // Create the app using the sharedApplication method
187     m_cocoaApp = [NSApplication sharedApplication];
188
189     // Enable response to application delegate messages
190     m_cocoaAppDelegate = [[wxNSApplicationDelegate alloc] init];
191     [m_cocoaApp setDelegate:m_cocoaAppDelegate];
192
193     // Enable response to "delegate" messages on the notification observer
194     [[NSNotificationCenter defaultCenter] addObserver:sg_cocoaAppObserver
195         selector:@selector(applicationWillBecomeActive:)
196         name:NSApplicationWillBecomeActiveNotification object:nil];
197
198     [[NSNotificationCenter defaultCenter] addObserver:sg_cocoaAppObserver
199         selector:@selector(applicationDidBecomeActive:)
200         name:NSApplicationDidBecomeActiveNotification object:nil];
201
202     [[NSNotificationCenter defaultCenter] addObserver:sg_cocoaAppObserver
203         selector:@selector(applicationWillResignActive:)
204         name:NSApplicationWillResignActiveNotification object:nil];
205
206     [[NSNotificationCenter defaultCenter] addObserver:sg_cocoaAppObserver
207         selector:@selector(applicationDidResignActive:)
208         name:NSApplicationDidResignActiveNotification object:nil];
209
210     [[NSNotificationCenter defaultCenter] addObserver:sg_cocoaAppObserver
211         selector:@selector(applicationWillUpdate:)
212         name:NSApplicationWillUpdateNotification object:nil];
213
214     // Enable response to system notifications
215     [[NSNotificationCenter defaultCenter] addObserver:sg_cocoaAppObserver
216         selector:@selector(controlTintChanged:)
217         name:NSControlTintDidChangeNotification object:nil];
218
219     wxMenuBarManager::CreateInstance();
220
221     wxDC::CocoaInitializeTextSystem();
222     return true;
223 }
224
225 wxApp::~wxApp()
226 {
227     if(m_cfRunLoopIdleObserver != NULL)
228     {
229         // Invalidate the observer which also removes it from the run loop.
230         CFRunLoopObserverInvalidate(m_cfRunLoopIdleObserver);
231         // Release the ref as we don't need it anymore.
232         m_cfRunLoopIdleObserver.reset();
233     }
234 }
235
236 bool wxApp::CallOnInit()
237 {
238 //    wxAutoNSAutoreleasePool pool;
239     return OnInit();
240 }
241
242 bool wxApp::OnInit()
243 {
244     if(!wxAppBase::OnInit())
245         return false;
246
247     return true;
248 }
249
250 void wxApp::Exit()
251 {
252     wxApp::CleanUp();
253
254     wxAppConsole::Exit();
255 }
256
257 // Yield to other processes
258 bool wxApp::Yield(bool onlyIfNeeded)
259 {
260     // MT-FIXME
261     static bool s_inYield = false;
262
263 #if wxUSE_LOG
264     // disable log flushing from here because a call to wxYield() shouldn't
265     // normally result in message boxes popping up &c
266     wxLog::Suspend();
267 #endif // wxUSE_LOG
268
269     if (s_inYield)
270     {
271         if ( !onlyIfNeeded )
272         {
273             wxFAIL_MSG( wxT("wxYield called recursively" ) );
274         }
275
276         return false;
277     }
278
279     s_inYield = true;
280
281     // Run the event loop until it is out of events
282     while(1)
283     {
284         wxAutoNSAutoreleasePool pool;
285         NSEvent *event = [GetNSApplication()
286                 nextEventMatchingMask:NSAnyEventMask
287                 untilDate:[NSDate distantPast]
288                 inMode:NSDefaultRunLoopMode
289                 dequeue: YES];
290         if(!event)
291             break;
292         [GetNSApplication() sendEvent: event];
293     }
294
295 #if wxUSE_LOG
296     // let the logs be flashed again
297     wxLog::Resume();
298 #endif // wxUSE_LOG
299
300     s_inYield = false;
301
302     return true;
303 }
304
305 void wxApp::WakeUpIdle()
306 {
307     [m_cocoaApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined
308             location:NSZeroPoint modifierFlags:NSAnyEventMask
309             timestamp:0 windowNumber:0 context:nil
310             subtype:0 data1:0 data2:0] atStart:NO];
311 }
312
313 extern "C" static void ObserveMainRunLoopBeforeWaiting(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info);
314 extern "C" static void ObserveMainRunLoopBeforeWaiting(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info)
315 {
316     static_cast<wxApp*>(info)->CF_ObserveMainRunLoopBeforeWaiting(observer, activity);
317 }
318
319 #if 0
320 static int sg_cApplicationWillUpdate = 0;
321 #endif
322
323 void wxApp::CocoaDelegate_applicationWillUpdate()
324 {
325     wxLogTrace(wxTRACE_COCOA,wxT("applicationWillUpdate"));
326
327 //    CFRunLoopRef cfRunLoop = [[NSRunLoop currentRunLoop] getCFRunLoop];
328     CFRunLoopRef cfRunLoop = CFRunLoopGetCurrent();
329     wxCFRef<CFStringRef> cfRunLoopMode(CFRunLoopCopyCurrentMode(cfRunLoop));
330
331     if(m_cfRunLoopIdleObserver != NULL && m_cfObservedRunLoopMode != cfRunLoopMode)
332     {
333         CFRunLoopObserverInvalidate(m_cfRunLoopIdleObserver);
334         m_cfRunLoopIdleObserver.reset();
335     }
336 #if 0
337     ++sg_cApplicationWillUpdate;
338 #endif
339     if(m_cfRunLoopIdleObserver == NULL)
340     {
341         // Enable idle event handling
342         CFRunLoopObserverContext observerContext =
343         {   0
344         ,   this
345         ,   NULL
346         ,   NULL
347         ,   NULL
348         };
349         m_cfRunLoopIdleObserver.reset(CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopBeforeWaiting, /*repeats*/FALSE, /*priority*/0, ObserveMainRunLoopBeforeWaiting, &observerContext));
350         m_cfObservedRunLoopMode = cfRunLoopMode;
351         CFRunLoopAddObserver(cfRunLoop, m_cfRunLoopIdleObserver, m_cfObservedRunLoopMode);
352     }
353 }
354
355 static inline bool FakeNeedMoreIdle()
356 {
357 #if 0
358 // Return true on every 10th call.
359     static int idleCount = 0;
360     return ++idleCount % 10;
361 #else
362     return false;
363 #endif
364 }
365
366 void wxApp::CF_ObserveMainRunLoopBeforeWaiting(CFRunLoopObserverRef observer, int activity)
367 {
368     // Ensure that the app knows we've been invalidated
369     m_cfRunLoopIdleObserver.reset();
370 #if 0
371     wxLogTrace(wxTRACE_COCOA,wxT("Idle BEGIN (%d)"), sg_cApplicationWillUpdate);
372     sg_cApplicationWillUpdate = 0;
373 #else
374     wxLogTrace(wxTRACE_COCOA,wxT("Idle BEGIN"));
375 #endif
376     if( ProcessIdle() || FakeNeedMoreIdle() )
377     {
378         wxLogTrace(wxTRACE_COCOA, wxT("Idle REQUEST MORE"));
379         [NSApp setWindowsNeedUpdate:YES];
380     }
381     else
382     {
383         wxLogTrace(wxTRACE_COCOA, wxT("Idle END"));
384     }
385 }
386
387 #ifdef __WXDEBUG__
388 void wxApp::OnAssert(const wxChar *file, int line, const wxChar* cond, const wxChar *msg)
389 {
390     m_isInAssert = true;
391     wxAppBase::OnAssert(file, line, cond, msg);
392     m_isInAssert = false;
393 }
394 #endif // __WXDEBUG__