]> git.saurik.com Git - wxWidgets.git/blob - src/cocoa/app.mm
fix for wx-config --inplace --rezflags output in wxCocoa (and reorganization of code...
[wxWidgets.git] / src / cocoa / app.mm
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: cocoa/app.mm
3 // Purpose: wxApp
4 // Author: David Elliott
5 // Modified by:
6 // Created: 2002/11/27
7 // RCS-ID: $Id$
8 // Copyright: (c) David Elliott
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/wxprec.h"
13 #ifndef WX_PRECOMP
14 #include "wx/defs.h"
15 #include "wx/app.h"
16 #include "wx/frame.h"
17 #include "wx/dialog.h"
18 #include "wx/dc.h"
19 #include "wx/intl.h"
20 #include "wx/log.h"
21 #endif
22
23 #include "wx/module.h"
24
25 #include "wx/cocoa/ObjcPose.h"
26 #include "wx/cocoa/autorelease.h"
27 #include "wx/cocoa/mbarman.h"
28
29 #if wxUSE_WX_RESOURCES
30 # include "wx/resource.h"
31 #endif
32
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>
40
41 // ========================================================================
42 // wxPoseAsInitializer
43 // ========================================================================
44 wxPoseAsInitializer *wxPoseAsInitializer::sm_first = NULL;
45
46 static bool sg_needIdle = true;
47
48 // ========================================================================
49 // wxPoserNSApplication
50 // ========================================================================
51 @interface wxPoserNSApplication : NSApplication
52 {
53 }
54
55 - (NSEvent *)nextEventMatchingMask:(unsigned int)mask untilDate:(NSDate *)expiration inMode:(NSString *)mode dequeue:(BOOL)flag;
56 - (void)sendEvent: (NSEvent*)anEvent;
57 @end // wxPoserNSApplication
58
59 WX_IMPLEMENT_POSER(wxPoserNSApplication);
60
61 @implementation wxPoserNSApplication : NSApplication
62
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.
74 */
75
76 - (NSEvent *)nextEventMatchingMask:(unsigned int)mask untilDate:(NSDate *)expiration inMode:(NSString *)mode dequeue:(BOOL)flag
77 {
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
81 if(event)
82 return event;
83 // No events, try doing some idle stuff
84 if(sg_needIdle
85 #ifdef __WXDEBUG__
86 && !wxTheApp->IsInAssert()
87 #endif
88 && ([NSDefaultRunLoopMode isEqualToString:mode] || [NSModalPanelRunLoopMode isEqualToString:mode]))
89 {
90 sg_needIdle = false;
91 wxLogDebug(wxT("Processing idle events"));
92 while(wxTheApp->ProcessIdle())
93 {
94 // Get the same events except don't block
95 NSEvent *event = [super nextEventMatchingMask:mask untilDate:nil/* equivalent to [NSDate distantPast] */ inMode:mode dequeue:flag];
96 // If we got one, simply return it
97 if(event)
98 return event;
99 // we didn't get one, do some idle work
100 wxLogDebug(wxT("Looping idle events"));
101 }
102 // No more idle work requested, block
103 wxLogDebug(wxT("Finished idle processing"));
104 }
105 else
106 wxLogDebug(wxT("Avoiding idle processing sg_needIdle=%d"),sg_needIdle);
107 return [super nextEventMatchingMask:mask untilDate:expiration inMode:mode dequeue:flag];
108 }
109
110 - (void)sendEvent: (NSEvent*)anEvent
111 {
112 wxLogDebug(wxT("SendEvent"));
113 sg_needIdle = true;
114 [super sendEvent: anEvent];
115 }
116
117 @end // wxPoserNSApplication
118
119 // ========================================================================
120 // wxNSApplicationDelegate
121 // ========================================================================
122 @interface wxNSApplicationDelegate : NSObject
123 {
124 }
125
126 // Delegate methods
127 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication;
128 - (void)applicationWillBecomeActive:(NSNotification *)notification;
129 - (void)applicationDidBecomeActive:(NSNotification *)notification;
130 - (void)applicationWillResignActive:(NSNotification *)notification;
131 - (void)applicationDidResignActive:(NSNotification *)notification;
132 @end // interface wxNSApplicationDelegate : NSObject
133
134 @implementation wxNSApplicationDelegate : NSObject
135
136 // NOTE: Terminate means that the event loop does NOT return and thus
137 // cleanup code doesn't properly execute. Furthermore, wxWindows has its
138 // own exit on frame delete mechanism.
139 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
140 {
141 return NO;
142 }
143
144 - (void)applicationWillBecomeActive:(NSNotification *)notification
145 {
146 wxTheApp->CocoaDelegate_applicationWillBecomeActive();
147 }
148
149 - (void)applicationDidBecomeActive:(NSNotification *)notification
150 {
151 wxTheApp->CocoaDelegate_applicationDidBecomeActive();
152 }
153
154 - (void)applicationWillResignActive:(NSNotification *)notification
155 {
156 wxTheApp->CocoaDelegate_applicationWillResignActive();
157 }
158
159 - (void)applicationDidResignActive:(NSNotification *)notification
160 {
161 wxTheApp->CocoaDelegate_applicationDidResignActive();
162 }
163
164 @end // implementation wxNSApplicationDelegate : NSObject
165
166 // ========================================================================
167 // wxApp
168 // ========================================================================
169
170 // ----------------------------------------------------------------------------
171 // wxApp Static member initialization
172 // ----------------------------------------------------------------------------
173 IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
174 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
175 EVT_IDLE(wxAppBase::OnIdle)
176 // EVT_END_SESSION(wxApp::OnEndSession)
177 // EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
178 END_EVENT_TABLE()
179
180 // ----------------------------------------------------------------------------
181 // wxApp initialization/cleanup
182 // ----------------------------------------------------------------------------
183 bool wxApp::Initialize(int& argc, wxChar **argv)
184 {
185 wxAutoNSAutoreleasePool pool;
186 m_cocoaMainThread = [NSThread currentThread];
187 // Mac OS X passes a process serial number command line argument when
188 // the application is launched from the Finder. This argument must be
189 // removed from the command line arguments before being handled by the
190 // application (otherwise applications would need to handle it)
191 if ( argc > 1 )
192 {
193 static const wxChar *ARG_PSN = _T("-psn_");
194 if ( wxStrncmp(argv[1], ARG_PSN, wxStrlen(ARG_PSN)) == 0 )
195 {
196 // remove this argument
197 --argc;
198 memmove(argv + 1, argv + 2, argc * sizeof(wxChar *));
199 }
200 }
201
202 // Posing must be completed before any instances of the Objective-C
203 // classes being posed as are created.
204 wxPoseAsInitializer::InitializePosers();
205
206 return wxAppBase::Initialize(argc, argv);
207 }
208
209 void wxApp::CleanUp()
210 {
211 wxAutoNSAutoreleasePool pool;
212
213 wxDC::CocoaShutdownTextSystem();
214 wxMenuBarManager::DestroyInstance();
215
216 [m_cocoaApp setDelegate:nil];
217 [m_cocoaAppDelegate release];
218 m_cocoaAppDelegate = NULL;
219
220 wxAppBase::CleanUp();
221 }
222
223 // ----------------------------------------------------------------------------
224 // wxApp creation
225 // ----------------------------------------------------------------------------
226 wxApp::wxApp()
227 {
228 m_topWindow = NULL;
229
230 #if WXWIN_COMPATIBILITY_2_2
231 m_wantDebugOutput = TRUE;
232 #endif
233 #ifdef __WXDEBUG__
234 m_isInAssert = FALSE;
235 #endif // __WXDEBUG__
236
237 argc = 0;
238 argv = NULL;
239 m_cocoaApp = NULL;
240 m_cocoaAppDelegate = NULL;
241 }
242
243 void wxApp::CocoaDelegate_applicationWillBecomeActive()
244 {
245 }
246
247 void wxApp::CocoaDelegate_applicationDidBecomeActive()
248 {
249 }
250
251 void wxApp::CocoaDelegate_applicationWillResignActive()
252 {
253 wxTopLevelWindowCocoa::DeactivatePendingWindow();
254 }
255
256 void wxApp::CocoaDelegate_applicationDidResignActive()
257 {
258 }
259
260 bool wxApp::OnInitGui()
261 {
262 wxAutoNSAutoreleasePool pool;
263 if(!wxAppBase::OnInitGui())
264 return FALSE;
265
266 // Create the app using the sharedApplication method
267 m_cocoaApp = [NSApplication sharedApplication];
268 m_cocoaAppDelegate = [[wxNSApplicationDelegate alloc] init];
269 [m_cocoaApp setDelegate:m_cocoaAppDelegate];
270
271 wxMenuBarManager::CreateInstance();
272
273 wxDC::CocoaInitializeTextSystem();
274 // [ m_cocoaApp setDelegate:m_cocoaApp ];
275 return TRUE;
276 }
277
278 bool wxApp::CallOnInit()
279 {
280 // wxAutoNSAutoreleasePool pool;
281 return OnInit();
282 }
283
284 bool wxApp::OnInit()
285 {
286 if(!wxAppBase::OnInit())
287 return FALSE;
288
289 return TRUE;
290 }
291
292 void wxApp::Exit()
293 {
294 wxApp::CleanUp();
295
296 wxAppConsole::Exit();
297 }
298
299 // Yield to other processes
300 bool wxApp::Yield(bool onlyIfNeeded)
301 {
302 // MT-FIXME
303 static bool s_inYield = false;
304
305 #if wxUSE_LOG
306 // disable log flushing from here because a call to wxYield() shouldn't
307 // normally result in message boxes popping up &c
308 wxLog::Suspend();
309 #endif // wxUSE_LOG
310
311 if (s_inYield)
312 {
313 if ( !onlyIfNeeded )
314 {
315 wxFAIL_MSG( wxT("wxYield called recursively" ) );
316 }
317
318 return false;
319 }
320
321 s_inYield = true;
322
323 // Run the event loop until it is out of events
324 while(NSEvent *event = [GetNSApplication()
325 nextEventMatchingMask:NSAnyEventMask
326 untilDate:[NSDate distantPast]
327 inMode:NSDefaultRunLoopMode
328 dequeue: YES])
329 {
330 [GetNSApplication() sendEvent: event];
331 }
332
333 #if wxUSE_LOG
334 // let the logs be flashed again
335 wxLog::Resume();
336 #endif // wxUSE_LOG
337
338 s_inYield = false;
339
340 return true;
341 }
342
343 void wxApp::WakeUpIdle()
344 {
345 [m_cocoaApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined
346 location:NSZeroPoint modifierFlags:NSAnyEventMask
347 timestamp:0 windowNumber:0 context:nil
348 subtype:0 data1:0 data2:0] atStart:NO];
349 }
350
351 #ifdef __WXDEBUG__
352 void wxApp::OnAssert(const wxChar *file, int line, const wxChar* cond, const wxChar *msg)
353 {
354 m_isInAssert = TRUE;
355 wxAppBase::OnAssert(file, line, cond, msg);
356 m_isInAssert = FALSE;
357 }
358 #endif // __WXDEBUG__
359