]> git.saurik.com Git - wxWidgets.git/blame - src/cocoa/app.mm
Really remove the droppings when there are no pages
[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
bb27b372 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"
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
f6d0a117
RN
80 RN: Even though Apple documentation states that nil can be passed in place
81 of [NSDate distantPast] in the untilDate parameter, this causes Jaguar (10.2)
82 to get stuck in some kind of loop deep within nextEventMatchingMask:, thus we
83 need to explicitly pass [NSDate distantPast] instead.
eb537cfb
DE
84*/
85
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
fb896a32
DE
235#if WXWIN_COMPATIBILITY_2_2
236 m_wantDebugOutput = TRUE;
237#endif
b93d8cc4
DE
238#ifdef __WXDEBUG__
239 m_isInAssert = FALSE;
240#endif // __WXDEBUG__
241
fb896a32
DE
242 argc = 0;
243 argv = NULL;
244 m_cocoaApp = NULL;
0187ddb4 245 m_cocoaAppDelegate = NULL;
fb896a32
DE
246}
247
0187ddb4
DE
248void wxApp::CocoaDelegate_applicationWillBecomeActive()
249{
250}
251
252void wxApp::CocoaDelegate_applicationDidBecomeActive()
253{
254}
255
256void wxApp::CocoaDelegate_applicationWillResignActive()
257{
39050120 258 wxTopLevelWindowCocoa::DeactivatePendingWindow();
0187ddb4
DE
259}
260
261void wxApp::CocoaDelegate_applicationDidResignActive()
262{
263}
264
fb896a32
DE
265bool wxApp::OnInitGui()
266{
47f1ad6a 267 wxAutoNSAutoreleasePool pool;
fb896a32
DE
268 if(!wxAppBase::OnInitGui())
269 return FALSE;
270
271 // Create the app using the sharedApplication method
272 m_cocoaApp = [NSApplication sharedApplication];
0187ddb4
DE
273 m_cocoaAppDelegate = [[wxNSApplicationDelegate alloc] init];
274 [m_cocoaApp setDelegate:m_cocoaAppDelegate];
bb27b372
RN
275 [[NSNotificationCenter defaultCenter] addObserver:m_cocoaAppDelegate
276 selector:@selector(controlTintChanged:)
277 name:NSControlTintDidChangeNotification object:nil];
af367f46
DE
278
279 wxMenuBarManager::CreateInstance();
280
891d0563 281 wxDC::CocoaInitializeTextSystem();
fb896a32
DE
282 return TRUE;
283}
284
47f1ad6a
DE
285bool wxApp::CallOnInit()
286{
bd3e8827 287// wxAutoNSAutoreleasePool pool;
47f1ad6a
DE
288 return OnInit();
289}
290
fb896a32
DE
291bool wxApp::OnInit()
292{
293 if(!wxAppBase::OnInit())
294 return FALSE;
295
296 return TRUE;
297}
298
70fb935a
DE
299void wxApp::Exit()
300{
301 wxApp::CleanUp();
302
303 wxAppConsole::Exit();
304}
305
fb896a32 306// Yield to other processes
fb896a32
DE
307bool wxApp::Yield(bool onlyIfNeeded)
308{
309 // MT-FIXME
310 static bool s_inYield = false;
311
312#if wxUSE_LOG
313 // disable log flushing from here because a call to wxYield() shouldn't
314 // normally result in message boxes popping up &c
315 wxLog::Suspend();
316#endif // wxUSE_LOG
317
318 if (s_inYield)
319 {
320 if ( !onlyIfNeeded )
321 {
322 wxFAIL_MSG( wxT("wxYield called recursively" ) );
323 }
324
325 return false;
326 }
327
328 s_inYield = true;
329
aaa5ab05 330 // Run the event loop until it is out of events
bb27b372
RN
331 while(1)
332 {
333 wxAutoNSAutoreleasePool pool;
334 NSEvent *event = [GetNSApplication()
aaa5ab05 335 nextEventMatchingMask:NSAnyEventMask
422d306c 336 untilDate:[NSDate distantPast]
aaa5ab05 337 inMode:NSDefaultRunLoopMode
bb27b372
RN
338 dequeue: YES];
339 if(!event)
340 break;
aaa5ab05
DE
341 [GetNSApplication() sendEvent: event];
342 }
fb896a32
DE
343
344#if wxUSE_LOG
345 // let the logs be flashed again
346 wxLog::Resume();
347#endif // wxUSE_LOG
348
349 s_inYield = false;
350
351 return true;
352}
353
eb537cfb
DE
354void wxApp::WakeUpIdle()
355{
356 [m_cocoaApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined
357 location:NSZeroPoint modifierFlags:NSAnyEventMask
358 timestamp:0 windowNumber:0 context:nil
359 subtype:0 data1:0 data2:0] atStart:NO];
360}
361
b93d8cc4
DE
362#ifdef __WXDEBUG__
363void wxApp::OnAssert(const wxChar *file, int line, const wxChar* cond, const wxChar *msg)
364{
365 m_isInAssert = TRUE;
366 wxAppBase::OnAssert(file, line, cond, msg);
367 m_isInAssert = FALSE;
368}
369#endif // __WXDEBUG__
370