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