Use wxLogTrace instead of wxLogDebug for trace messages
[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 #include "wx/cocoa/NSApplication.h"
29
30 #if wxUSE_WX_RESOURCES
31 #  include "wx/resource.h"
32 #endif
33
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>
41
42 // ========================================================================
43 // wxPoseAsInitializer
44 // ========================================================================
45 wxPoseAsInitializer *wxPoseAsInitializer::sm_first = NULL;
46
47 static bool sg_needIdle = true;
48
49 // ========================================================================
50 // wxPoserNSApplication
51 // ========================================================================
52 @interface wxPoserNSApplication : NSApplication
53 {
54 }
55
56 - (NSEvent *)nextEventMatchingMask:(unsigned int)mask untilDate:(NSDate *)expiration inMode:(NSString *)mode dequeue:(BOOL)flag;
57 - (void)sendEvent: (NSEvent*)anEvent;
58 @end // wxPoserNSApplication
59
60 WX_IMPLEMENT_POSER(wxPoserNSApplication);
61
62 @implementation wxPoserNSApplication : NSApplication
63
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.
75 */
76    
77 - (NSEvent *)nextEventMatchingMask:(unsigned int)mask untilDate:(NSDate *)expiration inMode:(NSString *)mode dequeue:(BOOL)flag
78 {
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
82     if(event)
83         return event;
84     // No events, try doing some idle stuff
85     if(sg_needIdle
86 #ifdef __WXDEBUG__
87         && !wxTheApp->IsInAssert()
88 #endif
89         && ([NSDefaultRunLoopMode isEqualToString:mode] || [NSModalPanelRunLoopMode isEqualToString:mode]))
90     {
91         sg_needIdle = false;
92         wxLogTrace(wxTRACE_COCOA,wxT("Processing idle events"));
93         while(wxTheApp->ProcessIdle())
94         {
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
98             if(event)
99                 return event;
100             // we didn't get one, do some idle work
101             wxLogTrace(wxTRACE_COCOA,wxT("Looping idle events"));
102         }
103         // No more idle work requested, block
104         wxLogTrace(wxTRACE_COCOA,wxT("Finished idle processing"));
105     }
106     else
107         wxLogTrace(wxTRACE_COCOA,wxT("Avoiding idle processing sg_needIdle=%d"),sg_needIdle);
108     return [super nextEventMatchingMask:mask untilDate:expiration inMode:mode dequeue:flag];
109 }
110
111 - (void)sendEvent: (NSEvent*)anEvent
112 {
113     wxLogTrace(wxTRACE_COCOA,wxT("SendEvent"));
114     sg_needIdle = true;
115     [super sendEvent: anEvent];
116 }
117
118 @end // wxPoserNSApplication
119
120 // ========================================================================
121 // wxNSApplicationDelegate
122 // ========================================================================
123 @implementation wxNSApplicationDelegate : NSObject
124
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
129 {
130     return NO;
131 }
132
133 - (void)applicationWillBecomeActive:(NSNotification *)notification
134 {
135     wxTheApp->CocoaDelegate_applicationWillBecomeActive();
136 }
137
138 - (void)applicationDidBecomeActive:(NSNotification *)notification
139 {
140     wxTheApp->CocoaDelegate_applicationDidBecomeActive();
141 }
142
143 - (void)applicationWillResignActive:(NSNotification *)notification
144 {
145     wxTheApp->CocoaDelegate_applicationWillResignActive();
146 }
147
148 - (void)applicationDidResignActive:(NSNotification *)notification
149 {
150     wxTheApp->CocoaDelegate_applicationDidResignActive();
151 }
152
153 @end // implementation wxNSApplicationDelegate : NSObject
154
155 // ========================================================================
156 // wxApp
157 // ========================================================================
158
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)
167 END_EVENT_TABLE()
168
169 // ----------------------------------------------------------------------------
170 // wxApp initialization/cleanup
171 // ----------------------------------------------------------------------------
172 bool wxApp::Initialize(int& argc, wxChar **argv)
173 {
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)
180     if ( argc > 1 )
181     {
182         static const wxChar *ARG_PSN = _T("-psn_");
183         if ( wxStrncmp(argv[1], ARG_PSN, wxStrlen(ARG_PSN)) == 0 )
184         {
185             // remove this argument
186             --argc;
187             memmove(argv + 1, argv + 2, argc * sizeof(wxChar *));
188         }
189     }
190
191     // Posing must be completed before any instances of the Objective-C
192     // classes being posed as are created.
193     wxPoseAsInitializer::InitializePosers();
194
195     return wxAppBase::Initialize(argc, argv);
196 }
197
198 void wxApp::CleanUp()
199 {
200     wxAutoNSAutoreleasePool pool;
201
202     wxDC::CocoaShutdownTextSystem();
203     wxMenuBarManager::DestroyInstance();
204
205     [m_cocoaApp setDelegate:nil];
206     [m_cocoaAppDelegate release];
207     m_cocoaAppDelegate = NULL;
208
209     wxAppBase::CleanUp();
210 }
211
212 // ----------------------------------------------------------------------------
213 // wxApp creation
214 // ----------------------------------------------------------------------------
215 wxApp::wxApp()
216 {
217     m_topWindow = NULL;
218
219 #if WXWIN_COMPATIBILITY_2_2
220     m_wantDebugOutput = TRUE;
221 #endif
222 #ifdef __WXDEBUG__
223     m_isInAssert = FALSE;
224 #endif // __WXDEBUG__
225
226     argc = 0;
227     argv = NULL;
228     m_cocoaApp = NULL;
229     m_cocoaAppDelegate = NULL;
230 }
231
232 void wxApp::CocoaDelegate_applicationWillBecomeActive()
233 {
234 }
235
236 void wxApp::CocoaDelegate_applicationDidBecomeActive()
237 {
238 }
239
240 void wxApp::CocoaDelegate_applicationWillResignActive()
241 {
242     wxTopLevelWindowCocoa::DeactivatePendingWindow();
243 }
244
245 void wxApp::CocoaDelegate_applicationDidResignActive()
246 {
247 }
248
249 bool wxApp::OnInitGui()
250 {
251     wxAutoNSAutoreleasePool pool;
252     if(!wxAppBase::OnInitGui())
253         return FALSE;
254
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];
259
260     wxMenuBarManager::CreateInstance();
261
262     wxDC::CocoaInitializeTextSystem();
263 //    [ m_cocoaApp setDelegate:m_cocoaApp ];
264     return TRUE;
265 }
266
267 bool wxApp::CallOnInit()
268 {
269 //    wxAutoNSAutoreleasePool pool;
270     return OnInit();
271 }
272
273 bool wxApp::OnInit()
274 {
275     if(!wxAppBase::OnInit())
276         return FALSE;
277
278     return TRUE;
279 }
280
281 void wxApp::Exit()
282 {
283     wxApp::CleanUp();
284
285     wxAppConsole::Exit();
286 }
287
288 // Yield to other processes
289 bool wxApp::Yield(bool onlyIfNeeded)
290 {
291     // MT-FIXME
292     static bool s_inYield = false;
293
294 #if wxUSE_LOG
295     // disable log flushing from here because a call to wxYield() shouldn't
296     // normally result in message boxes popping up &c
297     wxLog::Suspend();
298 #endif // wxUSE_LOG
299
300     if (s_inYield)
301     {
302         if ( !onlyIfNeeded )
303         {
304             wxFAIL_MSG( wxT("wxYield called recursively" ) );
305         }
306
307         return false;
308     }
309
310     s_inYield = true;
311
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
317                 dequeue: YES])
318     {
319         [GetNSApplication() sendEvent: event];
320     }
321
322 #if wxUSE_LOG
323     // let the logs be flashed again
324     wxLog::Resume();
325 #endif // wxUSE_LOG
326
327     s_inYield = false;
328
329     return true;
330 }
331
332 void wxApp::WakeUpIdle()
333 {
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];
338 }
339
340 #ifdef __WXDEBUG__
341 void wxApp::OnAssert(const wxChar *file, int line, const wxChar* cond, const wxChar *msg)
342 {
343     m_isInAssert = TRUE;
344     wxAppBase::OnAssert(file, line, cond, msg);
345     m_isInAssert = FALSE;
346 }
347 #endif // __WXDEBUG__
348