]> git.saurik.com Git - wxWidgets.git/blame - src/cocoa/app.mm
added assert to check that notebook page does have notebook as parent; removed duplic...
[wxWidgets.git] / src / cocoa / app.mm
CommitLineData
fb896a32
DE
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"
891d0563 26 #include "wx/dc.h"
fb896a32
DE
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
44wxApp *wxTheApp = NULL;
45wxPoseAsInitializer *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
106WX_IMPLEMENT_POSER(wxPoserNSApplication);
107
108// ============================================================================
109// functions
110// ============================================================================
111
112//----------------------------------------------------------------------
113// wxEntry
114//----------------------------------------------------------------------
115
116int WXDLLEXPORT wxEntryStart( int WXUNUSED(argc), char *WXUNUSED(argv)[] )
117{
118 return wxApp::Initialize();
119}
120
121int WXDLLEXPORT wxEntryInitGui()
122{
123 return wxTheApp->OnInitGui();
124}
125
126void WXDLLEXPORT wxEntryCleanup()
127{
128 wxApp::CleanUp();
129}
130
131int 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// ----------------------------------------------------------------------------
208void wxWakeUpIdle()
209{
210 wxTheApp->CocoaRequestIdle();
211}
212
213void 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// ----------------------------------------------------------------------------
228wxAppInitializerFunction wxAppBase::m_appInitFn = (wxAppInitializerFunction) NULL;
229
230#if !USE_SHARED_LIBRARY
231IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
232BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
233 EVT_IDLE(wxApp::OnIdle)
234// EVT_END_SESSION(wxApp::OnEndSession)
235// EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
236END_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
891d0563 315 wxDC::CocoaShutdownTextSystem();
fb896a32
DE
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
326wxApp::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
341void 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
350bool wxApp::OnInitGui()
351{
352 if(!wxAppBase::OnInitGui())
353 return FALSE;
354
355 // Create the app using the sharedApplication method
356 m_cocoaApp = [NSApplication sharedApplication];
891d0563 357 wxDC::CocoaInitializeTextSystem();
fb896a32
DE
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
367bool wxApp::OnInit()
368{
369 if(!wxAppBase::OnInit())
370 return FALSE;
371
372 return TRUE;
373}
374
375bool wxApp::Initialized()
376{
377 if (GetTopWindow())
378 return TRUE;
379 else
380 return FALSE;
381}
382
383int wxApp::MainLoop()
384{
385 [m_cocoaApp run];
386 return 0;
387}
388
389// Returns TRUE if more time is needed.
390bool wxApp::ProcessIdle()
391{
392 wxIdleEvent event;
393 event.SetEventObject(this);
394 ProcessEvent(event);
395
396 return event.MoreRequested();
397}
398
399void 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?
415bool wxApp::Pending()
416{
417 return 0;
418}
419
420// Dispatch a message.
421void wxApp::Dispatch()
422{
423}
424
425void 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
453bool 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
469bool 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
496bool 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
532void 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