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"
28 #include "wx/cocoa/NSApplication.h"
30 #if wxUSE_WX_RESOURCES
31 # include "wx/resource.h"
34 #import <AppKit/NSApplication.h>
35 #import <Foundation/NSRunLoop.h>
36 #import <Foundation/NSArray.h>
37 #import <Foundation/NSAutoreleasePool.h>
38 #import <Foundation/NSThread.h>
39 #import <AppKit/NSEvent.h>
40 #import <Foundation/NSString.h>
42 // ========================================================================
43 // wxPoseAsInitializer
44 // ========================================================================
45 wxPoseAsInitializer *wxPoseAsInitializer::sm_first = NULL;
47 static bool sg_needIdle = true;
49 // ========================================================================
50 // wxPoserNSApplication
51 // ========================================================================
52 @interface wxPoserNSApplication : NSApplication
56 - (NSEvent *)nextEventMatchingMask:(unsigned int)mask untilDate:(NSDate *)expiration inMode:(NSString *)mode dequeue:(BOOL)flag;
57 - (void)sendEvent: (NSEvent*)anEvent;
58 @end // wxPoserNSApplication
60 WX_IMPLEMENT_POSER(wxPoserNSApplication);
62 @implementation wxPoserNSApplication : NSApplication
64 /* NOTE: The old method of idle event handling added the handler using the
65 [NSRunLoop -performSelector:target:argument:order:modes] which caused
66 the invocation to occur at the begining of [NSApplication
67 -nextEventMatchingMask:untilDate:expiration:inMode:dequeue:]. However,
68 the code would be scheduled for invocation with every iteration of
69 the event loop. This new method simply overrides the method. The
70 same caveats apply. In particular, by the time the event loop has
71 called this method, it usually expects to receive an event. If you
72 plan on stopping the event loop, it is wise to send an event through
73 the queue to ensure this method will return.
74 See wxEventLoop::Exit() for more information.
77 - (NSEvent *)nextEventMatchingMask:(unsigned int)mask untilDate:(NSDate *)expiration inMode:(NSString *)mode dequeue:(BOOL)flag
79 // Get the same events except don't block
80 NSEvent *event = [super nextEventMatchingMask:mask untilDate:nil/* equivalent to [NSDate distantPast] */ inMode:mode dequeue:flag];
81 // If we got one, simply return it
84 // No events, try doing some idle stuff
87 && !wxTheApp->IsInAssert()
89 && ([NSDefaultRunLoopMode isEqualToString:mode] || [NSModalPanelRunLoopMode isEqualToString:mode]))
92 wxLogTrace(wxTRACE_COCOA,wxT("Processing idle events"));
93 while(wxTheApp->ProcessIdle())
95 // Get the same events except don't block
96 NSEvent *event = [super nextEventMatchingMask:mask untilDate:nil/* equivalent to [NSDate distantPast] */ inMode:mode dequeue:flag];
97 // If we got one, simply return it
100 // we didn't get one, do some idle work
101 wxLogTrace(wxTRACE_COCOA,wxT("Looping idle events"));
103 // No more idle work requested, block
104 wxLogTrace(wxTRACE_COCOA,wxT("Finished idle processing"));
107 wxLogTrace(wxTRACE_COCOA,wxT("Avoiding idle processing sg_needIdle=%d"),sg_needIdle);
108 return [super nextEventMatchingMask:mask untilDate:expiration inMode:mode dequeue:flag];
111 - (void)sendEvent: (NSEvent*)anEvent
113 wxLogTrace(wxTRACE_COCOA,wxT("SendEvent"));
115 [super sendEvent: anEvent];
118 @end // wxPoserNSApplication
120 // ========================================================================
121 // wxNSApplicationDelegate
122 // ========================================================================
123 @implementation wxNSApplicationDelegate : NSObject
125 // NOTE: Terminate means that the event loop does NOT return and thus
126 // cleanup code doesn't properly execute. Furthermore, wxWindows has its
127 // own exit on frame delete mechanism.
128 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
133 - (void)applicationWillBecomeActive:(NSNotification *)notification
135 wxTheApp->CocoaDelegate_applicationWillBecomeActive();
138 - (void)applicationDidBecomeActive:(NSNotification *)notification
140 wxTheApp->CocoaDelegate_applicationDidBecomeActive();
143 - (void)applicationWillResignActive:(NSNotification *)notification
145 wxTheApp->CocoaDelegate_applicationWillResignActive();
148 - (void)applicationDidResignActive:(NSNotification *)notification
150 wxTheApp->CocoaDelegate_applicationDidResignActive();
153 @end // implementation wxNSApplicationDelegate : NSObject
155 // ========================================================================
157 // ========================================================================
159 // ----------------------------------------------------------------------------
160 // wxApp Static member initialization
161 // ----------------------------------------------------------------------------
162 IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
163 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
164 EVT_IDLE(wxAppBase::OnIdle)
165 // EVT_END_SESSION(wxApp::OnEndSession)
166 // EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
169 // ----------------------------------------------------------------------------
170 // wxApp initialization/cleanup
171 // ----------------------------------------------------------------------------
172 bool wxApp::Initialize(int& argc, wxChar **argv)
174 wxAutoNSAutoreleasePool pool;
175 m_cocoaMainThread = [NSThread currentThread];
176 // Mac OS X passes a process serial number command line argument when
177 // the application is launched from the Finder. This argument must be
178 // removed from the command line arguments before being handled by the
179 // application (otherwise applications would need to handle it)
182 static const wxChar *ARG_PSN = _T("-psn_");
183 if ( wxStrncmp(argv[1], ARG_PSN, wxStrlen(ARG_PSN)) == 0 )
185 // remove this argument
187 memmove(argv + 1, argv + 2, argc * sizeof(wxChar *));
191 // Posing must be completed before any instances of the Objective-C
192 // classes being posed as are created.
193 wxPoseAsInitializer::InitializePosers();
195 return wxAppBase::Initialize(argc, argv);
198 void wxApp::CleanUp()
200 wxAutoNSAutoreleasePool pool;
202 wxDC::CocoaShutdownTextSystem();
203 wxMenuBarManager::DestroyInstance();
205 [m_cocoaApp setDelegate:nil];
206 [m_cocoaAppDelegate release];
207 m_cocoaAppDelegate = NULL;
209 wxAppBase::CleanUp();
212 // ----------------------------------------------------------------------------
214 // ----------------------------------------------------------------------------
219 #if WXWIN_COMPATIBILITY_2_2
220 m_wantDebugOutput = TRUE;
223 m_isInAssert = FALSE;
224 #endif // __WXDEBUG__
229 m_cocoaAppDelegate = NULL;
232 void wxApp::CocoaDelegate_applicationWillBecomeActive()
236 void wxApp::CocoaDelegate_applicationDidBecomeActive()
240 void wxApp::CocoaDelegate_applicationWillResignActive()
242 wxTopLevelWindowCocoa::DeactivatePendingWindow();
245 void wxApp::CocoaDelegate_applicationDidResignActive()
249 bool wxApp::OnInitGui()
251 wxAutoNSAutoreleasePool pool;
252 if(!wxAppBase::OnInitGui())
255 // Create the app using the sharedApplication method
256 m_cocoaApp = [NSApplication sharedApplication];
257 m_cocoaAppDelegate = [[wxNSApplicationDelegate alloc] init];
258 [m_cocoaApp setDelegate:m_cocoaAppDelegate];
260 wxMenuBarManager::CreateInstance();
262 wxDC::CocoaInitializeTextSystem();
263 // [ m_cocoaApp setDelegate:m_cocoaApp ];
267 bool wxApp::CallOnInit()
269 // wxAutoNSAutoreleasePool pool;
275 if(!wxAppBase::OnInit())
285 wxAppConsole::Exit();
288 // Yield to other processes
289 bool wxApp::Yield(bool onlyIfNeeded)
292 static bool s_inYield = false;
295 // disable log flushing from here because a call to wxYield() shouldn't
296 // normally result in message boxes popping up &c
304 wxFAIL_MSG( wxT("wxYield called recursively" ) );
312 // Run the event loop until it is out of events
313 while(NSEvent *event = [GetNSApplication()
314 nextEventMatchingMask:NSAnyEventMask
315 untilDate:[NSDate distantPast]
316 inMode:NSDefaultRunLoopMode
319 [GetNSApplication() sendEvent: event];
323 // let the logs be flashed again
332 void wxApp::WakeUpIdle()
334 [m_cocoaApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined
335 location:NSZeroPoint modifierFlags:NSAnyEventMask
336 timestamp:0 windowNumber:0 context:nil
337 subtype:0 data1:0 data2:0] atStart:NO];
341 void wxApp::OnAssert(const wxChar *file, int line, const wxChar* cond, const wxChar *msg)
344 wxAppBase::OnAssert(file, line, cond, msg);
345 m_isInAssert = FALSE;
347 #endif // __WXDEBUG__