New, reworked frame class for wxOS2 and more drawing routines in wxDC
[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
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 // For some composite controls (like a combobox), wndThis might be NULL
765 // because the subcontrol is not a wxWindow, but only the control itself
766 // is - try to catch this case
767 //
768 while (hWnd && !pWndThis)
769 {
770 hWnd = ::WinQueryWindow(hWnd, QW_PARENT);
771 pWndThis = wxFindWinFromHandle((WXHWND)hWnd);
772 }
773
774 //
775 // Try translations first; find the youngest window with
776 // a translation table. OS/2 has case sensative accels, so
777 // this block, coded by BK, removes that and helps make them
778 // case insensative.
779 //
780 if(pMsg->msg == WM_CHAR)
781 {
782 PBYTE pChmsg = (PBYTE)&(pMsg->msg);
783 USHORT uSch = CHARMSG(pChmsg)->chr;
784 bool bRc;
785
786 //
787 // Do not process keyup events
788 //
789 if(!(CHARMSG(pChmsg)->fs & KC_KEYUP))
790 {
791 if((CHARMSG(pChmsg)->fs & (KC_ALT | KC_CTRL)) && CHARMSG(pChmsg)->chr != 0)
792 CHARMSG(pChmsg)->chr = (USHORT)wxToupper((UCHAR)uSch);
793
794
795 for(pWnd = pWndThis; pWnd; pWnd = pWnd->GetParent() )
796 {
797 if((bRc = pWnd->OS2TranslateMessage(pWxmsg)) == TRUE)
798 break;
799 }
800
801 if(!bRc) // untranslated, should restore original value
802 CHARMSG(pChmsg)->chr = uSch;
803 }
804 }
805 //
806 // Anyone for a non-translation message? Try youngest descendants first.
807 //
808 // for (pWnd = pWndThis; pWnd; pWnd = pWnd->GetParent())
809 // {
810 // if (pWnd->OS2ProcessMessage(pWxmsg))
811 // return TRUE;
812 // }
813 return FALSE;
814 } // end of wxApp::ProcessMessage
815
816 void wxApp::OnIdle(
817 wxIdleEvent& rEvent
818 )
819 {
820 static bool sbInOnIdle = FALSE;
821
822 //
823 // Avoid recursion (via ProcessEvent default case)
824 //
825 if (sbInOnIdle)
826 return;
827
828 sbInOnIdle = TRUE;
829
830 //
831 // If there are pending events, we must process them: pending events
832 // are either events to the threads other than main or events posted
833 // with wxPostEvent() functions
834 //
835 ProcessPendingEvents();
836
837 //
838 // 'Garbage' collection of windows deleted with Close().
839 //
840 DeletePendingObjects();
841
842 #if wxUSE_LOG
843 //
844 // Flush the logged messages if any
845 //
846 wxLog::FlushActive();
847 #endif // wxUSE_LOG
848
849 //
850 // Send OnIdle events to all windows
851 //
852 if (SendIdleEvents())
853 {
854 //
855 // SendIdleEvents() returns TRUE if at least one window requested more
856 // idle events
857 //
858 rEvent.RequestMore(TRUE);
859 }
860 sbInOnIdle = FALSE;
861 } // end of wxApp::OnIdle
862
863 // Send idle event to all top-level windows
864 bool wxApp::SendIdleEvents()
865 {
866 bool bNeedMore = FALSE;
867 wxWindowList::Node* pNode = wxTopLevelWindows.GetFirst();
868
869 while (pNode)
870 {
871 wxWindow* pWin = pNode->GetData();
872
873 if (SendIdleEvents(pWin))
874 bNeedMore = TRUE;
875 pNode = pNode->GetNext();
876 }
877 return bNeedMore;
878 } // end of wxApp::SendIdleEvents
879
880 //
881 // Send idle event to window and all subwindows
882 //
883 bool wxApp::SendIdleEvents(
884 wxWindow* pWin
885 )
886 {
887 bool bNeedMore = FALSE;
888 wxIdleEvent vEvent;
889
890 vEvent.SetEventObject(pWin);
891 pWin->GetEventHandler()->ProcessEvent(vEvent);
892
893 if (vEvent.MoreRequested())
894 bNeedMore = TRUE;
895
896 wxNode* pNode = pWin->GetChildren().First();
897
898 while (pNode)
899 {
900 wxWindow* pWin = (wxWindow*) pNode->Data();
901
902 if (SendIdleEvents(pWin))
903 bNeedMore = TRUE;
904 pNode = pNode->Next();
905 }
906 return bNeedMore;
907 } // end of wxApp::SendIdleEvents
908
909 void wxApp::DeletePendingObjects()
910 {
911 wxNode* pNode = wxPendingDelete.First();
912
913 while (pNode)
914 {
915 wxObject* pObj = (wxObject *)pNode->Data();
916
917 delete pObj;
918
919 if (wxPendingDelete.Member(pObj))
920 delete pNode;
921
922 //
923 // Deleting one object may have deleted other pending
924 // objects, so start from beginning of list again.
925 //
926 pNode = wxPendingDelete.First();
927 }
928 } // end of wxApp::DeletePendingObjects
929
930 void wxApp::OnEndSession(
931 wxCloseEvent& WXUNUSED(rEvent))
932 {
933 if (GetTopWindow())
934 GetTopWindow()->Close(TRUE);
935 } // end of wxApp::OnEndSession
936
937 //
938 // Default behaviour: close the application with prompts. The
939 // user can veto the close, and therefore the end session.
940 //
941 void wxApp::OnQueryEndSession(
942 wxCloseEvent& rEvent
943 )
944 {
945 if (GetTopWindow())
946 {
947 if (!GetTopWindow()->Close(!rEvent.CanVeto()))
948 rEvent.Veto(TRUE);
949 }
950 } // end of wxApp::OnQueryEndSession
951
952 void wxExit()
953 {
954 wxLogError(_("Fatal error: exiting"));
955
956 wxApp::CleanUp();
957 } // end of wxExit
958
959 //
960 // Yield to incoming messages
961 //
962 bool wxYield()
963 {
964 HAB vHab = 0;
965 QMSG vMsg;
966
967 //
968 // Disable log flushing from here because a call to wxYield() shouldn't
969 // normally result in message boxes popping up &c
970 //
971 wxLog::Suspend();
972
973 //
974 // We want to go back to the main message loop
975 // if we see a WM_QUIT. (?)
976 //
977 while (::WinPeekMsg(vHab, &vMsg, (HWND)NULL, 0, 0, PM_NOREMOVE) && vMsg.msg != WM_QUIT)
978 {
979 #if wxUSE_THREADS
980 wxMutexGuiLeaveOrEnter();
981 #endif // wxUSE_THREADS
982 if (!wxTheApp->DoMessage())
983 break;
984 }
985 //
986 // If they are pending events, we must process them.
987 //
988 if (wxTheApp)
989 wxTheApp->ProcessPendingEvents();
990
991 //
992 // Let the logs be flashed again
993 //
994 wxLog::Resume();
995 return TRUE;
996 } // end of wxYield
997
998 wxIcon wxApp::GetStdIcon(
999 int nWhich
1000 ) const
1001 {
1002 switch(nWhich)
1003 {
1004 case wxICON_INFORMATION:
1005 return wxIcon("wxICON_INFO");
1006
1007 case wxICON_QUESTION:
1008 return wxIcon("wxICON_QUESTION");
1009
1010 case wxICON_EXCLAMATION:
1011 return wxIcon("wxICON_WARNING");
1012
1013 default:
1014 wxFAIL_MSG(wxT("requested non existent standard icon"));
1015 // still fall through
1016
1017 case wxICON_HAND:
1018 return wxIcon("wxICON_ERROR");
1019 }
1020 return wxIcon("wxICON_ERROR");
1021 } // end of wxApp::GetStdIcon
1022
1023 //-----------------------------------------------------------------------------
1024 // wxWakeUpIdle
1025 //-----------------------------------------------------------------------------
1026
1027 void wxWakeUpIdle()
1028 {
1029 //
1030 // Send the top window a dummy message so idle handler processing will
1031 // start up again. Doing it this way ensures that the idle handler
1032 // wakes up in the right thread (see also wxWakeUpMainThread() which does
1033 // the same for the main app thread only)
1034 //
1035 wxWindow* pTopWindow = wxTheApp->GetTopWindow();
1036
1037 if (pTopWindow)
1038 {
1039 if ( !::WinPostMsg(GetHwndOf(pTopWindow), WM_NULL, (MPARAM)0, (MPARAM)0))
1040 {
1041 //
1042 // Should never happen
1043 //
1044 wxLogLastError("PostMessage(WM_NULL)");
1045 }
1046 }
1047 } // end of wxWakeUpIdle
1048
1049 HAB wxGetInstance()
1050 {
1051 return vHabmain;
1052 }
1053
1054 void wxSetInstance(
1055 HAB vHab
1056 )
1057 {
1058 vHabmain = vHab;
1059 }
1060