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 wxLogDebug("doIdle called");
92 if(wxTheApp->IsInAssert())
94 wxLogDebug("Idle events ignored durring assertion dialog");
99 NSRunLoop *rl = [NSRunLoop currentRunLoop];
100 // runMode: beforeDate returns YES if something was done
101 while(wxTheApp->ProcessIdle()) // FIXME: AND NO EVENTS ARE PENDING
103 wxLogDebug("Looping for idle events");
105 if( [rl runMode:[rl currentMode] beforeDate:[NSDate distantPast]])
107 wxLogDebug("Found actual work to do");
113 wxLogDebug("Idle processing complete, requesting next idle event");
114 // Add ourself back into the run loop (on next event) if necessary
115 wxTheApp->CocoaRequestIdle();
118 // NOTE: Terminate means that the event loop does NOT return and thus
119 // cleanup code doesn't properly execute. Furthermore, wxWindows has its
120 // own exit on frame delete mechanism.
121 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
126 - (void)applicationWillBecomeActive:(NSNotification *)notification
128 wxTheApp->CocoaDelegate_applicationWillBecomeActive();
131 - (void)applicationDidBecomeActive:(NSNotification *)notification
133 wxTheApp->CocoaDelegate_applicationDidBecomeActive();
136 - (void)applicationWillResignActive:(NSNotification *)notification
138 wxTheApp->CocoaDelegate_applicationWillResignActive();
141 - (void)applicationDidResignActive:(NSNotification *)notification
143 wxTheApp->CocoaDelegate_applicationDidResignActive();
146 @end // implementation wxNSApplicationDelegate : NSObject
148 // ========================================================================
150 // ========================================================================
152 // ----------------------------------------------------------------------------
153 // wxApp Static member initialization
154 // ----------------------------------------------------------------------------
155 IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
156 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
157 EVT_IDLE(wxAppBase::OnIdle)
158 // EVT_END_SESSION(wxApp::OnEndSession)
159 // EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
162 // ----------------------------------------------------------------------------
163 // wxApp initialization/cleanup
164 // ----------------------------------------------------------------------------
165 bool wxApp::Initialize(int& argc, wxChar **argv)
167 wxAutoNSAutoreleasePool pool;
168 m_cocoaMainThread = [NSThread currentThread];
169 // Mac OS X passes a process serial number command line argument when
170 // the application is launched from the Finder. This argument must be
171 // removed from the command line arguments before being handled by the
172 // application (otherwise applications would need to handle it)
175 static const wxChar *ARG_PSN = _T("-psn_");
176 if ( wxStrncmp(argv[1], ARG_PSN, strlen(ARG_PSN)) == 0 )
178 // remove this argument
180 memmove(argv + 1, argv + 2, argc * sizeof(char *));
184 // Posing must be completed before any instances of the Objective-C
185 // classes being posed as are created.
186 wxPoseAsInitializer::InitializePosers();
188 return wxAppBase::Initialize(argc, argv);
191 void wxApp::CleanUp()
193 wxAutoNSAutoreleasePool pool;
195 wxDC::CocoaShutdownTextSystem();
196 wxMenuBarManager::DestroyInstance();
198 [m_cocoaApp setDelegate:nil];
199 [m_cocoaAppDelegate release];
200 m_cocoaAppDelegate = NULL;
202 wxAppBase::CleanUp();
205 // ----------------------------------------------------------------------------
207 // ----------------------------------------------------------------------------
213 #if WXWIN_COMPATIBILITY_2_2
214 m_wantDebugOutput = TRUE;
217 m_isInAssert = FALSE;
218 #endif // __WXDEBUG__
223 m_cocoaAppDelegate = NULL;
226 void wxApp::CocoaInstallIdleHandler()
228 // If we're not the main thread, don't install the idle handler
229 if(m_cocoaMainThread != [NSThread currentThread])
231 wxLogDebug("Attempt to install idle handler from secondary thread");
234 // If we're supposed to be stopping, don't add more idle events
235 if(![m_cocoaApp isRunning])
237 wxLogDebug("wxApp::CocoaInstallIdleHandler");
239 // Call doIdle for EVERYTHING dammit
240 // We'd need Foundation/NSConnection.h for this next constant, do we need it?
241 [[ NSRunLoop currentRunLoop ] performSelector:@selector(doIdle:) target:m_cocoaAppDelegate argument:NULL order:0 modes:[NSArray arrayWithObjects:NSDefaultRunLoopMode, /* NSConnectionReplyRunLoopMode,*/ NSModalPanelRunLoopMode, /**/NSEventTrackingRunLoopMode,/**/ nil] ];
243 In the Mac OS X implementation of Cocoa, the above method schedules
244 doIdle: to be called from *within* [NSApplication
245 -nextEventMatchingMask:untilDate:inMode:dequeue:]. That is, no
246 NSEvent object is generated and control does not return from that
247 method. In fact, control will only return from that method for the
248 usual reasons (e.g. a real event is received or the untilDate is reached).
249 This has implications when trying to stop the event loop and return to
250 its caller. See wxEventLoop::Exit
254 void wxApp::CocoaDelegate_applicationWillBecomeActive()
258 void wxApp::CocoaDelegate_applicationDidBecomeActive()
262 void wxApp::CocoaDelegate_applicationWillResignActive()
266 void wxApp::CocoaDelegate_applicationDidResignActive()
270 bool wxApp::OnInitGui()
272 wxAutoNSAutoreleasePool pool;
273 if(!wxAppBase::OnInitGui())
276 // Create the app using the sharedApplication method
277 m_cocoaApp = [NSApplication sharedApplication];
278 m_cocoaAppDelegate = [[wxNSApplicationDelegate alloc] init];
279 [m_cocoaApp setDelegate:m_cocoaAppDelegate];
281 wxMenuBarManager::CreateInstance();
283 wxDC::CocoaInitializeTextSystem();
284 // [ m_cocoaApp setDelegate:m_cocoaApp ];
286 wxLogDebug("Just for kicks");
287 [ m_cocoaAppDelegate performSelector:@selector(doIdle:) withObject:NULL ];
288 wxLogDebug("okay.. done now");
293 bool wxApp::CallOnInit()
295 // wxAutoNSAutoreleasePool pool;
301 if(!wxAppBase::OnInit())
311 wxAppConsole::Exit();
314 // Yield to other processes
315 bool wxApp::Yield(bool onlyIfNeeded)
318 static bool s_inYield = false;
321 // disable log flushing from here because a call to wxYield() shouldn't
322 // normally result in message boxes popping up &c
330 wxFAIL_MSG( wxT("wxYield called recursively" ) );
338 // Run the event loop until it is out of events
339 while(NSEvent *event = [GetNSApplication()
340 nextEventMatchingMask:NSAnyEventMask
341 untilDate:[NSDate distantPast]
342 inMode:NSDefaultRunLoopMode
345 [GetNSApplication() sendEvent: event];
349 // let the logs be flashed again
359 void wxApp::OnAssert(const wxChar *file, int line, const wxChar* cond, const wxChar *msg)
362 wxAppBase::OnAssert(file, line, cond, msg);
363 m_isInAssert = FALSE;
365 #endif // __WXDEBUG__