]> git.saurik.com Git - wxWidgets.git/blame - src/cocoa/app.mm
don't declare inline function with dllexport declaration, this provokes mingw32 warni...
[wxWidgets.git] / src / cocoa / app.mm
CommitLineData
fb896a32 1/////////////////////////////////////////////////////////////////////////////
8898456d 2// Name: src/cocoa/app.mm
fb896a32
DE
3// Purpose: wxApp
4// Author: David Elliott
5// Modified by:
6// Created: 2002/11/27
d89d4059 7// RCS-ID: $Id$
fb896a32 8// Copyright: (c) David Elliott
bb27b372 9// Licence: wxWidgets licence
fb896a32
DE
10/////////////////////////////////////////////////////////////////////////////
11
fb896a32 12#include "wx/wxprec.h"
8898456d 13
da80ae71
WS
14#include "wx/app.h"
15
fb896a32 16#ifndef WX_PRECOMP
891d0563 17 #include "wx/dc.h"
fb896a32
DE
18 #include "wx/intl.h"
19 #include "wx/log.h"
02761f6c 20 #include "wx/module.h"
fb896a32
DE
21#endif
22
fb45bb1f 23#include "wx/cocoa/ObjcPose.h"
493902ac 24#include "wx/cocoa/autorelease.h"
af367f46 25#include "wx/cocoa/mbarman.h"
bb27b372 26#include "wx/cocoa/NSApplication.h"
fb45bb1f 27
fb896a32
DE
28#import <AppKit/NSApplication.h>
29#import <Foundation/NSRunLoop.h>
14fc7eb4 30#import <Foundation/NSThread.h>
aaa5ab05 31#import <AppKit/NSEvent.h>
eb537cfb 32#import <Foundation/NSString.h>
bb27b372
RN
33#import <Foundation/NSNotification.h>
34#import <AppKit/NSCell.h>
fb896a32 35
70fb935a
DE
36// ========================================================================
37// wxPoseAsInitializer
38// ========================================================================
fb896a32
DE
39wxPoseAsInitializer *wxPoseAsInitializer::sm_first = NULL;
40
eb537cfb
DE
41static bool sg_needIdle = true;
42
70fb935a
DE
43// ========================================================================
44// wxPoserNSApplication
45// ========================================================================
fb896a32
DE
46@interface wxPoserNSApplication : NSApplication
47{
48}
49
eb537cfb 50- (NSEvent *)nextEventMatchingMask:(unsigned int)mask untilDate:(NSDate *)expiration inMode:(NSString *)mode dequeue:(BOOL)flag;
fb896a32 51- (void)sendEvent: (NSEvent*)anEvent;
fb896a32
DE
52@end // wxPoserNSApplication
53
70fb935a
DE
54WX_IMPLEMENT_POSER(wxPoserNSApplication);
55
fb896a32
DE
56@implementation wxPoserNSApplication : NSApplication
57
eb537cfb
DE
58/* NOTE: The old method of idle event handling added the handler using the
59 [NSRunLoop -performSelector:target:argument:order:modes] which caused
60 the invocation to occur at the begining of [NSApplication
61 -nextEventMatchingMask:untilDate:expiration:inMode:dequeue:]. However,
62 the code would be scheduled for invocation with every iteration of
63 the event loop. This new method simply overrides the method. The
64 same caveats apply. In particular, by the time the event loop has
65 called this method, it usually expects to receive an event. If you
66 plan on stopping the event loop, it is wise to send an event through
67 the queue to ensure this method will return.
68 See wxEventLoop::Exit() for more information.
422d306c 69
eba2de69
DE
70 This overridden method calls the superclass method with an untilDate
71 parameter that indicates nil should be returned if there are no pending
72 events. That is, nextEventMatchingMask: should not wait for an event.
73 If nil is returned then idle event processing occurs until the user
74 does not request anymore idle events or until a real event comes through.
75
8898456d 76 RN: Even though Apple documentation states that nil can be passed in place
f6d0a117 77 of [NSDate distantPast] in the untilDate parameter, this causes Jaguar (10.2)
8898456d 78 to get stuck in some kind of loop deep within nextEventMatchingMask:, thus we
f6d0a117 79 need to explicitly pass [NSDate distantPast] instead.
eb537cfb 80*/
8898456d 81
eb537cfb
DE
82- (NSEvent *)nextEventMatchingMask:(unsigned int)mask untilDate:(NSDate *)expiration inMode:(NSString *)mode dequeue:(BOOL)flag
83{
84 // Get the same events except don't block
422d306c 85 NSEvent *event = [super nextEventMatchingMask:mask untilDate:[NSDate distantPast] inMode:mode dequeue:flag];
eb537cfb
DE
86 // If we got one, simply return it
87 if(event)
88 return event;
89 // No events, try doing some idle stuff
bb27b372
RN
90 if(sg_needIdle
91#ifdef __WXDEBUG__
92 && !wxTheApp->IsInAssert()
93#endif
94 && ([NSDefaultRunLoopMode isEqualToString:mode] || [NSModalPanelRunLoopMode isEqualToString:mode]))
eb537cfb
DE
95 {
96 sg_needIdle = false;
bb27b372 97 wxLogTrace(wxTRACE_COCOA,wxT("Processing idle events"));
eb537cfb
DE
98 while(wxTheApp->ProcessIdle())
99 {
100 // Get the same events except don't block
422d306c 101 NSEvent *event = [super nextEventMatchingMask:mask untilDate:[NSDate distantPast] inMode:mode dequeue:flag];
eb537cfb
DE
102 // If we got one, simply return it
103 if(event)
104 return event;
105 // we didn't get one, do some idle work
bb27b372 106 wxLogTrace(wxTRACE_COCOA,wxT("Looping idle events"));
eb537cfb
DE
107 }
108 // No more idle work requested, block
bb27b372 109 wxLogTrace(wxTRACE_COCOA,wxT("Finished idle processing"));
eb537cfb
DE
110 }
111 else
bb27b372 112 wxLogTrace(wxTRACE_COCOA,wxT("Avoiding idle processing sg_needIdle=%d"),sg_needIdle);
eb537cfb
DE
113 return [super nextEventMatchingMask:mask untilDate:expiration inMode:mode dequeue:flag];
114}
115
ba808e24
DE
116- (void)sendEvent: (NSEvent*)anEvent
117{
bb27b372 118 wxLogTrace(wxTRACE_COCOA,wxT("SendEvent"));
eb537cfb 119 sg_needIdle = true;
ba808e24
DE
120 [super sendEvent: anEvent];
121}
122
123@end // wxPoserNSApplication
124
125// ========================================================================
126// wxNSApplicationDelegate
127// ========================================================================
ba808e24
DE
128@implementation wxNSApplicationDelegate : NSObject
129
2990ec97 130// NOTE: Terminate means that the event loop does NOT return and thus
bb27b372 131// cleanup code doesn't properly execute. Furthermore, wxWidgets has its
2990ec97 132// own exit on frame delete mechanism.
fb896a32
DE
133- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
134{
2990ec97 135 return NO;
fb896a32
DE
136}
137
0187ddb4
DE
138- (void)applicationWillBecomeActive:(NSNotification *)notification
139{
140 wxTheApp->CocoaDelegate_applicationWillBecomeActive();
141}
142
143- (void)applicationDidBecomeActive:(NSNotification *)notification
144{
145 wxTheApp->CocoaDelegate_applicationDidBecomeActive();
146}
147
148- (void)applicationWillResignActive:(NSNotification *)notification
149{
150 wxTheApp->CocoaDelegate_applicationWillResignActive();
151}
152
153- (void)applicationDidResignActive:(NSNotification *)notification
154{
155 wxTheApp->CocoaDelegate_applicationDidResignActive();
156}
157
bb27b372
RN
158- (void)controlTintChanged:(NSNotification *)notification
159{
422d306c 160 wxLogDebug(wxT("TODO: send EVT_SYS_COLOUR_CHANGED as appropriate"));
bb27b372
RN
161}
162
0187ddb4 163@end // implementation wxNSApplicationDelegate : NSObject
e2478fde 164
70fb935a
DE
165// ========================================================================
166// wxApp
167// ========================================================================
fb896a32
DE
168
169// ----------------------------------------------------------------------------
170// wxApp Static member initialization
171// ----------------------------------------------------------------------------
fb896a32
DE
172IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
173BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
955a9197 174 EVT_IDLE(wxAppBase::OnIdle)
fb896a32
DE
175// EVT_END_SESSION(wxApp::OnEndSession)
176// EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
177END_EVENT_TABLE()
fb896a32
DE
178
179// ----------------------------------------------------------------------------
05e2b077 180// wxApp initialization/cleanup
fb896a32 181// ----------------------------------------------------------------------------
05e2b077 182bool wxApp::Initialize(int& argc, wxChar **argv)
fb896a32 183{
47f1ad6a 184 wxAutoNSAutoreleasePool pool;
14fc7eb4 185 m_cocoaMainThread = [NSThread currentThread];
05e2b077
VZ
186 // Mac OS X passes a process serial number command line argument when
187 // the application is launched from the Finder. This argument must be
188 // removed from the command line arguments before being handled by the
189 // application (otherwise applications would need to handle it)
190 if ( argc > 1 )
191 {
192 static const wxChar *ARG_PSN = _T("-psn_");
b0c0a393 193 if ( wxStrncmp(argv[1], ARG_PSN, wxStrlen(ARG_PSN)) == 0 )
05e2b077
VZ
194 {
195 // remove this argument
33f39af3 196 --argc;
b0c0a393 197 memmove(argv + 1, argv + 2, argc * sizeof(wxChar *));
05e2b077
VZ
198 }
199 }
200
28ce3086
DE
201 // Posing must be completed before any instances of the Objective-C
202 // classes being posed as are created.
fb896a32 203 wxPoseAsInitializer::InitializePosers();
fb896a32 204
94826170 205 return wxAppBase::Initialize(argc, argv);
fb896a32
DE
206}
207
94826170 208void wxApp::CleanUp()
fb896a32 209{
0187ddb4
DE
210 wxAutoNSAutoreleasePool pool;
211
891d0563 212 wxDC::CocoaShutdownTextSystem();
af367f46 213 wxMenuBarManager::DestroyInstance();
94826170 214
0187ddb4 215 [m_cocoaApp setDelegate:nil];
bb27b372
RN
216 [[NSNotificationCenter defaultCenter] removeObserver:m_cocoaAppDelegate
217 name:NSControlTintDidChangeNotification object:nil];
0187ddb4
DE
218 [m_cocoaAppDelegate release];
219 m_cocoaAppDelegate = NULL;
220
94826170 221 wxAppBase::CleanUp();
fb896a32
DE
222}
223
224// ----------------------------------------------------------------------------
225// wxApp creation
226// ----------------------------------------------------------------------------
fb896a32
DE
227wxApp::wxApp()
228{
229 m_topWindow = NULL;
fb896a32 230
b93d8cc4 231#ifdef __WXDEBUG__
8898456d 232 m_isInAssert = false;
b93d8cc4
DE
233#endif // __WXDEBUG__
234
fb896a32
DE
235 argc = 0;
236 argv = NULL;
237 m_cocoaApp = NULL;
0187ddb4 238 m_cocoaAppDelegate = NULL;
fb896a32
DE
239}
240
0187ddb4
DE
241void wxApp::CocoaDelegate_applicationWillBecomeActive()
242{
243}
244
245void wxApp::CocoaDelegate_applicationDidBecomeActive()
246{
247}
248
249void wxApp::CocoaDelegate_applicationWillResignActive()
250{
39050120 251 wxTopLevelWindowCocoa::DeactivatePendingWindow();
0187ddb4
DE
252}
253
254void wxApp::CocoaDelegate_applicationDidResignActive()
255{
256}
257
fb896a32
DE
258bool wxApp::OnInitGui()
259{
47f1ad6a 260 wxAutoNSAutoreleasePool pool;
fb896a32 261 if(!wxAppBase::OnInitGui())
8898456d 262 return false;
fb896a32
DE
263
264 // Create the app using the sharedApplication method
265 m_cocoaApp = [NSApplication sharedApplication];
0187ddb4
DE
266 m_cocoaAppDelegate = [[wxNSApplicationDelegate alloc] init];
267 [m_cocoaApp setDelegate:m_cocoaAppDelegate];
bb27b372
RN
268 [[NSNotificationCenter defaultCenter] addObserver:m_cocoaAppDelegate
269 selector:@selector(controlTintChanged:)
270 name:NSControlTintDidChangeNotification object:nil];
af367f46
DE
271
272 wxMenuBarManager::CreateInstance();
273
891d0563 274 wxDC::CocoaInitializeTextSystem();
8898456d 275 return true;
fb896a32
DE
276}
277
47f1ad6a
DE
278bool wxApp::CallOnInit()
279{
bd3e8827 280// wxAutoNSAutoreleasePool pool;
47f1ad6a
DE
281 return OnInit();
282}
283
fb896a32
DE
284bool wxApp::OnInit()
285{
286 if(!wxAppBase::OnInit())
8898456d 287 return false;
fb896a32 288
8898456d 289 return true;
fb896a32
DE
290}
291
70fb935a
DE
292void wxApp::Exit()
293{
294 wxApp::CleanUp();
295
296 wxAppConsole::Exit();
297}
298
fb896a32 299// Yield to other processes
fb896a32
DE
300bool wxApp::Yield(bool onlyIfNeeded)
301{
302 // MT-FIXME
303 static bool s_inYield = false;
304
305#if wxUSE_LOG
306 // disable log flushing from here because a call to wxYield() shouldn't
307 // normally result in message boxes popping up &c
308 wxLog::Suspend();
309#endif // wxUSE_LOG
310
311 if (s_inYield)
312 {
313 if ( !onlyIfNeeded )
314 {
315 wxFAIL_MSG( wxT("wxYield called recursively" ) );
316 }
317
318 return false;
319 }
320
321 s_inYield = true;
322
aaa5ab05 323 // Run the event loop until it is out of events
bb27b372
RN
324 while(1)
325 {
326 wxAutoNSAutoreleasePool pool;
327 NSEvent *event = [GetNSApplication()
aaa5ab05 328 nextEventMatchingMask:NSAnyEventMask
422d306c 329 untilDate:[NSDate distantPast]
aaa5ab05 330 inMode:NSDefaultRunLoopMode
bb27b372
RN
331 dequeue: YES];
332 if(!event)
333 break;
aaa5ab05
DE
334 [GetNSApplication() sendEvent: event];
335 }
fb896a32
DE
336
337#if wxUSE_LOG
338 // let the logs be flashed again
339 wxLog::Resume();
340#endif // wxUSE_LOG
341
342 s_inYield = false;
343
344 return true;
345}
346
eb537cfb
DE
347void wxApp::WakeUpIdle()
348{
349 [m_cocoaApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined
350 location:NSZeroPoint modifierFlags:NSAnyEventMask
351 timestamp:0 windowNumber:0 context:nil
352 subtype:0 data1:0 data2:0] atStart:NO];
353}
354
b93d8cc4
DE
355#ifdef __WXDEBUG__
356void wxApp::OnAssert(const wxChar *file, int line, const wxChar* cond, const wxChar *msg)
357{
8898456d 358 m_isInAssert = true;
b93d8cc4 359 wxAppBase::OnAssert(file, line, cond, msg);
8898456d 360 m_isInAssert = false;
b93d8cc4
DE
361}
362#endif // __WXDEBUG__