1 /////////////////////////////////////////////////////////////////////////////
4 // Author: David Webster
8 // Copyright: (c) David Webster
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
19 #include "wx/gdicmn.h"
22 #include "wx/cursor.h"
24 #include "wx/palette.h"
26 #include "wx/dialog.h"
27 #include "wx/msgdlg.h"
29 #include "wx/dynarray.h"
30 # include "wx/wxchar.h"
35 #include "wx/module.h"
37 #include "wx/os2/private.h"
40 #include "wx/thread.h"
42 // define the array of QMSG strutures
43 WX_DECLARE_OBJARRAY(QMSG
, wxMsgArray
);
45 #include "wx/arrimpl.cpp"
47 WX_DEFINE_OBJARRAY(wxMsgArray
);
48 #endif // wxUSE_THREADS
50 #if wxUSE_WX_RESOURCES
51 #include "wx/resource.h"
55 #include "wx/tooltip.h"
56 #endif // wxUSE_TOOLTIPS
61 // ---------------------------------------------------------------------------
63 // ---------------------------------------------------------------------------
65 extern wxChar
* wxBuffer
;
66 extern wxList
* wxWinHandleList
;
67 extern wxList WXDLLEXPORT wxPendingDelete
;
68 extern wxCursor
* g_globalCursor
;
70 HAB vHabmain
= NULLHANDLE
;
72 wxApp
* wxTheApp
= NULL
;
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");
85 HICON wxSTD_FRAME_ICON
= (HICON
) NULL
;
86 HICON wxSTD_MDICHILDFRAME_ICON
= (HICON
) NULL
;
87 HICON wxSTD_MDIPARENTFRAME_ICON
= (HICON
) NULL
;
89 HICON wxDEFAULT_FRAME_ICON
= (HICON
) NULL
;
90 HICON wxDEFAULT_MDICHILDFRAME_ICON
= (HICON
) NULL
;
91 HICON wxDEFAULT_MDIPARENTFRAME_ICON
= (HICON
) NULL
;
93 HBRUSH wxDisableButtonBrush
= (HBRUSH
) 0;
95 // ===========================================================================
97 // ===========================================================================
99 // ---------------------------------------------------------------------------
101 // ---------------------------------------------------------------------------
103 IMPLEMENT_DYNAMIC_CLASS(wxApp
, wxEvtHandler
)
105 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
106 EVT_IDLE(wxApp::OnIdle
)
107 EVT_END_SESSION(wxApp::OnEndSession
)
108 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession
)
114 bool wxApp::Initialize(
119 // OS2 has to have an anchorblock
121 vHab
= WinInitialize(0);
128 // Some people may wish to use this, but
129 // probably it shouldn't be here by default.
131 // wxRedirectIOToConsole();
134 wxBuffer
= new wxChar
[1500]; // FIXME; why?
136 wxClassInfo::InitializeClasses();
139 wxPendingEventsLocker
= new wxCriticalSection
;
142 wxTheColourDatabase
= new wxColourDatabase(wxKEY_STRING
);
143 wxTheColourDatabase
->Initialize();
145 wxInitializeStockLists();
146 wxInitializeStockObjects();
148 #if wxUSE_WX_RESOURCES
149 wxInitializeResourceSystem();
152 wxBitmap::InitStandardHandlers();
154 RegisterWindowClasses(vHab
);
155 wxWinHandleList
= new wxList(wxKEY_INTEGER
);
157 // This is to foil optimizations in Visual C++ that throw out dummy.obj.
158 // PLEASE DO NOT ALTER THIS.
159 #if !defined(WXMAKINGDLL) && defined(__VISAGECPP__)
160 extern char wxDummyChar
;
161 if (wxDummyChar
) wxDummyChar
++;
164 // wxSetKeyboardHook(TRUE);
166 wxModule::RegisterModules();
167 if (!wxModule::InitializeModules())
170 } // end of wxApp::Initialize
172 // ---------------------------------------------------------------------------
173 // RegisterWindowClasses
174 // ---------------------------------------------------------------------------
176 bool wxApp::RegisterWindowClasses(
184 if (!::WinRegisterClass( vHab
187 ,CS_SIZEREDRAW
| CS_MOVENOTIFY
| CS_SYNCPAINT
191 vError
= ::WinGetLastError(vHab
);
192 sError
= wxPMErrorToStr(vError
);
193 wxLogLastError(sError
);
197 if (!::WinRegisterClass( vHab
198 ,wxFrameClassNameNoRedraw
204 vError
= ::WinGetLastError(vHab
);
205 sError
= wxPMErrorToStr(vError
);
206 wxLogLastError(sError
);
210 if (!::WinRegisterClass( vHab
213 ,CS_SIZEREDRAW
| CS_MOVENOTIFY
| CS_SYNCPAINT
217 vError
= ::WinGetLastError(vHab
);
218 sError
= wxPMErrorToStr(vError
);
219 wxLogLastError(sError
);
223 if (!::WinRegisterClass( vHab
224 ,wxMDIFrameClassNameNoRedraw
230 vError
= ::WinGetLastError(vHab
);
231 sError
= wxPMErrorToStr(vError
);
232 wxLogLastError(sError
);
236 if (!::WinRegisterClass( vHab
237 ,wxMDIChildFrameClassName
239 ,CS_MOVENOTIFY
| CS_SIZEREDRAW
| CS_SYNCPAINT
| CS_HITTEST
243 vError
= ::WinGetLastError(vHab
);
244 sError
= wxPMErrorToStr(vError
);
245 wxLogLastError(sError
);
249 if (!::WinRegisterClass( vHab
250 ,wxMDIChildFrameClassNameNoRedraw
256 vError
= ::WinGetLastError(vHab
);
257 sError
= wxPMErrorToStr(vError
);
258 wxLogLastError(sError
);
262 if (!::WinRegisterClass( vHab
265 ,CS_MOVENOTIFY
| CS_SIZEREDRAW
| CS_HITTEST
| CS_SAVEBITS
| CS_SYNCPAINT
269 vError
= ::WinGetLastError(vHab
);
270 sError
= wxPMErrorToStr(vError
);
271 wxLogLastError(sError
);
275 if (!::WinRegisterClass( vHab
278 ,CS_MOVENOTIFY
| CS_SIZEREDRAW
| CS_HITTEST
| CS_SAVEBITS
| CS_SYNCPAINT
282 vError
= ::WinGetLastError(vHab
);
283 sError
= wxPMErrorToStr(vError
);
284 wxLogLastError(sError
);
288 } // end of wxApp::RegisterWindowClasses
291 // Cleans up any wxWindows internal structures left lying around
293 void wxApp::CleanUp()
302 // Flush the logged messages if any and install a 'safer' log target: the
303 // default one (wxLogGui) can't be used after the resources are freed just
304 // below and the user suppliedo ne might be even more unsafe (using any
305 // wxWindows GUI function is unsafe starting from now)
307 wxLog::DontCreateOnDemand();
310 // This will flush the old messages if any
312 delete wxLog::SetActiveTarget(new wxLogStderr
);
316 // One last chance for pending objects to be cleaned up
318 wxTheApp
->DeletePendingObjects();
320 wxModule::CleanUpModules();
322 #if wxUSE_WX_RESOURCES
323 wxCleanUpResourceSystem();
326 wxDeleteStockObjects();
329 // Destroy all GDI lists, etc.
331 wxDeleteStockLists();
333 delete wxTheColourDatabase
;
334 wxTheColourDatabase
= NULL
;
336 wxBitmap::CleanUpHandlers();
342 // PM-SPECIFIC CLEANUP
345 // wxSetKeyboardHook(FALSE);
347 if (wxSTD_FRAME_ICON
)
348 ::WinFreeFileIcon(wxSTD_FRAME_ICON
);
349 if (wxSTD_MDICHILDFRAME_ICON
)
350 ::WinFreeFileIcon(wxSTD_MDICHILDFRAME_ICON
);
351 if (wxSTD_MDIPARENTFRAME_ICON
)
352 ::WinFreeFileIcon(wxSTD_MDIPARENTFRAME_ICON
);
354 if (wxDEFAULT_FRAME_ICON
)
355 ::WinFreeFileIcon(wxDEFAULT_FRAME_ICON
);
356 if (wxDEFAULT_MDICHILDFRAME_ICON
)
357 ::WinFreeFileIcon(wxDEFAULT_MDICHILDFRAME_ICON
);
358 if (wxDEFAULT_MDIPARENTFRAME_ICON
)
359 ::WinFreeFileIcon(wxDEFAULT_MDIPARENTFRAME_ICON
);
361 if ( wxDisableButtonBrush
)
363 // TODO: ::DeleteObject( wxDisableButtonBrush );
367 delete wxWinHandleList
;
369 delete wxPendingEvents
;
371 delete wxPendingEventsLocker
;
372 // If we don't do the following, we get an apparent memory leak.
373 ((wxEvtHandler
&) wxDefaultValidator
).ClearEventLocker();
376 wxClassInfo::CleanUpClasses();
378 // Delete Message queue
380 ::WinDestroyMsgQueue(wxTheApp
->m_hMq
);
385 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
386 // At this point we want to check if there are any memory
387 // blocks that aren't part of the wxDebugContext itself,
388 // as a special case. Then when dumping we need to ignore
389 // wxDebugContext, too.
390 if (wxDebugContext::CountObjectsLeft(TRUE
) > 0)
392 wxLogDebug(wxT("There were memory leaks."));
393 wxDebugContext::Dump();
394 wxDebugContext::PrintStatistics();
396 // wxDebugContext::SetStream(NULL, NULL);
400 // do it as the very last thing because everything else can log messages
401 delete wxLog::SetActiveTarget(NULL
);
403 } // end of wxApp::CleanUp
412 if (!wxApp::Initialize(vHab
))
416 // create the application object or ensure that one already exists
420 // The app may have declared a global application object, but we recommend
421 // the IMPLEMENT_APP macro is used instead, which sets an initializer
422 // function for delayed, dynamic app object construction.
423 wxCHECK_MSG( wxApp::GetInitializerFunction(), 0,
424 wxT("No initializer - use IMPLEMENT_APP macro.") );
425 wxTheApp
= (*wxApp::GetInitializerFunction()) ();
427 wxCHECK_MSG( wxTheApp
, 0, wxT("You have to define an instance of wxApp!") );
428 wxTheApp
->argc
= argc
;
431 wxTheApp
->argv
= new wxChar
*[argc
+1];
437 wxTheApp
->argv
[nArgc
] = wxStrdup(wxConvLibc
.cMB2WX(argv
[nArgc
]));
440 wxTheApp
->argv
[nArgc
] = (wxChar
*)NULL
;
442 wxTheApp
->argv
= argv
;
445 wxString
sName(wxFileNameFromPath(argv
[0]));
447 wxStripExtension(sName
);
448 wxTheApp
->SetAppName(sName
);
452 if (!wxTheApp
->OnInitGui())
457 if (wxTheApp
->OnInit())
459 nRetValue
= wxTheApp
->OnRun();
464 wxWindow
* pTopWindow
= wxTheApp
->GetTopWindow();
468 // Forcibly delete the window.
469 if (pTopWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
470 pTopWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
472 pTopWindow
->Close(TRUE
);
473 wxTheApp
->DeletePendingObjects();
478 wxTheApp
->SetTopWindow(NULL
);
486 bool wxApp::OnInitGui()
491 m_hMq
= ::WinCreateMsgQueue(vHabmain
, 0);
494 vError
= ::WinGetLastError(vHabmain
);
495 sError
= wxPMErrorToStr(vError
);
500 } // end of wxApp::OnInitGui
503 // Static member initialization
505 wxAppInitializerFunction
wxAppBase::m_appInitFn
= (wxAppInitializerFunction
) NULL
;
511 m_wantDebugOutput
= TRUE
;
515 m_nPrintMode
= wxPRINT_WINDOWS
;
516 m_exitOnFrameDelete
= TRUE
;
519 } // end of wxApp::wxApp
524 // Delete command-line args
529 for (i
= 0; i
< argc
; i
++)
535 } // end of wxApp::~wxApp
537 bool wxApp::Initialized()
543 } // end of wxApp::Initialized
546 // Get and process a message, returning FALSE if WM_QUIT
547 // received (and also set the flag telling the app to exit the main loop)
549 bool wxApp::DoMessage()
551 BOOL bRc
= ::WinGetMsg(vHabmain
, &svCurrentMsg
, HWND(NULL
), 0, 0);
557 m_bKeepGoing
= FALSE
;
562 // should never happen, but let's test for it nevertheless
563 wxLogLastError("GetMessage");
568 wxASSERT_MSG( wxThread::IsMain()
569 ,wxT("only the main thread can process Windows messages")
572 static bool sbHadGuiLock
= TRUE
;
573 static wxMsgArray svSavedMessages
;
576 // If a secondary thread owns is doing GUI calls, save all messages for
577 // later processing - we can't process them right now because it will
578 // lead to recursive library calls (and we're not reentrant)
580 if (!wxGuiOwnedByMainThread())
582 sbHadGuiLock
= FALSE
;
585 // Leave out WM_COMMAND messages: too dangerous, sometimes
586 // the message will be processed twice
588 if ( !wxIsWaitingForThread() ||
589 svCurrentMsg
.msg
!= WM_COMMAND
)
591 svSavedMessages
.Add(svCurrentMsg
);
598 // Have we just regained the GUI lock? if so, post all of the saved
605 size_t nCount
= svSavedMessages
.Count();
607 for (size_t n
= 0; n
< nCount
; n
++)
609 QMSG vMsg
= svSavedMessages
[n
];
611 if ( !ProcessMessage((WXMSG
*)&vMsg
) )
613 ::WinDispatchMsg(vHabmain
, &vMsg
);
616 svSavedMessages
.Empty();
619 #endif // wxUSE_THREADS
621 // Process the message
622 if (!ProcessMessage((WXMSG
*)&svCurrentMsg
))
624 ::WinDispatchMsg(vHabmain
, (PQMSG
)&svCurrentMsg
);
628 } // end of wxApp::DoMessage
630 //////////////////////////////////////////////////////////////////////////////
632 // Keep trying to process messages until WM_QUIT
635 // If there are messages to be processed, they will all be
636 // processed and OnIdle will not be called.
637 // When there are no more messages, OnIdle is called.
638 // If OnIdle requests more time,
639 // it will be repeatedly called so long as there are no pending messages.
640 // A 'feature' of this is that once OnIdle has decided that no more processing
641 // is required, then it won't get processing time until further messages
642 // are processed (it'll sit in DoMessage).
644 //////////////////////////////////////////////////////////////////////////////
645 int wxApp::MainLoop()
652 wxMutexGuiLeaveOrEnter();
653 #endif // wxUSE_THREADS
654 while (!Pending() && ProcessIdle())
660 return (int)svCurrentMsg
.mp1
;
661 } // end of wxApp::MainLoop
664 // Returns TRUE if more time is needed.
666 bool wxApp::ProcessIdle()
670 vEvent
.SetEventObject(this);
671 ProcessEvent(vEvent
);
672 return vEvent
.MoreRequested();
673 } // end of wxApp::ProcessIdle
675 void wxApp::ExitMainLoop()
677 m_bKeepGoing
= FALSE
;
680 bool wxApp::Pending()
682 return (::WinPeekMsg(vHabmain
, (PQMSG
)&svCurrentMsg
, (HWND
)NULL
, 0, 0, PM_NOREMOVE
) != 0);
685 void wxApp::Dispatch()
690 //////////////////////////////////////////////////////////////////////////////
692 // Give all windows a chance to preprocess
693 // the message. Some may have accelerator tables, or have
694 // MDI complications.
696 //////////////////////////////////////////////////////////////////////////////
697 bool wxApp::ProcessMessage(
701 QMSG
* pMsg
= (PQMSG
)pWxmsg
;
702 HWND hWnd
= pMsg
->hwnd
;
703 wxWindow
* pWndThis
= wxFindWinFromHandle((WXHWND
)hWnd
);
708 // We must relay WM_MOUSEMOVE events to the tooltip ctrl if we want it to
709 // popup the tooltip bubbles
711 if (pWndThis
&& (pMsg
->msg
== WM_MOUSEMOVE
))
713 wxToolTip
* pToolTip
= pWndThis
->GetToolTip();
716 pToolTip
->RelayEvent(pWxmsg
);
719 #endif // wxUSE_TOOLTIPS
722 // For some composite controls (like a combobox), wndThis might be NULL
723 // because the subcontrol is not a wxWindow, but only the control itself
724 // is - try to catch this case
726 while (hWnd
&& !pWndThis
)
728 hWnd
= ::WinQueryWindow(hWnd
, QW_PARENT
);
729 pWndThis
= wxFindWinFromHandle((WXHWND
)hWnd
);
733 // Try translations first; find the youngest window with
734 // a translation table.
737 for (pWnd
= pWndThis
; pWnd
; pWnd
= pWnd
->GetParent() )
739 if (pMsg
->msg
== WM_CHAR
)
740 if (pWnd
->OS2TranslateMessage(pWxmsg
))
745 // Anyone for a non-translation message? Try youngest descendants first.
747 for (pWnd
= pWndThis
; pWnd
; pWnd
= pWnd
->GetParent())
749 if (pWnd
->OS2ProcessMessage(pWxmsg
))
753 } // end of wxApp::ProcessMessage
759 static bool sbInOnIdle
= FALSE
;
762 // Avoid recursion (via ProcessEvent default case)
770 // If there are pending events, we must process them: pending events
771 // are either events to the threads other than main or events posted
772 // with wxPostEvent() functions
774 ProcessPendingEvents();
777 // 'Garbage' collection of windows deleted with Close().
779 DeletePendingObjects();
783 // Flush the logged messages if any
785 wxLog::FlushActive();
789 // Send OnIdle events to all windows
791 if (SendIdleEvents())
794 // SendIdleEvents() returns TRUE if at least one window requested more
797 rEvent
.RequestMore(TRUE
);
800 } // end of wxApp::OnIdle
802 // Send idle event to all top-level windows
803 bool wxApp::SendIdleEvents()
805 bool bNeedMore
= FALSE
;
806 wxWindowList::Node
* pNode
= wxTopLevelWindows
.GetFirst();
810 wxWindow
* pWin
= pNode
->GetData();
812 if (SendIdleEvents(pWin
))
814 pNode
= pNode
->GetNext();
817 } // end of wxApp::SendIdleEvents
820 // Send idle event to window and all subwindows
822 bool wxApp::SendIdleEvents(
826 bool bNeedMore
= FALSE
;
829 vEvent
.SetEventObject(pWin
);
830 pWin
->GetEventHandler()->ProcessEvent(vEvent
);
832 if (vEvent
.MoreRequested())
835 wxNode
* pNode
= pWin
->GetChildren().First();
839 wxWindow
* pWin
= (wxWindow
*) pNode
->Data();
841 if (SendIdleEvents(pWin
))
843 pNode
= pNode
->Next();
846 } // end of wxApp::SendIdleEvents
848 void wxApp::DeletePendingObjects()
850 wxNode
* pNode
= wxPendingDelete
.First();
854 wxObject
* pObj
= (wxObject
*)pNode
->Data();
858 if (wxPendingDelete
.Member(pObj
))
862 // Deleting one object may have deleted other pending
863 // objects, so start from beginning of list again.
865 pNode
= wxPendingDelete
.First();
867 } // end of wxApp::DeletePendingObjects
869 void wxApp::OnEndSession(
870 wxCloseEvent
& WXUNUSED(rEvent
))
873 GetTopWindow()->Close(TRUE
);
874 } // end of wxApp::OnEndSession
877 // Default behaviour: close the application with prompts. The
878 // user can veto the close, and therefore the end session.
880 void wxApp::OnQueryEndSession(
886 if (!GetTopWindow()->Close(!rEvent
.CanVeto()))
889 } // end of wxApp::OnQueryEndSession
893 wxLogError(_("Fatal error: exiting"));
899 // Yield to incoming messages
907 // Disable log flushing from here because a call to wxYield() shouldn't
908 // normally result in message boxes popping up &c
913 // We want to go back to the main message loop
914 // if we see a WM_QUIT. (?)
916 while (::WinPeekMsg(vHab
, &vMsg
, (HWND
)NULL
, 0, 0, PM_NOREMOVE
) && vMsg
.msg
!= WM_QUIT
)
919 wxMutexGuiLeaveOrEnter();
920 #endif // wxUSE_THREADS
921 if (!wxTheApp
->DoMessage())
925 // If they are pending events, we must process them.
928 wxTheApp
->ProcessPendingEvents();
931 // Let the logs be flashed again
937 wxIcon
wxApp::GetStdIcon(
943 case wxICON_INFORMATION
:
944 return wxIcon("wxICON_INFO");
946 case wxICON_QUESTION
:
947 return wxIcon("wxICON_QUESTION");
949 case wxICON_EXCLAMATION
:
950 return wxIcon("wxICON_WARNING");
953 wxFAIL_MSG(wxT("requested non existent standard icon"));
954 // still fall through
957 return wxIcon("wxICON_ERROR");
959 return wxIcon("wxICON_ERROR");
960 } // end of wxApp::GetStdIcon
962 //-----------------------------------------------------------------------------
964 //-----------------------------------------------------------------------------
969 // Send the top window a dummy message so idle handler processing will
970 // start up again. Doing it this way ensures that the idle handler
971 // wakes up in the right thread (see also wxWakeUpMainThread() which does
972 // the same for the main app thread only)
974 wxWindow
* pTopWindow
= wxTheApp
->GetTopWindow();
978 if ( !::WinPostMsg(GetHwndOf(pTopWindow
), WM_NULL
, (MPARAM
)0, (MPARAM
)0))
981 // Should never happen
983 wxLogLastError("PostMessage(WM_NULL)");
986 } // end of wxWakeUpIdle