]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/cocoa/app.mm
remove gtk1 code
[wxWidgets.git] / src / cocoa / app.mm
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/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// Software 2000 Ltd.
10// Licence: wxWidgets licence
11/////////////////////////////////////////////////////////////////////////////
12
13#include "wx/wxprec.h"
14
15#include "wx/app.h"
16
17#ifndef WX_PRECOMP
18 #include "wx/dc.h"
19 #include "wx/intl.h"
20 #include "wx/log.h"
21 #include "wx/module.h"
22#endif
23
24#include "wx/cocoa/ObjcRef.h"
25#include "wx/cocoa/autorelease.h"
26#include "wx/cocoa/mbarman.h"
27#include "wx/cocoa/NSApplication.h"
28
29#import <AppKit/NSApplication.h>
30#import <Foundation/NSRunLoop.h>
31#import <Foundation/NSThread.h>
32#import <AppKit/NSEvent.h>
33#import <Foundation/NSString.h>
34#import <Foundation/NSNotification.h>
35#import <AppKit/NSCell.h>
36
37bool wxApp::sm_isEmbedded = false; // Normally we're not a plugin
38
39// wxNSApplicationObserver singleton.
40static wxObjcAutoRefFromAlloc<wxNSApplicationObserver*> sg_cocoaAppObserver = [[WX_GET_OBJC_CLASS(wxNSApplicationObserver) alloc] init];
41
42// ========================================================================
43// wxNSApplicationDelegate
44// ========================================================================
45@implementation wxNSApplicationDelegate : NSObject
46
47// NOTE: Terminate means that the event loop does NOT return and thus
48// cleanup code doesn't properly execute. Furthermore, wxWidgets has its
49// own exit on frame delete mechanism.
50- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
51{
52 return NO;
53}
54
55@end // implementation wxNSApplicationDelegate : NSObject
56WX_IMPLEMENT_GET_OBJC_CLASS(wxNSApplicationDelegate,NSObject)
57
58// ========================================================================
59// wxNSApplicationObserver
60// ========================================================================
61@implementation wxNSApplicationObserver : NSObject
62
63- (void)applicationWillBecomeActive:(NSNotification *)notification
64{
65 wxTheApp->CocoaDelegate_applicationWillBecomeActive();
66}
67
68- (void)applicationDidBecomeActive:(NSNotification *)notification
69{
70 wxTheApp->CocoaDelegate_applicationDidBecomeActive();
71}
72
73- (void)applicationWillResignActive:(NSNotification *)notification
74{
75 wxTheApp->CocoaDelegate_applicationWillResignActive();
76}
77
78- (void)applicationDidResignActive:(NSNotification *)notification
79{
80 wxTheApp->CocoaDelegate_applicationDidResignActive();
81}
82
83- (void)applicationWillUpdate:(NSNotification *)notification;
84{
85 wxTheApp->CocoaDelegate_applicationWillUpdate();
86}
87
88- (void)controlTintChanged:(NSNotification *)notification
89{
90 wxLogDebug(wxT("TODO: send EVT_SYS_COLOUR_CHANGED as appropriate"));
91}
92
93@end // implementation wxNSApplicationObserver : NSObject
94WX_IMPLEMENT_GET_OBJC_CLASS(wxNSApplicationObserver,NSObject)
95
96// ========================================================================
97// wxApp
98// ========================================================================
99
100// ----------------------------------------------------------------------------
101// wxApp Static member initialization
102// ----------------------------------------------------------------------------
103IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
104BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
105 EVT_IDLE(wxAppBase::OnIdle)
106// EVT_END_SESSION(wxApp::OnEndSession)
107// EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
108END_EVENT_TABLE()
109
110// ----------------------------------------------------------------------------
111// wxApp initialization/cleanup
112// ----------------------------------------------------------------------------
113bool wxApp::Initialize(int& argc, wxChar **argv)
114{
115 wxAutoNSAutoreleasePool pool;
116 m_cocoaMainThread = [NSThread currentThread];
117 // Mac OS X passes a process serial number command line argument when
118 // the application is launched from the Finder. This argument must be
119 // removed from the command line arguments before being handled by the
120 // application (otherwise applications would need to handle it)
121 if ( argc > 1 )
122 {
123 static const wxChar *ARG_PSN = _T("-psn_");
124 if ( wxStrncmp(argv[1], ARG_PSN, wxStrlen(ARG_PSN)) == 0 )
125 {
126 // remove this argument
127 --argc;
128 memmove(argv + 1, argv + 2, argc * sizeof(wxChar *));
129 }
130 }
131
132 return wxAppBase::Initialize(argc, argv);
133}
134
135void wxApp::CleanUp()
136{
137 wxAutoNSAutoreleasePool pool;
138
139 wxDC::CocoaShutdownTextSystem();
140 wxMenuBarManager::DestroyInstance();
141
142 [[NSNotificationCenter defaultCenter] removeObserver:sg_cocoaAppObserver];
143 if(!sm_isEmbedded)
144 {
145 [m_cocoaApp setDelegate:nil];
146 [m_cocoaAppDelegate release];
147 m_cocoaAppDelegate = NULL;
148 }
149
150 wxAppBase::CleanUp();
151}
152
153// ----------------------------------------------------------------------------
154// wxApp creation
155// ----------------------------------------------------------------------------
156wxApp::wxApp()
157{
158 m_topWindow = NULL;
159
160#ifdef __WXDEBUG__
161 m_isInAssert = false;
162#endif // __WXDEBUG__
163
164 argc = 0;
165 argv = NULL;
166 m_cocoaApp = NULL;
167 m_cocoaAppDelegate = NULL;
168}
169
170void wxApp::CocoaDelegate_applicationWillBecomeActive()
171{
172}
173
174void wxApp::CocoaDelegate_applicationDidBecomeActive()
175{
176}
177
178void wxApp::CocoaDelegate_applicationWillResignActive()
179{
180 wxTopLevelWindowCocoa::DeactivatePendingWindow();
181}
182
183void wxApp::CocoaDelegate_applicationDidResignActive()
184{
185}
186
187bool wxApp::OnInitGui()
188{
189 wxAutoNSAutoreleasePool pool;
190 if(!wxAppBase::OnInitGui())
191 return false;
192
193 // Create the app using the sharedApplication method
194 m_cocoaApp = [NSApplication sharedApplication];
195
196 if(!sm_isEmbedded)
197 {
198 // Enable response to application delegate messages
199 m_cocoaAppDelegate = [[WX_GET_OBJC_CLASS(wxNSApplicationDelegate) alloc] init];
200 [m_cocoaApp setDelegate:m_cocoaAppDelegate];
201 }
202
203 // Enable response to "delegate" messages on the notification observer
204 [[NSNotificationCenter defaultCenter] addObserver:sg_cocoaAppObserver
205 selector:@selector(applicationWillBecomeActive:)
206 name:NSApplicationWillBecomeActiveNotification object:nil];
207
208 [[NSNotificationCenter defaultCenter] addObserver:sg_cocoaAppObserver
209 selector:@selector(applicationDidBecomeActive:)
210 name:NSApplicationDidBecomeActiveNotification object:nil];
211
212 [[NSNotificationCenter defaultCenter] addObserver:sg_cocoaAppObserver
213 selector:@selector(applicationWillResignActive:)
214 name:NSApplicationWillResignActiveNotification object:nil];
215
216 [[NSNotificationCenter defaultCenter] addObserver:sg_cocoaAppObserver
217 selector:@selector(applicationDidResignActive:)
218 name:NSApplicationDidResignActiveNotification object:nil];
219
220 [[NSNotificationCenter defaultCenter] addObserver:sg_cocoaAppObserver
221 selector:@selector(applicationWillUpdate:)
222 name:NSApplicationWillUpdateNotification object:nil];
223
224 // Enable response to system notifications
225 [[NSNotificationCenter defaultCenter] addObserver:sg_cocoaAppObserver
226 selector:@selector(controlTintChanged:)
227 name:NSControlTintDidChangeNotification object:nil];
228
229 if(!sm_isEmbedded)
230 wxMenuBarManager::CreateInstance();
231
232 wxDC::CocoaInitializeTextSystem();
233 return true;
234}
235
236wxApp::~wxApp()
237{
238 if(m_cfRunLoopIdleObserver != NULL)
239 {
240 // Invalidate the observer which also removes it from the run loop.
241 CFRunLoopObserverInvalidate(m_cfRunLoopIdleObserver);
242 // Release the ref as we don't need it anymore.
243 m_cfRunLoopIdleObserver.reset();
244 }
245}
246
247bool wxApp::CallOnInit()
248{
249// wxAutoNSAutoreleasePool pool;
250 return OnInit();
251}
252
253bool wxApp::OnInit()
254{
255 if(!wxAppBase::OnInit())
256 return false;
257
258 return true;
259}
260
261void wxApp::Exit()
262{
263 wxApp::CleanUp();
264
265 wxAppConsole::Exit();
266}
267
268// Yield to other processes
269bool wxApp::Yield(bool onlyIfNeeded)
270{
271 // MT-FIXME
272 static bool s_inYield = false;
273
274#if wxUSE_LOG
275 // disable log flushing from here because a call to wxYield() shouldn't
276 // normally result in message boxes popping up &c
277 wxLog::Suspend();
278#endif // wxUSE_LOG
279
280 if (s_inYield)
281 {
282 if ( !onlyIfNeeded )
283 {
284 wxFAIL_MSG( wxT("wxYield called recursively" ) );
285 }
286
287 return false;
288 }
289
290 s_inYield = true;
291
292 // Run the event loop until it is out of events
293 while(1)
294 {
295 wxAutoNSAutoreleasePool pool;
296 NSEvent *event = [GetNSApplication()
297 nextEventMatchingMask:NSAnyEventMask
298 untilDate:[NSDate distantPast]
299 inMode:NSDefaultRunLoopMode
300 dequeue: YES];
301 if(!event)
302 break;
303 [GetNSApplication() sendEvent: event];
304 }
305
306#if wxUSE_LOG
307 // let the logs be flashed again
308 wxLog::Resume();
309#endif // wxUSE_LOG
310
311 s_inYield = false;
312
313 return true;
314}
315
316void wxApp::WakeUpIdle()
317{
318 [m_cocoaApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined
319 location:NSZeroPoint modifierFlags:NSAnyEventMask
320 timestamp:0 windowNumber:0 context:nil
321 subtype:0 data1:0 data2:0] atStart:NO];
322}
323
324extern "C" static void ObserveMainRunLoopBeforeWaiting(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info);
325extern "C" static void ObserveMainRunLoopBeforeWaiting(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info)
326{
327 static_cast<wxApp*>(info)->CF_ObserveMainRunLoopBeforeWaiting(observer, activity);
328}
329
330#if 0
331static int sg_cApplicationWillUpdate = 0;
332#endif
333
334void wxApp::CocoaDelegate_applicationWillUpdate()
335{
336 wxLogTrace(wxTRACE_COCOA,wxT("applicationWillUpdate"));
337
338// CFRunLoopRef cfRunLoop = [[NSRunLoop currentRunLoop] getCFRunLoop];
339 CFRunLoopRef cfRunLoop = CFRunLoopGetCurrent();
340 wxCFRef<CFStringRef> cfRunLoopMode(CFRunLoopCopyCurrentMode(cfRunLoop));
341
342 if(m_cfRunLoopIdleObserver != NULL && m_cfObservedRunLoopMode != cfRunLoopMode)
343 {
344 CFRunLoopObserverInvalidate(m_cfRunLoopIdleObserver);
345 m_cfRunLoopIdleObserver.reset();
346 }
347#if 0
348 ++sg_cApplicationWillUpdate;
349#endif
350 if(m_cfRunLoopIdleObserver == NULL)
351 {
352 // Enable idle event handling
353 CFRunLoopObserverContext observerContext =
354 { 0
355 , this
356 , NULL
357 , NULL
358 , NULL
359 };
360 m_cfRunLoopIdleObserver.reset(CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopBeforeWaiting, /*repeats*/FALSE, /*priority*/0, ObserveMainRunLoopBeforeWaiting, &observerContext));
361 m_cfObservedRunLoopMode = cfRunLoopMode;
362 CFRunLoopAddObserver(cfRunLoop, m_cfRunLoopIdleObserver, m_cfObservedRunLoopMode);
363 }
364}
365
366static inline bool FakeNeedMoreIdle()
367{
368#if 0
369// Return true on every 10th call.
370 static int idleCount = 0;
371 return ++idleCount % 10;
372#else
373 return false;
374#endif
375}
376
377void wxApp::CF_ObserveMainRunLoopBeforeWaiting(CFRunLoopObserverRef observer, int activity)
378{
379 // Ensure that the app knows we've been invalidated
380 m_cfRunLoopIdleObserver.reset();
381#if 0
382 wxLogTrace(wxTRACE_COCOA,wxT("Idle BEGIN (%d)"), sg_cApplicationWillUpdate);
383 sg_cApplicationWillUpdate = 0;
384#else
385 wxLogTrace(wxTRACE_COCOA,wxT("Idle BEGIN"));
386#endif
387 if( ProcessIdle() || FakeNeedMoreIdle() )
388 {
389 wxLogTrace(wxTRACE_COCOA, wxT("Idle REQUEST MORE"));
390 [NSApp setWindowsNeedUpdate:YES];
391 }
392 else
393 {
394 wxLogTrace(wxTRACE_COCOA, wxT("Idle END"));
395 }
396}
397
398#ifdef __WXDEBUG__
399void wxApp::OnAssert(const wxChar *file, int line, const wxChar* cond, const wxChar *msg)
400{
401 m_isInAssert = true;
402 wxAppBase::OnAssert(file, line, cond, msg);
403 m_isInAssert = false;
404}
405#endif // __WXDEBUG__