X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/e39af974ef7846e26686ae39d74e4696c1fef0c3..6ce43ac97db5cab1373d2e3c158849faffa8128d:/src/os2/evtloop.cpp diff --git a/src/os2/evtloop.cpp b/src/os2/evtloop.cpp index 2b72b4088d..38d378623b 100644 --- a/src/os2/evtloop.cpp +++ b/src/os2/evtloop.cpp @@ -31,22 +31,26 @@ #ifndef WX_PRECOMP #include "wx/window.h" #include "wx/app.h" + #include "wx/timer.h" #endif //WX_PRECOMP #include "wx/evtloop.h" +#include "wx/log.h" #include "wx/tooltip.h" +#include "wx/ptr_scpd.h" #include "wx/os2/private.h" #if wxUSE_THREADS // define the array of QMSG strutures WX_DECLARE_OBJARRAY(QMSG, wxMsgArray); - // VS: this is a bit dirty - it duplicates same declaration in app.cpp - // (and there's no WX_DEFINE_OBJARRAY for that reason - it is already - // defined in app.cpp). + + #include "wx/arrimpl.cpp" + + WX_DEFINE_OBJARRAY(wxMsgArray); #endif -extern HAB vHabMain; +extern HAB vHabmain; // ---------------------------------------------------------------------------- // wxEventLoopImpl @@ -77,6 +81,36 @@ private: int m_exitcode; }; +// ---------------------------------------------------------------------------- +// helper class +// ---------------------------------------------------------------------------- + +wxDEFINE_TIED_SCOPED_PTR_TYPE(wxEventLoopImpl); + +// this object sets the wxEventLoop given to the ctor as the currently active +// one and unsets it in its dtor +class wxEventLoopActivator +{ +public: + wxEventLoopActivator(wxEventLoop **pActive, + wxEventLoop *evtLoop) + { + m_pActive = pActive; + m_evtLoopOld = *pActive; + *pActive = evtLoop; + } + + ~wxEventLoopActivator() + { + // restore the previously active event loop + *m_pActive = m_evtLoopOld; + } + +private: + wxEventLoop *m_evtLoopOld; + wxEventLoop **m_pActive; +}; + // ============================================================================ // wxEventLoopImpl implementation // ============================================================================ @@ -91,44 +125,92 @@ void wxEventLoopImpl::ProcessMessage(QMSG *msg) if ( !PreProcessMessage(msg) ) { // if it wasn't done, dispatch it to the corresponding window - ::WinDispatchMsg(vHabMain, msg); + ::WinDispatchMsg(vHabmain, msg); } } -bool wxEventLoopImpl::PreProcessMessage(QMSG *msg) +bool wxEventLoopImpl::PreProcessMessage(QMSG *pMsg) { - HWND hWnd = msg->hwnd; - wxWindow *wndThis = wxFindWinFromHandle((WXHWND)hWnd); - -#if wxUSE_TOOLTIPS - // we must relay WM_MOUSEMOVE events to the tooltip ctrl if we want it to - // popup the tooltip bubbles - if ( wndThis && (msg->message == WM_MOUSEMOVE) ) + HWND hWnd = pMsg->hwnd; + wxWindow *pWndThis = wxFindWinFromHandle((WXHWND)hWnd); + wxWindow *pWnd; + + // + // Pass non-system timer messages to the wxTimerProc + // + if (pMsg->msg == WM_TIMER && + (SHORT1FROMMP(pMsg->mp1) != TID_CURSOR && + SHORT1FROMMP(pMsg->mp1) != TID_FLASHWINDOW && + SHORT1FROMMP(pMsg->mp1) != TID_SCROLL && + SHORT1FROMMP(pMsg->mp1) != 0x0000 + )) + wxTimerProc(NULL, 0, (int)pMsg->mp1, 0); + + // Allow the window to prevent certain messages from being + // translated/processed (this is currently used by wxTextCtrl to always + // grab Ctrl-C/V/X, even if they are also accelerators in some parent) + // + if (pWndThis && !pWndThis->OS2ShouldPreProcessMessage((WXMSG*)pMsg)) { - wxToolTip *tt = wndThis->GetToolTip(); - if ( tt ) - { - tt->RelayEvent((WXMSG *)msg); - } + return FALSE; } -#endif // wxUSE_TOOLTIPS - // try translations first; find the youngest window with a translation - // table. - wxWindow *wnd; - for ( wnd = wndThis; wnd; wnd = wnd->GetParent() ) + // + // For some composite controls (like a combobox), wndThis might be NULL + // because the subcontrol is not a wxWindow, but only the control itself + // is - try to catch this case + // + while (hWnd && !pWndThis) { - if ( wnd->OS2TranslateMessage((WXMSG *)msg) ) - return TRUE; + hWnd = ::WinQueryWindow(hWnd, QW_PARENT); + pWndThis = wxFindWinFromHandle((WXHWND)hWnd); } - // Anyone for a non-translation message? Try youngest descendants first. - for ( wnd = wndThis; wnd; wnd = wnd->GetParent() ) + + // + // Try translations first; find the youngest window with + // a translation table. OS/2 has case sensiive accels, so + // this block, coded by BK, removes that and helps make them + // case insensitive. + // + if(pMsg->msg == WM_CHAR) { - if ( wnd->OS2ProcessMessage((WXMSG *)msg) ) - return TRUE; + PBYTE pChmsg = (PBYTE)&(pMsg->msg); + USHORT uSch = CHARMSG(pChmsg)->chr; + bool bRc = FALSE; + + // + // Do not process keyup events + // + if(!(CHARMSG(pChmsg)->fs & KC_KEYUP)) + { + if((CHARMSG(pChmsg)->fs & (KC_ALT | KC_CTRL)) && CHARMSG(pChmsg)->chr != 0) + CHARMSG(pChmsg)->chr = (USHORT)wxToupper((UCHAR)uSch); + + + for(pWnd = pWndThis; pWnd; pWnd = pWnd->GetParent() ) + { + if((bRc = pWnd->OS2TranslateMessage((WXMSG*)pMsg)) == TRUE) + break; + // stop at first top level window, i.e. don't try to process the + // key strokes originating in a dialog using the accelerators of + // the parent frame - this doesn't make much sense + if ( pWnd->IsTopLevel() ) + break; + } + + if(!bRc) // untranslated, should restore original value + CHARMSG(pChmsg)->chr = uSch; + } } - + // + // Anyone for a non-translation message? Try youngest descendants first. + // +// for (pWnd = pWndThis->GetParent(); pWnd; pWnd = pWnd->GetParent()) +// { +// if (pWnd->OS2ProcessMessage(pWxmsg)) +// return TRUE; +// } return FALSE; } @@ -145,7 +227,7 @@ bool wxEventLoopImpl::SendIdleMessage() // wxEventLoop implementation // ============================================================================ -wxEventLoop *wxEventLoop::ms_activeLoop = NULL; +wxEventLoop *wxEventLoopBase::ms_activeLoop = NULL; // ---------------------------------------------------------------------------- // wxEventLoop running and exiting @@ -156,20 +238,47 @@ wxEventLoop::~wxEventLoop() wxASSERT_MSG( !m_impl, _T("should have been deleted in Run()") ); } -bool wxEventLoop::IsRunning() const +////////////////////////////////////////////////////////////////////////////// +// +// Keep trying to process messages until WM_QUIT +// received. +// +// If there are messages to be processed, they will all be +// processed and OnIdle will not be called. +// When there are no more messages, OnIdle is called. +// If OnIdle requests more time, +// it will be repeatedly called so long as there are no pending messages. +// A 'feature' of this is that once OnIdle has decided that no more processing +// is required, then it won't get processing time until further messages +// are processed (it'll sit in Dispatch). +// +////////////////////////////////////////////////////////////////////////////// +class CallEventLoopMethod { - return m_impl != NULL; -} +public: + typedef void (wxEventLoop::*FuncType)(); + + CallEventLoopMethod(wxEventLoop *evtLoop, FuncType fn) + : m_evtLoop(evtLoop), m_fn(fn) { } + ~CallEventLoopMethod() { (m_evtLoop->*m_fn)(); } + +private: + wxEventLoop *m_evtLoop; + FuncType m_fn; +}; int wxEventLoop::Run() { // event loops are not recursive, you need to create another loop! wxCHECK_MSG( !IsRunning(), -1, _T("can't reenter a message loop") ); - m_impl = new wxEventLoopImpl; + // SendIdleMessage() and Dispatch() below may throw so the code here should + // be exception-safe, hence we must use local objects for all actions we + // should undo + wxEventLoopActivator activate(&ms_activeLoop, this); + wxEventLoopImplTiedPtr impl(&m_impl, new wxEventLoopImpl); - wxEventLoop *oldLoop = ms_activeLoop; - ms_activeLoop = this; + CallEventLoopMethod callOnExit(this, &wxEventLoop::OnExit); for ( ;; ) { @@ -180,24 +289,25 @@ int wxEventLoop::Run() // generate and process idle events for as long as we don't have // anything else to do while ( !Pending() && m_impl->SendIdleMessage() ) - ; - - // a message came or no more idle processing to do, sit in Dispatch() - // waiting for the next message - if ( !Dispatch() ) - { - // we got WM_QUIT - break; - } + { + wxTheApp->HandleSockets(); + wxMilliSleep(10); + } + + wxTheApp->HandleSockets(); + if (Pending()) + { + if ( !Dispatch() ) + { + // we got WM_QUIT + break; + } + } + else + wxMilliSleep(10); } - int exitcode = m_impl->GetExitCode(); - delete m_impl; - m_impl = NULL; - - ms_activeLoop = oldLoop; - - return exitcode; + return m_impl->GetExitCode(); } void wxEventLoop::Exit(int rc) @@ -216,7 +326,7 @@ void wxEventLoop::Exit(int rc) bool wxEventLoop::Pending() const { QMSG msg; - return ::WinPeekMsg(vHabMain, &msg, 0, 0, 0, PM_NOREMOVE) != 0; + return ::WinPeekMsg(vHabmain, &msg, 0, 0, 0, PM_NOREMOVE) != 0; } bool wxEventLoop::Dispatch() @@ -224,23 +334,14 @@ bool wxEventLoop::Dispatch() wxCHECK_MSG( IsRunning(), FALSE, _T("can't call Dispatch() if not running") ); QMSG msg; - BOOL rc = ::WinGetMsg(vHabMain, &msg, (HWND) NULL, 0, 0); + BOOL bRc = ::WinGetMsg(vHabmain, &msg, (HWND) NULL, 0, 0); - if ( rc == 0 ) + if ( bRc == 0 ) { // got WM_QUIT return FALSE; } - if ( rc == -1 ) - { - // should never happen, but let's test for it nevertheless - wxLogLastError(wxT("GetMessage")); - - // still break from the loop - return FALSE; - } - #if wxUSE_THREADS wxASSERT_MSG( wxThread::IsMain(), wxT("only the main thread can process Windows messages") ); @@ -257,7 +358,7 @@ bool wxEventLoop::Dispatch() // leave out WM_COMMAND messages: too dangerous, sometimes // the message will be processed twice - if ( !wxIsWaitingForThread() || msg.message != WM_COMMAND ) + if ( !wxIsWaitingForThread() || msg.msg != WM_COMMAND ) { s_aSavedMessages.Add(msg); } @@ -278,7 +379,7 @@ bool wxEventLoop::Dispatch() size_t count = s_aSavedMessages.Count(); for ( size_t n = 0; n < count; n++ ) { - MSG& msg = s_aSavedMessages[n]; + QMSG& msg = s_aSavedMessages[n]; m_impl->ProcessMessage(&msg); }