]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/cocoa/app.mm
Use WXNSView just like wxWindow does when creating a wxControl. There are
[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)
104
105// ----------------------------------------------------------------------------
106// wxApp initialization/cleanup
107// ----------------------------------------------------------------------------
108bool wxApp::Initialize(int& argc, wxChar **argv)
109{
110 wxAutoNSAutoreleasePool pool;
111 m_cocoaMainThread = [NSThread currentThread];
112 // Mac OS X passes a process serial number command line argument when
113 // the application is launched from the Finder. This argument must be
114 // removed from the command line arguments before being handled by the
115 // application (otherwise applications would need to handle it)
116 if ( argc > 1 )
117 {
118 static const wxChar *ARG_PSN = _T("-psn_");
119 if ( wxStrncmp(argv[1], ARG_PSN, wxStrlen(ARG_PSN)) == 0 )
120 {
121 // remove this argument
122 --argc;
123 memmove(argv + 1, argv + 2, argc * sizeof(wxChar *));
124 }
125 }
126
127 return wxAppBase::Initialize(argc, argv);
128}
129
130void wxApp::CleanUp()
131{
132 wxAutoNSAutoreleasePool pool;
133
134 wxDC::CocoaShutdownTextSystem();
135 wxMenuBarManager::DestroyInstance();
136
137 [[NSNotificationCenter defaultCenter] removeObserver:sg_cocoaAppObserver];
138 if(!sm_isEmbedded)
139 {
140 [m_cocoaApp setDelegate:nil];
141 [m_cocoaAppDelegate release];
142 m_cocoaAppDelegate = NULL;
143 }
144
145 wxAppBase::CleanUp();
146}
147
148// ----------------------------------------------------------------------------
149// wxApp creation
150// ----------------------------------------------------------------------------
151wxApp::wxApp()
152{
153 m_topWindow = NULL;
154
155#ifdef __WXDEBUG__
156 m_isInAssert = false;
157#endif // __WXDEBUG__
158
159 argc = 0;
160 argv = NULL;
161 m_cocoaApp = NULL;
162 m_cocoaAppDelegate = NULL;
163}
164
165void wxApp::CocoaDelegate_applicationWillBecomeActive()
166{
167}
168
169void wxApp::CocoaDelegate_applicationDidBecomeActive()
170{
171}
172
173void wxApp::CocoaDelegate_applicationWillResignActive()
174{
175 wxTopLevelWindowCocoa::DeactivatePendingWindow();
176}
177
178void wxApp::CocoaDelegate_applicationDidResignActive()
179{
180}
181
182bool wxApp::OnInitGui()
183{
184 wxAutoNSAutoreleasePool pool;
185 if(!wxAppBase::OnInitGui())
186 return false;
187
188 // Create the app using the sharedApplication method
189 m_cocoaApp = [NSApplication sharedApplication];
190
191 if(!sm_isEmbedded)
192 {
193 // Enable response to application delegate messages
194 m_cocoaAppDelegate = [[WX_GET_OBJC_CLASS(wxNSApplicationDelegate) alloc] init];
195 [m_cocoaApp setDelegate:m_cocoaAppDelegate];
196 }
197
198 // Enable response to "delegate" messages on the notification observer
199 [[NSNotificationCenter defaultCenter] addObserver:sg_cocoaAppObserver
200 selector:@selector(applicationWillBecomeActive:)
201 name:NSApplicationWillBecomeActiveNotification object:nil];
202
203 [[NSNotificationCenter defaultCenter] addObserver:sg_cocoaAppObserver
204 selector:@selector(applicationDidBecomeActive:)
205 name:NSApplicationDidBecomeActiveNotification object:nil];
206
207 [[NSNotificationCenter defaultCenter] addObserver:sg_cocoaAppObserver
208 selector:@selector(applicationWillResignActive:)
209 name:NSApplicationWillResignActiveNotification object:nil];
210
211 [[NSNotificationCenter defaultCenter] addObserver:sg_cocoaAppObserver
212 selector:@selector(applicationDidResignActive:)
213 name:NSApplicationDidResignActiveNotification object:nil];
214
215 [[NSNotificationCenter defaultCenter] addObserver:sg_cocoaAppObserver
216 selector:@selector(applicationWillUpdate:)
217 name:NSApplicationWillUpdateNotification object:nil];
218
219 // Enable response to system notifications
220 [[NSNotificationCenter defaultCenter] addObserver:sg_cocoaAppObserver
221 selector:@selector(controlTintChanged:)
222 name:NSControlTintDidChangeNotification object:nil];
223
224 if(!sm_isEmbedded)
225 wxMenuBarManager::CreateInstance();
226
227 wxDC::CocoaInitializeTextSystem();
228 return true;
229}
230
231wxApp::~wxApp()
232{
233 if(m_cfRunLoopIdleObserver != NULL)
234 {
235 // Invalidate the observer which also removes it from the run loop.
236 CFRunLoopObserverInvalidate(m_cfRunLoopIdleObserver);
237 // Release the ref as we don't need it anymore.
238 m_cfRunLoopIdleObserver.reset();
239 }
240}
241
242bool wxApp::CallOnInit()
243{
244// wxAutoNSAutoreleasePool pool;
245 return OnInit();
246}
247
248bool wxApp::OnInit()
249{
250 if(!wxAppBase::OnInit())
251 return false;
252
253 return true;
254}
255
256void wxApp::Exit()
257{
258 wxApp::CleanUp();
259
260 wxAppConsole::Exit();
261}
262
263// Yield to other processes
264bool wxApp::Yield(bool onlyIfNeeded)
265{
266 // MT-FIXME
267 static bool s_inYield = false;
268
269#if wxUSE_LOG
270 // disable log flushing from here because a call to wxYield() shouldn't
271 // normally result in message boxes popping up &c
272 wxLog::Suspend();
273#endif // wxUSE_LOG
274
275 if (s_inYield)
276 {
277 if ( !onlyIfNeeded )
278 {
279 wxFAIL_MSG( wxT("wxYield called recursively" ) );
280 }
281
282 return false;
283 }
284
285 s_inYield = true;
286
287 // Run the event loop until it is out of events
288 while(1)
289 {
290 wxAutoNSAutoreleasePool pool;
291 NSEvent *event = [GetNSApplication()
292 nextEventMatchingMask:NSAnyEventMask
293 untilDate:[NSDate distantPast]
294 inMode:NSDefaultRunLoopMode
295 dequeue: YES];
296 if(!event)
297 break;
298 [GetNSApplication() sendEvent: event];
299 }
300
301#if wxUSE_LOG
302 // let the logs be flashed again
303 wxLog::Resume();
304#endif // wxUSE_LOG
305
306 s_inYield = false;
307
308 return true;
309}
310
311void wxApp::WakeUpIdle()
312{
313 [m_cocoaApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined
314 location:NSZeroPoint modifierFlags:NSAnyEventMask
315 timestamp:0 windowNumber:0 context:nil
316 subtype:0 data1:0 data2:0] atStart:NO];
317}
318
319extern "C" static void ObserveMainRunLoopBeforeWaiting(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info);
320extern "C" static void ObserveMainRunLoopBeforeWaiting(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info)
321{
322 static_cast<wxApp*>(info)->CF_ObserveMainRunLoopBeforeWaiting(observer, activity);
323}
324
325#if 0
326static int sg_cApplicationWillUpdate = 0;
327#endif
328
329void wxApp::CocoaDelegate_applicationWillUpdate()
330{
331 wxLogTrace(wxTRACE_COCOA,wxT("applicationWillUpdate"));
332
333// CFRunLoopRef cfRunLoop = [[NSRunLoop currentRunLoop] getCFRunLoop];
334 CFRunLoopRef cfRunLoop = CFRunLoopGetCurrent();
335 wxCFRef<CFStringRef> cfRunLoopMode(CFRunLoopCopyCurrentMode(cfRunLoop));
336
337 if(m_cfRunLoopIdleObserver != NULL && m_cfObservedRunLoopMode != cfRunLoopMode)
338 {
339 CFRunLoopObserverInvalidate(m_cfRunLoopIdleObserver);
340 m_cfRunLoopIdleObserver.reset();
341 }
342#if 0
343 ++sg_cApplicationWillUpdate;
344#endif
345 if(m_cfRunLoopIdleObserver == NULL)
346 {
347 // Enable idle event handling
348 CFRunLoopObserverContext observerContext =
349 { 0
350 , this
351 , NULL
352 , NULL
353 , NULL
354 };
355 m_cfRunLoopIdleObserver.reset(CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopBeforeWaiting, /*repeats*/FALSE, /*priority*/0, ObserveMainRunLoopBeforeWaiting, &observerContext));
356 m_cfObservedRunLoopMode = cfRunLoopMode;
357 CFRunLoopAddObserver(cfRunLoop, m_cfRunLoopIdleObserver, m_cfObservedRunLoopMode);
358 }
359}
360
361static inline bool FakeNeedMoreIdle()
362{
363#if 0
364// Return true on every 10th call.
365 static int idleCount = 0;
366 return ++idleCount % 10;
367#else
368 return false;
369#endif
370}
371
372void wxApp::CF_ObserveMainRunLoopBeforeWaiting(CFRunLoopObserverRef observer, int activity)
373{
374 // Ensure that the app knows we've been invalidated
375 m_cfRunLoopIdleObserver.reset();
376#if 0
377 wxLogTrace(wxTRACE_COCOA,wxT("Idle BEGIN (%d)"), sg_cApplicationWillUpdate);
378 sg_cApplicationWillUpdate = 0;
379#else
380 wxLogTrace(wxTRACE_COCOA,wxT("Idle BEGIN"));
381#endif
382 if( ProcessIdle() || FakeNeedMoreIdle() )
383 {
384 wxLogTrace(wxTRACE_COCOA, wxT("Idle REQUEST MORE"));
385 [NSApp setWindowsNeedUpdate:YES];
386 }
387 else
388 {
389 wxLogTrace(wxTRACE_COCOA, wxT("Idle END"));
390 }
391}
392
393#ifdef __WXDEBUG__
394void wxApp::OnAssert(const wxChar *file, int line, const wxChar* cond, const wxChar *msg)
395{
396 m_isInAssert = true;
397 wxAppBase::OnAssert(file, line, cond, msg);
398 m_isInAssert = false;
399}
400#endif // __WXDEBUG__