]> git.saurik.com Git - wxWidgets.git/blame - src/cocoa/app.mm
use GetFont() instead of (possibly not initialized) m_font in GetCharWidth/Height()
[wxWidgets.git] / src / cocoa / app.mm
CommitLineData
fb896a32
DE
1/////////////////////////////////////////////////////////////////////////////
2// Name: cocoa/app.mm
3// Purpose: wxApp
4// Author: David Elliott
5// Modified by:
6// Created: 2002/11/27
d89d4059 7// RCS-ID: $Id$
fb896a32 8// Copyright: (c) David Elliott
d89d4059 9// Licence: wxWindows licence
fb896a32
DE
10/////////////////////////////////////////////////////////////////////////////
11
fb896a32
DE
12#include "wx/wxprec.h"
13#ifndef WX_PRECOMP
14 #include "wx/defs.h"
15 #include "wx/app.h"
891d0563 16 #include "wx/dc.h"
fb896a32
DE
17 #include "wx/intl.h"
18 #include "wx/log.h"
fb896a32
DE
19#endif
20
11c08416
DE
21#include "wx/module.h"
22
fb45bb1f 23#include "wx/cocoa/ObjcPose.h"
493902ac 24#include "wx/cocoa/autorelease.h"
af367f46 25#include "wx/cocoa/mbarman.h"
7b466aee 26#include "wx/cocoa/NSApplication.h"
fb45bb1f 27
fb896a32
DE
28#if wxUSE_WX_RESOURCES
29# include "wx/resource.h"
30#endif
31
32#import <AppKit/NSApplication.h>
33#import <Foundation/NSRunLoop.h>
14fc7eb4 34#import <Foundation/NSThread.h>
aaa5ab05 35#import <AppKit/NSEvent.h>
eb537cfb 36#import <Foundation/NSString.h>
fb896a32 37
70fb935a
DE
38// ========================================================================
39// wxPoseAsInitializer
40// ========================================================================
fb896a32
DE
41wxPoseAsInitializer *wxPoseAsInitializer::sm_first = NULL;
42
eb537cfb
DE
43static bool sg_needIdle = true;
44
70fb935a
DE
45// ========================================================================
46// wxPoserNSApplication
47// ========================================================================
fb896a32
DE
48@interface wxPoserNSApplication : NSApplication
49{
50}
51
eb537cfb 52- (NSEvent *)nextEventMatchingMask:(unsigned int)mask untilDate:(NSDate *)expiration inMode:(NSString *)mode dequeue:(BOOL)flag;
fb896a32 53- (void)sendEvent: (NSEvent*)anEvent;
fb896a32
DE
54@end // wxPoserNSApplication
55
70fb935a
DE
56WX_IMPLEMENT_POSER(wxPoserNSApplication);
57
fb896a32
DE
58@implementation wxPoserNSApplication : NSApplication
59
eb537cfb
DE
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.
71*/
72
73- (NSEvent *)nextEventMatchingMask:(unsigned int)mask untilDate:(NSDate *)expiration inMode:(NSString *)mode dequeue:(BOOL)flag
74{
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
78 if(event)
79 return event;
80 // No events, try doing some idle stuff
6edf960c
DE
81 if(sg_needIdle
82#ifdef __WXDEBUG__
83 && !wxTheApp->IsInAssert()
84#endif
85 && ([NSDefaultRunLoopMode isEqualToString:mode] || [NSModalPanelRunLoopMode isEqualToString:mode]))
eb537cfb
DE
86 {
87 sg_needIdle = false;
48580976 88 wxLogTrace(wxTRACE_COCOA,wxT("Processing idle events"));
eb537cfb
DE
89 while(wxTheApp->ProcessIdle())
90 {
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
94 if(event)
95 return event;
96 // we didn't get one, do some idle work
48580976 97 wxLogTrace(wxTRACE_COCOA,wxT("Looping idle events"));
eb537cfb
DE
98 }
99 // No more idle work requested, block
48580976 100 wxLogTrace(wxTRACE_COCOA,wxT("Finished idle processing"));
eb537cfb
DE
101 }
102 else
48580976 103 wxLogTrace(wxTRACE_COCOA,wxT("Avoiding idle processing sg_needIdle=%d"),sg_needIdle);
eb537cfb
DE
104 return [super nextEventMatchingMask:mask untilDate:expiration inMode:mode dequeue:flag];
105}
106
ba808e24
DE
107- (void)sendEvent: (NSEvent*)anEvent
108{
48580976 109 wxLogTrace(wxTRACE_COCOA,wxT("SendEvent"));
eb537cfb 110 sg_needIdle = true;
ba808e24
DE
111 [super sendEvent: anEvent];
112}
113
114@end // wxPoserNSApplication
115
116// ========================================================================
117// wxNSApplicationDelegate
118// ========================================================================
ba808e24
DE
119@implementation wxNSApplicationDelegate : NSObject
120
2990ec97
DE
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.
fb896a32
DE
124- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
125{
2990ec97 126 return NO;
fb896a32
DE
127}
128
0187ddb4
DE
129- (void)applicationWillBecomeActive:(NSNotification *)notification
130{
131 wxTheApp->CocoaDelegate_applicationWillBecomeActive();
132}
133
134- (void)applicationDidBecomeActive:(NSNotification *)notification
135{
136 wxTheApp->CocoaDelegate_applicationDidBecomeActive();
137}
138
139- (void)applicationWillResignActive:(NSNotification *)notification
140{
141 wxTheApp->CocoaDelegate_applicationWillResignActive();
142}
143
144- (void)applicationDidResignActive:(NSNotification *)notification
145{
146 wxTheApp->CocoaDelegate_applicationDidResignActive();
147}
148
149@end // implementation wxNSApplicationDelegate : NSObject
e2478fde 150
70fb935a
DE
151// ========================================================================
152// wxApp
153// ========================================================================
fb896a32
DE
154
155// ----------------------------------------------------------------------------
156// wxApp Static member initialization
157// ----------------------------------------------------------------------------
fb896a32
DE
158IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
159BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
955a9197 160 EVT_IDLE(wxAppBase::OnIdle)
fb896a32
DE
161// EVT_END_SESSION(wxApp::OnEndSession)
162// EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
163END_EVENT_TABLE()
fb896a32
DE
164
165// ----------------------------------------------------------------------------
05e2b077 166// wxApp initialization/cleanup
fb896a32 167// ----------------------------------------------------------------------------
05e2b077 168bool wxApp::Initialize(int& argc, wxChar **argv)
fb896a32 169{
47f1ad6a 170 wxAutoNSAutoreleasePool pool;
14fc7eb4 171 m_cocoaMainThread = [NSThread currentThread];
05e2b077
VZ
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)
176 if ( argc > 1 )
177 {
178 static const wxChar *ARG_PSN = _T("-psn_");
b0c0a393 179 if ( wxStrncmp(argv[1], ARG_PSN, wxStrlen(ARG_PSN)) == 0 )
05e2b077
VZ
180 {
181 // remove this argument
33f39af3 182 --argc;
b0c0a393 183 memmove(argv + 1, argv + 2, argc * sizeof(wxChar *));
05e2b077
VZ
184 }
185 }
186
28ce3086
DE
187 // Posing must be completed before any instances of the Objective-C
188 // classes being posed as are created.
fb896a32 189 wxPoseAsInitializer::InitializePosers();
fb896a32 190
94826170 191 return wxAppBase::Initialize(argc, argv);
fb896a32
DE
192}
193
94826170 194void wxApp::CleanUp()
fb896a32 195{
0187ddb4
DE
196 wxAutoNSAutoreleasePool pool;
197
891d0563 198 wxDC::CocoaShutdownTextSystem();
af367f46 199 wxMenuBarManager::DestroyInstance();
94826170 200
0187ddb4
DE
201 [m_cocoaApp setDelegate:nil];
202 [m_cocoaAppDelegate release];
203 m_cocoaAppDelegate = NULL;
204
94826170 205 wxAppBase::CleanUp();
fb896a32
DE
206}
207
208// ----------------------------------------------------------------------------
209// wxApp creation
210// ----------------------------------------------------------------------------
fb896a32
DE
211wxApp::wxApp()
212{
213 m_topWindow = NULL;
fb896a32 214
fb896a32
DE
215#if WXWIN_COMPATIBILITY_2_2
216 m_wantDebugOutput = TRUE;
217#endif
b93d8cc4
DE
218#ifdef __WXDEBUG__
219 m_isInAssert = FALSE;
220#endif // __WXDEBUG__
221
fb896a32
DE
222 argc = 0;
223 argv = NULL;
224 m_cocoaApp = NULL;
0187ddb4 225 m_cocoaAppDelegate = NULL;
fb896a32
DE
226}
227
0187ddb4
DE
228void wxApp::CocoaDelegate_applicationWillBecomeActive()
229{
230}
231
232void wxApp::CocoaDelegate_applicationDidBecomeActive()
233{
234}
235
236void wxApp::CocoaDelegate_applicationWillResignActive()
237{
39050120 238 wxTopLevelWindowCocoa::DeactivatePendingWindow();
0187ddb4
DE
239}
240
241void wxApp::CocoaDelegate_applicationDidResignActive()
242{
243}
244
fb896a32
DE
245bool wxApp::OnInitGui()
246{
47f1ad6a 247 wxAutoNSAutoreleasePool pool;
fb896a32
DE
248 if(!wxAppBase::OnInitGui())
249 return FALSE;
250
251 // Create the app using the sharedApplication method
252 m_cocoaApp = [NSApplication sharedApplication];
0187ddb4
DE
253 m_cocoaAppDelegate = [[wxNSApplicationDelegate alloc] init];
254 [m_cocoaApp setDelegate:m_cocoaAppDelegate];
af367f46
DE
255
256 wxMenuBarManager::CreateInstance();
257
891d0563 258 wxDC::CocoaInitializeTextSystem();
fb896a32 259// [ m_cocoaApp setDelegate:m_cocoaApp ];
fb896a32
DE
260 return TRUE;
261}
262
47f1ad6a
DE
263bool wxApp::CallOnInit()
264{
bd3e8827 265// wxAutoNSAutoreleasePool pool;
47f1ad6a
DE
266 return OnInit();
267}
268
fb896a32
DE
269bool wxApp::OnInit()
270{
271 if(!wxAppBase::OnInit())
272 return FALSE;
273
274 return TRUE;
275}
276
70fb935a
DE
277void wxApp::Exit()
278{
279 wxApp::CleanUp();
280
281 wxAppConsole::Exit();
282}
283
fb896a32 284// Yield to other processes
fb896a32
DE
285bool wxApp::Yield(bool onlyIfNeeded)
286{
287 // MT-FIXME
288 static bool s_inYield = false;
289
290#if wxUSE_LOG
291 // disable log flushing from here because a call to wxYield() shouldn't
292 // normally result in message boxes popping up &c
293 wxLog::Suspend();
294#endif // wxUSE_LOG
295
296 if (s_inYield)
297 {
298 if ( !onlyIfNeeded )
299 {
300 wxFAIL_MSG( wxT("wxYield called recursively" ) );
301 }
302
303 return false;
304 }
305
306 s_inYield = true;
307
aaa5ab05
DE
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
313 dequeue: YES])
314 {
315 [GetNSApplication() sendEvent: event];
316 }
fb896a32
DE
317
318#if wxUSE_LOG
319 // let the logs be flashed again
320 wxLog::Resume();
321#endif // wxUSE_LOG
322
323 s_inYield = false;
324
325 return true;
326}
327
eb537cfb
DE
328void wxApp::WakeUpIdle()
329{
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];
334}
335
b93d8cc4
DE
336#ifdef __WXDEBUG__
337void wxApp::OnAssert(const wxChar *file, int line, const wxChar* cond, const wxChar *msg)
338{
339 m_isInAssert = TRUE;
340 wxAppBase::OnAssert(file, line, cond, msg);
341 m_isInAssert = FALSE;
342}
343#endif // __WXDEBUG__
344