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>
39 #import <Foundation/NSString.h>
41 // ========================================================================
42 // wxPoseAsInitializer
43 // ========================================================================
44 wxPoseAsInitializer *wxPoseAsInitializer::sm_first = NULL;
46 static bool sg_needIdle = true;
48 // ========================================================================
49 // wxPoserNSApplication
50 // ========================================================================
51 @interface wxPoserNSApplication : NSApplication
55 - (NSEvent *)nextEventMatchingMask:(unsigned int)mask untilDate:(NSDate *)expiration inMode:(NSString *)mode dequeue:(BOOL)flag;
56 - (void)sendEvent: (NSEvent*)anEvent;
57 @end // wxPoserNSApplication
59 WX_IMPLEMENT_POSER(wxPoserNSApplication);
61 @implementation wxPoserNSApplication : NSApplication
63 /* NOTE: The old method of idle event handling added the handler using the
64 [NSRunLoop -performSelector:target:argument:order:modes] which caused
65 the invocation to occur at the begining of [NSApplication
66 -nextEventMatchingMask:untilDate:expiration:inMode:dequeue:]. However,
67 the code would be scheduled for invocation with every iteration of
68 the event loop. This new method simply overrides the method. The
69 same caveats apply. In particular, by the time the event loop has
70 called this method, it usually expects to receive an event. If you
71 plan on stopping the event loop, it is wise to send an event through
72 the queue to ensure this method will return.
73 See wxEventLoop::Exit() for more information.
76 - (NSEvent *)nextEventMatchingMask:(unsigned int)mask untilDate:(NSDate *)expiration inMode:(NSString *)mode dequeue:(BOOL)flag
78 // Get the same events except don't block
79 NSEvent *event = [super nextEventMatchingMask:mask untilDate:nil/* equivalent to [NSDate distantPast] */ inMode:mode dequeue:flag];
80 // If we got one, simply return it
83 // No events, try doing some idle stuff
84 if(sg_needIdle && !wxTheApp->IsInAssert() && ([NSDefaultRunLoopMode isEqualToString:mode] || [NSModalPanelRunLoopMode isEqualToString:mode]))
87 wxLogDebug("Processing idle events");
88 while(wxTheApp->ProcessIdle())
90 // Get the same events except don't block
91 NSEvent *event = [super nextEventMatchingMask:mask untilDate:nil/* equivalent to [NSDate distantPast] */ inMode:mode dequeue:flag];
92 // If we got one, simply return it
95 // we didn't get one, do some idle work
96 wxLogDebug("Looping idle events");
98 // No more idle work requested, block
99 wxLogDebug("Finished idle processing");
102 wxLogDebug("Avoiding idle processing sg_needIdle=%d",sg_needIdle);
103 return [super nextEventMatchingMask:mask untilDate:expiration inMode:mode dequeue:flag];
106 - (void)sendEvent: (NSEvent*)anEvent
108 wxLogDebug("SendEvent");
110 [super sendEvent: anEvent];
113 @end // wxPoserNSApplication
115 // ========================================================================
116 // wxNSApplicationDelegate
117 // ========================================================================
118 @interface wxNSApplicationDelegate : NSObject
123 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication;
124 - (void)applicationWillBecomeActive:(NSNotification *)notification;
125 - (void)applicationDidBecomeActive:(NSNotification *)notification;
126 - (void)applicationWillResignActive:(NSNotification *)notification;
127 - (void)applicationDidResignActive:(NSNotification *)notification;
128 @end // interface wxNSApplicationDelegate : NSObject
130 @implementation wxNSApplicationDelegate : NSObject
132 // NOTE: Terminate means that the event loop does NOT return and thus
133 // cleanup code doesn't properly execute. Furthermore, wxWindows has its
134 // own exit on frame delete mechanism.
135 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
140 - (void)applicationWillBecomeActive:(NSNotification *)notification
142 wxTheApp->CocoaDelegate_applicationWillBecomeActive();
145 - (void)applicationDidBecomeActive:(NSNotification *)notification
147 wxTheApp->CocoaDelegate_applicationDidBecomeActive();
150 - (void)applicationWillResignActive:(NSNotification *)notification
152 wxTheApp->CocoaDelegate_applicationWillResignActive();
155 - (void)applicationDidResignActive:(NSNotification *)notification
157 wxTheApp->CocoaDelegate_applicationDidResignActive();
160 @end // implementation wxNSApplicationDelegate : NSObject
162 // ========================================================================
164 // ========================================================================
166 // ----------------------------------------------------------------------------
167 // wxApp Static member initialization
168 // ----------------------------------------------------------------------------
169 IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
170 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
171 EVT_IDLE(wxAppBase::OnIdle)
172 // EVT_END_SESSION(wxApp::OnEndSession)
173 // EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
176 // ----------------------------------------------------------------------------
177 // wxApp initialization/cleanup
178 // ----------------------------------------------------------------------------
179 bool wxApp::Initialize(int& argc, wxChar **argv)
181 wxAutoNSAutoreleasePool pool;
182 m_cocoaMainThread = [NSThread currentThread];
183 // Mac OS X passes a process serial number command line argument when
184 // the application is launched from the Finder. This argument must be
185 // removed from the command line arguments before being handled by the
186 // application (otherwise applications would need to handle it)
189 static const wxChar *ARG_PSN = _T("-psn_");
190 if ( wxStrncmp(argv[1], ARG_PSN, strlen(ARG_PSN)) == 0 )
192 // remove this argument
194 memmove(argv + 1, argv + 2, argc * sizeof(char *));
198 // Posing must be completed before any instances of the Objective-C
199 // classes being posed as are created.
200 wxPoseAsInitializer::InitializePosers();
202 return wxAppBase::Initialize(argc, argv);
205 void wxApp::CleanUp()
207 wxAutoNSAutoreleasePool pool;
209 wxDC::CocoaShutdownTextSystem();
210 wxMenuBarManager::DestroyInstance();
212 [m_cocoaApp setDelegate:nil];
213 [m_cocoaAppDelegate release];
214 m_cocoaAppDelegate = NULL;
216 wxAppBase::CleanUp();
219 // ----------------------------------------------------------------------------
221 // ----------------------------------------------------------------------------
226 #if WXWIN_COMPATIBILITY_2_2
227 m_wantDebugOutput = TRUE;
230 m_isInAssert = FALSE;
231 #endif // __WXDEBUG__
236 m_cocoaAppDelegate = NULL;
239 void wxApp::CocoaDelegate_applicationWillBecomeActive()
243 void wxApp::CocoaDelegate_applicationDidBecomeActive()
247 void wxApp::CocoaDelegate_applicationWillResignActive()
249 wxTopLevelWindowCocoa::DeactivatePendingWindow();
252 void wxApp::CocoaDelegate_applicationDidResignActive()
256 bool wxApp::OnInitGui()
258 wxAutoNSAutoreleasePool pool;
259 if(!wxAppBase::OnInitGui())
262 // Create the app using the sharedApplication method
263 m_cocoaApp = [NSApplication sharedApplication];
264 m_cocoaAppDelegate = [[wxNSApplicationDelegate alloc] init];
265 [m_cocoaApp setDelegate:m_cocoaAppDelegate];
267 wxMenuBarManager::CreateInstance();
269 wxDC::CocoaInitializeTextSystem();
270 // [ m_cocoaApp setDelegate:m_cocoaApp ];
274 bool wxApp::CallOnInit()
276 // wxAutoNSAutoreleasePool pool;
282 if(!wxAppBase::OnInit())
292 wxAppConsole::Exit();
295 // Yield to other processes
296 bool wxApp::Yield(bool onlyIfNeeded)
299 static bool s_inYield = false;
302 // disable log flushing from here because a call to wxYield() shouldn't
303 // normally result in message boxes popping up &c
311 wxFAIL_MSG( wxT("wxYield called recursively" ) );
319 // Run the event loop until it is out of events
320 while(NSEvent *event = [GetNSApplication()
321 nextEventMatchingMask:NSAnyEventMask
322 untilDate:[NSDate distantPast]
323 inMode:NSDefaultRunLoopMode
326 [GetNSApplication() sendEvent: event];
330 // let the logs be flashed again
339 void wxApp::WakeUpIdle()
341 [m_cocoaApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined
342 location:NSZeroPoint modifierFlags:NSAnyEventMask
343 timestamp:0 windowNumber:0 context:nil
344 subtype:0 data1:0 data2:0] atStart:NO];
348 void wxApp::OnAssert(const wxChar *file, int line, const wxChar* cond, const wxChar *msg)
351 wxAppBase::OnAssert(file, line, cond, msg);
352 m_isInAssert = FALSE;
354 #endif // __WXDEBUG__