]> git.saurik.com Git - wxWidgets.git/blame - src/cocoa/app.mm
Added wxAutoNSAutoreleasePool where needed for controls sample.
[wxWidgets.git] / src / cocoa / app.mm
CommitLineData
fb896a32
DE
1/////////////////////////////////////////////////////////////////////////////
2// Name: cocoa/app.mm
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
065e208e 9// Licence: wxWidgets licence
fb896a32
DE
10/////////////////////////////////////////////////////////////////////////////
11
fb896a32
DE
12#include "wx/wxprec.h"
13#ifndef WX_PRECOMP
14 #include "wx/defs.h"
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"
7b466aee 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>
6fbcc6ca
DE
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.
73*/
74
75- (NSEvent *)nextEventMatchingMask:(unsigned int)mask untilDate:(NSDate *)expiration inMode:(NSString *)mode dequeue:(BOOL)flag
76{
77 // Get the same events except don't block
78 NSEvent *event = [super nextEventMatchingMask:mask untilDate:nil/* equivalent to [NSDate distantPast] */ inMode:mode dequeue:flag];
79 // If we got one, simply return it
80 if(event)
81 return event;
82 // No events, try doing some idle stuff
6edf960c
DE
83 if(sg_needIdle
84#ifdef __WXDEBUG__
85 && !wxTheApp->IsInAssert()
86#endif
87 && ([NSDefaultRunLoopMode isEqualToString:mode] || [NSModalPanelRunLoopMode isEqualToString:mode]))
eb537cfb
DE
88 {
89 sg_needIdle = false;
48580976 90 wxLogTrace(wxTRACE_COCOA,wxT("Processing idle events"));
eb537cfb
DE
91 while(wxTheApp->ProcessIdle())
92 {
93 // Get the same events except don't block
94 NSEvent *event = [super nextEventMatchingMask:mask untilDate:nil/* equivalent to [NSDate distantPast] */ inMode:mode dequeue:flag];
95 // If we got one, simply return it
96 if(event)
97 return event;
98 // we didn't get one, do some idle work
48580976 99 wxLogTrace(wxTRACE_COCOA,wxT("Looping idle events"));
eb537cfb
DE
100 }
101 // No more idle work requested, block
48580976 102 wxLogTrace(wxTRACE_COCOA,wxT("Finished idle processing"));
eb537cfb
DE
103 }
104 else
48580976 105 wxLogTrace(wxTRACE_COCOA,wxT("Avoiding idle processing sg_needIdle=%d"),sg_needIdle);
eb537cfb
DE
106 return [super nextEventMatchingMask:mask untilDate:expiration inMode:mode dequeue:flag];
107}
108
ba808e24
DE
109- (void)sendEvent: (NSEvent*)anEvent
110{
48580976 111 wxLogTrace(wxTRACE_COCOA,wxT("SendEvent"));
eb537cfb 112 sg_needIdle = true;
ba808e24
DE
113 [super sendEvent: anEvent];
114}
115
116@end // wxPoserNSApplication
117
118// ========================================================================
119// wxNSApplicationDelegate
120// ========================================================================
ba808e24
DE
121@implementation wxNSApplicationDelegate : NSObject
122
2990ec97 123// NOTE: Terminate means that the event loop does NOT return and thus
065e208e 124// cleanup code doesn't properly execute. Furthermore, wxWidgets has its
2990ec97 125// own exit on frame delete mechanism.
fb896a32
DE
126- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
127{
2990ec97 128 return NO;
fb896a32
DE
129}
130
0187ddb4
DE
131- (void)applicationWillBecomeActive:(NSNotification *)notification
132{
133 wxTheApp->CocoaDelegate_applicationWillBecomeActive();
134}
135
136- (void)applicationDidBecomeActive:(NSNotification *)notification
137{
138 wxTheApp->CocoaDelegate_applicationDidBecomeActive();
139}
140
141- (void)applicationWillResignActive:(NSNotification *)notification
142{
143 wxTheApp->CocoaDelegate_applicationWillResignActive();
144}
145
146- (void)applicationDidResignActive:(NSNotification *)notification
147{
148 wxTheApp->CocoaDelegate_applicationDidResignActive();
149}
150
6fbcc6ca
DE
151- (void)controlTintChanged:(NSNotification *)notification
152{
153 wxLogDebug("TODO: send EVT_SYS_COLOUR_CHANGED as appropriate");
154}
155
0187ddb4 156@end // implementation wxNSApplicationDelegate : NSObject
e2478fde 157
70fb935a
DE
158// ========================================================================
159// wxApp
160// ========================================================================
fb896a32
DE
161
162// ----------------------------------------------------------------------------
163// wxApp Static member initialization
164// ----------------------------------------------------------------------------
fb896a32
DE
165IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
166BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
955a9197 167 EVT_IDLE(wxAppBase::OnIdle)
fb896a32
DE
168// EVT_END_SESSION(wxApp::OnEndSession)
169// EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
170END_EVENT_TABLE()
fb896a32
DE
171
172// ----------------------------------------------------------------------------
05e2b077 173// wxApp initialization/cleanup
fb896a32 174// ----------------------------------------------------------------------------
05e2b077 175bool wxApp::Initialize(int& argc, wxChar **argv)
fb896a32 176{
47f1ad6a 177 wxAutoNSAutoreleasePool pool;
14fc7eb4 178 m_cocoaMainThread = [NSThread currentThread];
05e2b077
VZ
179 // Mac OS X passes a process serial number command line argument when
180 // the application is launched from the Finder. This argument must be
181 // removed from the command line arguments before being handled by the
182 // application (otherwise applications would need to handle it)
183 if ( argc > 1 )
184 {
185 static const wxChar *ARG_PSN = _T("-psn_");
b0c0a393 186 if ( wxStrncmp(argv[1], ARG_PSN, wxStrlen(ARG_PSN)) == 0 )
05e2b077
VZ
187 {
188 // remove this argument
33f39af3 189 --argc;
b0c0a393 190 memmove(argv + 1, argv + 2, argc * sizeof(wxChar *));
05e2b077
VZ
191 }
192 }
193
28ce3086
DE
194 // Posing must be completed before any instances of the Objective-C
195 // classes being posed as are created.
fb896a32 196 wxPoseAsInitializer::InitializePosers();
fb896a32 197
94826170 198 return wxAppBase::Initialize(argc, argv);
fb896a32
DE
199}
200
94826170 201void wxApp::CleanUp()
fb896a32 202{
0187ddb4
DE
203 wxAutoNSAutoreleasePool pool;
204
891d0563 205 wxDC::CocoaShutdownTextSystem();
af367f46 206 wxMenuBarManager::DestroyInstance();
94826170 207
0187ddb4 208 [m_cocoaApp setDelegate:nil];
6fbcc6ca
DE
209 [[NSNotificationCenter defaultCenter] removeObserver:m_cocoaAppDelegate
210 name:NSControlTintDidChangeNotification object:nil];
0187ddb4
DE
211 [m_cocoaAppDelegate release];
212 m_cocoaAppDelegate = NULL;
213
94826170 214 wxAppBase::CleanUp();
fb896a32
DE
215}
216
217// ----------------------------------------------------------------------------
218// wxApp creation
219// ----------------------------------------------------------------------------
fb896a32
DE
220wxApp::wxApp()
221{
222 m_topWindow = NULL;
fb896a32 223
fb896a32
DE
224#if WXWIN_COMPATIBILITY_2_2
225 m_wantDebugOutput = TRUE;
226#endif
b93d8cc4
DE
227#ifdef __WXDEBUG__
228 m_isInAssert = FALSE;
229#endif // __WXDEBUG__
230
fb896a32
DE
231 argc = 0;
232 argv = NULL;
233 m_cocoaApp = NULL;
0187ddb4 234 m_cocoaAppDelegate = NULL;
fb896a32
DE
235}
236
0187ddb4
DE
237void wxApp::CocoaDelegate_applicationWillBecomeActive()
238{
239}
240
241void wxApp::CocoaDelegate_applicationDidBecomeActive()
242{
243}
244
245void wxApp::CocoaDelegate_applicationWillResignActive()
246{
39050120 247 wxTopLevelWindowCocoa::DeactivatePendingWindow();
0187ddb4
DE
248}
249
250void wxApp::CocoaDelegate_applicationDidResignActive()
251{
252}
253
fb896a32
DE
254bool wxApp::OnInitGui()
255{
47f1ad6a 256 wxAutoNSAutoreleasePool pool;
fb896a32
DE
257 if(!wxAppBase::OnInitGui())
258 return FALSE;
259
260 // Create the app using the sharedApplication method
261 m_cocoaApp = [NSApplication sharedApplication];
0187ddb4
DE
262 m_cocoaAppDelegate = [[wxNSApplicationDelegate alloc] init];
263 [m_cocoaApp setDelegate:m_cocoaAppDelegate];
6fbcc6ca
DE
264 [[NSNotificationCenter defaultCenter] addObserver:m_cocoaAppDelegate
265 selector:@selector(controlTintChanged:)
266 name:NSControlTintDidChangeNotification object:nil];
af367f46
DE
267
268 wxMenuBarManager::CreateInstance();
269
891d0563 270 wxDC::CocoaInitializeTextSystem();
fb896a32
DE
271 return TRUE;
272}
273
47f1ad6a
DE
274bool wxApp::CallOnInit()
275{
bd3e8827 276// wxAutoNSAutoreleasePool pool;
47f1ad6a
DE
277 return OnInit();
278}
279
fb896a32
DE
280bool wxApp::OnInit()
281{
282 if(!wxAppBase::OnInit())
283 return FALSE;
284
285 return TRUE;
286}
287
70fb935a
DE
288void wxApp::Exit()
289{
290 wxApp::CleanUp();
291
292 wxAppConsole::Exit();
293}
294
fb896a32 295// Yield to other processes
fb896a32
DE
296bool wxApp::Yield(bool onlyIfNeeded)
297{
298 // MT-FIXME
299 static bool s_inYield = false;
300
301#if wxUSE_LOG
302 // disable log flushing from here because a call to wxYield() shouldn't
303 // normally result in message boxes popping up &c
304 wxLog::Suspend();
305#endif // wxUSE_LOG
306
307 if (s_inYield)
308 {
309 if ( !onlyIfNeeded )
310 {
311 wxFAIL_MSG( wxT("wxYield called recursively" ) );
312 }
313
314 return false;
315 }
316
317 s_inYield = true;
318
aaa5ab05 319 // Run the event loop until it is out of events
5ea738ff
DE
320 while(1)
321 {
322 wxAutoNSAutoreleasePool pool;
323 NSEvent *event = [GetNSApplication()
aaa5ab05 324 nextEventMatchingMask:NSAnyEventMask
5ea738ff 325 untilDate:nil /* ==[NSDate distantPast] */
aaa5ab05 326 inMode:NSDefaultRunLoopMode
5ea738ff
DE
327 dequeue: YES];
328 if(!event)
329 break;
aaa5ab05
DE
330 [GetNSApplication() sendEvent: event];
331 }
fb896a32
DE
332
333#if wxUSE_LOG
334 // let the logs be flashed again
335 wxLog::Resume();
336#endif // wxUSE_LOG
337
338 s_inYield = false;
339
340 return true;
341}
342
eb537cfb
DE
343void wxApp::WakeUpIdle()
344{
345 [m_cocoaApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined
346 location:NSZeroPoint modifierFlags:NSAnyEventMask
347 timestamp:0 windowNumber:0 context:nil
348 subtype:0 data1:0 data2:0] atStart:NO];
349}
350
b93d8cc4
DE
351#ifdef __WXDEBUG__
352void wxApp::OnAssert(const wxChar *file, int line, const wxChar* cond, const wxChar *msg)
353{
354 m_isInAssert = TRUE;
355 wxAppBase::OnAssert(file, line, cond, msg);
356 m_isInAssert = FALSE;
357}
358#endif // __WXDEBUG__
359