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 void wxSetKeyboardHook(bool doIt
);
66 extern wxCursor
* g_globalCursor
;
68 HINSTANCE wxhInstance
= 0;
70 wxApp
* wxTheApp
= NULL
;
73 // FIXME why not const? and not static?
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
wxWndProc(HWND
, UINT
, MPARAM
, MPARAM
);
98 // ===========================================================================
100 // ===========================================================================
102 // ---------------------------------------------------------------------------
104 // ---------------------------------------------------------------------------
106 #if !USE_SHARED_LIBRARY
107 IMPLEMENT_DYNAMIC_CLASS(wxApp
, wxEvtHandler
)
109 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
110 EVT_IDLE(wxApp::OnIdle
)
111 EVT_END_SESSION(wxApp::OnEndSession
)
112 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession
)
117 bool wxApp::Initialize(
121 // Some people may wish to use this, but
122 // probably it shouldn't be here by default.
124 // wxRedirectIOToConsole();
127 wxBuffer
= new wxChar
[1500]; // FIXME; why?
129 wxClassInfo::InitializeClasses();
132 wxGetResource(wxT("wxWindows"), wxT("OsVersion"), &wxOsVersion
);
135 // I'm annoyed ... I don't know where to put this and I don't want to
136 // create a module for that as it's part of the core.
137 wxTheColourDatabase
= new wxColourDatabase(wxKEY_STRING
);
138 wxTheColourDatabase
->Initialize();
140 wxInitializeStockLists();
141 wxInitializeStockObjects();
143 #if wxUSE_WX_RESOURCES
144 wxInitializeResourceSystem();
147 wxBitmap::InitStandardHandlers();
149 g_globalCursor
= new wxCursor
;
152 wxSTD_FRAME_ICON
= ::WinLoadFileIcon(wxT("wxSTD_FRAME"), TRUE
);
153 wxSTD_MDIPARENTFRAME_ICON
= ::WinLoadFileIcon(wxT("wxSTD_MDIPARENTFRAME"), TRUE
);
154 wxSTD_MDICHILDFRAME_ICON
= ::WinLoadFileIcon(wxT("wxSTD_MDICHILDFRAME"), TRUE
);
156 wxDEFAULT_FRAME_ICON
= ::WinLoadFileIcon(wxT("wxDEFAULT_FRAME"), TRUE
);
157 wxDEFAULT_MDIPARENTFRAME_ICON
= ::WinLoadFileIcon(wxT("wxDEFAULT_MDIPARENTFRAME"), TRUE
);
158 wxDEFAULT_MDICHILDFRAME_ICON
= ::WinLoadFileIcon(wxT("wxDEFAULT_MDICHILDFRAME"), TRUE
);
160 RegisterWindowClasses(vHab
);
161 wxWinHandleList
= new wxList(wxKEY_INTEGER
);
163 // This is to foil optimizations in Visual C++ that throw out dummy.obj.
164 // PLEASE DO NOT ALTER THIS.
165 #if !defined(WXMAKINGDLL)
166 extern char wxDummyChar
;
167 if (wxDummyChar
) wxDummyChar
++;
170 wxSetKeyboardHook(TRUE
);
172 wxModule::RegisterModules();
173 if (!wxModule::InitializeModules())
178 // ---------------------------------------------------------------------------
179 // RegisterWindowClasses
180 // ---------------------------------------------------------------------------
182 // TODO we should only register classes really used by the app. For this it
183 // would be enough to just delay the class registration until an attempt
184 // to create a window of this class is made.
185 bool wxApp::RegisterWindowClasses(
191 if ((rc
= ::WinRegisterClass( vHab
194 ,CS_SIZEREDRAW
| CS_SYNCPAINT
| CS_HITTEST
| CS_CLIPCHILDREN
| CS_FRAME
198 wxLogLastError("RegisterClass(frame)");
203 if (!::WinRegisterClass( vHab
204 ,wxFrameClassNameNoRedraw
206 ,CS_HITTEST
| CS_CLIPCHILDREN
| CS_FRAME
210 wxLogLastError("RegisterClass(no redraw frame)");
215 if (!::WinRegisterClass( vHab
218 ,CS_SIZEREDRAW
| CS_SYNCPAINT
| CS_HITTEST
| CS_CLIPCHILDREN
| CS_FRAME
222 wxLogLastError("RegisterClass(MDI parent)");
227 if (!::WinRegisterClass( vHab
228 ,wxMDIFrameClassNameNoRedraw
230 ,CS_HITTEST
| CS_CLIPCHILDREN
| CS_FRAME
234 wxLogLastError("RegisterClass(no redraw MDI parent)");
239 if (!::WinRegisterClass( vHab
240 ,wxMDIChildFrameClassName
242 ,CS_MOVENOTIFY
| CS_SIZEREDRAW
| CS_SYNCPAINT
| CS_HITTEST
| CS_CLIPSIBLINGS
| CS_FRAME
246 wxLogLastError("RegisterClass(MDI child)");
251 if (!::WinRegisterClass( vHab
252 ,wxMDIChildFrameClassNameNoRedraw
254 ,CS_HITTEST
| CS_CLIPSIBLINGS
| CS_FRAME
258 wxLogLastError("RegisterClass(no redraw MDI child)");
263 if (!::WinRegisterClass( vHab
266 ,CS_MOVENOTIFY
| CS_SIZEREDRAW
| CS_HITTEST
| CS_CLIPSIBLINGS
| CS_SAVEBITS
| CS_SYNCPAINT
270 wxLogLastError("RegisterClass(Panel)");
275 if (!::WinRegisterClass( vHab
278 ,CS_MOVENOTIFY
| CS_SIZEREDRAW
| CS_HITTEST
| CS_CLIPSIBLINGS
| CS_SAVEBITS
| CS_SYNCPAINT
282 wxLogLastError("RegisterClass(Canvas)");
289 //// Cleans up any wxWindows internal structures left lying around
291 void wxApp::CleanUp()
296 // flush the logged messages if any and install a 'safer' log target: the
297 // default one (wxLogGui) can't be used after the resources are freed just
298 // below and the user suppliedo ne might be even more unsafe (using any
299 // wxWindows GUI function is unsafe starting from now)
300 wxLog::DontCreateOnDemand();
302 // this will flush the old messages if any
303 delete wxLog::SetActiveTarget(new wxLogStderr
);
306 // One last chance for pending objects to be cleaned up
307 wxTheApp
->DeletePendingObjects();
309 wxModule::CleanUpModules();
311 #if wxUSE_WX_RESOURCES
312 wxCleanUpResourceSystem();
314 // wxDefaultResourceTable->ClearTable();
317 // Indicate that the cursor can be freed, so that cursor won't be deleted
318 // by deleting the bitmap list before g_globalCursor goes out of scope
319 // (double deletion of the cursor).
320 wxSetCursor(wxNullCursor
);
321 delete g_globalCursor
;
322 g_globalCursor
= NULL
;
324 wxDeleteStockObjects();
326 // Destroy all GDI lists, etc.
327 wxDeleteStockLists();
329 delete wxTheColourDatabase
;
330 wxTheColourDatabase
= NULL
;
332 wxBitmap::CleanUpHandlers();
337 //// WINDOWS-SPECIFIC CLEANUP
339 wxSetKeyboardHook(FALSE
);
341 if (wxSTD_FRAME_ICON
)
342 ::WinFreeFileIcon(wxSTD_FRAME_ICON
);
343 if (wxSTD_MDICHILDFRAME_ICON
)
344 ::WinFreeFileIcon(wxSTD_MDICHILDFRAME_ICON
);
345 if (wxSTD_MDIPARENTFRAME_ICON
)
346 ::WinFreeFileIcon(wxSTD_MDIPARENTFRAME_ICON
);
348 if (wxDEFAULT_FRAME_ICON
)
349 ::WinFreeFileIcon(wxDEFAULT_FRAME_ICON
);
350 if (wxDEFAULT_MDICHILDFRAME_ICON
)
351 ::WinFreeFileIcon(wxDEFAULT_MDICHILDFRAME_ICON
);
352 if (wxDEFAULT_MDIPARENTFRAME_ICON
)
353 ::WinFreeFileIcon(wxDEFAULT_MDIPARENTFRAME_ICON
);
355 if ( wxDisableButtonBrush
)
357 // TODO: ::DeleteObject( wxDisableButtonBrush );
361 delete wxWinHandleList
;
363 // GL: I'm annoyed ... I don't know where to put this and I don't want to
364 // create a module for that as it's part of the core.
366 delete wxPendingEvents
;
367 delete wxPendingEventsLocker
;
368 // If we don't do the following, we get an apparent memory leak.
369 ((wxEvtHandler
&) wxDefaultValidator
).ClearEventLocker();
372 wxClassInfo::CleanUpClasses();
377 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
378 // At this point we want to check if there are any memory
379 // blocks that aren't part of the wxDebugContext itself,
380 // as a special case. Then when dumping we need to ignore
381 // wxDebugContext, too.
382 if (wxDebugContext::CountObjectsLeft(TRUE
) > 0)
384 wxLogDebug(wxT("There were memory leaks."));
385 wxDebugContext::Dump();
386 wxDebugContext::PrintStatistics();
388 // wxDebugContext::SetStream(NULL, NULL);
392 // do it as the very last thing because everything else can log messages
393 delete wxLog::SetActiveTarget(NULL
);
404 if (!wxApp::Initialize(vHab
))
408 // create the application object or ensure that one already exists
412 wxCHECK_MSG( wxApp::GetInitializerFunction()
414 ,wxT("wxWindows error: No initializer - use IMPLEMENT_APP macro.\n")
417 wxAppInitializerFunction fnAppIni
= wxApp::GetInitializerFunction();
418 wxObject
* pTest_app
= fnAppIni();
420 wxTheApp
= (wxApp
*)pTest_app
;
422 wxCHECK_MSG( wxTheApp
, -1, wxT("wxWindows error: no application object") );
423 wxTheApp
->argc
= argc
;
426 wxTheApp
->argv
= new wxChar
*[argc
+1];
432 wxTheApp
->argv
[nArgc
] = wxStrdup(wxConvLibc
.cMB2WX(argv
[nArgc
]));
435 wxTheApp
->argv
[nArgc
] = (wxChar
*)NULL
;
437 wxTheApp
->argv
= argv
;
440 wxString
sName(wxFileNameFromPath(argv
[0]));
442 wxStripExtension(sName
);
443 wxTheApp
->SetAppName(sName
);
447 if (!wxTheApp
->OnInitGui())
452 if (wxTheApp
->OnInit())
460 wxWindow
* pTopWindow
= wxTheApp
->GetTopWindow();
464 // Forcibly delete the window.
465 if (pTopWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
466 pTopWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
468 pTopWindow
->Close(TRUE
);
469 wxTheApp
->DeletePendingObjects();
474 wxTheApp
->SetTopWindow(NULL
);
483 bool wxApp::OnInitGui()
485 vHabmain
= WinInitialize(0);
486 m_hMq
= WinCreateMsgQueue(vHabmain
, 0);
492 // Static member initialization
494 wxAppInitializerFunction
wxAppBase::m_appInitFn
= (wxAppInitializerFunction
) NULL
;
500 m_wantDebugOutput
= TRUE
;
504 m_nPrintMode
= wxPRINT_WINDOWS
;
505 m_exitOnFrameDelete
= TRUE
;
511 // Delete command-line args
513 for (i
= 0; i
< argc
; i
++)
520 bool wxApp::Initialized()
529 // Get and process a message, returning FALSE if WM_QUIT
530 // received (and also set the flag telling the app to exit the main loop)
532 bool wxApp::DoMessage()
534 BOOL bRc
= ::WinGetMsg(vHabmain
, &m_vMsg
, HWND(NULL
), 0, 0);
539 m_bKeepGoing
= FALSE
;
544 // should never happen, but let's test for it nevertheless
545 wxLogLastError("GetMessage");
550 wxASSERT_MSG( wxThread::IsMain()
551 ,wxT("only the main thread can process Windows messages")
554 static bool sbHadGuiLock
= TRUE
;
555 static wxMsgArray svSavedMessages
;
558 // if a secondary thread owns is doing GUI calls, save all messages for
559 // later processing - we can't process them right now because it will
560 // lead to recursive library calls (and we're not reentrant)
562 if (!wxGuiOwnedByMainThread())
564 sbHadGuiLock
= FALSE
;
566 // leave out WM_COMMAND messages: too dangerous, sometimes
567 // the message will be processed twice
568 if ( !wxIsWaitingForThread() ||
569 svCurrentMsg
.msg
!= WM_COMMAND
)
571 svSavedMessages
.Add(svCurrentMsg
);
578 // have we just regained the GUI lock? if so, post all of the saved
581 // FIXME of course, it's not _exactly_ the same as processing the
582 // messages normally - expect some things to break...
588 size_t nCount
= svSavedMessages
.Count();
590 for (size_t n
= 0; n
< nCount
; n
++)
592 QMSG vMsg
= svSavedMessages
[n
];
594 if ( !ProcessMessage((WXMSG
*)&vMsg
) )
596 ::WinDispatchMsg(vHabmain
, &vMsg
);
599 svSavedMessages
.Empty();
602 #endif // wxUSE_THREADS
604 // Process the message
605 if (!ProcessMessage((WXMSG
*)&svCurrentMsg
) )
607 ::WinDispatchMsg(vHabmain
, (PQMSG
)&svCurrentMsg
);
613 //////////////////////////////////////////////////////////////////////////////
615 // Keep trying to process messages until WM_QUIT
618 // If there are messages to be processed, they will all be
619 // processed and OnIdle will not be called.
620 // When there are no more messages, OnIdle is called.
621 // If OnIdle requests more time,
622 // it will be repeatedly called so long as there are no pending messages.
623 // A 'feature' of this is that once OnIdle has decided that no more processing
624 // is required, then it won't get processing time until further messages
625 // are processed (it'll sit in DoMessage).
627 //////////////////////////////////////////////////////////////////////////////
628 int wxApp::MainLoop()
635 wxMutexGuiLeaveOrEnter();
636 #endif // wxUSE_THREADS
637 while (!::WinPeekMsg(vHabmain
, &svCurrentMsg
, (HWND
)NULL
, 0, 0, PM_NOREMOVE
) &&
643 return (int)svCurrentMsg
.mp1
;
647 // Returns TRUE if more time is needed.
649 bool wxApp::ProcessIdle()
653 vEvent
.SetEventObject(this);
654 ProcessEvent(vEvent
);
655 return vEvent
.MoreRequested();
659 void wxApp::ProcessPendingEvents()
661 wxNode
* pNode
= wxPendingEvents
->First();
662 wxCriticalSectionLocker
vLocker(*wxPendingEventsLocker
);
666 wxEvtHandler
* pHandler
= (wxEvtHandler
*)pNode
->Data();
667 pHandler
->ProcessPendingEvents();
670 pNode
= wxPendingEvents
->First();
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
* vMsg
= (PQMSG
)pWxmsg
;
702 HWND hWnd
= vMsg
->hwnd
;
703 wxWindow
* pWndThis
= wxFindWinFromHandle((WXHWND
)hWnd
);
707 // for some composite controls (like a combobox), wndThis might be NULL
708 // because the subcontrol is not a wxWindow, but only the control itself
709 // is - try to catch this case
711 while (hWnd
&& !pWndThis
)
713 hWnd
= ::WinQueryWindow(hWnd
, QW_PARENT
);
714 pWndThis
= wxFindWinFromHandle((WXHWND
)hWnd
);
717 // Anyone for a non-translation message? Try youngest descendants first.
718 for (pWnd
= pWndThis
; pWnd
; pWnd
= pWnd
->GetParent())
720 if (pWnd
->OS2ProcessMessage(pWxmsg
))
730 static bool sbInOnIdle
= FALSE
;
733 // Avoid recursion (via ProcessEvent default case)
741 // 'Garbage' collection of windows deleted with Close().
743 DeletePendingObjects();
746 // flush the logged messages if any
747 wxLog
* pLog
= wxLog::GetActiveTarget();
749 if (pLog
!= NULL
&& pLog
->HasPendingMessages())
753 // Send OnIdle events to all windows
754 if (SendIdleEvents())
757 // SendIdleEvents() returns TRUE if at least one window requested more
760 rEvent
.RequestMore(TRUE
);
764 // If they are pending events, we must process them.
767 ProcessPendingEvents();
774 // **** please implement me! ****
775 // Wake up the idle handler processor, even if it is in another thread...
778 // Send idle event to all top-level windows
779 bool wxApp::SendIdleEvents()
781 bool bNeedMore
= FALSE
;
782 wxWindowList::Node
* pNode
= wxTopLevelWindows
.GetFirst();
786 wxWindow
* pWin
= pNode
->GetData();
788 if (SendIdleEvents(pWin
))
790 pNode
= pNode
->GetNext();
796 // Send idle event to window and all subwindows
798 bool wxApp::SendIdleEvents(
802 bool bNeedMore
= FALSE
;
805 vEvent
.SetEventObject(pWin
);
806 pWin
->GetEventHandler()->ProcessEvent(vEvent
);
808 if (vEvent
.MoreRequested())
811 wxNode
* pNode
= pWin
->GetChildren().First();
815 wxWindow
* pWin
= (wxWindow
*) pNode
->Data();
817 if (SendIdleEvents(pWin
))
819 pNode
= pNode
->Next();
824 void wxApp::DeletePendingObjects()
826 wxNode
* pNode
= wxPendingDelete
.First();
830 wxObject
* pObj
= (wxObject
*)pNode
->Data();
834 if (wxPendingDelete
.Member(pObj
))
838 // Deleting one object may have deleted other pending
839 // objects, so start from beginning of list again.
841 pNode
= wxPendingDelete
.First();
845 void wxApp::OnEndSession(
846 wxCloseEvent
& WXUNUSED(rEvent
))
849 GetTopWindow()->Close(TRUE
);
853 // Default behaviour: close the application with prompts. The
854 // user can veto the close, and therefore the end session.
856 void wxApp::OnQueryEndSession(
862 if (!GetTopWindow()->Close(!rEvent
.CanVeto()))
869 wxLogError(_("Fatal error: exiting"));
874 // Yield to incoming messages
879 // We want to go back to the main message loop
880 // if we see a WM_QUIT. (?)
881 while (::WinPeekMsg(vHab
, &vMsg
, (HWND
)NULL
, 0, 0, PM_NOREMOVE
) && vMsg
.msg
!= WM_QUIT
)
883 if (!wxTheApp
->DoMessage())
886 // If they are pending events, we must process them.
888 wxTheApp
->ProcessPendingEvents();
893 wxIcon
wxApp::GetStdIcon(
899 case wxICON_INFORMATION
:
900 return wxIcon("wxICON_INFO");
902 case wxICON_QUESTION
:
903 return wxIcon("wxICON_QUESTION");
905 case wxICON_EXCLAMATION
:
906 return wxIcon("wxICON_WARNING");
909 wxFAIL_MSG(wxT("requested non existent standard icon"));
910 // still fall through
913 return wxIcon("wxICON_ERROR");
915 return wxIcon("wxICON_ERROR");
918 HINSTANCE
wxGetInstance()
923 void wxSetInstance(HINSTANCE hInst
)