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