X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/251b80c4b5bd980bcddb2df94d5601b2b9345e1d..c81394808bf7efd84e4294e44a9a9a7b7f6dd8a9:/src/os2/evtloop.cpp?ds=sidebyside diff --git a/src/os2/evtloop.cpp b/src/os2/evtloop.cpp index 919d51e4cf..6624e1bc4a 100644 --- a/src/os2/evtloop.cpp +++ b/src/os2/evtloop.cpp @@ -1,12 +1,12 @@ /////////////////////////////////////////////////////////////////////////////// -// Name: os2/evtloop.cpp -// Purpose: implements wxEventLoop for PM +// Name: src/os2/evtloop.cpp +// Purpose: implements wxGUIEventLoop for PM // Author: Vadim Zeitlin // Modified by: // Created: 01.06.01 // RCS-ID: $Id$ // Copyright: (c) 2001 Vadim Zeitlin -// License: wxWindows license +// Licence: wxWindows licence /////////////////////////////////////////////////////////////////////////////// // ============================================================================ @@ -17,10 +17,6 @@ // headers // ---------------------------------------------------------------------------- -#ifdef __GNUG__ - #pragma implementation "evtloop.h" -#endif - // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" @@ -31,22 +27,27 @@ #ifndef WX_PRECOMP #include "wx/window.h" #include "wx/app.h" + #include "wx/timer.h" + #include "wx/log.h" #endif //WX_PRECOMP #include "wx/evtloop.h" #include "wx/tooltip.h" +#include "wx/scopedptr.h" #include "wx/os2/private.h" +#include "wx/os2/private/timer.h" // for wxTimerProc #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 +78,12 @@ private: int m_exitcode; }; +// ---------------------------------------------------------------------------- +// helper class +// ---------------------------------------------------------------------------- + +wxDEFINE_TIED_SCOPED_PTR_TYPE(wxEventLoopImpl); + // ============================================================================ // wxEventLoopImpl implementation // ============================================================================ @@ -91,44 +98,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; } @@ -138,40 +193,63 @@ bool wxEventLoopImpl::PreProcessMessage(QMSG *msg) bool wxEventLoopImpl::SendIdleMessage() { - wxIdleEvent event; - - return wxTheApp->ProcessEvent(event) && event.MoreRequested(); + return wxTheApp->ProcessIdle() ; } // ============================================================================ -// wxEventLoop implementation +// wxGUIEventLoop implementation // ============================================================================ -wxEventLoop *wxEventLoop::ms_activeLoop = NULL; - // ---------------------------------------------------------------------------- -// wxEventLoop running and exiting +// wxGUIEventLoop running and exiting // ---------------------------------------------------------------------------- -wxEventLoop::~wxEventLoop() +wxGUIEventLoop::~wxGUIEventLoop() { - wxASSERT_MSG( !m_impl, _T("should have been deleted in Run()") ); + wxASSERT_MSG( !m_impl, wxT("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 (wxGUIEventLoop::*FuncType)(); + + CallEventLoopMethod(wxGUIEventLoop *evtLoop, FuncType fn) + : m_evtLoop(evtLoop), m_fn(fn) { } + ~CallEventLoopMethod() { (m_evtLoop->*m_fn)(); } + +private: + wxGUIEventLoop *m_evtLoop; + FuncType m_fn; +}; -int wxEventLoop::Run() +int wxGUIEventLoop::Run() { // event loops are not recursive, you need to create another loop! - wxCHECK_MSG( !IsRunning(), -1, _T("can't reenter a message loop") ); + wxCHECK_MSG( !IsRunning(), -1, wxT("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(this); + wxEventLoopImplTiedPtr impl(&m_impl, new wxEventLoopImpl); - wxEventLoop *oldLoop = ms_activeLoop; - ms_activeLoop = this; + CallEventLoopMethod callOnExit(this, &wxGUIEventLoop::OnExit); for ( ;; ) { @@ -182,29 +260,32 @@ 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() ) - ; + { + wxTheApp->HandleSockets(); + wxMilliSleep(10); + } - // a message came or no more idle processing to do, sit in Dispatch() - // waiting for the next message - if ( !Dispatch() ) + wxTheApp->HandleSockets(); + if (Pending()) { - // we got WM_QUIT - break; + if ( !Dispatch() ) + { + // we got WM_QUIT + break; + } } + else + wxMilliSleep(10); } - int exitcode = m_impl->GetExitCode(); - delete m_impl; - m_impl = NULL; - - ms_activeLoop = oldLoop; + OnExit(); - return exitcode; + return m_impl->GetExitCode(); } -void wxEventLoop::Exit(int rc) +void wxGUIEventLoop::Exit(int rc) { - wxCHECK_RET( IsRunning(), _T("can't call Exit() if not running") ); + wxCHECK_RET( IsRunning(), wxT("can't call Exit() if not running") ); m_impl->SetExitCode(rc); @@ -212,42 +293,33 @@ void wxEventLoop::Exit(int rc) } // ---------------------------------------------------------------------------- -// wxEventLoop message processing dispatching +// wxGUIEventLoop message processing dispatching // ---------------------------------------------------------------------------- -bool wxEventLoop::Pending() const +bool wxGUIEventLoop::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() +bool wxGUIEventLoop::Dispatch() { - wxCHECK_MSG( IsRunning(), FALSE, _T("can't call Dispatch() if not running") ); + wxCHECK_MSG( IsRunning(), false, wxT("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; + return false; } #if wxUSE_THREADS wxASSERT_MSG( wxThread::IsMain(), wxT("only the main thread can process Windows messages") ); - static bool s_hadGuiLock = TRUE; + static bool s_hadGuiLock = true; static wxMsgArray s_aSavedMessages; // if a secondary thread owning the mutex is doing GUI calls, save all @@ -255,16 +327,16 @@ bool wxEventLoop::Dispatch() // it will lead to recursive library calls (and we're not reentrant) if ( !wxGuiOwnedByMainThread() ) { - s_hadGuiLock = FALSE; + s_hadGuiLock = false; // 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); } - return TRUE; + return true; } else { @@ -275,12 +347,12 @@ bool wxEventLoop::Dispatch() // messages normally - expect some things to break... if ( !s_hadGuiLock ) { - s_hadGuiLock = TRUE; + s_hadGuiLock = true; 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); } @@ -291,6 +363,55 @@ bool wxEventLoop::Dispatch() m_impl->ProcessMessage(&msg); - return TRUE; + return true; } +// +// Yield to incoming messages +// +bool wxGUIEventLoop::YieldFor(long eventsToProcess) +{ + HAB vHab = 0; + QMSG vMsg; + + // + // Disable log flushing from here because a call to wxYield() shouldn't + // normally result in message boxes popping up &c + // + wxLog::Suspend(); + + m_isInsideYield = true; + m_eventsToProcessInsideYield = eventsToProcess; + + // + // We want to go back to the main message loop + // if we see a WM_QUIT. (?) + // + while (::WinPeekMsg(vHab, &vMsg, (HWND)NULL, 0, 0, PM_NOREMOVE) && vMsg.msg != WM_QUIT) + { + // TODO: implement event filtering using the eventsToProcess mask + +#if wxUSE_THREADS + wxMutexGuiLeaveOrEnter(); +#endif // wxUSE_THREADS + if (!wxTheApp->Dispatch()) + break; + } + + // + // If they are pending events, we must process them. + // + if (wxTheApp) + { + wxTheApp->ProcessPendingEvents(); + wxTheApp->HandleSockets(); + } + + // + // Let the logs be flashed again + // + wxLog::Resume(); + m_isInsideYield = false; + + return true; +} // end of wxYield