]> git.saurik.com Git - wxWidgets.git/blob - src/cocoa/app.mm
supported controls on toolbar
[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 license
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #include "wx/wxprec.h"
21 #ifndef WX_PRECOMP
22 #include "wx/defs.h"
23 #include "wx/app.h"
24 #include "wx/frame.h"
25 #include "wx/dialog.h"
26 #include "wx/dc.h"
27 #include "wx/intl.h"
28 #include "wx/log.h"
29 #include "wx/cocoa/ObjcPose.h"
30 #endif
31
32 #if wxUSE_WX_RESOURCES
33 # include "wx/resource.h"
34 #endif
35
36 #import <AppKit/NSApplication.h>
37 #import <Foundation/NSRunLoop.h>
38 #import <Foundation/NSArray.h>
39
40 // ----------------------------------------------------------------------------
41 // globals
42 // ----------------------------------------------------------------------------
43
44 wxApp *wxTheApp = NULL;
45 wxPoseAsInitializer *wxPoseAsInitializer::sm_first = NULL;
46
47 @interface wxPoserNSApplication : NSApplication
48 {
49 }
50
51 - (void)doIdle: (id)data;
52 - (void)finishLaunching;
53 - (void)sendEvent: (NSEvent*)anEvent;
54 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication;
55 @end // wxPoserNSApplication
56
57 @implementation wxPoserNSApplication : NSApplication
58
59 - (void)doIdle: (id)data
60 {
61 wxASSERT(wxTheApp);
62 wxLogDebug("doIdle called");
63 NSRunLoop *rl = [NSRunLoop currentRunLoop];
64 // runMode: beforeDate returns YES if something was done
65 while(wxTheApp->ProcessIdle()) // FIXME: AND NO EVENTS ARE PENDING
66 {
67 wxLogDebug("Looping for idle events");
68 #if 1
69 if( [rl runMode:[rl currentMode] beforeDate:[NSDate distantPast]])
70 {
71 wxLogDebug("Found actual work to do");
72 break;
73 }
74 #endif
75 }
76 wxLogDebug("Idle processing complete, requesting next idle event");
77 // Add ourself back into the run loop (on next event) if necessary
78 wxTheApp->CocoaRequestIdle();
79 }
80
81 - (void)finishLaunching
82 {
83 wxLogDebug("finishLaunching");
84 bool initsuccess = wxTheApp->OnInit();
85 if(!initsuccess)
86 [super stop: NULL];
87
88 [super finishLaunching];
89 }
90
91 - (void)sendEvent: (NSEvent*)anEvent
92 {
93 wxLogDebug("SendEvent");
94 wxTheApp->CocoaInstallRequestedIdleHandler();
95 [super sendEvent: anEvent];
96 }
97
98 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
99 {
100 BOOL ret = wxTheApp->GetExitOnFrameDelete();
101 wxLogDebug("applicationShouldTermintaeAfterLastWindowClosed=%d",ret);
102 return ret;
103 }
104
105 @end // wxPoserNSApplication
106 WX_IMPLEMENT_POSER(wxPoserNSApplication);
107
108 // ============================================================================
109 // functions
110 // ============================================================================
111
112 //----------------------------------------------------------------------
113 // wxEntry
114 //----------------------------------------------------------------------
115
116 int WXDLLEXPORT wxEntryStart( int WXUNUSED(argc), char *WXUNUSED(argv)[] )
117 {
118 return wxApp::Initialize();
119 }
120
121 int WXDLLEXPORT wxEntryInitGui()
122 {
123 return wxTheApp->OnInitGui();
124 }
125
126 void WXDLLEXPORT wxEntryCleanup()
127 {
128 wxApp::CleanUp();
129 }
130
131 int wxEntry( int argc, char *argv[])
132 {
133 if (!wxEntryStart(argc, argv)) {
134 return 0;
135 }
136 wxLogDebug("Creating application");
137 // create the application object or ensure that one already exists
138 if (!wxTheApp)
139 {
140 // The app may have declared a global application object, but we recommend
141 // the IMPLEMENT_APP macro is used instead, which sets an initializer
142 // function for delayed, dynamic app object construction.
143 wxCHECK_MSG( wxApp::GetInitializerFunction(), 0,
144 wxT("No initializer - use IMPLEMENT_APP macro.") );
145
146 wxTheApp = (wxApp*) (*wxApp::GetInitializerFunction()) ();
147 }
148
149 wxCHECK_MSG( wxTheApp, 0, wxT("You have to define an instance of wxApp!") );
150
151 // Mac OS X passes a process serial number command line argument when
152 // the application is launched from the Finder. This argument must be
153 // removed from the command line arguments before being handled by the
154 // application (otherwise applications would need to handle it)
155
156 if (argc > 1) {
157 char theArg[6] = "";
158 strncpy(theArg, argv[1], 5);
159
160 if (strcmp(theArg, "-psn_") == 0) {
161 // assume the argument is always the only one and remove it
162 --argc;
163 }
164 }
165
166 wxTheApp->argc = argc;
167 wxTheApp->argv = argv;
168
169 wxLogDebug("initializing gui");
170 // GUI-specific initialization, such as creating an app context.
171 wxEntryInitGui();
172
173 // Here frames insert themselves automatically
174 // into wxTopLevelWindows by getting created
175 // in OnInit().
176
177 int retValue = 0;
178
179 wxLogDebug("Time to run");
180 retValue = wxTheApp->OnRun();
181
182 wxWindow *topWindow = wxTheApp->GetTopWindow();
183 if ( topWindow )
184 {
185 // Forcibly delete the window.
186 if ( topWindow->IsKindOf(CLASSINFO(wxFrame)) ||
187 topWindow->IsKindOf(CLASSINFO(wxDialog)) )
188 {
189 topWindow->Close(TRUE);
190 }
191 else
192 {
193 delete topWindow;
194 wxTheApp->SetTopWindow(NULL);
195 }
196 }
197
198 wxTheApp->OnExit();
199
200 wxEntryCleanup();
201
202 return retValue;
203 }
204
205 // ----------------------------------------------------------------------------
206 // other functions
207 // ----------------------------------------------------------------------------
208 void wxWakeUpIdle()
209 {
210 wxTheApp->CocoaRequestIdle();
211 }
212
213 void wxExit()
214 {
215 wxLogError(_("Fatal error: exiting"));
216
217 wxApp::CleanUp();
218 exit(1);
219 }
220
221 // ============================================================================
222 // wxApp implementation
223 // ============================================================================
224
225 // ----------------------------------------------------------------------------
226 // wxApp Static member initialization
227 // ----------------------------------------------------------------------------
228 wxAppInitializerFunction wxAppBase::m_appInitFn = (wxAppInitializerFunction) NULL;
229
230 #if !USE_SHARED_LIBRARY
231 IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
232 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
233 EVT_IDLE(wxApp::OnIdle)
234 // EVT_END_SESSION(wxApp::OnEndSession)
235 // EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
236 END_EVENT_TABLE()
237 #endif
238
239 // ----------------------------------------------------------------------------
240 // wxApp static functions
241 // ----------------------------------------------------------------------------
242 /*static*/ bool wxApp::Initialize()
243 {
244 wxPoseAsInitializer::InitializePosers();
245 wxClassInfo::InitializeClasses();
246
247 #if wxUSE_THREADS
248 wxPendingEventsLocker = new wxCriticalSection;
249 #endif
250
251 wxTheColourDatabase = new wxColourDatabase(wxKEY_STRING);
252 wxTheColourDatabase->Initialize();
253
254 wxInitializeStockLists();
255 wxInitializeStockObjects();
256
257 #if wxUSE_WX_RESOURCES
258 wxInitializeResourceSystem();
259 #endif
260
261 wxBitmap::InitStandardHandlers();
262
263 wxModule::RegisterModules();
264 if (!wxModule::InitializeModules()) {
265 return FALSE;
266 }
267 return TRUE;
268 }
269
270 /*static*/ void wxApp::CleanUp()
271 {
272 wxModule::CleanUpModules();
273
274 #if wxUSE_WX_RESOURCES
275 wxCleanUpResourceSystem();
276 #endif
277
278 wxDeleteStockObjects() ;
279
280 // Destroy all GDI lists, etc.
281 wxDeleteStockLists();
282
283 delete wxTheColourDatabase;
284 wxTheColourDatabase = NULL;
285
286 wxBitmap::CleanUpHandlers();
287
288 delete wxPendingEvents;
289
290 #if wxUSE_THREADS
291 delete wxPendingEventsLocker;
292 // If we don't do the following, we get an apparent memory leak.
293 ((wxEvtHandler&) wxDefaultValidator).ClearEventLocker();
294 #endif
295
296 wxClassInfo::CleanUpClasses();
297
298 delete wxTheApp;
299 wxTheApp = NULL;
300
301 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
302 // At this point we want to check if there are any memory
303 // blocks that aren't part of the wxDebugContext itself,
304 // as a special case. Then when dumping we need to ignore
305 // wxDebugContext, too.
306 if (wxDebugContext::CountObjectsLeft(TRUE) > 0)
307 {
308 wxLogDebug(wxT("There were memory leaks."));
309 wxDebugContext::Dump();
310 wxDebugContext::PrintStatistics();
311 }
312 // wxDebugContext::SetStream(NULL, NULL);
313 #endif
314
315 wxDC::CocoaShutdownTextSystem();
316 #if wxUSE_LOG
317 // do it as the very last thing because everything else can log messages
318 delete wxLog::SetActiveTarget(NULL);
319 #endif // wxUSE_LOG
320 }
321
322 // ----------------------------------------------------------------------------
323 // wxApp creation
324 // ----------------------------------------------------------------------------
325
326 wxApp::wxApp()
327 {
328 m_topWindow = NULL;
329 wxTheApp = this;
330
331 m_isIdle = true;
332 #if WXWIN_COMPATIBILITY_2_2
333 m_wantDebugOutput = TRUE;
334 #endif
335
336 argc = 0;
337 argv = NULL;
338 m_cocoaApp = NULL;
339 }
340
341 void wxApp::CocoaInstallIdleHandler()
342 {
343 wxLogDebug("wxApp::CocoaInstallIdleHandler");
344 m_isIdle = false;
345 // Call doIdle for EVERYTHING dammit
346 // We'd need Foundation/NSConnection.h for this next constant, do we need it?
347 [[ NSRunLoop currentRunLoop ] performSelector:@selector(doIdle:) target:m_cocoaApp argument:NULL order:0 modes:[NSArray arrayWithObjects:NSDefaultRunLoopMode, /* NSConnectionReplyRunLoopMode,*/ NSModalPanelRunLoopMode, /**/NSEventTrackingRunLoopMode,/**/ nil] ];
348 }
349
350 bool wxApp::OnInitGui()
351 {
352 if(!wxAppBase::OnInitGui())
353 return FALSE;
354
355 // Create the app using the sharedApplication method
356 m_cocoaApp = [NSApplication sharedApplication];
357 wxDC::CocoaInitializeTextSystem();
358 // [ m_cocoaApp setDelegate:m_cocoaApp ];
359 #if 0
360 wxLogDebug("Just for kicks");
361 [ m_cocoaApp performSelector:@selector(doIdle:) withObject:NULL ];
362 wxLogDebug("okay.. done now");
363 #endif
364 return TRUE;
365 }
366
367 bool wxApp::OnInit()
368 {
369 if(!wxAppBase::OnInit())
370 return FALSE;
371
372 return TRUE;
373 }
374
375 bool wxApp::Initialized()
376 {
377 if (GetTopWindow())
378 return TRUE;
379 else
380 return FALSE;
381 }
382
383 int wxApp::MainLoop()
384 {
385 [m_cocoaApp run];
386 return 0;
387 }
388
389 // Returns TRUE if more time is needed.
390 bool wxApp::ProcessIdle()
391 {
392 wxIdleEvent event;
393 event.SetEventObject(this);
394 ProcessEvent(event);
395
396 return event.MoreRequested();
397 }
398
399 void wxApp::ExitMainLoop()
400 {
401 wxLogDebug("wxApp::ExitMailLoop m_isIdle=%d, isRunning=%d",(int)m_isIdle,(int)[m_cocoaApp isRunning]);
402 // CocoaInstallRequestedIdleHandler();
403 // if(m_isIdle)
404 // [[ NSRunLoop currentRunLoop ] performSelector:@selector(doIdle:) target:m_cocoaApp argument:NULL order:0 modes:[NSArray arrayWithObjects:NSDefaultRunLoopMode, /* NSConnectionReplyRunLoopMode, NSModalPanelRunLoopMode, NSEventTrackingRunLoopMode,*/ nil] ];
405 // actually.. we WANT the idle event
406 // or not
407 #if 0
408 if(!m_isIdle)
409 [[ NSRunLoop currentRunLoop ] cancelPerformSelector:@selector(doIdle:) target:m_cocoaApp argument:NULL];
410 #endif
411 [m_cocoaApp terminate: m_cocoaApp];
412 }
413
414 // Is a message/event pending?
415 bool wxApp::Pending()
416 {
417 return 0;
418 }
419
420 // Dispatch a message.
421 void wxApp::Dispatch()
422 {
423 }
424
425 void wxApp::OnIdle(wxIdleEvent& event)
426 {
427 wxLogDebug("wxApp::OnIdle");
428 static bool s_inOnIdle = FALSE;
429
430 // Avoid recursion (via ProcessEvent default case)
431 if ( s_inOnIdle )
432 return;
433 s_inOnIdle = TRUE;
434
435
436 DeletePendingObjects();
437
438 // flush the logged messages if any
439 wxLog *pLog = wxLog::GetActiveTarget();
440 if ( pLog != NULL && pLog->HasPendingMessages() )
441 pLog->Flush();
442
443 // Send OnIdle events to all windows
444 bool needMore = SendIdleEvents();
445
446 if (needMore)
447 event.RequestMore(TRUE);
448
449 s_inOnIdle = FALSE;
450 }
451
452 // Send idle event to all top-level windows
453 bool wxApp::SendIdleEvents()
454 {
455 bool needMore = FALSE;
456 wxWindowList::Node* node = wxTopLevelWindows.GetFirst();
457 while (node)
458 {
459 wxWindow* win = node->GetData();
460 if (SendIdleEvents(win))
461 needMore = TRUE;
462
463 node = node->GetNext();
464 }
465 return needMore;
466 }
467
468 // Send idle event to window and all subwindows
469 bool wxApp::SendIdleEvents(wxWindow* win)
470 {
471 // wxLogDebug("SendIdleEvents win=%p",win);
472 bool needMore = FALSE;
473
474 wxIdleEvent event;
475 event.SetEventObject(win);
476 win->ProcessEvent(event);
477
478 if (event.MoreRequested())
479 needMore = TRUE;
480
481 wxWindowList::Node* node = win->GetChildren().GetFirst();
482 while (node)
483 {
484 // wxLogDebug("child=%p",node->Data());
485 wxWindow* win = node->GetData();
486 if (SendIdleEvents(win))
487 needMore = TRUE;
488
489 node = node->GetNext();
490 }
491 return needMore;
492 }
493
494 // Yield to other processes
495
496 bool wxApp::Yield(bool onlyIfNeeded)
497 {
498 // MT-FIXME
499 static bool s_inYield = false;
500
501 #if wxUSE_LOG
502 // disable log flushing from here because a call to wxYield() shouldn't
503 // normally result in message boxes popping up &c
504 wxLog::Suspend();
505 #endif // wxUSE_LOG
506
507 if (s_inYield)
508 {
509 if ( !onlyIfNeeded )
510 {
511 wxFAIL_MSG( wxT("wxYield called recursively" ) );
512 }
513
514 return false;
515 }
516
517 s_inYield = true;
518
519 wxLogDebug("WARNING: SUPPOSED to have yielded!");
520 // FIXME: Do something!
521
522 #if wxUSE_LOG
523 // let the logs be flashed again
524 wxLog::Resume();
525 #endif // wxUSE_LOG
526
527 s_inYield = false;
528
529 return true;
530 }
531
532 void wxApp::DeletePendingObjects()
533 {
534 wxNode *node = wxPendingDelete.GetFirst();
535 while (node)
536 {
537 wxObject *obj = (wxObject *)node->GetData();
538
539 delete obj;
540
541 if (wxPendingDelete.Find(obj))
542 delete node;
543
544 node = wxPendingDelete.GetFirst();
545 }
546 }
547
548 // platform specifics
549