1 /////////////////////////////////////////////////////////////////////////////
4 // Author: David Elliott
8 // Copyright: (c) David Elliott
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 #include "wx/wxprec.h"
25 #include "wx/dialog.h"
28 #include "wx/cocoa/ObjcPose.h"
31 #if wxUSE_WX_RESOURCES
32 # include "wx/resource.h"
35 #import <AppKit/NSApplication.h>
36 #import <Foundation/NSRunLoop.h>
37 #import <Foundation/NSArray.h>
39 // ----------------------------------------------------------------------------
41 // ----------------------------------------------------------------------------
43 wxApp *wxTheApp = NULL;
44 wxPoseAsInitializer *wxPoseAsInitializer::sm_first = NULL;
46 @interface wxPoserNSApplication : NSApplication
50 - (void)doIdle: (id)data;
51 - (void)finishLaunching;
52 - (void)sendEvent: (NSEvent*)anEvent;
53 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication;
54 @end // wxPoserNSApplication
56 @implementation wxPoserNSApplication : NSApplication
58 - (void)doIdle: (id)data
61 wxLogDebug("doIdle called");
62 NSRunLoop *rl = [NSRunLoop currentRunLoop];
63 // runMode: beforeDate returns YES if something was done
64 while(wxTheApp->ProcessIdle()) // FIXME: AND NO EVENTS ARE PENDING
66 wxLogDebug("Looping for idle events");
68 if( [rl runMode:[rl currentMode] beforeDate:[NSDate distantPast]])
70 wxLogDebug("Found actual work to do");
75 wxLogDebug("Idle processing complete, requesting next idle event");
76 // Add ourself back into the run loop (on next event) if necessary
77 wxTheApp->CocoaRequestIdle();
80 - (void)finishLaunching
82 wxLogDebug("finishLaunching");
83 bool initsuccess = wxTheApp->OnInit();
87 [super finishLaunching];
90 - (void)sendEvent: (NSEvent*)anEvent
92 wxLogDebug("SendEvent");
93 wxTheApp->CocoaInstallRequestedIdleHandler();
94 [super sendEvent: anEvent];
97 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
99 BOOL ret = wxTheApp->GetExitOnFrameDelete();
100 wxLogDebug("applicationShouldTermintaeAfterLastWindowClosed=%d",ret);
104 @end // wxPoserNSApplication
105 WX_IMPLEMENT_POSER(wxPoserNSApplication);
107 // ============================================================================
109 // ============================================================================
111 //----------------------------------------------------------------------
113 //----------------------------------------------------------------------
115 int WXDLLEXPORT wxEntryStart( int WXUNUSED(argc), char *WXUNUSED(argv)[] )
117 return wxApp::Initialize();
120 int WXDLLEXPORT wxEntryInitGui()
122 return wxTheApp->OnInitGui();
125 void WXDLLEXPORT wxEntryCleanup()
130 int wxEntry( int argc, char *argv[])
132 if (!wxEntryStart(argc, argv)) {
135 wxLogDebug("Creating application");
136 // create the application object or ensure that one already exists
139 // The app may have declared a global application object, but we recommend
140 // the IMPLEMENT_APP macro is used instead, which sets an initializer
141 // function for delayed, dynamic app object construction.
142 wxCHECK_MSG( wxApp::GetInitializerFunction(), 0,
143 wxT("No initializer - use IMPLEMENT_APP macro.") );
145 wxTheApp = (wxApp*) (*wxApp::GetInitializerFunction()) ();
148 wxCHECK_MSG( wxTheApp, 0, wxT("You have to define an instance of wxApp!") );
150 // Mac OS X passes a process serial number command line argument when
151 // the application is launched from the Finder. This argument must be
152 // removed from the command line arguments before being handled by the
153 // application (otherwise applications would need to handle it)
157 strncpy(theArg, argv[1], 5);
159 if (strcmp(theArg, "-psn_") == 0) {
160 // assume the argument is always the only one and remove it
165 wxTheApp->argc = argc;
166 wxTheApp->argv = argv;
168 wxLogDebug("initializing gui");
169 // GUI-specific initialization, such as creating an app context.
172 // Here frames insert themselves automatically
173 // into wxTopLevelWindows by getting created
178 wxLogDebug("Time to run");
179 retValue = wxTheApp->OnRun();
181 wxWindow *topWindow = wxTheApp->GetTopWindow();
184 // Forcibly delete the window.
185 if ( topWindow->IsKindOf(CLASSINFO(wxFrame)) ||
186 topWindow->IsKindOf(CLASSINFO(wxDialog)) )
188 topWindow->Close(TRUE);
193 wxTheApp->SetTopWindow(NULL);
204 // ----------------------------------------------------------------------------
206 // ----------------------------------------------------------------------------
209 wxTheApp->CocoaRequestIdle();
214 wxLogError(_("Fatal error: exiting"));
220 // ============================================================================
221 // wxApp implementation
222 // ============================================================================
224 // ----------------------------------------------------------------------------
225 // wxApp Static member initialization
226 // ----------------------------------------------------------------------------
227 wxAppInitializerFunction wxAppBase::m_appInitFn = (wxAppInitializerFunction) NULL;
229 #if !USE_SHARED_LIBRARY
230 IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
231 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
232 EVT_IDLE(wxApp::OnIdle)
233 // EVT_END_SESSION(wxApp::OnEndSession)
234 // EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
238 // ----------------------------------------------------------------------------
239 // wxApp static functions
240 // ----------------------------------------------------------------------------
241 /*static*/ bool wxApp::Initialize()
243 wxPoseAsInitializer::InitializePosers();
244 wxClassInfo::InitializeClasses();
247 wxPendingEventsLocker = new wxCriticalSection;
250 wxTheColourDatabase = new wxColourDatabase(wxKEY_STRING);
251 wxTheColourDatabase->Initialize();
253 wxInitializeStockLists();
254 wxInitializeStockObjects();
256 #if wxUSE_WX_RESOURCES
257 wxInitializeResourceSystem();
260 wxBitmap::InitStandardHandlers();
262 wxModule::RegisterModules();
263 if (!wxModule::InitializeModules()) {
269 /*static*/ void wxApp::CleanUp()
271 wxModule::CleanUpModules();
273 #if wxUSE_WX_RESOURCES
274 wxCleanUpResourceSystem();
277 wxDeleteStockObjects() ;
279 // Destroy all GDI lists, etc.
280 wxDeleteStockLists();
282 delete wxTheColourDatabase;
283 wxTheColourDatabase = NULL;
285 wxBitmap::CleanUpHandlers();
287 delete wxPendingEvents;
290 delete wxPendingEventsLocker;
291 // If we don't do the following, we get an apparent memory leak.
292 ((wxEvtHandler&) wxDefaultValidator).ClearEventLocker();
295 wxClassInfo::CleanUpClasses();
300 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
301 // At this point we want to check if there are any memory
302 // blocks that aren't part of the wxDebugContext itself,
303 // as a special case. Then when dumping we need to ignore
304 // wxDebugContext, too.
305 if (wxDebugContext::CountObjectsLeft(TRUE) > 0)
307 wxLogDebug(wxT("There were memory leaks."));
308 wxDebugContext::Dump();
309 wxDebugContext::PrintStatistics();
311 // wxDebugContext::SetStream(NULL, NULL);
315 // do it as the very last thing because everything else can log messages
316 delete wxLog::SetActiveTarget(NULL);
320 // ----------------------------------------------------------------------------
322 // ----------------------------------------------------------------------------
330 #if WXWIN_COMPATIBILITY_2_2
331 m_wantDebugOutput = TRUE;
339 void wxApp::CocoaInstallIdleHandler()
341 wxLogDebug("wxApp::CocoaInstallIdleHandler");
343 // Call doIdle for EVERYTHING dammit
344 // We'd need Foundation/NSConnection.h for this next constant, do we need it?
345 [[ NSRunLoop currentRunLoop ] performSelector:@selector(doIdle:) target:m_cocoaApp argument:NULL order:0 modes:[NSArray arrayWithObjects:NSDefaultRunLoopMode, /* NSConnectionReplyRunLoopMode,*/ NSModalPanelRunLoopMode, /**/NSEventTrackingRunLoopMode,/**/ nil] ];
348 bool wxApp::OnInitGui()
350 if(!wxAppBase::OnInitGui())
353 // Create the app using the sharedApplication method
354 m_cocoaApp = [NSApplication sharedApplication];
355 // [ m_cocoaApp setDelegate:m_cocoaApp ];
357 wxLogDebug("Just for kicks");
358 [ m_cocoaApp performSelector:@selector(doIdle:) withObject:NULL ];
359 wxLogDebug("okay.. done now");
366 if(!wxAppBase::OnInit())
372 bool wxApp::Initialized()
380 int wxApp::MainLoop()
386 // Returns TRUE if more time is needed.
387 bool wxApp::ProcessIdle()
390 event.SetEventObject(this);
393 return event.MoreRequested();
396 void wxApp::ExitMainLoop()
398 wxLogDebug("wxApp::ExitMailLoop m_isIdle=%d, isRunning=%d",(int)m_isIdle,(int)[m_cocoaApp isRunning]);
399 // CocoaInstallRequestedIdleHandler();
401 // [[ NSRunLoop currentRunLoop ] performSelector:@selector(doIdle:) target:m_cocoaApp argument:NULL order:0 modes:[NSArray arrayWithObjects:NSDefaultRunLoopMode, /* NSConnectionReplyRunLoopMode, NSModalPanelRunLoopMode, NSEventTrackingRunLoopMode,*/ nil] ];
402 // actually.. we WANT the idle event
406 [[ NSRunLoop currentRunLoop ] cancelPerformSelector:@selector(doIdle:) target:m_cocoaApp argument:NULL];
408 [m_cocoaApp terminate: m_cocoaApp];
411 // Is a message/event pending?
412 bool wxApp::Pending()
417 // Dispatch a message.
418 void wxApp::Dispatch()
422 void wxApp::OnIdle(wxIdleEvent& event)
424 wxLogDebug("wxApp::OnIdle");
425 static bool s_inOnIdle = FALSE;
427 // Avoid recursion (via ProcessEvent default case)
433 DeletePendingObjects();
435 // flush the logged messages if any
436 wxLog *pLog = wxLog::GetActiveTarget();
437 if ( pLog != NULL && pLog->HasPendingMessages() )
440 // Send OnIdle events to all windows
441 bool needMore = SendIdleEvents();
444 event.RequestMore(TRUE);
449 // Send idle event to all top-level windows
450 bool wxApp::SendIdleEvents()
452 bool needMore = FALSE;
453 wxWindowList::Node* node = wxTopLevelWindows.GetFirst();
456 wxWindow* win = node->GetData();
457 if (SendIdleEvents(win))
460 node = node->GetNext();
465 // Send idle event to window and all subwindows
466 bool wxApp::SendIdleEvents(wxWindow* win)
468 // wxLogDebug("SendIdleEvents win=%p",win);
469 bool needMore = FALSE;
472 event.SetEventObject(win);
473 win->ProcessEvent(event);
475 if (event.MoreRequested())
478 wxWindowList::Node* node = win->GetChildren().GetFirst();
481 // wxLogDebug("child=%p",node->Data());
482 wxWindow* win = node->GetData();
483 if (SendIdleEvents(win))
486 node = node->GetNext();
491 // Yield to other processes
493 bool wxApp::Yield(bool onlyIfNeeded)
496 static bool s_inYield = false;
499 // disable log flushing from here because a call to wxYield() shouldn't
500 // normally result in message boxes popping up &c
508 wxFAIL_MSG( wxT("wxYield called recursively" ) );
516 wxLogDebug("WARNING: SUPPOSED to have yielded!");
517 // FIXME: Do something!
520 // let the logs be flashed again
529 void wxApp::DeletePendingObjects()
531 wxNode *node = wxPendingDelete.GetFirst();
534 wxObject *obj = (wxObject *)node->GetData();
538 if (wxPendingDelete.Find(obj))
541 node = wxPendingDelete.GetFirst();
545 // platform specifics