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