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"
57 // ---------------------------------------------------------------------------
59 // ---------------------------------------------------------------------------
61 extern wxChar
* wxBuffer
;
62 extern wxChar
* wxOsVersion
;
63 extern wxList
* wxWinHandleList
;
64 extern wxList WXDLLEXPORT wxPendingDelete
;
65 extern wxCursor
* g_globalCursor
;
67 HINSTANCE wxhInstance
= 0;
69 wxApp
* wxTheApp
= NULL
;
72 // FIXME why not const? and not static?
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 MRESULT EXPENTRY
wxWndProc( HWND
101 // ===========================================================================
103 // ===========================================================================
105 // ---------------------------------------------------------------------------
107 // ---------------------------------------------------------------------------
109 IMPLEMENT_DYNAMIC_CLASS(wxApp
, wxEvtHandler
)
111 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
112 EVT_IDLE(wxApp::OnIdle
)
113 EVT_END_SESSION(wxApp::OnEndSession
)
114 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession
)
118 bool wxApp::Initialize(
123 // OS2 has to have an anchorblock
125 vHab
= WinInitialize(0);
132 // Some people may wish to use this, but
133 // probably it shouldn't be here by default.
135 // wxRedirectIOToConsole();
138 wxBuffer
= new wxChar
[1500]; // FIXME; why?
140 wxClassInfo::InitializeClasses();
143 wxGetResource(wxT("wxWindows"), wxT("OsVersion"), &wxOsVersion
);
146 // I'm annoyed ... I don't know where to put this and I don't want to
147 // create a module for that as it's part of the core.
148 wxTheColourDatabase
= new wxColourDatabase(wxKEY_STRING
);
149 wxTheColourDatabase
->Initialize();
151 wxInitializeStockLists();
152 wxInitializeStockObjects();
154 #if wxUSE_WX_RESOURCES
155 wxInitializeResourceSystem();
158 wxBitmap::InitStandardHandlers();
160 g_globalCursor
= new wxCursor
;
163 wxSTD_FRAME_ICON
= ::WinLoadFileIcon(wxT("wxSTD_FRAME"), TRUE
);
164 wxSTD_MDIPARENTFRAME_ICON
= ::WinLoadFileIcon(wxT("wxSTD_MDIPARENTFRAME"), TRUE
);
165 wxSTD_MDICHILDFRAME_ICON
= ::WinLoadFileIcon(wxT("wxSTD_MDICHILDFRAME"), TRUE
);
167 wxDEFAULT_FRAME_ICON
= ::WinLoadFileIcon(wxT("wxDEFAULT_FRAME"), TRUE
);
168 wxDEFAULT_MDIPARENTFRAME_ICON
= ::WinLoadFileIcon(wxT("wxDEFAULT_MDIPARENTFRAME"), TRUE
);
169 wxDEFAULT_MDICHILDFRAME_ICON
= ::WinLoadFileIcon(wxT("wxDEFAULT_MDICHILDFRAME"), TRUE
);
171 RegisterWindowClasses(vHab
);
172 wxWinHandleList
= new wxList(wxKEY_INTEGER
);
174 // This is to foil optimizations in Visual C++ that throw out dummy.obj.
175 // PLEASE DO NOT ALTER THIS.
176 #if !defined(WXMAKINGDLL) && defined(__VISAGECPP__)
177 extern char wxDummyChar
;
178 if (wxDummyChar
) wxDummyChar
++;
181 // wxSetKeyboardHook(TRUE);
183 wxModule::RegisterModules();
184 if (!wxModule::InitializeModules())
189 // ---------------------------------------------------------------------------
190 // RegisterWindowClasses
191 // ---------------------------------------------------------------------------
193 // TODO we should only register classes really used by the app. For this it
194 // would be enough to just delay the class registration until an attempt
195 // to create a window of this class is made.
196 bool wxApp::RegisterWindowClasses(
204 if (!::WinRegisterClass( vHab
207 ,CS_SIZEREDRAW
| CS_SYNCPAINT
211 vError
= ::WinGetLastError(vHab
);
212 sError
= wxPMErrorToStr(vError
);
213 wxLogLastError(sError
);
217 if (!::WinRegisterClass( vHab
218 ,wxFrameClassNameNoRedraw
224 vError
= ::WinGetLastError(vHab
);
225 sError
= wxPMErrorToStr(vError
);
226 wxLogLastError(sError
);
230 if (!::WinRegisterClass( vHab
233 ,CS_SIZEREDRAW
| CS_SYNCPAINT
237 vError
= ::WinGetLastError(vHab
);
238 sError
= wxPMErrorToStr(vError
);
239 wxLogLastError(sError
);
243 if (!::WinRegisterClass( vHab
244 ,wxMDIFrameClassNameNoRedraw
250 vError
= ::WinGetLastError(vHab
);
251 sError
= wxPMErrorToStr(vError
);
252 wxLogLastError(sError
);
256 if (!::WinRegisterClass( vHab
257 ,wxMDIChildFrameClassName
259 ,CS_MOVENOTIFY
| CS_SIZEREDRAW
| CS_SYNCPAINT
| CS_HITTEST
263 vError
= ::WinGetLastError(vHab
);
264 sError
= wxPMErrorToStr(vError
);
265 wxLogLastError(sError
);
269 if (!::WinRegisterClass( vHab
270 ,wxMDIChildFrameClassNameNoRedraw
276 vError
= ::WinGetLastError(vHab
);
277 sError
= wxPMErrorToStr(vError
);
278 wxLogLastError(sError
);
282 if (!::WinRegisterClass( vHab
285 ,CS_MOVENOTIFY
| CS_SIZEREDRAW
| CS_HITTEST
| CS_SAVEBITS
| CS_SYNCPAINT
289 vError
= ::WinGetLastError(vHab
);
290 sError
= wxPMErrorToStr(vError
);
291 wxLogLastError(sError
);
295 if (!::WinRegisterClass( vHab
298 ,CS_MOVENOTIFY
| CS_SIZEREDRAW
| CS_HITTEST
| CS_SAVEBITS
| CS_SYNCPAINT
302 vError
= ::WinGetLastError(vHab
);
303 sError
= wxPMErrorToStr(vError
);
304 wxLogLastError(sError
);
310 //// Cleans up any wxWindows internal structures left lying around
312 void wxApp::CleanUp()
317 // flush the logged messages if any and install a 'safer' log target: the
318 // default one (wxLogGui) can't be used after the resources are freed just
319 // below and the user suppliedo ne might be even more unsafe (using any
320 // wxWindows GUI function is unsafe starting from now)
321 wxLog::DontCreateOnDemand();
323 // this will flush the old messages if any
324 #if (!(defined(__VISAGECPP__) && __IBMCPP__ < 400))
325 // another VA 3.0 memory problem here
326 delete wxLog::SetActiveTarget(new wxLogStderr
);
330 // One last chance for pending objects to be cleaned up
331 wxTheApp
->DeletePendingObjects();
333 #if (!(defined(__VISAGECPP__) && __IBMCPP__ < 400))
334 // another VA 3.0 memory problem here
335 wxModule::CleanUpModules();
338 #if wxUSE_WX_RESOURCES
339 wxCleanUpResourceSystem();
341 // wxDefaultResourceTable->ClearTable();
344 // Indicate that the cursor can be freed, so that cursor won't be deleted
345 // by deleting the bitmap list before g_globalCursor goes out of scope
346 // (double deletion of the cursor).
347 wxSetCursor(wxNullCursor
);
348 #if (!(defined(__VISAGECPP__) && __IBMCPP__ < 400))
349 // another VA 3.0 memory problem here
350 delete g_globalCursor
;
352 g_globalCursor
= NULL
;
354 wxDeleteStockObjects();
356 // Destroy all GDI lists, etc.
357 wxDeleteStockLists();
359 delete wxTheColourDatabase
;
360 wxTheColourDatabase
= NULL
;
362 wxBitmap::CleanUpHandlers();
367 //// WINDOWS-SPECIFIC CLEANUP
369 // wxSetKeyboardHook(FALSE);
371 if (wxSTD_FRAME_ICON
)
372 ::WinFreeFileIcon(wxSTD_FRAME_ICON
);
373 if (wxSTD_MDICHILDFRAME_ICON
)
374 ::WinFreeFileIcon(wxSTD_MDICHILDFRAME_ICON
);
375 if (wxSTD_MDIPARENTFRAME_ICON
)
376 ::WinFreeFileIcon(wxSTD_MDIPARENTFRAME_ICON
);
378 if (wxDEFAULT_FRAME_ICON
)
379 ::WinFreeFileIcon(wxDEFAULT_FRAME_ICON
);
380 if (wxDEFAULT_MDICHILDFRAME_ICON
)
381 ::WinFreeFileIcon(wxDEFAULT_MDICHILDFRAME_ICON
);
382 if (wxDEFAULT_MDIPARENTFRAME_ICON
)
383 ::WinFreeFileIcon(wxDEFAULT_MDIPARENTFRAME_ICON
);
385 if ( wxDisableButtonBrush
)
387 // TODO: ::DeleteObject( wxDisableButtonBrush );
391 delete wxWinHandleList
;
393 // GL: I'm annoyed ... I don't know where to put this and I don't want to
394 // create a module for that as it's part of the core.
396 delete wxPendingEvents
;
397 delete wxPendingEventsLocker
;
398 // If we don't do the following, we get an apparent memory leak.
399 ((wxEvtHandler
&) wxDefaultValidator
).ClearEventLocker();
402 wxClassInfo::CleanUpClasses();
407 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
408 // At this point we want to check if there are any memory
409 // blocks that aren't part of the wxDebugContext itself,
410 // as a special case. Then when dumping we need to ignore
411 // wxDebugContext, too.
412 if (wxDebugContext::CountObjectsLeft(TRUE
) > 0)
414 wxLogDebug(wxT("There were memory leaks."));
415 wxDebugContext::Dump();
416 wxDebugContext::PrintStatistics();
418 // wxDebugContext::SetStream(NULL, NULL);
422 // do it as the very last thing because everything else can log messages
423 delete wxLog::SetActiveTarget(NULL
);
434 if (!wxApp::Initialize(vHab
))
438 // create the application object or ensure that one already exists
442 // The app may have declared a global application object, but we recommend
443 // the IMPLEMENT_APP macro is used instead, which sets an initializer
444 // function for delayed, dynamic app object construction.
445 wxCHECK_MSG( wxApp::GetInitializerFunction(), 0,
446 wxT("No initializer - use IMPLEMENT_APP macro.") );
447 wxTheApp
= (*wxApp::GetInitializerFunction()) ();
449 wxCHECK_MSG( wxTheApp
, 0, wxT("You have to define an instance of wxApp!") );
450 wxTheApp
->argc
= argc
;
453 wxTheApp
->argv
= new wxChar
*[argc
+1];
459 wxTheApp
->argv
[nArgc
] = wxStrdup(wxConvLibc
.cMB2WX(argv
[nArgc
]));
462 wxTheApp
->argv
[nArgc
] = (wxChar
*)NULL
;
464 wxTheApp
->argv
= argv
;
467 wxString
sName(wxFileNameFromPath(argv
[0]));
469 wxStripExtension(sName
);
470 wxTheApp
->SetAppName(sName
);
474 if (!wxTheApp
->OnInitGui())
479 if (wxTheApp
->OnInit())
481 nRetValue
= wxTheApp
->OnRun();
486 wxWindow
* pTopWindow
= wxTheApp
->GetTopWindow();
490 // Forcibly delete the window.
491 if (pTopWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
492 pTopWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
494 pTopWindow
->Close(TRUE
);
495 wxTheApp
->DeletePendingObjects();
500 wxTheApp
->SetTopWindow(NULL
);
508 bool wxApp::OnInitGui()
513 m_hMq
= ::WinCreateMsgQueue(vHabmain
, 0);
516 vError
= ::WinGetLastError(vHabmain
);
517 sError
= wxPMErrorToStr(vError
);
525 // Static member initialization
527 wxAppInitializerFunction
wxAppBase::m_appInitFn
= (wxAppInitializerFunction
) NULL
;
533 m_wantDebugOutput
= TRUE
;
537 m_nPrintMode
= wxPRINT_WINDOWS
;
538 m_exitOnFrameDelete
= TRUE
;
545 // Delete command-line args
547 for (i
= 0; i
< argc
; i
++)
555 bool wxApp::Initialized()
564 // Get and process a message, returning FALSE if WM_QUIT
565 // received (and also set the flag telling the app to exit the main loop)
567 bool wxApp::DoMessage()
569 BOOL bRc
= ::WinGetMsg(vHabmain
, &m_vMsg
, HWND(NULL
), 0, 0);
574 m_bKeepGoing
= FALSE
;
579 // should never happen, but let's test for it nevertheless
580 wxLogLastError("GetMessage");
585 wxASSERT_MSG( wxThread::IsMain()
586 ,wxT("only the main thread can process Windows messages")
589 static bool sbHadGuiLock
= TRUE
;
590 static wxMsgArray svSavedMessages
;
593 // if a secondary thread owns is doing GUI calls, save all messages for
594 // later processing - we can't process them right now because it will
595 // lead to recursive library calls (and we're not reentrant)
597 if (!wxGuiOwnedByMainThread())
599 sbHadGuiLock
= FALSE
;
601 // leave out WM_COMMAND messages: too dangerous, sometimes
602 // the message will be processed twice
603 if ( !wxIsWaitingForThread() ||
604 svCurrentMsg
.msg
!= WM_COMMAND
)
606 svSavedMessages
.Add(svCurrentMsg
);
613 // have we just regained the GUI lock? if so, post all of the saved
616 // FIXME of course, it's not _exactly_ the same as processing the
617 // messages normally - expect some things to break...
623 size_t nCount
= svSavedMessages
.Count();
625 for (size_t n
= 0; n
< nCount
; n
++)
627 QMSG vMsg
= svSavedMessages
[n
];
629 if ( !ProcessMessage((WXMSG
*)&vMsg
) )
631 ::WinDispatchMsg(vHabmain
, &vMsg
);
634 svSavedMessages
.Empty();
637 #endif // wxUSE_THREADS
639 // Process the message
640 if (!ProcessMessage((WXMSG
*)&svCurrentMsg
) )
642 ::WinDispatchMsg(vHabmain
, (PQMSG
)&svCurrentMsg
);
648 //////////////////////////////////////////////////////////////////////////////
650 // Keep trying to process messages until WM_QUIT
653 // If there are messages to be processed, they will all be
654 // processed and OnIdle will not be called.
655 // When there are no more messages, OnIdle is called.
656 // If OnIdle requests more time,
657 // it will be repeatedly called so long as there are no pending messages.
658 // A 'feature' of this is that once OnIdle has decided that no more processing
659 // is required, then it won't get processing time until further messages
660 // are processed (it'll sit in DoMessage).
662 //////////////////////////////////////////////////////////////////////////////
663 int wxApp::MainLoop()
670 wxMutexGuiLeaveOrEnter();
671 #endif // wxUSE_THREADS
672 while (!::WinPeekMsg(vHabmain
, &svCurrentMsg
, (HWND
)NULL
, 0, 0, PM_NOREMOVE
) &&
678 return (int)svCurrentMsg
.mp1
;
682 // Returns TRUE if more time is needed.
684 bool wxApp::ProcessIdle()
688 vEvent
.SetEventObject(this);
689 ProcessEvent(vEvent
);
690 return vEvent
.MoreRequested();
694 void wxApp::ProcessPendingEvents()
696 wxNode
* pNode
= wxPendingEvents
->First();
697 wxCriticalSectionLocker
vLocker(*wxPendingEventsLocker
);
701 wxEvtHandler
* pHandler
= (wxEvtHandler
*)pNode
->Data();
702 pHandler
->ProcessPendingEvents();
705 pNode
= wxPendingEvents
->First();
710 void wxApp::ExitMainLoop()
712 m_bKeepGoing
= FALSE
;
715 bool wxApp::Pending()
717 return (::WinPeekMsg(vHabmain
, (PQMSG
)&svCurrentMsg
, (HWND
)NULL
, 0, 0, PM_NOREMOVE
) != 0);
720 void wxApp::Dispatch()
725 //////////////////////////////////////////////////////////////////////////////
727 // Give all windows a chance to preprocess
728 // the message. Some may have accelerator tables, or have
729 // MDI complications.
731 //////////////////////////////////////////////////////////////////////////////
732 bool wxApp::ProcessMessage(
736 QMSG
* vMsg
= (PQMSG
)pWxmsg
;
737 HWND hWnd
= vMsg
->hwnd
;
738 wxWindow
* pWndThis
= wxFindWinFromHandle((WXHWND
)hWnd
);
742 // for some composite controls (like a combobox), wndThis might be NULL
743 // because the subcontrol is not a wxWindow, but only the control itself
744 // is - try to catch this case
746 while (hWnd
&& !pWndThis
)
748 hWnd
= ::WinQueryWindow(hWnd
, QW_PARENT
);
749 pWndThis
= wxFindWinFromHandle((WXHWND
)hWnd
);
752 // Anyone for a non-translation message? Try youngest descendants first.
753 for (pWnd
= pWndThis
; pWnd
; pWnd
= pWnd
->GetParent())
755 if (pWnd
->OS2ProcessMessage(pWxmsg
))
765 static bool sbInOnIdle
= FALSE
;
768 // Avoid recursion (via ProcessEvent default case)
776 // 'Garbage' collection of windows deleted with Close().
778 DeletePendingObjects();
781 // flush the logged messages if any
782 wxLog
* pLog
= wxLog::GetActiveTarget();
784 if (pLog
!= NULL
&& pLog
->HasPendingMessages())
788 // Send OnIdle events to all windows
789 if (SendIdleEvents())
792 // SendIdleEvents() returns TRUE if at least one window requested more
795 rEvent
.RequestMore(TRUE
);
799 // If they are pending events, we must process them.
802 ProcessPendingEvents();
809 // **** please implement me! ****
810 // Wake up the idle handler processor, even if it is in another thread...
813 // Send idle event to all top-level windows
814 bool wxApp::SendIdleEvents()
816 bool bNeedMore
= FALSE
;
817 wxWindowList::Node
* pNode
= wxTopLevelWindows
.GetFirst();
821 wxWindow
* pWin
= pNode
->GetData();
823 if (SendIdleEvents(pWin
))
825 pNode
= pNode
->GetNext();
831 // Send idle event to window and all subwindows
833 bool wxApp::SendIdleEvents(
837 bool bNeedMore
= FALSE
;
840 vEvent
.SetEventObject(pWin
);
841 pWin
->GetEventHandler()->ProcessEvent(vEvent
);
843 if (vEvent
.MoreRequested())
846 wxNode
* pNode
= pWin
->GetChildren().First();
850 wxWindow
* pWin
= (wxWindow
*) pNode
->Data();
852 if (SendIdleEvents(pWin
))
854 pNode
= pNode
->Next();
859 void wxApp::DeletePendingObjects()
861 wxNode
* pNode
= wxPendingDelete
.First();
865 wxObject
* pObj
= (wxObject
*)pNode
->Data();
869 if (wxPendingDelete
.Member(pObj
))
873 // Deleting one object may have deleted other pending
874 // objects, so start from beginning of list again.
876 pNode
= wxPendingDelete
.First();
880 void wxApp::OnEndSession(
881 wxCloseEvent
& WXUNUSED(rEvent
))
884 GetTopWindow()->Close(TRUE
);
888 // Default behaviour: close the application with prompts. The
889 // user can veto the close, and therefore the end session.
891 void wxApp::OnQueryEndSession(
897 if (!GetTopWindow()->Close(!rEvent
.CanVeto()))
904 wxLogError(_("Fatal error: exiting"));
909 // Yield to incoming messages
914 // We want to go back to the main message loop
915 // if we see a WM_QUIT. (?)
916 while (::WinPeekMsg(vHab
, &vMsg
, (HWND
)NULL
, 0, 0, PM_NOREMOVE
) && vMsg
.msg
!= WM_QUIT
)
918 if (!wxTheApp
->DoMessage())
921 // If they are pending events, we must process them.
923 wxTheApp
->ProcessPendingEvents();
928 wxIcon
wxApp::GetStdIcon(
934 case wxICON_INFORMATION
:
935 return wxIcon("wxICON_INFO");
937 case wxICON_QUESTION
:
938 return wxIcon("wxICON_QUESTION");
940 case wxICON_EXCLAMATION
:
941 return wxIcon("wxICON_WARNING");
944 wxFAIL_MSG(wxT("requested non existent standard icon"));
945 // still fall through
948 return wxIcon("wxICON_ERROR");
950 return wxIcon("wxICON_ERROR");
953 HINSTANCE
wxGetInstance()
958 void wxSetInstance(HINSTANCE hInst
)