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