]> git.saurik.com Git - wxWidgets.git/blame - src/cocoa/app.mm
mention ShouldInheritColours() change
[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
d89d4059 9// Licence: wxWindows 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"
16 #include "wx/frame.h"
17 #include "wx/dialog.h"
891d0563 18 #include "wx/dc.h"
fb896a32
DE
19 #include "wx/intl.h"
20 #include "wx/log.h"
fb896a32
DE
21#endif
22
11c08416
DE
23#include "wx/module.h"
24
fb45bb1f 25#include "wx/cocoa/ObjcPose.h"
493902ac 26#include "wx/cocoa/autorelease.h"
af367f46 27#include "wx/cocoa/mbarman.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>
35#import <Foundation/NSArray.h>
47f1ad6a 36#import <Foundation/NSAutoreleasePool.h>
14fc7eb4 37#import <Foundation/NSThread.h>
aaa5ab05 38#import <AppKit/NSEvent.h>
fb896a32 39
70fb935a
DE
40// ========================================================================
41// wxPoseAsInitializer
42// ========================================================================
fb896a32
DE
43wxPoseAsInitializer *wxPoseAsInitializer::sm_first = NULL;
44
70fb935a
DE
45// ========================================================================
46// wxPoserNSApplication
47// ========================================================================
fb896a32
DE
48@interface wxPoserNSApplication : NSApplication
49{
50}
51
fb896a32 52- (void)sendEvent: (NSEvent*)anEvent;
fb896a32
DE
53@end // wxPoserNSApplication
54
70fb935a
DE
55WX_IMPLEMENT_POSER(wxPoserNSApplication);
56
fb896a32
DE
57@implementation wxPoserNSApplication : NSApplication
58
ba808e24
DE
59- (void)sendEvent: (NSEvent*)anEvent
60{
61 wxLogDebug("SendEvent");
62 wxTheApp->CocoaInstallRequestedIdleHandler();
63 [super sendEvent: anEvent];
64}
65
66@end // wxPoserNSApplication
67
68// ========================================================================
69// wxNSApplicationDelegate
70// ========================================================================
71@interface wxNSApplicationDelegate : NSObject
72{
73}
74
75- (void)doIdle: (id)data;
76// Delegate methods
77- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication;
78- (void)applicationWillBecomeActive:(NSNotification *)notification;
79- (void)applicationDidBecomeActive:(NSNotification *)notification;
80- (void)applicationWillResignActive:(NSNotification *)notification;
81- (void)applicationDidResignActive:(NSNotification *)notification;
82@end // interface wxNSApplicationDelegate : NSObject
83
84@implementation wxNSApplicationDelegate : NSObject
85
fb896a32
DE
86- (void)doIdle: (id)data
87{
88 wxASSERT(wxTheApp);
af367f46
DE
89 wxASSERT(wxMenuBarManager::GetInstance());
90 wxMenuBarManager::GetInstance()->CocoaInternalIdle();
fb896a32 91 wxLogDebug("doIdle called");
b93d8cc4
DE
92#ifdef __WXDEBUG__
93 if(wxTheApp->IsInAssert())
fb896a32 94 {
b93d8cc4
DE
95 wxLogDebug("Idle events ignored durring assertion dialog");
96 }
97 else
98#endif
99 {
100 NSRunLoop *rl = [NSRunLoop currentRunLoop];
101 // runMode: beforeDate returns YES if something was done
102 while(wxTheApp->ProcessIdle()) // FIXME: AND NO EVENTS ARE PENDING
fb896a32 103 {
b93d8cc4
DE
104 wxLogDebug("Looping for idle events");
105 #if 1
106 if( [rl runMode:[rl currentMode] beforeDate:[NSDate distantPast]])
107 {
108 wxLogDebug("Found actual work to do");
109 break;
110 }
111 #endif
fb896a32 112 }
fb896a32
DE
113 }
114 wxLogDebug("Idle processing complete, requesting next idle event");
115 // Add ourself back into the run loop (on next event) if necessary
116 wxTheApp->CocoaRequestIdle();
117}
118
2990ec97
DE
119// NOTE: Terminate means that the event loop does NOT return and thus
120// cleanup code doesn't properly execute. Furthermore, wxWindows has its
121// own exit on frame delete mechanism.
fb896a32
DE
122- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
123{
2990ec97 124 return NO;
fb896a32
DE
125}
126
0187ddb4
DE
127- (void)applicationWillBecomeActive:(NSNotification *)notification
128{
129 wxTheApp->CocoaDelegate_applicationWillBecomeActive();
130}
131
132- (void)applicationDidBecomeActive:(NSNotification *)notification
133{
134 wxTheApp->CocoaDelegate_applicationDidBecomeActive();
135}
136
137- (void)applicationWillResignActive:(NSNotification *)notification
138{
139 wxTheApp->CocoaDelegate_applicationWillResignActive();
140}
141
142- (void)applicationDidResignActive:(NSNotification *)notification
143{
144 wxTheApp->CocoaDelegate_applicationDidResignActive();
145}
146
147@end // implementation wxNSApplicationDelegate : NSObject
e2478fde 148
70fb935a
DE
149// ========================================================================
150// wxApp
151// ========================================================================
fb896a32
DE
152
153// ----------------------------------------------------------------------------
154// wxApp Static member initialization
155// ----------------------------------------------------------------------------
fb896a32
DE
156IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
157BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
955a9197 158 EVT_IDLE(wxAppBase::OnIdle)
fb896a32
DE
159// EVT_END_SESSION(wxApp::OnEndSession)
160// EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
161END_EVENT_TABLE()
fb896a32
DE
162
163// ----------------------------------------------------------------------------
05e2b077 164// wxApp initialization/cleanup
fb896a32 165// ----------------------------------------------------------------------------
05e2b077 166bool wxApp::Initialize(int& argc, wxChar **argv)
fb896a32 167{
47f1ad6a 168 wxAutoNSAutoreleasePool pool;
14fc7eb4 169 m_cocoaMainThread = [NSThread currentThread];
05e2b077
VZ
170 // Mac OS X passes a process serial number command line argument when
171 // the application is launched from the Finder. This argument must be
172 // removed from the command line arguments before being handled by the
173 // application (otherwise applications would need to handle it)
174 if ( argc > 1 )
175 {
176 static const wxChar *ARG_PSN = _T("-psn_");
33f39af3 177 if ( wxStrncmp(argv[1], ARG_PSN, strlen(ARG_PSN)) == 0 )
05e2b077
VZ
178 {
179 // remove this argument
33f39af3
GD
180 --argc;
181 memmove(argv + 1, argv + 2, argc * sizeof(char *));
05e2b077
VZ
182 }
183 }
184
28ce3086
DE
185 // Posing must be completed before any instances of the Objective-C
186 // classes being posed as are created.
fb896a32 187 wxPoseAsInitializer::InitializePosers();
fb896a32 188
94826170 189 return wxAppBase::Initialize(argc, argv);
fb896a32
DE
190}
191
94826170 192void wxApp::CleanUp()
fb896a32 193{
0187ddb4
DE
194 wxAutoNSAutoreleasePool pool;
195
891d0563 196 wxDC::CocoaShutdownTextSystem();
af367f46 197 wxMenuBarManager::DestroyInstance();
94826170 198
0187ddb4
DE
199 [m_cocoaApp setDelegate:nil];
200 [m_cocoaAppDelegate release];
201 m_cocoaAppDelegate = NULL;
202
94826170 203 wxAppBase::CleanUp();
fb896a32
DE
204}
205
206// ----------------------------------------------------------------------------
207// wxApp creation
208// ----------------------------------------------------------------------------
fb896a32
DE
209wxApp::wxApp()
210{
211 m_topWindow = NULL;
fb896a32
DE
212
213 m_isIdle = true;
214#if WXWIN_COMPATIBILITY_2_2
215 m_wantDebugOutput = TRUE;
216#endif
b93d8cc4
DE
217#ifdef __WXDEBUG__
218 m_isInAssert = FALSE;
219#endif // __WXDEBUG__
220
fb896a32
DE
221 argc = 0;
222 argv = NULL;
223 m_cocoaApp = NULL;
0187ddb4 224 m_cocoaAppDelegate = NULL;
fb896a32
DE
225}
226
227void wxApp::CocoaInstallIdleHandler()
228{
14fc7eb4
DE
229 // If we're not the main thread, don't install the idle handler
230 if(m_cocoaMainThread != [NSThread currentThread])
231 {
232 wxLogDebug("Attempt to install idle handler from secondary thread");
233 return;
234 }
bc34fa26
DE
235 // If we're supposed to be stopping, don't add more idle events
236 if(![m_cocoaApp isRunning])
237 return;
fb896a32
DE
238 wxLogDebug("wxApp::CocoaInstallIdleHandler");
239 m_isIdle = false;
240 // Call doIdle for EVERYTHING dammit
241// We'd need Foundation/NSConnection.h for this next constant, do we need it?
ba808e24 242 [[ NSRunLoop currentRunLoop ] performSelector:@selector(doIdle:) target:m_cocoaAppDelegate argument:NULL order:0 modes:[NSArray arrayWithObjects:NSDefaultRunLoopMode, /* NSConnectionReplyRunLoopMode,*/ NSModalPanelRunLoopMode, /**/NSEventTrackingRunLoopMode,/**/ nil] ];
59d6b6a9
DE
243 /* Notes:
244 In the Mac OS X implementation of Cocoa, the above method schedules
245 doIdle: to be called from *within* [NSApplication
246 -nextEventMatchingMask:untilDate:inMode:dequeue:]. That is, no
247 NSEvent object is generated and control does not return from that
248 method. In fact, control will only return from that method for the
249 usual reasons (e.g. a real event is received or the untilDate is reached).
250 This has implications when trying to stop the event loop and return to
251 its caller. See wxEventLoop::Exit
252 */
fb896a32
DE
253}
254
0187ddb4
DE
255void wxApp::CocoaDelegate_applicationWillBecomeActive()
256{
257}
258
259void wxApp::CocoaDelegate_applicationDidBecomeActive()
260{
261}
262
263void wxApp::CocoaDelegate_applicationWillResignActive()
264{
265}
266
267void wxApp::CocoaDelegate_applicationDidResignActive()
268{
269}
270
fb896a32
DE
271bool wxApp::OnInitGui()
272{
47f1ad6a 273 wxAutoNSAutoreleasePool pool;
fb896a32
DE
274 if(!wxAppBase::OnInitGui())
275 return FALSE;
276
277 // Create the app using the sharedApplication method
278 m_cocoaApp = [NSApplication sharedApplication];
0187ddb4
DE
279 m_cocoaAppDelegate = [[wxNSApplicationDelegate alloc] init];
280 [m_cocoaApp setDelegate:m_cocoaAppDelegate];
af367f46
DE
281
282 wxMenuBarManager::CreateInstance();
283
891d0563 284 wxDC::CocoaInitializeTextSystem();
fb896a32
DE
285// [ m_cocoaApp setDelegate:m_cocoaApp ];
286 #if 0
287 wxLogDebug("Just for kicks");
ba808e24 288 [ m_cocoaAppDelegate performSelector:@selector(doIdle:) withObject:NULL ];
fb896a32
DE
289 wxLogDebug("okay.. done now");
290 #endif
291 return TRUE;
292}
293
47f1ad6a
DE
294bool wxApp::CallOnInit()
295{
bd3e8827 296// wxAutoNSAutoreleasePool pool;
47f1ad6a
DE
297 return OnInit();
298}
299
fb896a32
DE
300bool wxApp::OnInit()
301{
302 if(!wxAppBase::OnInit())
303 return FALSE;
304
305 return TRUE;
306}
307
70fb935a
DE
308void wxApp::Exit()
309{
310 wxApp::CleanUp();
311
312 wxAppConsole::Exit();
313}
314
fb896a32 315// Yield to other processes
fb896a32
DE
316bool wxApp::Yield(bool onlyIfNeeded)
317{
318 // MT-FIXME
319 static bool s_inYield = false;
320
321#if wxUSE_LOG
322 // disable log flushing from here because a call to wxYield() shouldn't
323 // normally result in message boxes popping up &c
324 wxLog::Suspend();
325#endif // wxUSE_LOG
326
327 if (s_inYield)
328 {
329 if ( !onlyIfNeeded )
330 {
331 wxFAIL_MSG( wxT("wxYield called recursively" ) );
332 }
333
334 return false;
335 }
336
337 s_inYield = true;
338
aaa5ab05
DE
339 // Run the event loop until it is out of events
340 while(NSEvent *event = [GetNSApplication()
341 nextEventMatchingMask:NSAnyEventMask
342 untilDate:[NSDate distantPast]
343 inMode:NSDefaultRunLoopMode
344 dequeue: YES])
345 {
346 [GetNSApplication() sendEvent: event];
347 }
fb896a32
DE
348
349#if wxUSE_LOG
350 // let the logs be flashed again
351 wxLog::Resume();
352#endif // wxUSE_LOG
353
354 s_inYield = false;
355
356 return true;
357}
358
b93d8cc4
DE
359#ifdef __WXDEBUG__
360void wxApp::OnAssert(const wxChar *file, int line, const wxChar* cond, const wxChar *msg)
361{
362 m_isInAssert = TRUE;
363 wxAppBase::OnAssert(file, line, cond, msg);
364 m_isInAssert = FALSE;
365}
366#endif // __WXDEBUG__
367