]> git.saurik.com Git - wxWidgets.git/blob - src/cocoa/app.mm
show the selected item with customs colour correctly when the control doesn't have...
[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, sizeof(ARG_PSN) - 1) == 0 )
178 {
179 // remove this argument
180 memmove(argv, argv + 1, argc--);
181 }
182 }
183
184 // Posing must be completed before any instances of the Objective-C
185 // classes being posed as are created.
186 wxPoseAsInitializer::InitializePosers();
187
188 return wxAppBase::Initialize(argc, argv);
189 }
190
191 void wxApp::CleanUp()
192 {
193 wxAutoNSAutoreleasePool pool;
194
195 wxDC::CocoaShutdownTextSystem();
196 wxMenuBarManager::DestroyInstance();
197
198 [m_cocoaApp setDelegate:nil];
199 [m_cocoaAppDelegate release];
200 m_cocoaAppDelegate = NULL;
201
202 wxAppBase::CleanUp();
203 }
204
205 // ----------------------------------------------------------------------------
206 // wxApp creation
207 // ----------------------------------------------------------------------------
208 wxApp::wxApp()
209 {
210 m_topWindow = NULL;
211
212 m_isIdle = true;
213 #if WXWIN_COMPATIBILITY_2_2
214 m_wantDebugOutput = TRUE;
215 #endif
216 #ifdef __WXDEBUG__
217 m_isInAssert = FALSE;
218 #endif // __WXDEBUG__
219
220 argc = 0;
221 argv = NULL;
222 m_cocoaApp = NULL;
223 m_cocoaAppDelegate = NULL;
224 }
225
226 void wxApp::CocoaInstallIdleHandler()
227 {
228 // If we're not the main thread, don't install the idle handler
229 if(m_cocoaMainThread != [NSThread currentThread])
230 {
231 wxLogDebug("Attempt to install idle handler from secondary thread");
232 return;
233 }
234 // If we're supposed to be stopping, don't add more idle events
235 if(![m_cocoaApp isRunning])
236 return;
237 wxLogDebug("wxApp::CocoaInstallIdleHandler");
238 m_isIdle = false;
239 // Call doIdle for EVERYTHING dammit
240 // We'd need Foundation/NSConnection.h for this next constant, do we need it?
241 [[ NSRunLoop currentRunLoop ] performSelector:@selector(doIdle:) target:m_cocoaAppDelegate argument:NULL order:0 modes:[NSArray arrayWithObjects:NSDefaultRunLoopMode, /* NSConnectionReplyRunLoopMode,*/ NSModalPanelRunLoopMode, /**/NSEventTrackingRunLoopMode,/**/ nil] ];
242 /* Notes:
243 In the Mac OS X implementation of Cocoa, the above method schedules
244 doIdle: to be called from *within* [NSApplication
245 -nextEventMatchingMask:untilDate:inMode:dequeue:]. That is, no
246 NSEvent object is generated and control does not return from that
247 method. In fact, control will only return from that method for the
248 usual reasons (e.g. a real event is received or the untilDate is reached).
249 This has implications when trying to stop the event loop and return to
250 its caller. See wxEventLoop::Exit
251 */
252 }
253
254 void wxApp::CocoaDelegate_applicationWillBecomeActive()
255 {
256 }
257
258 void wxApp::CocoaDelegate_applicationDidBecomeActive()
259 {
260 }
261
262 void wxApp::CocoaDelegate_applicationWillResignActive()
263 {
264 }
265
266 void wxApp::CocoaDelegate_applicationDidResignActive()
267 {
268 }
269
270 bool wxApp::OnInitGui()
271 {
272 wxAutoNSAutoreleasePool pool;
273 if(!wxAppBase::OnInitGui())
274 return FALSE;
275
276 // Create the app using the sharedApplication method
277 m_cocoaApp = [NSApplication sharedApplication];
278 m_cocoaAppDelegate = [[wxNSApplicationDelegate alloc] init];
279 [m_cocoaApp setDelegate:m_cocoaAppDelegate];
280
281 wxMenuBarManager::CreateInstance();
282
283 wxDC::CocoaInitializeTextSystem();
284 // [ m_cocoaApp setDelegate:m_cocoaApp ];
285 #if 0
286 wxLogDebug("Just for kicks");
287 [ m_cocoaAppDelegate performSelector:@selector(doIdle:) withObject:NULL ];
288 wxLogDebug("okay.. done now");
289 #endif
290 return TRUE;
291 }
292
293 bool wxApp::CallOnInit()
294 {
295 // wxAutoNSAutoreleasePool pool;
296 return OnInit();
297 }
298
299 bool wxApp::OnInit()
300 {
301 if(!wxAppBase::OnInit())
302 return FALSE;
303
304 return TRUE;
305 }
306
307 void wxApp::Exit()
308 {
309 wxApp::CleanUp();
310
311 wxAppConsole::Exit();
312 }
313
314 // Yield to other processes
315 bool wxApp::Yield(bool onlyIfNeeded)
316 {
317 // MT-FIXME
318 static bool s_inYield = false;
319
320 #if wxUSE_LOG
321 // disable log flushing from here because a call to wxYield() shouldn't
322 // normally result in message boxes popping up &c
323 wxLog::Suspend();
324 #endif // wxUSE_LOG
325
326 if (s_inYield)
327 {
328 if ( !onlyIfNeeded )
329 {
330 wxFAIL_MSG( wxT("wxYield called recursively" ) );
331 }
332
333 return false;
334 }
335
336 s_inYield = true;
337
338 // Run the event loop until it is out of events
339 while(NSEvent *event = [GetNSApplication()
340 nextEventMatchingMask:NSAnyEventMask
341 untilDate:[NSDate distantPast]
342 inMode:NSDefaultRunLoopMode
343 dequeue: YES])
344 {
345 [GetNSApplication() sendEvent: event];
346 }
347
348 #if wxUSE_LOG
349 // let the logs be flashed again
350 wxLog::Resume();
351 #endif // wxUSE_LOG
352
353 s_inYield = false;
354
355 return true;
356 }
357
358 #ifdef __WXDEBUG__
359 void wxApp::OnAssert(const wxChar *file, int line, const wxChar* cond, const wxChar *msg)
360 {
361 m_isInAssert = TRUE;
362 wxAppBase::OnAssert(file, line, cond, msg);
363 m_isInAssert = FALSE;
364 }
365 #endif // __WXDEBUG__
366