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"
29 #include "wx/cocoa/ObjcPose.h"
32 #if wxUSE_WX_RESOURCES
33 # include "wx/resource.h"
36 #import <AppKit/NSApplication.h>
37 #import <Foundation/NSRunLoop.h>
38 #import <Foundation/NSArray.h>
40 // ----------------------------------------------------------------------------
42 // ----------------------------------------------------------------------------
44 wxApp *wxTheApp = NULL;
45 wxPoseAsInitializer *wxPoseAsInitializer::sm_first = NULL;
47 @interface wxPoserNSApplication : NSApplication
51 - (void)doIdle: (id)data;
52 - (void)finishLaunching;
53 - (void)sendEvent: (NSEvent*)anEvent;
54 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication;
55 @end // wxPoserNSApplication
57 @implementation wxPoserNSApplication : NSApplication
59 - (void)doIdle: (id)data
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
67 wxLogDebug("Looping for idle events");
69 if( [rl runMode:[rl currentMode] beforeDate:[NSDate distantPast]])
71 wxLogDebug("Found actual work to do");
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();
81 - (void)finishLaunching
83 wxLogDebug("finishLaunching");
84 bool initsuccess = wxTheApp->OnInit();
88 [super finishLaunching];
91 - (void)sendEvent: (NSEvent*)anEvent
93 wxLogDebug("SendEvent");
94 wxTheApp->CocoaInstallRequestedIdleHandler();
95 [super sendEvent: anEvent];
98 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
100 BOOL ret = wxTheApp->GetExitOnFrameDelete();
101 wxLogDebug("applicationShouldTermintaeAfterLastWindowClosed=%d",ret);
105 @end // wxPoserNSApplication
106 WX_IMPLEMENT_POSER(wxPoserNSApplication);
108 // ============================================================================
110 // ============================================================================
112 //----------------------------------------------------------------------
114 //----------------------------------------------------------------------
116 int WXDLLEXPORT wxEntryStart( int WXUNUSED(argc), char *WXUNUSED(argv)[] )
118 return wxApp::Initialize();
121 int WXDLLEXPORT wxEntryInitGui()
123 return wxTheApp->OnInitGui();
126 void WXDLLEXPORT wxEntryCleanup()
131 int wxEntry( int argc, char *argv[])
133 if (!wxEntryStart(argc, argv)) {
136 wxLogDebug("Creating application");
137 // create the application object or ensure that one already exists
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.") );
146 wxTheApp = (wxApp*) (*wxApp::GetInitializerFunction()) ();
149 wxCHECK_MSG( wxTheApp, 0, wxT("You have to define an instance of wxApp!") );
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)
158 strncpy(theArg, argv[1], 5);
160 if (strcmp(theArg, "-psn_") == 0) {
161 // assume the argument is always the only one and remove it
166 wxTheApp->argc = argc;
167 wxTheApp->argv = argv;
169 wxLogDebug("initializing gui");
170 // GUI-specific initialization, such as creating an app context.
173 // Here frames insert themselves automatically
174 // into wxTopLevelWindows by getting created
179 wxLogDebug("Time to run");
180 retValue = wxTheApp->OnRun();
182 wxWindow *topWindow = wxTheApp->GetTopWindow();
185 // Forcibly delete the window.
186 if ( topWindow->IsKindOf(CLASSINFO(wxFrame)) ||
187 topWindow->IsKindOf(CLASSINFO(wxDialog)) )
189 topWindow->Close(TRUE);
194 wxTheApp->SetTopWindow(NULL);
205 // ----------------------------------------------------------------------------
207 // ----------------------------------------------------------------------------
210 wxTheApp->CocoaRequestIdle();
215 wxLogError(_("Fatal error: exiting"));
221 // ============================================================================
222 // wxApp implementation
223 // ============================================================================
225 // ----------------------------------------------------------------------------
226 // wxApp Static member initialization
227 // ----------------------------------------------------------------------------
228 wxAppInitializerFunction wxAppBase::m_appInitFn = (wxAppInitializerFunction) NULL;
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)
239 // ----------------------------------------------------------------------------
240 // wxApp static functions
241 // ----------------------------------------------------------------------------
242 /*static*/ bool wxApp::Initialize()
244 wxPoseAsInitializer::InitializePosers();
245 wxClassInfo::InitializeClasses();
248 wxPendingEventsLocker = new wxCriticalSection;
251 wxTheColourDatabase = new wxColourDatabase(wxKEY_STRING);
252 wxTheColourDatabase->Initialize();
254 wxInitializeStockLists();
255 wxInitializeStockObjects();
257 #if wxUSE_WX_RESOURCES
258 wxInitializeResourceSystem();
261 wxBitmap::InitStandardHandlers();
263 wxModule::RegisterModules();
264 if (!wxModule::InitializeModules()) {
270 /*static*/ void wxApp::CleanUp()
272 wxModule::CleanUpModules();
274 #if wxUSE_WX_RESOURCES
275 wxCleanUpResourceSystem();
278 wxDeleteStockObjects() ;
280 // Destroy all GDI lists, etc.
281 wxDeleteStockLists();
283 delete wxTheColourDatabase;
284 wxTheColourDatabase = NULL;
286 wxBitmap::CleanUpHandlers();
288 delete wxPendingEvents;
291 delete wxPendingEventsLocker;
292 // If we don't do the following, we get an apparent memory leak.
293 ((wxEvtHandler&) wxDefaultValidator).ClearEventLocker();
296 wxClassInfo::CleanUpClasses();
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)
308 wxLogDebug(wxT("There were memory leaks."));
309 wxDebugContext::Dump();
310 wxDebugContext::PrintStatistics();
312 // wxDebugContext::SetStream(NULL, NULL);
315 wxDC::CocoaShutdownTextSystem();
317 // do it as the very last thing because everything else can log messages
318 delete wxLog::SetActiveTarget(NULL);
322 // ----------------------------------------------------------------------------
324 // ----------------------------------------------------------------------------
332 #if WXWIN_COMPATIBILITY_2_2
333 m_wantDebugOutput = TRUE;
341 void wxApp::CocoaInstallIdleHandler()
343 wxLogDebug("wxApp::CocoaInstallIdleHandler");
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] ];
350 bool wxApp::OnInitGui()
352 if(!wxAppBase::OnInitGui())
355 // Create the app using the sharedApplication method
356 m_cocoaApp = [NSApplication sharedApplication];
357 wxDC::CocoaInitializeTextSystem();
358 // [ m_cocoaApp setDelegate:m_cocoaApp ];
360 wxLogDebug("Just for kicks");
361 [ m_cocoaApp performSelector:@selector(doIdle:) withObject:NULL ];
362 wxLogDebug("okay.. done now");
369 if(!wxAppBase::OnInit())
375 bool wxApp::Initialized()
383 int wxApp::MainLoop()
389 // Returns TRUE if more time is needed.
390 bool wxApp::ProcessIdle()
393 event.SetEventObject(this);
396 return event.MoreRequested();
399 void wxApp::ExitMainLoop()
401 wxLogDebug("wxApp::ExitMailLoop m_isIdle=%d, isRunning=%d",(int)m_isIdle,(int)[m_cocoaApp isRunning]);
402 // CocoaInstallRequestedIdleHandler();
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
409 [[ NSRunLoop currentRunLoop ] cancelPerformSelector:@selector(doIdle:) target:m_cocoaApp argument:NULL];
411 [m_cocoaApp terminate: m_cocoaApp];
414 // Is a message/event pending?
415 bool wxApp::Pending()
420 // Dispatch a message.
421 void wxApp::Dispatch()
425 void wxApp::OnIdle(wxIdleEvent& event)
427 wxLogDebug("wxApp::OnIdle");
428 static bool s_inOnIdle = FALSE;
430 // Avoid recursion (via ProcessEvent default case)
436 DeletePendingObjects();
438 // flush the logged messages if any
439 wxLog *pLog = wxLog::GetActiveTarget();
440 if ( pLog != NULL && pLog->HasPendingMessages() )
443 // Send OnIdle events to all windows
444 bool needMore = SendIdleEvents();
447 event.RequestMore(TRUE);
452 // Send idle event to all top-level windows
453 bool wxApp::SendIdleEvents()
455 bool needMore = FALSE;
456 wxWindowList::Node* node = wxTopLevelWindows.GetFirst();
459 wxWindow* win = node->GetData();
460 if (SendIdleEvents(win))
463 node = node->GetNext();
468 // Send idle event to window and all subwindows
469 bool wxApp::SendIdleEvents(wxWindow* win)
471 // wxLogDebug("SendIdleEvents win=%p",win);
472 bool needMore = FALSE;
475 event.SetEventObject(win);
476 win->ProcessEvent(event);
478 if (event.MoreRequested())
481 wxWindowList::Node* node = win->GetChildren().GetFirst();
484 // wxLogDebug("child=%p",node->Data());
485 wxWindow* win = node->GetData();
486 if (SendIdleEvents(win))
489 node = node->GetNext();
494 // Yield to other processes
496 bool wxApp::Yield(bool onlyIfNeeded)
499 static bool s_inYield = false;
502 // disable log flushing from here because a call to wxYield() shouldn't
503 // normally result in message boxes popping up &c
511 wxFAIL_MSG( wxT("wxYield called recursively" ) );
519 wxLogDebug("WARNING: SUPPOSED to have yielded!");
520 // FIXME: Do something!
523 // let the logs be flashed again
532 void wxApp::DeletePendingObjects()
534 wxNode *node = wxPendingDelete.GetFirst();
537 wxObject *obj = (wxObject *)node->GetData();
541 if (wxPendingDelete.Find(obj))
544 node = wxPendingDelete.GetFirst();
548 // platform specifics