1 /////////////////////////////////////////////////////////////////////////////
4 // Author: David Elliott
8 // Copyright: (c) David Elliott
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 #include "wx/wxprec.h"
17 #include "wx/dialog.h"
23 #include "wx/module.h"
25 #include "wx/cocoa/ObjcPose.h"
26 #include "wx/cocoa/autorelease.h"
27 #include "wx/cocoa/mbarman.h"
29 #if wxUSE_WX_RESOURCES
30 # include "wx/resource.h"
33 #import <AppKit/NSApplication.h>
34 #import <Foundation/NSRunLoop.h>
35 #import <Foundation/NSArray.h>
36 #import <Foundation/NSAutoreleasePool.h>
37 #import <Foundation/NSThread.h>
38 #import <AppKit/NSEvent.h>
40 // ========================================================================
41 // wxPoseAsInitializer
42 // ========================================================================
43 wxPoseAsInitializer *wxPoseAsInitializer::sm_first = NULL;
45 // ========================================================================
46 // wxPoserNSApplication
47 // ========================================================================
48 @interface wxPoserNSApplication : NSApplication
52 - (void)sendEvent: (NSEvent*)anEvent;
53 @end // wxPoserNSApplication
55 WX_IMPLEMENT_POSER(wxPoserNSApplication);
57 @implementation wxPoserNSApplication : NSApplication
59 - (void)sendEvent: (NSEvent*)anEvent
61 wxLogDebug("SendEvent");
62 wxTheApp->CocoaInstallRequestedIdleHandler();
63 [super sendEvent: anEvent];
66 @end // wxPoserNSApplication
68 // ========================================================================
69 // wxNSApplicationDelegate
70 // ========================================================================
71 @interface wxNSApplicationDelegate : NSObject
75 - (void)doIdle: (id)data;
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
84 @implementation wxNSApplicationDelegate : NSObject
86 - (void)doIdle: (id)data
89 wxASSERT(wxMenuBarManager::GetInstance());
90 wxMenuBarManager::GetInstance()->CocoaInternalIdle();
91 wxLogDebug("doIdle called");
93 if(wxTheApp->IsInAssert())
95 wxLogDebug("Idle events ignored durring assertion dialog");
100 NSRunLoop *rl = [NSRunLoop currentRunLoop];
101 // runMode: beforeDate returns YES if something was done
102 while(wxTheApp->ProcessIdle()) // FIXME: AND NO EVENTS ARE PENDING
104 wxLogDebug("Looping for idle events");
106 if( [rl runMode:[rl currentMode] beforeDate:[NSDate distantPast]])
108 wxLogDebug("Found actual work to do");
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();
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.
122 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
127 - (void)applicationWillBecomeActive:(NSNotification *)notification
129 wxTheApp->CocoaDelegate_applicationWillBecomeActive();
132 - (void)applicationDidBecomeActive:(NSNotification *)notification
134 wxTheApp->CocoaDelegate_applicationDidBecomeActive();
137 - (void)applicationWillResignActive:(NSNotification *)notification
139 wxTheApp->CocoaDelegate_applicationWillResignActive();
142 - (void)applicationDidResignActive:(NSNotification *)notification
144 wxTheApp->CocoaDelegate_applicationDidResignActive();
147 @end // implementation wxNSApplicationDelegate : NSObject
149 // ========================================================================
151 // ========================================================================
153 // ----------------------------------------------------------------------------
154 // wxApp Static member initialization
155 // ----------------------------------------------------------------------------
156 IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
157 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
158 EVT_IDLE(wxAppBase::OnIdle)
159 // EVT_END_SESSION(wxApp::OnEndSession)
160 // EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
163 // ----------------------------------------------------------------------------
164 // wxApp initialization/cleanup
165 // ----------------------------------------------------------------------------
166 bool wxApp::Initialize(int& argc, wxChar **argv)
168 wxAutoNSAutoreleasePool pool;
169 m_cocoaMainThread = [NSThread currentThread];
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)
176 static const wxChar *ARG_PSN = _T("-psn_");
177 if ( wxStrncmp(argv[1], ARG_PSN, strlen(ARG_PSN)) == 0 )
179 // remove this argument
181 memmove(argv + 1, argv + 2, argc * sizeof(char *));
185 // Posing must be completed before any instances of the Objective-C
186 // classes being posed as are created.
187 wxPoseAsInitializer::InitializePosers();
189 return wxAppBase::Initialize(argc, argv);
192 void wxApp::CleanUp()
194 wxAutoNSAutoreleasePool pool;
196 wxDC::CocoaShutdownTextSystem();
197 wxMenuBarManager::DestroyInstance();
199 [m_cocoaApp setDelegate:nil];
200 [m_cocoaAppDelegate release];
201 m_cocoaAppDelegate = NULL;
203 wxAppBase::CleanUp();
206 // ----------------------------------------------------------------------------
208 // ----------------------------------------------------------------------------
214 #if WXWIN_COMPATIBILITY_2_2
215 m_wantDebugOutput = TRUE;
218 m_isInAssert = FALSE;
219 #endif // __WXDEBUG__
224 m_cocoaAppDelegate = NULL;
227 void wxApp::CocoaInstallIdleHandler()
229 // If we're not the main thread, don't install the idle handler
230 if(m_cocoaMainThread != [NSThread currentThread])
232 wxLogDebug("Attempt to install idle handler from secondary thread");
235 // If we're supposed to be stopping, don't add more idle events
236 if(![m_cocoaApp isRunning])
238 wxLogDebug("wxApp::CocoaInstallIdleHandler");
240 // Call doIdle for EVERYTHING dammit
241 // We'd need Foundation/NSConnection.h for this next constant, do we need it?
242 [[ NSRunLoop currentRunLoop ] performSelector:@selector(doIdle:) target:m_cocoaAppDelegate argument:NULL order:0 modes:[NSArray arrayWithObjects:NSDefaultRunLoopMode, /* NSConnectionReplyRunLoopMode,*/ NSModalPanelRunLoopMode, /**/NSEventTrackingRunLoopMode,/**/ nil] ];
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
255 void wxApp::CocoaDelegate_applicationWillBecomeActive()
259 void wxApp::CocoaDelegate_applicationDidBecomeActive()
263 void wxApp::CocoaDelegate_applicationWillResignActive()
267 void wxApp::CocoaDelegate_applicationDidResignActive()
271 bool wxApp::OnInitGui()
273 wxAutoNSAutoreleasePool pool;
274 if(!wxAppBase::OnInitGui())
277 // Create the app using the sharedApplication method
278 m_cocoaApp = [NSApplication sharedApplication];
279 m_cocoaAppDelegate = [[wxNSApplicationDelegate alloc] init];
280 [m_cocoaApp setDelegate:m_cocoaAppDelegate];
282 wxMenuBarManager::CreateInstance();
284 wxDC::CocoaInitializeTextSystem();
285 // [ m_cocoaApp setDelegate:m_cocoaApp ];
287 wxLogDebug("Just for kicks");
288 [ m_cocoaAppDelegate performSelector:@selector(doIdle:) withObject:NULL ];
289 wxLogDebug("okay.. done now");
294 bool wxApp::CallOnInit()
296 // wxAutoNSAutoreleasePool pool;
302 if(!wxAppBase::OnInit())
312 wxAppConsole::Exit();
315 // Yield to other processes
316 bool wxApp::Yield(bool onlyIfNeeded)
319 static bool s_inYield = false;
322 // disable log flushing from here because a call to wxYield() shouldn't
323 // normally result in message boxes popping up &c
331 wxFAIL_MSG( wxT("wxYield called recursively" ) );
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
346 [GetNSApplication() sendEvent: event];
350 // let the logs be flashed again
360 void wxApp::OnAssert(const wxChar *file, int line, const wxChar* cond, const wxChar *msg)
363 wxAppBase::OnAssert(file, line, cond, msg);
364 m_isInAssert = FALSE;
366 #endif // __WXDEBUG__