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