]> git.saurik.com Git - wxWidgets.git/blob - src/cocoa/app.mm
PCH-less compilation fix
[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__