wxApp development for WXPM
[wxWidgets.git] / src / os2 / app.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: app.cpp
3 // Purpose: wxApp
4 // Author: David Webster
5 // Modified by:
6 // Created: 10/13/99
7 // RCS-ID: $Id$
8 // Copyright: (c) David Webster
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #ifndef WX_PRECOMP
16 #include "wx/frame.h"
17 #include "wx/app.h"
18 #include "wx/utils.h"
19 #include "wx/gdicmn.h"
20 #include "wx/pen.h"
21 #include "wx/brush.h"
22 #include "wx/cursor.h"
23 #include "wx/icon.h"
24 #include "wx/palette.h"
25 #include "wx/dc.h"
26 #include "wx/dialog.h"
27 #include "wx/msgdlg.h"
28 #include "wx/intl.h"
29 #include "wx/dynarray.h"
30 # include "wx/wxchar.h"
31 # include "wx/icon.h"
32 #endif
33
34 #include "wx/log.h"
35 #include "wx/module.h"
36
37 #include "wx/os2/private.h"
38
39 #if wxUSE_THREADS
40 #include "wx/thread.h"
41
42 // define the array of QMSG strutures
43 WX_DECLARE_OBJARRAY(QMSG, wxMsgArray);
44
45 #include "wx/arrimpl.cpp"
46
47 WX_DEFINE_OBJARRAY(wxMsgArray);
48 #endif // wxUSE_THREADS
49
50 #if wxUSE_WX_RESOURCES
51 #include "wx/resource.h"
52 #endif
53
54 #include <string.h>
55 #include <ctype.h>
56
57 // ---------------------------------------------------------------------------
58 // global variables
59 // ---------------------------------------------------------------------------
60
61 extern wxChar* wxBuffer;
62 extern wxChar* wxOsVersion;
63 extern wxList* wxWinHandleList;
64 extern wxList WXDLLEXPORT wxPendingDelete;
65 extern void wxSetKeyboardHook(bool doIt);
66 extern wxCursor* g_globalCursor;
67
68 HINSTANCE wxhInstance = 0;
69 QMSG svCurrentMsg;
70 wxApp* wxTheApp = NULL;
71
72 // FIXME why not const? and not static?
73
74 // NB: all "NoRedraw" classes must have the same names as the "normal" classes
75 // with NR suffix - wxWindow::OS2Create() supposes this
76 wxChar wxFrameClassName[] = wxT("wxFrameClass");
77 wxChar wxFrameClassNameNoRedraw[] = wxT("wxFrameClassNR");
78 wxChar wxMDIFrameClassName[] = wxT("wxMDIFrameClass");
79 wxChar wxMDIFrameClassNameNoRedraw[] = wxT("wxMDIFrameClassNR");
80 wxChar wxMDIChildFrameClassName[] = wxT("wxMDIChildFrameClass");
81 wxChar wxMDIChildFrameClassNameNoRedraw[] = wxT("wxMDIChildFrameClassNR");
82 wxChar wxPanelClassName[] = wxT("wxPanelClass");
83 wxChar wxCanvasClassName[] = wxT("wxCanvasClass");
84
85 HICON wxSTD_FRAME_ICON = (HICON) NULL;
86 HICON wxSTD_MDICHILDFRAME_ICON = (HICON) NULL;
87 HICON wxSTD_MDIPARENTFRAME_ICON = (HICON) NULL;
88
89 HICON wxDEFAULT_FRAME_ICON = (HICON) NULL;
90 HICON wxDEFAULT_MDICHILDFRAME_ICON = (HICON) NULL;
91 HICON wxDEFAULT_MDIPARENTFRAME_ICON = (HICON) NULL;
92
93 HBRUSH wxDisableButtonBrush = (HBRUSH) 0;
94
95 MRESULT wxWndProc(HWND, UINT, MPARAM, MPARAM);
96
97 // ===========================================================================
98 // implementation
99 // ===========================================================================
100
101 // ---------------------------------------------------------------------------
102 // wxApp
103 // ---------------------------------------------------------------------------
104
105 #if !USE_SHARED_LIBRARY
106 IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
107
108 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
109 EVT_IDLE(wxApp::OnIdle)
110 EVT_END_SESSION(wxApp::OnEndSession)
111 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
112 END_EVENT_TABLE()
113 #endif
114
115 //// Initialize
116 bool wxApp::Initialize(
117 HAB vHab
118 )
119 {
120 // Some people may wish to use this, but
121 // probably it shouldn't be here by default.
122 #ifdef __WXDEBUG__
123 // wxRedirectIOToConsole();
124 #endif
125
126 wxBuffer = new wxChar[1500]; // FIXME; why?
127
128 wxClassInfo::InitializeClasses();
129
130 #if wxUSE_RESOURCES
131 wxGetResource(wxT("wxWindows"), wxT("OsVersion"), &wxOsVersion);
132 #endif
133
134 // I'm annoyed ... I don't know where to put this and I don't want to
135 // create a module for that as it's part of the core.
136 wxTheColourDatabase = new wxColourDatabase(wxKEY_STRING);
137 wxTheColourDatabase->Initialize();
138
139 wxInitializeStockLists();
140 wxInitializeStockObjects();
141
142 #if wxUSE_WX_RESOURCES
143 wxInitializeResourceSystem();
144 #endif
145
146 wxBitmap::InitStandardHandlers();
147
148 g_globalCursor = new wxCursor;
149
150 #if 0
151 wxSTD_FRAME_ICON = ::WinLoadFileIcon(wxT("wxSTD_FRAME"), TRUE);
152 wxSTD_MDIPARENTFRAME_ICON = ::WinLoadFileIcon(wxT("wxSTD_MDIPARENTFRAME"), TRUE);
153 wxSTD_MDICHILDFRAME_ICON = ::WinLoadFileIcon(wxT("wxSTD_MDICHILDFRAME"), TRUE);
154
155 wxDEFAULT_FRAME_ICON = ::WinLoadFileIcon(wxT("wxDEFAULT_FRAME"), TRUE);
156 wxDEFAULT_MDIPARENTFRAME_ICON = ::WinLoadFileIcon(wxT("wxDEFAULT_MDIPARENTFRAME"), TRUE);
157 wxDEFAULT_MDICHILDFRAME_ICON = ::WinLoadFileIcon(wxT("wxDEFAULT_MDICHILDFRAME"), TRUE);
158 #endif
159 RegisterWindowClasses(vHab);
160 wxWinHandleList = new wxList(wxKEY_INTEGER);
161
162 // This is to foil optimizations in Visual C++ that throw out dummy.obj.
163 // PLEASE DO NOT ALTER THIS.
164 #if !defined(WXMAKINGDLL)
165 extern char wxDummyChar;
166 if (wxDummyChar) wxDummyChar++;
167 #endif
168
169 wxSetKeyboardHook(TRUE);
170
171 wxModule::RegisterModules();
172 if (!wxModule::InitializeModules())
173 return FALSE;
174 return TRUE;
175 }
176
177 // ---------------------------------------------------------------------------
178 // RegisterWindowClasses
179 // ---------------------------------------------------------------------------
180
181 // TODO we should only register classes really used by the app. For this it
182 // would be enough to just delay the class registration until an attempt
183 // to create a window of this class is made.
184 bool wxApp::RegisterWindowClasses(
185 HAB vHab
186 )
187 {
188
189 if (!::WinRegisterClass( vHab
190 ,wxFrameClassName
191 ,(PFNWP)wxWndProc
192 ,CS_SIZEREDRAW | CS_SYNCPAINT | CS_HITTEST | CS_CLIPCHILDREN | CS_FRAME
193 ,0
194 ))
195 {
196 wxLogLastError("RegisterClass(frame)");
197
198 return FALSE;
199 }
200
201 if (!::WinRegisterClass( vHab
202 ,wxFrameClassNameNoRedraw
203 ,(PFNWP)wxWndProc
204 ,CS_HITTEST | CS_CLIPCHILDREN | CS_FRAME
205 ,0
206 ))
207 {
208 wxLogLastError("RegisterClass(no redraw frame)");
209
210 return FALSE;
211 }
212
213 if (!::WinRegisterClass( vHab
214 ,wxMDIFrameClassName
215 ,(PFNWP)wxWndProc
216 ,CS_SIZEREDRAW | CS_SYNCPAINT | CS_HITTEST | CS_CLIPCHILDREN | CS_FRAME
217 ,0
218 ))
219 {
220 wxLogLastError("RegisterClass(MDI parent)");
221
222 return FALSE;
223 }
224
225 if (!::WinRegisterClass( vHab
226 ,wxMDIFrameClassNameNoRedraw
227 ,(PFNWP)wxWndProc
228 ,CS_HITTEST | CS_CLIPCHILDREN | CS_FRAME
229 ,0
230 ))
231 {
232 wxLogLastError("RegisterClass(no redraw MDI parent)");
233
234 return FALSE;
235 }
236
237 if (!::WinRegisterClass( vHab
238 ,wxMDIChildFrameClassName
239 ,(PFNWP)wxWndProc
240 ,CS_MOVENOTIFY | CS_SIZEREDRAW | CS_SYNCPAINT | CS_HITTEST | CS_CLIPSIBLINGS | CS_FRAME
241 ,0
242 ))
243 {
244 wxLogLastError("RegisterClass(MDI child)");
245
246 return FALSE;
247 }
248
249 if (!::WinRegisterClass( vHab
250 ,wxMDIChildFrameClassNameNoRedraw
251 ,(PFNWP)wxWndProc
252 ,CS_HITTEST | CS_CLIPSIBLINGS | CS_FRAME
253 ,0
254 ))
255 {
256 wxLogLastError("RegisterClass(no redraw MDI child)");
257
258 return FALSE;
259 }
260
261 if (!::WinRegisterClass( vHab
262 ,wxPanelClassName
263 ,(PFNWP)wxWndProc
264 ,CS_MOVENOTIFY | CS_SIZEREDRAW | CS_HITTEST | CS_CLIPSIBLINGS | CS_SAVEBITS | CS_SYNCPAINT
265 ,0
266 ))
267 {
268 wxLogLastError("RegisterClass(Panel)");
269
270 return FALSE;
271 }
272
273 if (!::WinRegisterClass( vHab
274 ,wxCanvasClassName
275 ,(PFNWP)wxWndProc
276 ,CS_MOVENOTIFY | CS_SIZEREDRAW | CS_HITTEST | CS_CLIPSIBLINGS | CS_SAVEBITS | CS_SYNCPAINT
277 ,0
278 ))
279 {
280 wxLogLastError("RegisterClass(Canvas)");
281
282 return FALSE;
283 }
284 return TRUE;
285 }
286
287 //// Cleans up any wxWindows internal structures left lying around
288
289 void wxApp::CleanUp()
290 {
291 //// COMMON CLEANUP
292
293 #if wxUSE_LOG
294 // flush the logged messages if any and install a 'safer' log target: the
295 // default one (wxLogGui) can't be used after the resources are freed just
296 // below and the user suppliedo ne might be even more unsafe (using any
297 // wxWindows GUI function is unsafe starting from now)
298 wxLog::DontCreateOnDemand();
299
300 // this will flush the old messages if any
301 delete wxLog::SetActiveTarget(new wxLogStderr);
302 #endif // wxUSE_LOG
303
304 // One last chance for pending objects to be cleaned up
305 wxTheApp->DeletePendingObjects();
306
307 wxModule::CleanUpModules();
308
309 #if wxUSE_WX_RESOURCES
310 wxCleanUpResourceSystem();
311
312 // wxDefaultResourceTable->ClearTable();
313 #endif
314
315 // Indicate that the cursor can be freed, so that cursor won't be deleted
316 // by deleting the bitmap list before g_globalCursor goes out of scope
317 // (double deletion of the cursor).
318 wxSetCursor(wxNullCursor);
319 delete g_globalCursor;
320 g_globalCursor = NULL;
321
322 wxDeleteStockObjects();
323
324 // Destroy all GDI lists, etc.
325 wxDeleteStockLists();
326
327 delete wxTheColourDatabase;
328 wxTheColourDatabase = NULL;
329
330 wxBitmap::CleanUpHandlers();
331
332 delete[] wxBuffer;
333 wxBuffer = NULL;
334
335 //// WINDOWS-SPECIFIC CLEANUP
336
337 wxSetKeyboardHook(FALSE);
338
339 if (wxSTD_FRAME_ICON)
340 ::WinFreeFileIcon(wxSTD_FRAME_ICON);
341 if (wxSTD_MDICHILDFRAME_ICON)
342 ::WinFreeFileIcon(wxSTD_MDICHILDFRAME_ICON);
343 if (wxSTD_MDIPARENTFRAME_ICON)
344 ::WinFreeFileIcon(wxSTD_MDIPARENTFRAME_ICON);
345
346 if (wxDEFAULT_FRAME_ICON)
347 ::WinFreeFileIcon(wxDEFAULT_FRAME_ICON);
348 if (wxDEFAULT_MDICHILDFRAME_ICON)
349 ::WinFreeFileIcon(wxDEFAULT_MDICHILDFRAME_ICON);
350 if (wxDEFAULT_MDIPARENTFRAME_ICON)
351 ::WinFreeFileIcon(wxDEFAULT_MDIPARENTFRAME_ICON);
352
353 if ( wxDisableButtonBrush )
354 {
355 // TODO: ::DeleteObject( wxDisableButtonBrush );
356 }
357
358 if (wxWinHandleList)
359 delete wxWinHandleList;
360
361 // GL: I'm annoyed ... I don't know where to put this and I don't want to
362 // create a module for that as it's part of the core.
363 #if wxUSE_THREADS
364 delete wxPendingEvents;
365 delete wxPendingEventsLocker;
366 // If we don't do the following, we get an apparent memory leak.
367 ((wxEvtHandler&) wxDefaultValidator).ClearEventLocker();
368 #endif
369
370 wxClassInfo::CleanUpClasses();
371
372 delete wxTheApp;
373 wxTheApp = NULL;
374
375 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
376 // At this point we want to check if there are any memory
377 // blocks that aren't part of the wxDebugContext itself,
378 // as a special case. Then when dumping we need to ignore
379 // wxDebugContext, too.
380 if (wxDebugContext::CountObjectsLeft(TRUE) > 0)
381 {
382 wxLogDebug(wxT("There were memory leaks."));
383 wxDebugContext::Dump();
384 wxDebugContext::PrintStatistics();
385 }
386 // wxDebugContext::SetStream(NULL, NULL);
387 #endif
388
389 #if wxUSE_LOG
390 // do it as the very last thing because everything else can log messages
391 delete wxLog::SetActiveTarget(NULL);
392 #endif // wxUSE_LOG
393 }
394
395 int wxEntry(
396 int argc
397 , char* argv[]
398 )
399 {
400 HAB vHab;
401
402 if (!wxApp::Initialize(vHab))
403 return 0;
404
405 //
406 // create the application object or ensure that one already exists
407 //
408 if (!wxTheApp)
409 {
410 wxCHECK_MSG( wxApp::GetInitializerFunction()
411 ,-1
412 ,wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n")
413 );
414
415 wxAppInitializerFunction fnAppIni = wxApp::GetInitializerFunction();
416 wxObject* pTest_app = fnAppIni();
417
418 wxTheApp = (wxApp*)pTest_app;
419 }
420 wxCHECK_MSG( wxTheApp, -1, wxT("wxWindows error: no application object") );
421 wxTheApp->argc = argc;
422
423 #if wxUSE_UNICODE
424 wxTheApp->argv = new wxChar*[argc+1];
425
426 int nArgc = 0;
427
428 while (nArgc < argc)
429 {
430 wxTheApp->argv[nArgc] = wxStrdup(wxConvLibc.cMB2WX(argv[nArgc]));
431 nArgc++;
432 }
433 wxTheApp->argv[nArgc] = (wxChar *)NULL;
434 #else
435 wxTheApp->argv = argv;
436 #endif
437
438 wxString sName(wxFileNameFromPath(argv[0]));
439
440 wxStripExtension(sName);
441 wxTheApp->SetAppName(sName);
442
443 int nRetValue = 0;
444
445 if (!wxTheApp->OnInitGui())
446 nRetValue = -1;
447
448 if (nRetValue == 0)
449 {
450 if (wxTheApp->OnInit())
451 {
452 nRetValue = -1;
453 }
454 }
455
456 if (nRetValue == 0)
457 {
458 wxWindow* pTopWindow = wxTheApp->GetTopWindow();
459
460 if (pTopWindow)
461 {
462 // Forcibly delete the window.
463 if (pTopWindow->IsKindOf(CLASSINFO(wxFrame)) ||
464 pTopWindow->IsKindOf(CLASSINFO(wxDialog)) )
465 {
466 pTopWindow->Close(TRUE);
467 wxTheApp->DeletePendingObjects();
468 }
469 else
470 {
471 delete pTopWindow;
472 wxTheApp->SetTopWindow(NULL);
473 }
474 }
475 }
476 wxTheApp->OnExit();
477 wxApp::CleanUp();
478 return(nRetValue);
479 }
480
481 bool wxApp::OnInitGui()
482 {
483 m_vHab = WinInitialize(0);
484 m_hMq = WinCreateMsgQueue(m_vHab, 0);
485
486 return TRUE;
487 }
488
489 //
490 // Static member initialization
491 //
492 wxAppInitializerFunction wxAppBase::m_appInitFn = (wxAppInitializerFunction) NULL;
493
494 wxApp::wxApp()
495 {
496 m_topWindow = NULL;
497 wxTheApp = this;
498 m_wantDebugOutput = TRUE;
499
500 argc = 0;
501 argv = NULL;
502 m_nPrintMode = wxPRINT_WINDOWS;
503 m_exitOnFrameDelete = TRUE;
504 m_bAuto3D = TRUE;
505 }
506
507 wxApp::~wxApp()
508 {
509 // Delete command-line args
510 int i;
511 for (i = 0; i < argc; i++)
512 {
513 delete[] argv[i];
514 }
515 delete[] argv;
516 }
517
518 bool wxApp::Initialized()
519 {
520 if (GetTopWindow())
521 return TRUE;
522 else
523 return FALSE;
524 }
525
526 //
527 // Get and process a message, returning FALSE if WM_QUIT
528 // received (and also set the flag telling the app to exit the main loop)
529 //
530 bool wxApp::DoMessage()
531 {
532 BOOL bRc = ::WinGetMsg(m_vHab, &m_vMsg, HWND(NULL), 0, 0);
533
534 if (bRc == 0)
535 {
536 // got WM_QUIT
537 m_bKeepGoing = FALSE;
538 return FALSE;
539 }
540 else if (bRc == -1)
541 {
542 // should never happen, but let's test for it nevertheless
543 wxLogLastError("GetMessage");
544 }
545 else
546 {
547 #if wxUSE_THREADS
548 wxASSERT_MSG( wxThread::IsMain()
549 ,wxT("only the main thread can process Windows messages")
550 );
551
552 static bool sbHadGuiLock = TRUE;
553 static wxMsgArray svSavedMessages;
554
555 //
556 // if a secondary thread owns is doing GUI calls, save all messages for
557 // later processing - we can't process them right now because it will
558 // lead to recursive library calls (and we're not reentrant)
559 //
560 if (!wxGuiOwnedByMainThread())
561 {
562 sbHadGuiLock = FALSE;
563
564 // leave out WM_COMMAND messages: too dangerous, sometimes
565 // the message will be processed twice
566 if ( !wxIsWaitingForThread() ||
567 svCurrentMsg.msg != WM_COMMAND )
568 {
569 svSavedMessages.Add(svCurrentMsg);
570 }
571 return TRUE;
572 }
573 else
574 {
575 //
576 // have we just regained the GUI lock? if so, post all of the saved
577 // messages
578 //
579 // FIXME of course, it's not _exactly_ the same as processing the
580 // messages normally - expect some things to break...
581 //
582 if (!sbHadGuiLock )
583 {
584 sbHadGuiLock = TRUE;
585
586 size_t nCount = svSavedMessages.Count();
587
588 for (size_t n = 0; n < nCount; n++)
589 {
590 QMSG vMsg = svSavedMessages[n];
591
592 if ( !ProcessMessage((WXMSG *)&vMsg) )
593 {
594 ::WinDispatchMsg(m_vHab, &vMsg);
595 }
596 }
597 svSavedMessages.Empty();
598 }
599 }
600 #endif // wxUSE_THREADS
601
602 // Process the message
603 if (!ProcessMessage((WXMSG *)&svCurrentMsg) )
604 {
605 ::WinDispatchMsg(m_vHab, (PQMSG)&svCurrentMsg);
606 }
607 }
608 return TRUE;
609 }
610
611 //////////////////////////////////////////////////////////////////////////////
612 //
613 // Keep trying to process messages until WM_QUIT
614 // received.
615 //
616 // If there are messages to be processed, they will all be
617 // processed and OnIdle will not be called.
618 // When there are no more messages, OnIdle is called.
619 // If OnIdle requests more time,
620 // it will be repeatedly called so long as there are no pending messages.
621 // A 'feature' of this is that once OnIdle has decided that no more processing
622 // is required, then it won't get processing time until further messages
623 // are processed (it'll sit in DoMessage).
624 //
625 //////////////////////////////////////////////////////////////////////////////
626 int wxApp::MainLoop()
627 {
628 m_bKeepGoing = TRUE;
629
630 while (m_bKeepGoing)
631 {
632 #if wxUSE_THREADS
633 wxMutexGuiLeaveOrEnter();
634 #endif // wxUSE_THREADS
635 while (!::WinPeekMsg(m_vHab, &svCurrentMsg, (HWND)NULL, 0, 0, PM_NOREMOVE) &&
636 ProcessIdle() )
637 {
638 }
639 DoMessage();
640 }
641 return (int)svCurrentMsg.mp1;
642 }
643
644 //
645 // Returns TRUE if more time is needed.
646 //
647 bool wxApp::ProcessIdle()
648 {
649 wxIdleEvent vEvent;
650
651 vEvent.SetEventObject(this);
652 ProcessEvent(vEvent);
653 return vEvent.MoreRequested();
654 }
655
656 #if wxUSE_THREADS
657 void wxApp::ProcessPendingEvents()
658 {
659 wxNode* pNode = wxPendingEvents->First();
660 wxCriticalSectionLocker vLocker(*wxPendingEventsLocker);
661
662 while (pNode)
663 {
664 wxEvtHandler* pHandler = (wxEvtHandler *)pNode->Data();
665 pHandler->ProcessPendingEvents();
666
667 delete pNode;
668 pNode = wxPendingEvents->First();
669 }
670 }
671 #endif
672
673 void wxApp::ExitMainLoop()
674 {
675 m_bKeepGoing = FALSE;
676 }
677
678 bool wxApp::Pending()
679 {
680 return (::WinPeekMsg(m_vHab, (PQMSG)&svCurrentMsg, (HWND)NULL, 0, 0, PM_NOREMOVE) != 0);
681 }
682
683 void wxApp::Dispatch()
684 {
685 DoMessage();
686 }
687
688 //////////////////////////////////////////////////////////////////////////////
689 //
690 // Give all windows a chance to preprocess
691 // the message. Some may have accelerator tables, or have
692 // MDI complications.
693 //
694 //////////////////////////////////////////////////////////////////////////////
695 bool wxApp::ProcessMessage(
696 WXMSG* pWxmsg
697 )
698 {
699 QMSG* vMsg = (PQMSG)pWxmsg;
700 HWND hWnd = vMsg->hwnd;
701 wxWindow* pWndThis = wxFindWinFromHandle((WXHWND)hWnd);
702 wxWindow* pWnd;
703
704 //
705 // for some composite controls (like a combobox), wndThis might be NULL
706 // because the subcontrol is not a wxWindow, but only the control itself
707 // is - try to catch this case
708 //
709 while (hWnd && !pWndThis)
710 {
711 hWnd = ::WinQueryWindow(hWnd, QW_PARENT);
712 pWndThis = wxFindWinFromHandle((WXHWND)hWnd);
713 }
714
715 // Anyone for a non-translation message? Try youngest descendants first.
716 for (pWnd = pWndThis; pWnd; pWnd = pWnd->GetParent())
717 {
718 if (pWnd->OS2ProcessMessage(pWxmsg))
719 return TRUE;
720 }
721 return FALSE;
722 }
723
724 void wxApp::OnIdle(
725 wxIdleEvent& rEvent
726 )
727 {
728 static bool sbInOnIdle = FALSE;
729
730 //
731 // Avoid recursion (via ProcessEvent default case)
732 //
733 if (sbInOnIdle )
734 return;
735
736 sbInOnIdle = TRUE;
737
738 //
739 // 'Garbage' collection of windows deleted with Close().
740 //
741 DeletePendingObjects();
742
743 #if wxUSE_LOG
744 // flush the logged messages if any
745 wxLog* pLog = wxLog::GetActiveTarget();
746
747 if (pLog != NULL && pLog->HasPendingMessages())
748 pLog->Flush();
749 #endif // wxUSE_LOG
750
751 // Send OnIdle events to all windows
752 if (SendIdleEvents())
753 {
754 //
755 // SendIdleEvents() returns TRUE if at least one window requested more
756 // idle events
757 //
758 rEvent.RequestMore(TRUE);
759 }
760
761 //
762 // If they are pending events, we must process them.
763 //
764 #if wxUSE_THREADS
765 ProcessPendingEvents();
766 #endif
767 sbInOnIdle = FALSE;
768 }
769
770 // Send idle event to all top-level windows
771 bool wxApp::SendIdleEvents()
772 {
773 bool bNeedMore = FALSE;
774 wxWindowList::Node* pNode = wxTopLevelWindows.GetFirst();
775
776 while (pNode)
777 {
778 wxWindow* pWin = pNode->GetData();
779
780 if (SendIdleEvents(pWin))
781 bNeedMore = TRUE;
782 pNode = pNode->GetNext();
783 }
784 return bNeedMore;
785 }
786
787 //
788 // Send idle event to window and all subwindows
789 //
790 bool wxApp::SendIdleEvents(
791 wxWindow* pWin
792 )
793 {
794 bool bNeedMore = FALSE;
795 wxIdleEvent vEvent;
796
797 vEvent.SetEventObject(pWin);
798 pWin->GetEventHandler()->ProcessEvent(vEvent);
799
800 if (vEvent.MoreRequested())
801 bNeedMore = TRUE;
802
803 wxNode* pNode = pWin->GetChildren().First();
804
805 while (pNode)
806 {
807 wxWindow* pWin = (wxWindow*) pNode->Data();
808
809 if (SendIdleEvents(pWin))
810 bNeedMore = TRUE;
811 pNode = pNode->Next();
812 }
813 return bNeedMore;
814 }
815
816 void wxApp::DeletePendingObjects()
817 {
818 wxNode* pNode = wxPendingDelete.First();
819
820 while (pNode)
821 {
822 wxObject* pObj = (wxObject *)pNode->Data();
823
824 delete pObj;
825
826 if (wxPendingDelete.Member(pObj))
827 delete pNode;
828
829 //
830 // Deleting one object may have deleted other pending
831 // objects, so start from beginning of list again.
832 //
833 pNode = wxPendingDelete.First();
834 }
835 }
836
837 void wxApp::OnEndSession(
838 wxCloseEvent& WXUNUSED(rEvent))
839 {
840 if (GetTopWindow())
841 GetTopWindow()->Close(TRUE);
842 }
843
844 //
845 // Default behaviour: close the application with prompts. The
846 // user can veto the close, and therefore the end session.
847 //
848 void wxApp::OnQueryEndSession(
849 wxCloseEvent& rEvent
850 )
851 {
852 if (GetTopWindow())
853 {
854 if (!GetTopWindow()->Close(!rEvent.CanVeto()))
855 rEvent.Veto(TRUE);
856 }
857 }
858
859 void wxExit()
860 {
861 wxLogError(_("Fatal error: exiting"));
862
863 wxApp::CleanUp();
864 }
865
866 // Yield to incoming messages
867 bool wxYield()
868 {
869 HAB vHab;
870 QMSG vMsg;
871 // We want to go back to the main message loop
872 // if we see a WM_QUIT. (?)
873 while (::WinPeekMsg(vHab, &vMsg, (HWND)NULL, 0, 0, PM_NOREMOVE) && vMsg.msg != WM_QUIT)
874 {
875 if (!wxTheApp->DoMessage())
876 break;
877 }
878 // If they are pending events, we must process them.
879 #if wxUSE_THREADS
880 wxTheApp->ProcessPendingEvents();
881 #endif
882 return TRUE;
883 }
884
885 wxIcon wxApp::GetStdIcon(
886 int nWhich
887 ) const
888 {
889 switch(nWhich)
890 {
891 case wxICON_INFORMATION:
892 return wxIcon("wxICON_INFO");
893
894 case wxICON_QUESTION:
895 return wxIcon("wxICON_QUESTION");
896
897 case wxICON_EXCLAMATION:
898 return wxIcon("wxICON_WARNING");
899
900 default:
901 wxFAIL_MSG(wxT("requested non existent standard icon"));
902 // still fall through
903
904 case wxICON_HAND:
905 return wxIcon("wxICON_ERROR");
906 }
907 return wxIcon("wxICON_ERROR");
908 }
909
910 HINSTANCE wxGetInstance()
911 {
912 return wxhInstance;
913 }
914
915 void wxSetInstance(HINSTANCE hInst)
916 {
917 wxhInstance = hInst;
918 }
919
920