]> git.saurik.com Git - wxWidgets.git/blame - src/cocoa/app.mm
Fix the off-by-one a little differently, and correct a refresh problem
[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"
16 #include "wx/frame.h"
17 #include "wx/dialog.h"
891d0563 18 #include "wx/dc.h"
fb896a32
DE
19 #include "wx/intl.h"
20 #include "wx/log.h"
fb896a32
DE
21#endif
22
11c08416
DE
23#include "wx/module.h"
24
fb45bb1f 25#include "wx/cocoa/ObjcPose.h"
493902ac 26#include "wx/cocoa/autorelease.h"
af367f46 27#include "wx/cocoa/mbarman.h"
7b466aee 28#include "wx/cocoa/NSApplication.h"
fb45bb1f 29
fb896a32
DE
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>
47f1ad6a 37#import <Foundation/NSAutoreleasePool.h>
14fc7eb4 38#import <Foundation/NSThread.h>
aaa5ab05 39#import <AppKit/NSEvent.h>
eb537cfb 40#import <Foundation/NSString.h>
fb896a32 41
70fb935a
DE
42// ========================================================================
43// wxPoseAsInitializer
44// ========================================================================
fb896a32
DE
45wxPoseAsInitializer *wxPoseAsInitializer::sm_first = NULL;
46
eb537cfb
DE
47static bool sg_needIdle = true;
48
70fb935a
DE
49// ========================================================================
50// wxPoserNSApplication
51// ========================================================================
fb896a32
DE
52@interface wxPoserNSApplication : NSApplication
53{
54}
55
eb537cfb 56- (NSEvent *)nextEventMatchingMask:(unsigned int)mask untilDate:(NSDate *)expiration inMode:(NSString *)mode dequeue:(BOOL)flag;
fb896a32 57- (void)sendEvent: (NSEvent*)anEvent;
fb896a32
DE
58@end // wxPoserNSApplication
59
70fb935a
DE
60WX_IMPLEMENT_POSER(wxPoserNSApplication);
61
fb896a32
DE
62@implementation wxPoserNSApplication : NSApplication
63
eb537cfb
DE
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
6edf960c
DE
85 if(sg_needIdle
86#ifdef __WXDEBUG__
87 && !wxTheApp->IsInAssert()
88#endif
89 && ([NSDefaultRunLoopMode isEqualToString:mode] || [NSModalPanelRunLoopMode isEqualToString:mode]))
eb537cfb
DE
90 {
91 sg_needIdle = false;
48580976 92 wxLogTrace(wxTRACE_COCOA,wxT("Processing idle events"));
eb537cfb
DE
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
48580976 101 wxLogTrace(wxTRACE_COCOA,wxT("Looping idle events"));
eb537cfb
DE
102 }
103 // No more idle work requested, block
48580976 104 wxLogTrace(wxTRACE_COCOA,wxT("Finished idle processing"));
eb537cfb
DE
105 }
106 else
48580976 107 wxLogTrace(wxTRACE_COCOA,wxT("Avoiding idle processing sg_needIdle=%d"),sg_needIdle);
eb537cfb
DE
108 return [super nextEventMatchingMask:mask untilDate:expiration inMode:mode dequeue:flag];
109}
110
ba808e24
DE
111- (void)sendEvent: (NSEvent*)anEvent
112{
48580976 113 wxLogTrace(wxTRACE_COCOA,wxT("SendEvent"));
eb537cfb 114 sg_needIdle = true;
ba808e24
DE
115 [super sendEvent: anEvent];
116}
117
118@end // wxPoserNSApplication
119
120// ========================================================================
121// wxNSApplicationDelegate
122// ========================================================================
ba808e24
DE
123@implementation wxNSApplicationDelegate : NSObject
124
2990ec97
DE
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.
fb896a32
DE
128- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
129{
2990ec97 130 return NO;
fb896a32
DE
131}
132
0187ddb4
DE
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
e2478fde 154
70fb935a
DE
155// ========================================================================
156// wxApp
157// ========================================================================
fb896a32
DE
158
159// ----------------------------------------------------------------------------
160// wxApp Static member initialization
161// ----------------------------------------------------------------------------
fb896a32
DE
162IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
163BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
955a9197 164 EVT_IDLE(wxAppBase::OnIdle)
fb896a32
DE
165// EVT_END_SESSION(wxApp::OnEndSession)
166// EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
167END_EVENT_TABLE()
fb896a32
DE
168
169// ----------------------------------------------------------------------------
05e2b077 170// wxApp initialization/cleanup
fb896a32 171// ----------------------------------------------------------------------------
05e2b077 172bool wxApp::Initialize(int& argc, wxChar **argv)
fb896a32 173{
47f1ad6a 174 wxAutoNSAutoreleasePool pool;
14fc7eb4 175 m_cocoaMainThread = [NSThread currentThread];
05e2b077
VZ
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_");
b0c0a393 183 if ( wxStrncmp(argv[1], ARG_PSN, wxStrlen(ARG_PSN)) == 0 )
05e2b077
VZ
184 {
185 // remove this argument
33f39af3 186 --argc;
b0c0a393 187 memmove(argv + 1, argv + 2, argc * sizeof(wxChar *));
05e2b077
VZ
188 }
189 }
190
28ce3086
DE
191 // Posing must be completed before any instances of the Objective-C
192 // classes being posed as are created.
fb896a32 193 wxPoseAsInitializer::InitializePosers();
fb896a32 194
94826170 195 return wxAppBase::Initialize(argc, argv);
fb896a32
DE
196}
197
94826170 198void wxApp::CleanUp()
fb896a32 199{
0187ddb4
DE
200 wxAutoNSAutoreleasePool pool;
201
891d0563 202 wxDC::CocoaShutdownTextSystem();
af367f46 203 wxMenuBarManager::DestroyInstance();
94826170 204
0187ddb4
DE
205 [m_cocoaApp setDelegate:nil];
206 [m_cocoaAppDelegate release];
207 m_cocoaAppDelegate = NULL;
208
94826170 209 wxAppBase::CleanUp();
fb896a32
DE
210}
211
212// ----------------------------------------------------------------------------
213// wxApp creation
214// ----------------------------------------------------------------------------
fb896a32
DE
215wxApp::wxApp()
216{
217 m_topWindow = NULL;
fb896a32 218
fb896a32
DE
219#if WXWIN_COMPATIBILITY_2_2
220 m_wantDebugOutput = TRUE;
221#endif
b93d8cc4
DE
222#ifdef __WXDEBUG__
223 m_isInAssert = FALSE;
224#endif // __WXDEBUG__
225
fb896a32
DE
226 argc = 0;
227 argv = NULL;
228 m_cocoaApp = NULL;
0187ddb4 229 m_cocoaAppDelegate = NULL;
fb896a32
DE
230}
231
0187ddb4
DE
232void wxApp::CocoaDelegate_applicationWillBecomeActive()
233{
234}
235
236void wxApp::CocoaDelegate_applicationDidBecomeActive()
237{
238}
239
240void wxApp::CocoaDelegate_applicationWillResignActive()
241{
39050120 242 wxTopLevelWindowCocoa::DeactivatePendingWindow();
0187ddb4
DE
243}
244
245void wxApp::CocoaDelegate_applicationDidResignActive()
246{
247}
248
fb896a32
DE
249bool wxApp::OnInitGui()
250{
47f1ad6a 251 wxAutoNSAutoreleasePool pool;
fb896a32
DE
252 if(!wxAppBase::OnInitGui())
253 return FALSE;
254
255 // Create the app using the sharedApplication method
256 m_cocoaApp = [NSApplication sharedApplication];
0187ddb4
DE
257 m_cocoaAppDelegate = [[wxNSApplicationDelegate alloc] init];
258 [m_cocoaApp setDelegate:m_cocoaAppDelegate];
af367f46
DE
259
260 wxMenuBarManager::CreateInstance();
261
891d0563 262 wxDC::CocoaInitializeTextSystem();
fb896a32 263// [ m_cocoaApp setDelegate:m_cocoaApp ];
fb896a32
DE
264 return TRUE;
265}
266
47f1ad6a
DE
267bool wxApp::CallOnInit()
268{
bd3e8827 269// wxAutoNSAutoreleasePool pool;
47f1ad6a
DE
270 return OnInit();
271}
272
fb896a32
DE
273bool wxApp::OnInit()
274{
275 if(!wxAppBase::OnInit())
276 return FALSE;
277
278 return TRUE;
279}
280
70fb935a
DE
281void wxApp::Exit()
282{
283 wxApp::CleanUp();
284
285 wxAppConsole::Exit();
286}
287
fb896a32 288// Yield to other processes
fb896a32
DE
289bool 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
aaa5ab05
DE
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 }
fb896a32
DE
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
eb537cfb
DE
332void 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
b93d8cc4
DE
340#ifdef __WXDEBUG__
341void 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