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 wxChar
* wxOsVersion
;
67 extern wxList
* wxWinHandleList
;
68 extern wxList WXDLLEXPORT wxPendingDelete
;
69 extern wxCursor
* g_globalCursor
;
71 HAB vHabmain
= NULLHANDLE
;
73 wxApp
* wxTheApp
= NULL
;
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");
86 HICON wxSTD_FRAME_ICON
= (HICON
) NULL
;
87 HICON wxSTD_MDICHILDFRAME_ICON
= (HICON
) NULL
;
88 HICON wxSTD_MDIPARENTFRAME_ICON
= (HICON
) NULL
;
90 HICON wxDEFAULT_FRAME_ICON
= (HICON
) NULL
;
91 HICON wxDEFAULT_MDICHILDFRAME_ICON
= (HICON
) NULL
;
92 HICON wxDEFAULT_MDIPARENTFRAME_ICON
= (HICON
) NULL
;
94 HBRUSH wxDisableButtonBrush
= (HBRUSH
) 0;
96 MRESULT EXPENTRY
wxWndProc( HWND
102 // ===========================================================================
104 // ===========================================================================
106 // ---------------------------------------------------------------------------
108 // ---------------------------------------------------------------------------
110 IMPLEMENT_DYNAMIC_CLASS(wxApp
, wxEvtHandler
)
112 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
113 EVT_IDLE(wxApp::OnIdle
)
114 EVT_END_SESSION(wxApp::OnEndSession
)
115 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession
)
121 bool wxApp::Initialize(
126 // OS2 has to have an anchorblock
128 vHab
= WinInitialize(0);
135 // Some people may wish to use this, but
136 // probably it shouldn't be here by default.
138 // wxRedirectIOToConsole();
141 wxBuffer
= new wxChar
[1500]; // FIXME; why?
143 wxClassInfo::InitializeClasses();
146 wxGetResource(wxT("wxWindows"), wxT("OsVersion"), &wxOsVersion
);
150 wxPendingEventsLocker
= new wxCriticalSection
;
153 wxTheColourDatabase
= new wxColourDatabase(wxKEY_STRING
);
154 wxTheColourDatabase
->Initialize();
156 wxInitializeStockLists();
157 wxInitializeStockObjects();
159 #if wxUSE_WX_RESOURCES
160 wxInitializeResourceSystem();
163 wxBitmap::InitStandardHandlers();
165 RegisterWindowClasses(vHab
);
166 wxWinHandleList
= new wxList(wxKEY_INTEGER
);
168 // This is to foil optimizations in Visual C++ that throw out dummy.obj.
169 // PLEASE DO NOT ALTER THIS.
170 #if !defined(WXMAKINGDLL) && defined(__VISAGECPP__)
171 extern char wxDummyChar
;
172 if (wxDummyChar
) wxDummyChar
++;
175 // wxSetKeyboardHook(TRUE);
177 wxModule::RegisterModules();
178 if (!wxModule::InitializeModules())
181 } // end of wxApp::Initialize
183 // ---------------------------------------------------------------------------
184 // RegisterWindowClasses
185 // ---------------------------------------------------------------------------
187 bool wxApp::RegisterWindowClasses(
195 if (!::WinRegisterClass( vHab
198 ,CS_SIZEREDRAW
| CS_SYNCPAINT
202 vError
= ::WinGetLastError(vHab
);
203 sError
= wxPMErrorToStr(vError
);
204 wxLogLastError(sError
);
208 if (!::WinRegisterClass( vHab
209 ,wxFrameClassNameNoRedraw
215 vError
= ::WinGetLastError(vHab
);
216 sError
= wxPMErrorToStr(vError
);
217 wxLogLastError(sError
);
221 if (!::WinRegisterClass( vHab
224 ,CS_SIZEREDRAW
| CS_SYNCPAINT
228 vError
= ::WinGetLastError(vHab
);
229 sError
= wxPMErrorToStr(vError
);
230 wxLogLastError(sError
);
234 if (!::WinRegisterClass( vHab
235 ,wxMDIFrameClassNameNoRedraw
241 vError
= ::WinGetLastError(vHab
);
242 sError
= wxPMErrorToStr(vError
);
243 wxLogLastError(sError
);
247 if (!::WinRegisterClass( vHab
248 ,wxMDIChildFrameClassName
250 ,CS_MOVENOTIFY
| CS_SIZEREDRAW
| CS_SYNCPAINT
| CS_HITTEST
254 vError
= ::WinGetLastError(vHab
);
255 sError
= wxPMErrorToStr(vError
);
256 wxLogLastError(sError
);
260 if (!::WinRegisterClass( vHab
261 ,wxMDIChildFrameClassNameNoRedraw
267 vError
= ::WinGetLastError(vHab
);
268 sError
= wxPMErrorToStr(vError
);
269 wxLogLastError(sError
);
273 if (!::WinRegisterClass( vHab
276 ,CS_MOVENOTIFY
| CS_SIZEREDRAW
| CS_HITTEST
| CS_SAVEBITS
| CS_SYNCPAINT
280 vError
= ::WinGetLastError(vHab
);
281 sError
= wxPMErrorToStr(vError
);
282 wxLogLastError(sError
);
286 if (!::WinRegisterClass( vHab
289 ,CS_MOVENOTIFY
| CS_SIZEREDRAW
| CS_HITTEST
| CS_SAVEBITS
| CS_SYNCPAINT
293 vError
= ::WinGetLastError(vHab
);
294 sError
= wxPMErrorToStr(vError
);
295 wxLogLastError(sError
);
299 } // end of wxApp::RegisterWindowClasses
302 // Cleans up any wxWindows internal structures left lying around
304 void wxApp::CleanUp()
313 // Flush the logged messages if any and install a 'safer' log target: the
314 // default one (wxLogGui) can't be used after the resources are freed just
315 // below and the user suppliedo ne might be even more unsafe (using any
316 // wxWindows GUI function is unsafe starting from now)
318 wxLog::DontCreateOnDemand();
321 // This will flush the old messages if any
323 delete wxLog::SetActiveTarget(new wxLogStderr
);
327 // One last chance for pending objects to be cleaned up
329 wxTheApp
->DeletePendingObjects();
331 wxModule::CleanUpModules();
333 #if wxUSE_WX_RESOURCES
334 wxCleanUpResourceSystem();
337 wxDeleteStockObjects();
340 // Destroy all GDI lists, etc.
342 wxDeleteStockLists();
344 delete wxTheColourDatabase
;
345 wxTheColourDatabase
= NULL
;
347 wxBitmap::CleanUpHandlers();
353 // PM-SPECIFIC CLEANUP
356 // wxSetKeyboardHook(FALSE);
358 if (wxSTD_FRAME_ICON
)
359 ::WinFreeFileIcon(wxSTD_FRAME_ICON
);
360 if (wxSTD_MDICHILDFRAME_ICON
)
361 ::WinFreeFileIcon(wxSTD_MDICHILDFRAME_ICON
);
362 if (wxSTD_MDIPARENTFRAME_ICON
)
363 ::WinFreeFileIcon(wxSTD_MDIPARENTFRAME_ICON
);
365 if (wxDEFAULT_FRAME_ICON
)
366 ::WinFreeFileIcon(wxDEFAULT_FRAME_ICON
);
367 if (wxDEFAULT_MDICHILDFRAME_ICON
)
368 ::WinFreeFileIcon(wxDEFAULT_MDICHILDFRAME_ICON
);
369 if (wxDEFAULT_MDIPARENTFRAME_ICON
)
370 ::WinFreeFileIcon(wxDEFAULT_MDIPARENTFRAME_ICON
);
372 if ( wxDisableButtonBrush
)
374 // TODO: ::DeleteObject( wxDisableButtonBrush );
378 delete wxWinHandleList
;
380 delete wxPendingEvents
;
382 delete wxPendingEventsLocker
;
383 // If we don't do the following, we get an apparent memory leak.
384 ((wxEvtHandler
&) wxDefaultValidator
).ClearEventLocker();
387 wxClassInfo::CleanUpClasses();
392 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
393 // At this point we want to check if there are any memory
394 // blocks that aren't part of the wxDebugContext itself,
395 // as a special case. Then when dumping we need to ignore
396 // wxDebugContext, too.
397 if (wxDebugContext::CountObjectsLeft(TRUE
) > 0)
399 wxLogDebug(wxT("There were memory leaks."));
400 wxDebugContext::Dump();
401 wxDebugContext::PrintStatistics();
403 // wxDebugContext::SetStream(NULL, NULL);
407 // do it as the very last thing because everything else can log messages
408 delete wxLog::SetActiveTarget(NULL
);
410 } // end of wxApp::CleanUp
419 if (!wxApp::Initialize(vHab
))
423 // create the application object or ensure that one already exists
427 // The app may have declared a global application object, but we recommend
428 // the IMPLEMENT_APP macro is used instead, which sets an initializer
429 // function for delayed, dynamic app object construction.
430 wxCHECK_MSG( wxApp::GetInitializerFunction(), 0,
431 wxT("No initializer - use IMPLEMENT_APP macro.") );
432 wxTheApp
= (*wxApp::GetInitializerFunction()) ();
434 wxCHECK_MSG( wxTheApp
, 0, wxT("You have to define an instance of wxApp!") );
435 wxTheApp
->argc
= argc
;
438 wxTheApp
->argv
= new wxChar
*[argc
+1];
444 wxTheApp
->argv
[nArgc
] = wxStrdup(wxConvLibc
.cMB2WX(argv
[nArgc
]));
447 wxTheApp
->argv
[nArgc
] = (wxChar
*)NULL
;
449 wxTheApp
->argv
= argv
;
452 wxString
sName(wxFileNameFromPath(argv
[0]));
454 wxStripExtension(sName
);
455 wxTheApp
->SetAppName(sName
);
459 if (!wxTheApp
->OnInitGui())
464 if (wxTheApp
->OnInit())
466 nRetValue
= wxTheApp
->OnRun();
471 wxWindow
* pTopWindow
= wxTheApp
->GetTopWindow();
475 // Forcibly delete the window.
476 if (pTopWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
477 pTopWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
479 pTopWindow
->Close(TRUE
);
480 wxTheApp
->DeletePendingObjects();
485 wxTheApp
->SetTopWindow(NULL
);
493 bool wxApp::OnInitGui()
498 m_hMq
= ::WinCreateMsgQueue(vHabmain
, 0);
501 vError
= ::WinGetLastError(vHabmain
);
502 sError
= wxPMErrorToStr(vError
);
507 } // end of wxApp::OnInitGui
510 // Static member initialization
512 wxAppInitializerFunction
wxAppBase::m_appInitFn
= (wxAppInitializerFunction
) NULL
;
518 m_wantDebugOutput
= TRUE
;
522 m_nPrintMode
= wxPRINT_WINDOWS
;
523 m_exitOnFrameDelete
= TRUE
;
525 } // end of wxApp::wxApp
530 // Delete command-line args
534 for (i
= 0; i
< argc
; i
++)
540 } // end of wxApp::~wxApp
542 bool wxApp::Initialized()
548 } // end of wxApp::Initialized
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)
554 bool wxApp::DoMessage()
556 BOOL bRc
= ::WinGetMsg(vHabmain
, &m_vMsg
, HWND(NULL
), 0, 0);
561 m_bKeepGoing
= FALSE
;
566 // should never happen, but let's test for it nevertheless
567 wxLogLastError("GetMessage");
572 wxASSERT_MSG( wxThread::IsMain()
573 ,wxT("only the main thread can process Windows messages")
576 static bool sbHadGuiLock
= TRUE
;
577 static wxMsgArray svSavedMessages
;
580 // If a secondary thread owns is doing GUI calls, save all messages for
581 // later processing - we can't process them right now because it will
582 // lead to recursive library calls (and we're not reentrant)
584 if (!wxGuiOwnedByMainThread())
586 sbHadGuiLock
= FALSE
;
589 // Leave out WM_COMMAND messages: too dangerous, sometimes
590 // the message will be processed twice
592 if ( !wxIsWaitingForThread() ||
593 svCurrentMsg
.msg
!= WM_COMMAND
)
595 svSavedMessages
.Add(svCurrentMsg
);
602 // Have we just regained the GUI lock? if so, post all of the saved
609 size_t nCount
= svSavedMessages
.Count();
611 for (size_t n
= 0; n
< nCount
; n
++)
613 QMSG vMsg
= svSavedMessages
[n
];
615 if ( !ProcessMessage((WXMSG
*)&vMsg
) )
617 ::WinDispatchMsg(vHabmain
, &vMsg
);
620 svSavedMessages
.Empty();
623 #endif // wxUSE_THREADS
625 // Process the message
626 if (!ProcessMessage((WXMSG
*)&svCurrentMsg
) )
628 ::WinDispatchMsg(vHabmain
, (PQMSG
)&svCurrentMsg
);
632 } // end of wxApp::DoMessage
634 //////////////////////////////////////////////////////////////////////////////
636 // Keep trying to process messages until WM_QUIT
639 // If there are messages to be processed, they will all be
640 // processed and OnIdle will not be called.
641 // When there are no more messages, OnIdle is called.
642 // If OnIdle requests more time,
643 // it will be repeatedly called so long as there are no pending messages.
644 // A 'feature' of this is that once OnIdle has decided that no more processing
645 // is required, then it won't get processing time until further messages
646 // are processed (it'll sit in DoMessage).
648 //////////////////////////////////////////////////////////////////////////////
649 int wxApp::MainLoop()
656 wxMutexGuiLeaveOrEnter();
657 #endif // wxUSE_THREADS
658 while (!Pending() && ProcessIdle())
663 return (int)svCurrentMsg
.mp1
;
664 } // end of wxApp::MainLoop
667 // Returns TRUE if more time is needed.
669 bool wxApp::ProcessIdle()
673 vEvent
.SetEventObject(this);
674 ProcessEvent(vEvent
);
675 return vEvent
.MoreRequested();
676 } // end of wxApp::ProcessIdle
678 void wxApp::ExitMainLoop()
680 m_bKeepGoing
= FALSE
;
683 bool wxApp::Pending()
685 return (::WinPeekMsg(vHabmain
, (PQMSG
)&svCurrentMsg
, (HWND
)NULL
, 0, 0, PM_NOREMOVE
) != 0);
688 void wxApp::Dispatch()
693 //////////////////////////////////////////////////////////////////////////////
695 // Give all windows a chance to preprocess
696 // the message. Some may have accelerator tables, or have
697 // MDI complications.
699 //////////////////////////////////////////////////////////////////////////////
700 bool wxApp::ProcessMessage(
704 QMSG
* vMsg
= (PQMSG
)pWxmsg
;
705 HWND hWnd
= vMsg
->hwnd
;
706 wxWindow
* pWndThis
= wxFindWinFromHandle((WXHWND
)hWnd
);
711 // We must relay WM_MOUSEMOVE events to the tooltip ctrl if we want it to
712 // popup the tooltip bubbles
714 if (pWndThis
&& (vMsg
->msg
== WM_MOUSEMOVE
))
716 wxToolTip
* pToolTip
= pWndThis
->GetToolTip();
719 pToolTip
->RelayEvent(pWxmsg
);
722 #endif // wxUSE_TOOLTIPS
725 // For some composite controls (like a combobox), wndThis might be NULL
726 // because the subcontrol is not a wxWindow, but only the control itself
727 // is - try to catch this case
729 while (hWnd
&& !pWndThis
)
731 hWnd
= ::WinQueryWindow(hWnd
, QW_PARENT
);
732 pWndThis
= wxFindWinFromHandle((WXHWND
)hWnd
);
736 // Anyone for a non-translation message? Try youngest descendants first.
738 for (pWnd
= pWndThis
; pWnd
; pWnd
= pWnd
->GetParent())
740 if (pWnd
->OS2ProcessMessage(pWxmsg
))
744 } // end of wxApp::ProcessMessage
750 static bool sbInOnIdle
= FALSE
;
753 // Avoid recursion (via ProcessEvent default case)
761 // If there are pending events, we must process them: pending events
762 // are either events to the threads other than main or events posted
763 // with wxPostEvent() functions
765 ProcessPendingEvents();
768 // 'Garbage' collection of windows deleted with Close().
770 DeletePendingObjects();
774 // Flush the logged messages if any
776 wxLog::FlushActive();
780 // Send OnIdle events to all windows
782 if (SendIdleEvents())
785 // SendIdleEvents() returns TRUE if at least one window requested more
788 rEvent
.RequestMore(TRUE
);
791 } // end of wxApp::OnIdle
793 // Send idle event to all top-level windows
794 bool wxApp::SendIdleEvents()
796 bool bNeedMore
= FALSE
;
797 wxWindowList::Node
* pNode
= wxTopLevelWindows
.GetFirst();
801 wxWindow
* pWin
= pNode
->GetData();
803 if (SendIdleEvents(pWin
))
805 pNode
= pNode
->GetNext();
808 } // end of wxApp::SendIdleEvents
811 // Send idle event to window and all subwindows
813 bool wxApp::SendIdleEvents(
817 bool bNeedMore
= FALSE
;
820 vEvent
.SetEventObject(pWin
);
821 pWin
->GetEventHandler()->ProcessEvent(vEvent
);
823 if (vEvent
.MoreRequested())
826 wxNode
* pNode
= pWin
->GetChildren().First();
830 wxWindow
* pWin
= (wxWindow
*) pNode
->Data();
832 if (SendIdleEvents(pWin
))
834 pNode
= pNode
->Next();
837 } // end of wxApp::SendIdleEvents
839 void wxApp::DeletePendingObjects()
841 wxNode
* pNode
= wxPendingDelete
.First();
845 wxObject
* pObj
= (wxObject
*)pNode
->Data();
849 if (wxPendingDelete
.Member(pObj
))
853 // Deleting one object may have deleted other pending
854 // objects, so start from beginning of list again.
856 pNode
= wxPendingDelete
.First();
858 } // end of wxApp::DeletePendingObjects
860 void wxApp::OnEndSession(
861 wxCloseEvent
& WXUNUSED(rEvent
))
864 GetTopWindow()->Close(TRUE
);
865 } // end of wxApp::OnEndSession
868 // Default behaviour: close the application with prompts. The
869 // user can veto the close, and therefore the end session.
871 void wxApp::OnQueryEndSession(
877 if (!GetTopWindow()->Close(!rEvent
.CanVeto()))
880 } // end of wxApp::OnQueryEndSession
884 wxLogError(_("Fatal error: exiting"));
890 // Yield to incoming messages
898 // Disable log flushing from here because a call to wxYield() shouldn't
899 // normally result in message boxes popping up &c
904 // We want to go back to the main message loop
905 // if we see a WM_QUIT. (?)
907 while (::WinPeekMsg(vHab
, &vMsg
, (HWND
)NULL
, 0, 0, PM_NOREMOVE
) && vMsg
.msg
!= WM_QUIT
)
910 wxMutexGuiLeaveOrEnter();
911 #endif // wxUSE_THREADS
912 if (!wxTheApp
->DoMessage())
916 // If they are pending events, we must process them.
919 wxTheApp
->ProcessPendingEvents();
922 // Let the logs be flashed again
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");
951 } // end of wxApp::GetStdIcon
953 //-----------------------------------------------------------------------------
955 //-----------------------------------------------------------------------------
960 // Send the top window a dummy message so idle handler processing will
961 // start up again. Doing it this way ensures that the idle handler
962 // wakes up in the right thread (see also wxWakeUpMainThread() which does
963 // the same for the main app thread only)
965 wxWindow
* pTopWindow
= wxTheApp
->GetTopWindow();
969 if ( !::WinPostMsg(GetHwndOf(pTopWindow
), WM_NULL
, (MPARAM
)0, (MPARAM
)0))
972 // Should never happen
974 wxLogLastError("PostMessage(WM_NULL)");
977 } // end of wxWakeUpIdle
979 HINSTANCE
wxGetInstance()
984 void wxSetInstance(HINSTANCE hInst
)