1 /////////////////////////////////////////////////////////////////////////////
4 // Author: David Elliott
8 // Copyright: (c) David Elliott
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 #include "wx/wxprec.h"
21 #include "wx/module.h"
23 #include "wx/cocoa/ObjcPose.h"
24 #include "wx/cocoa/autorelease.h"
25 #include "wx/cocoa/mbarman.h"
26 #include "wx/cocoa/NSApplication.h"
28 #if wxUSE_WX_RESOURCES
29 # include "wx/resource.h"
32 #import <AppKit/NSApplication.h>
33 #import <Foundation/NSRunLoop.h>
34 #import <Foundation/NSThread.h>
35 #import <AppKit/NSEvent.h>
36 #import <Foundation/NSString.h>
38 // ========================================================================
39 // wxPoseAsInitializer
40 // ========================================================================
41 wxPoseAsInitializer *wxPoseAsInitializer::sm_first = NULL;
43 static bool sg_needIdle = true;
45 // ========================================================================
46 // wxPoserNSApplication
47 // ========================================================================
48 @interface wxPoserNSApplication : NSApplication
52 - (NSEvent *)nextEventMatchingMask:(unsigned int)mask untilDate:(NSDate *)expiration inMode:(NSString *)mode dequeue:(BOOL)flag;
53 - (void)sendEvent: (NSEvent*)anEvent;
54 @end // wxPoserNSApplication
56 WX_IMPLEMENT_POSER(wxPoserNSApplication);
58 @implementation wxPoserNSApplication : NSApplication
60 /* NOTE: The old method of idle event handling added the handler using the
61 [NSRunLoop -performSelector:target:argument:order:modes] which caused
62 the invocation to occur at the begining of [NSApplication
63 -nextEventMatchingMask:untilDate:expiration:inMode:dequeue:]. However,
64 the code would be scheduled for invocation with every iteration of
65 the event loop. This new method simply overrides the method. The
66 same caveats apply. In particular, by the time the event loop has
67 called this method, it usually expects to receive an event. If you
68 plan on stopping the event loop, it is wise to send an event through
69 the queue to ensure this method will return.
70 See wxEventLoop::Exit() for more information.
73 - (NSEvent *)nextEventMatchingMask:(unsigned int)mask untilDate:(NSDate *)expiration inMode:(NSString *)mode dequeue:(BOOL)flag
75 // Get the same events except don't block
76 NSEvent *event = [super nextEventMatchingMask:mask untilDate:nil/* equivalent to [NSDate distantPast] */ inMode:mode dequeue:flag];
77 // If we got one, simply return it
80 // No events, try doing some idle stuff
83 && !wxTheApp->IsInAssert()
85 && ([NSDefaultRunLoopMode isEqualToString:mode] || [NSModalPanelRunLoopMode isEqualToString:mode]))
88 wxLogTrace(wxTRACE_COCOA,wxT("Processing idle events"));
89 while(wxTheApp->ProcessIdle())
91 // Get the same events except don't block
92 NSEvent *event = [super nextEventMatchingMask:mask untilDate:nil/* equivalent to [NSDate distantPast] */ inMode:mode dequeue:flag];
93 // If we got one, simply return it
96 // we didn't get one, do some idle work
97 wxLogTrace(wxTRACE_COCOA,wxT("Looping idle events"));
99 // No more idle work requested, block
100 wxLogTrace(wxTRACE_COCOA,wxT("Finished idle processing"));
103 wxLogTrace(wxTRACE_COCOA,wxT("Avoiding idle processing sg_needIdle=%d"),sg_needIdle);
104 return [super nextEventMatchingMask:mask untilDate:expiration inMode:mode dequeue:flag];
107 - (void)sendEvent: (NSEvent*)anEvent
109 wxLogTrace(wxTRACE_COCOA,wxT("SendEvent"));
111 [super sendEvent: anEvent];
114 @end // wxPoserNSApplication
116 // ========================================================================
117 // wxNSApplicationDelegate
118 // ========================================================================
119 @implementation wxNSApplicationDelegate : NSObject
121 // NOTE: Terminate means that the event loop does NOT return and thus
122 // cleanup code doesn't properly execute. Furthermore, wxWindows has its
123 // own exit on frame delete mechanism.
124 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
129 - (void)applicationWillBecomeActive:(NSNotification *)notification
131 wxTheApp->CocoaDelegate_applicationWillBecomeActive();
134 - (void)applicationDidBecomeActive:(NSNotification *)notification
136 wxTheApp->CocoaDelegate_applicationDidBecomeActive();
139 - (void)applicationWillResignActive:(NSNotification *)notification
141 wxTheApp->CocoaDelegate_applicationWillResignActive();
144 - (void)applicationDidResignActive:(NSNotification *)notification
146 wxTheApp->CocoaDelegate_applicationDidResignActive();
149 @end // implementation wxNSApplicationDelegate : NSObject
151 // ========================================================================
153 // ========================================================================
155 // ----------------------------------------------------------------------------
156 // wxApp Static member initialization
157 // ----------------------------------------------------------------------------
158 IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
159 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
160 EVT_IDLE(wxAppBase::OnIdle)
161 // EVT_END_SESSION(wxApp::OnEndSession)
162 // EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
165 // ----------------------------------------------------------------------------
166 // wxApp initialization/cleanup
167 // ----------------------------------------------------------------------------
168 bool wxApp::Initialize(int& argc, wxChar **argv)
170 wxAutoNSAutoreleasePool pool;
171 m_cocoaMainThread = [NSThread currentThread];
172 // Mac OS X passes a process serial number command line argument when
173 // the application is launched from the Finder. This argument must be
174 // removed from the command line arguments before being handled by the
175 // application (otherwise applications would need to handle it)
178 static const wxChar *ARG_PSN = _T("-psn_");
179 if ( wxStrncmp(argv[1], ARG_PSN, wxStrlen(ARG_PSN)) == 0 )
181 // remove this argument
183 memmove(argv + 1, argv + 2, argc * sizeof(wxChar *));
187 // Posing must be completed before any instances of the Objective-C
188 // classes being posed as are created.
189 wxPoseAsInitializer::InitializePosers();
191 return wxAppBase::Initialize(argc, argv);
194 void wxApp::CleanUp()
196 wxAutoNSAutoreleasePool pool;
198 wxDC::CocoaShutdownTextSystem();
199 wxMenuBarManager::DestroyInstance();
201 [m_cocoaApp setDelegate:nil];
202 [m_cocoaAppDelegate release];
203 m_cocoaAppDelegate = NULL;
205 wxAppBase::CleanUp();
208 // ----------------------------------------------------------------------------
210 // ----------------------------------------------------------------------------
215 #if WXWIN_COMPATIBILITY_2_2
216 m_wantDebugOutput = TRUE;
219 m_isInAssert = FALSE;
220 #endif // __WXDEBUG__
225 m_cocoaAppDelegate = NULL;
228 void wxApp::CocoaDelegate_applicationWillBecomeActive()
232 void wxApp::CocoaDelegate_applicationDidBecomeActive()
236 void wxApp::CocoaDelegate_applicationWillResignActive()
238 wxTopLevelWindowCocoa::DeactivatePendingWindow();
241 void wxApp::CocoaDelegate_applicationDidResignActive()
245 bool wxApp::OnInitGui()
247 wxAutoNSAutoreleasePool pool;
248 if(!wxAppBase::OnInitGui())
251 // Create the app using the sharedApplication method
252 m_cocoaApp = [NSApplication sharedApplication];
253 m_cocoaAppDelegate = [[wxNSApplicationDelegate alloc] init];
254 [m_cocoaApp setDelegate:m_cocoaAppDelegate];
256 wxMenuBarManager::CreateInstance();
258 wxDC::CocoaInitializeTextSystem();
259 // [ m_cocoaApp setDelegate:m_cocoaApp ];
263 bool wxApp::CallOnInit()
265 // wxAutoNSAutoreleasePool pool;
271 if(!wxAppBase::OnInit())
281 wxAppConsole::Exit();
284 // Yield to other processes
285 bool wxApp::Yield(bool onlyIfNeeded)
288 static bool s_inYield = false;
291 // disable log flushing from here because a call to wxYield() shouldn't
292 // normally result in message boxes popping up &c
300 wxFAIL_MSG( wxT("wxYield called recursively" ) );
308 // Run the event loop until it is out of events
309 while(NSEvent *event = [GetNSApplication()
310 nextEventMatchingMask:NSAnyEventMask
311 untilDate:[NSDate distantPast]
312 inMode:NSDefaultRunLoopMode
315 [GetNSApplication() sendEvent: event];
319 // let the logs be flashed again
328 void wxApp::WakeUpIdle()
330 [m_cocoaApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined
331 location:NSZeroPoint modifierFlags:NSAnyEventMask
332 timestamp:0 windowNumber:0 context:nil
333 subtype:0 data1:0 data2:0] atStart:NO];
337 void wxApp::OnAssert(const wxChar *file, int line, const wxChar* cond, const wxChar *msg)
340 wxAppBase::OnAssert(file, line, cond, msg);
341 m_isInAssert = FALSE;
343 #endif // __WXDEBUG__