]> git.saurik.com Git - wxWidgets.git/blob - src/cocoa/app.mm
don't refresh the font unnecessarily (patch from Robert Vazan)
[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
40 // ========================================================================
41 // wxPoseAsInitializer
42 // ========================================================================
43 wxPoseAsInitializer *wxPoseAsInitializer::sm_first = NULL;
44
45 // ========================================================================
46 // wxPoserNSApplication
47 // ========================================================================
48 @interface wxPoserNSApplication : NSApplication
49 {
50 }
51
52 - (void)sendEvent: (NSEvent*)anEvent;
53 @end // wxPoserNSApplication
54
55 WX_IMPLEMENT_POSER(wxPoserNSApplication);
56
57 @implementation wxPoserNSApplication : NSApplication
58
59 - (void)sendEvent: (NSEvent*)anEvent
60 {
61 wxLogDebug("SendEvent");
62 wxTheApp->CocoaInstallRequestedIdleHandler();
63 [super sendEvent: anEvent];
64 }
65
66 @end // wxPoserNSApplication
67
68 // ========================================================================
69 // wxNSApplicationDelegate
70 // ========================================================================
71 @interface wxNSApplicationDelegate : NSObject
72 {
73 }
74
75 - (void)doIdle: (id)data;
76 // Delegate methods
77 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication;
78 - (void)applicationWillBecomeActive:(NSNotification *)notification;
79 - (void)applicationDidBecomeActive:(NSNotification *)notification;
80 - (void)applicationWillResignActive:(NSNotification *)notification;
81 - (void)applicationDidResignActive:(NSNotification *)notification;
82 @end // interface wxNSApplicationDelegate : NSObject
83
84 @implementation wxNSApplicationDelegate : NSObject
85
86 - (void)doIdle: (id)data
87 {
88 wxASSERT(wxTheApp);
89 wxASSERT(wxMenuBarManager::GetInstance());
90 wxMenuBarManager::GetInstance()->CocoaInternalIdle();
91 wxLogDebug("doIdle called");
92 #ifdef __WXDEBUG__
93 if(wxTheApp->IsInAssert())
94 {
95 wxLogDebug("Idle events ignored durring assertion dialog");
96 }
97 else
98 #endif
99 {
100 NSRunLoop *rl = [NSRunLoop currentRunLoop];
101 // runMode: beforeDate returns YES if something was done
102 while(wxTheApp->ProcessIdle()) // FIXME: AND NO EVENTS ARE PENDING
103 {
104 wxLogDebug("Looping for idle events");
105 #if 1
106 if( [rl runMode:[rl currentMode] beforeDate:[NSDate distantPast]])
107 {
108 wxLogDebug("Found actual work to do");
109 break;
110 }
111 #endif
112 }
113 }
114 wxLogDebug("Idle processing complete, requesting next idle event");
115 // Add ourself back into the run loop (on next event) if necessary
116 wxTheApp->CocoaRequestIdle();
117 }
118
119 // NOTE: Terminate means that the event loop does NOT return and thus
120 // cleanup code doesn't properly execute. Furthermore, wxWindows has its
121 // own exit on frame delete mechanism.
122 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
123 {
124 return NO;
125 }
126
127 - (void)applicationWillBecomeActive:(NSNotification *)notification
128 {
129 wxTheApp->CocoaDelegate_applicationWillBecomeActive();
130 }
131
132 - (void)applicationDidBecomeActive:(NSNotification *)notification
133 {
134 wxTheApp->CocoaDelegate_applicationDidBecomeActive();
135 }
136
137 - (void)applicationWillResignActive:(NSNotification *)notification
138 {
139 wxTheApp->CocoaDelegate_applicationWillResignActive();
140 }
141
142 - (void)applicationDidResignActive:(NSNotification *)notification
143 {
144 wxTheApp->CocoaDelegate_applicationDidResignActive();
145 }
146
147 @end // implementation wxNSApplicationDelegate : NSObject
148
149 // ========================================================================
150 // wxApp
151 // ========================================================================
152
153 // ----------------------------------------------------------------------------
154 // wxApp Static member initialization
155 // ----------------------------------------------------------------------------
156 IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
157 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
158 EVT_IDLE(wxAppBase::OnIdle)
159 // EVT_END_SESSION(wxApp::OnEndSession)
160 // EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
161 END_EVENT_TABLE()
162
163 // ----------------------------------------------------------------------------
164 // wxApp initialization/cleanup
165 // ----------------------------------------------------------------------------
166 bool wxApp::Initialize(int& argc, wxChar **argv)
167 {
168 wxAutoNSAutoreleasePool pool;
169 m_cocoaMainThread = [NSThread currentThread];
170 // Mac OS X passes a process serial number command line argument when
171 // the application is launched from the Finder. This argument must be
172 // removed from the command line arguments before being handled by the
173 // application (otherwise applications would need to handle it)
174 if ( argc > 1 )
175 {
176 static const wxChar *ARG_PSN = _T("-psn_");
177 if ( wxStrncmp(argv[1], ARG_PSN, strlen(ARG_PSN)) == 0 )
178 {
179 // remove this argument
180 --argc;
181 memmove(argv + 1, argv + 2, argc * sizeof(char *));
182 }
183 }
184
185 // Posing must be completed before any instances of the Objective-C
186 // classes being posed as are created.
187 wxPoseAsInitializer::InitializePosers();
188
189 return wxAppBase::Initialize(argc, argv);
190 }
191
192 void wxApp::CleanUp()
193 {
194 wxAutoNSAutoreleasePool pool;
195
196 wxDC::CocoaShutdownTextSystem();
197 wxMenuBarManager::DestroyInstance();
198
199 [m_cocoaApp setDelegate:nil];
200 [m_cocoaAppDelegate release];
201 m_cocoaAppDelegate = NULL;
202
203 wxAppBase::CleanUp();
204 }
205
206 // ----------------------------------------------------------------------------
207 // wxApp creation
208 // ----------------------------------------------------------------------------
209 wxApp::wxApp()
210 {
211 m_topWindow = NULL;
212
213 m_isIdle = true;
214 #if WXWIN_COMPATIBILITY_2_2
215 m_wantDebugOutput = TRUE;
216 #endif
217 #ifdef __WXDEBUG__
218 m_isInAssert = FALSE;
219 #endif // __WXDEBUG__
220
221 argc = 0;
222 argv = NULL;
223 m_cocoaApp = NULL;
224 m_cocoaAppDelegate = NULL;
225 }
226
227 void wxApp::CocoaInstallIdleHandler()
228 {
229 // If we're not the main thread, don't install the idle handler
230 if(m_cocoaMainThread != [NSThread currentThread])
231 {
232 wxLogDebug("Attempt to install idle handler from secondary thread");
233 return;
234 }
235 // If we're supposed to be stopping, don't add more idle events
236 if(![m_cocoaApp isRunning])
237 return;
238 wxLogDebug("wxApp::CocoaInstallIdleHandler");
239 m_isIdle = false;
240 // Call doIdle for EVERYTHING dammit
241 // We'd need Foundation/NSConnection.h for this next constant, do we need it?
242 [[ NSRunLoop currentRunLoop ] performSelector:@selector(doIdle:) target:m_cocoaAppDelegate argument:NULL order:0 modes:[NSArray arrayWithObjects:NSDefaultRunLoopMode, /* NSConnectionReplyRunLoopMode,*/ NSModalPanelRunLoopMode, /**/NSEventTrackingRunLoopMode,/**/ nil] ];
243 /* Notes:
244 In the Mac OS X implementation of Cocoa, the above method schedules
245 doIdle: to be called from *within* [NSApplication
246 -nextEventMatchingMask:untilDate:inMode:dequeue:]. That is, no
247 NSEvent object is generated and control does not return from that
248 method. In fact, control will only return from that method for the
249 usual reasons (e.g. a real event is received or the untilDate is reached).
250 This has implications when trying to stop the event loop and return to
251 its caller. See wxEventLoop::Exit
252 */
253 }
254
255 void wxApp::CocoaDelegate_applicationWillBecomeActive()
256 {
257 }
258
259 void wxApp::CocoaDelegate_applicationDidBecomeActive()
260 {
261 }
262
263 void wxApp::CocoaDelegate_applicationWillResignActive()
264 {
265 }
266
267 void wxApp::CocoaDelegate_applicationDidResignActive()
268 {
269 }
270
271 bool wxApp::OnInitGui()
272 {
273 wxAutoNSAutoreleasePool pool;
274 if(!wxAppBase::OnInitGui())
275 return FALSE;
276
277 // Create the app using the sharedApplication method
278 m_cocoaApp = [NSApplication sharedApplication];
279 m_cocoaAppDelegate = [[wxNSApplicationDelegate alloc] init];
280 [m_cocoaApp setDelegate:m_cocoaAppDelegate];
281
282 wxMenuBarManager::CreateInstance();
283
284 wxDC::CocoaInitializeTextSystem();
285 // [ m_cocoaApp setDelegate:m_cocoaApp ];
286 #if 0
287 wxLogDebug("Just for kicks");
288 [ m_cocoaAppDelegate performSelector:@selector(doIdle:) withObject:NULL ];
289 wxLogDebug("okay.. done now");
290 #endif
291 return TRUE;
292 }
293
294 bool wxApp::CallOnInit()
295 {
296 // wxAutoNSAutoreleasePool pool;
297 return OnInit();
298 }
299
300 bool wxApp::OnInit()
301 {
302 if(!wxAppBase::OnInit())
303 return FALSE;
304
305 return TRUE;
306 }
307
308 void wxApp::Exit()
309 {
310 wxApp::CleanUp();
311
312 wxAppConsole::Exit();
313 }
314
315 // Yield to other processes
316 bool wxApp::Yield(bool onlyIfNeeded)
317 {
318 // MT-FIXME
319 static bool s_inYield = false;
320
321 #if wxUSE_LOG
322 // disable log flushing from here because a call to wxYield() shouldn't
323 // normally result in message boxes popping up &c
324 wxLog::Suspend();
325 #endif // wxUSE_LOG
326
327 if (s_inYield)
328 {
329 if ( !onlyIfNeeded )
330 {
331 wxFAIL_MSG( wxT("wxYield called recursively" ) );
332 }
333
334 return false;
335 }
336
337 s_inYield = true;
338
339 // Run the event loop until it is out of events
340 while(NSEvent *event = [GetNSApplication()
341 nextEventMatchingMask:NSAnyEventMask
342 untilDate:[NSDate distantPast]
343 inMode:NSDefaultRunLoopMode
344 dequeue: YES])
345 {
346 [GetNSApplication() sendEvent: event];
347 }
348
349 #if wxUSE_LOG
350 // let the logs be flashed again
351 wxLog::Resume();
352 #endif // wxUSE_LOG
353
354 s_inYield = false;
355
356 return true;
357 }
358
359 #ifdef __WXDEBUG__
360 void wxApp::OnAssert(const wxChar *file, int line, const wxChar* cond, const wxChar *msg)
361 {
362 m_isInAssert = TRUE;
363 wxAppBase::OnAssert(file, line, cond, msg);
364 m_isInAssert = FALSE;
365 }
366 #endif // __WXDEBUG__
367