1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        os2/evtloop.cpp 
   3 // Purpose:     implements wxEventLoop for PM 
   4 // Author:      Vadim Zeitlin 
   8 // Copyright:   (c) 2001 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr> 
   9 // License:     wxWindows licence 
  10 /////////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  21     #pragma implementation "evtloop.h" 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  32     #include "wx/window.h" 
  37 #include "wx/evtloop.h" 
  39 #include "wx/tooltip.h" 
  40 #include "wx/ptr_scpd.h" 
  42 #include "wx/os2/private.h" 
  45     // define the array of QMSG strutures 
  46     WX_DECLARE_OBJARRAY(QMSG
, wxMsgArray
); 
  48     #include "wx/arrimpl.cpp" 
  50     WX_DEFINE_OBJARRAY(wxMsgArray
); 
  55 // ---------------------------------------------------------------------------- 
  57 // ---------------------------------------------------------------------------- 
  59 class WXDLLEXPORT wxEventLoopImpl
 
  63     wxEventLoopImpl() { SetExitCode(0); } 
  66     void ProcessMessage(QMSG 
*msg
); 
  68     // generate an idle message, return TRUE if more idle time requested 
  69     bool SendIdleMessage(); 
  71     // set/get the exit code 
  72     void SetExitCode(int exitcode
) { m_exitcode 
= exitcode
; } 
  73     int GetExitCode() const { return m_exitcode
; } 
  76     // preprocess a message, return TRUE if processed (i.e. no further 
  77     // dispatching required) 
  78     bool PreProcessMessage(QMSG 
*msg
); 
  80     // the exit code of the event loop 
  84 // ---------------------------------------------------------------------------- 
  86 // ---------------------------------------------------------------------------- 
  88 wxDEFINE_TIED_SCOPED_PTR_TYPE(wxEventLoopImpl
); 
  90 // this object sets the wxEventLoop given to the ctor as the currently active 
  91 // one and unsets it in its dtor 
  92 class wxEventLoopActivator
 
  95     wxEventLoopActivator(wxEventLoop 
**pActive
, 
  99         m_evtLoopOld 
= *pActive
; 
 103     ~wxEventLoopActivator() 
 105         // restore the previously active event loop 
 106         *m_pActive 
= m_evtLoopOld
; 
 110     wxEventLoop 
*m_evtLoopOld
; 
 111     wxEventLoop 
**m_pActive
; 
 114 // ============================================================================ 
 115 // wxEventLoopImpl implementation 
 116 // ============================================================================ 
 118 // ---------------------------------------------------------------------------- 
 119 // wxEventLoopImpl message processing 
 120 // ---------------------------------------------------------------------------- 
 122 void wxEventLoopImpl::ProcessMessage(QMSG 
*msg
) 
 124     // give us the chance to preprocess the message first 
 125     if ( !PreProcessMessage(msg
) ) 
 127         // if it wasn't done, dispatch it to the corresponding window 
 128         ::WinDispatchMsg(vHabmain
, msg
); 
 132 bool wxEventLoopImpl::PreProcessMessage(QMSG 
*pMsg
) 
 134     HWND hWnd 
= pMsg
->hwnd
; 
 135     wxWindow 
*pWndThis 
= wxFindWinFromHandle((WXHWND
)hWnd
); 
 139     // Pass non-system timer messages to the wxTimerProc 
 141     if (pMsg
->msg 
== WM_TIMER 
&& 
 142         (SHORT1FROMMP(pMsg
->mp1
) != TID_CURSOR 
&& 
 143          SHORT1FROMMP(pMsg
->mp1
) != TID_FLASHWINDOW 
&& 
 144          SHORT1FROMMP(pMsg
->mp1
) != TID_SCROLL 
&& 
 145          SHORT1FROMMP(pMsg
->mp1
) != 0x0000 
 147         wxTimerProc(NULL
, 0, (int)pMsg
->mp1
, 0); 
 149     // Allow the window to prevent certain messages from being 
 150     // translated/processed (this is currently used by wxTextCtrl to always 
 151     // grab Ctrl-C/V/X, even if they are also accelerators in some parent) 
 153     if (pWndThis 
&& !pWndThis
->OS2ShouldPreProcessMessage((WXMSG
*)pMsg
)) 
 159     // For some composite controls (like a combobox), wndThis might be NULL 
 160     // because the subcontrol is not a wxWindow, but only the control itself 
 161     // is - try to catch this case 
 163     while (hWnd 
&& !pWndThis
) 
 165         hWnd 
= ::WinQueryWindow(hWnd
, QW_PARENT
); 
 166         pWndThis 
= wxFindWinFromHandle((WXHWND
)hWnd
); 
 171     // Try translations first; find the youngest window with 
 172     // a translation table. OS/2 has case sensiive accels, so 
 173     // this block, coded by BK, removes that and helps make them 
 176     if(pMsg
->msg 
== WM_CHAR
) 
 178        PBYTE                        pChmsg 
= (PBYTE
)&(pMsg
->msg
); 
 179        USHORT                       uSch  
= CHARMSG(pChmsg
)->chr
; 
 183        // Do not process keyup events 
 185        if(!(CHARMSG(pChmsg
)->fs 
& KC_KEYUP
)) 
 187            if((CHARMSG(pChmsg
)->fs 
& (KC_ALT 
| KC_CTRL
)) && CHARMSG(pChmsg
)->chr 
!= 0) 
 188                 CHARMSG(pChmsg
)->chr 
= (USHORT
)wxToupper((UCHAR
)uSch
); 
 191            for(pWnd 
= pWndThis
; pWnd
; pWnd 
= pWnd
->GetParent() ) 
 193                if((bRc 
= pWnd
->OS2TranslateMessage((WXMSG
*)pMsg
)) == TRUE
) 
 195             // stop at first top level window, i.e. don't try to process the 
 196             // key strokes originating in a dialog using the accelerators of 
 197             // the parent frame - this doesn't make much sense 
 198             if ( pWnd
->IsTopLevel() ) 
 202             if(!bRc
)    // untranslated, should restore original value 
 203                 CHARMSG(pChmsg
)->chr 
= uSch
; 
 207     // Anyone for a non-translation message? Try youngest descendants first. 
 209 //  for (pWnd = pWndThis->GetParent(); pWnd; pWnd = pWnd->GetParent()) 
 211 //      if (pWnd->OS2ProcessMessage(pWxmsg)) 
 217 // ---------------------------------------------------------------------------- 
 218 // wxEventLoopImpl idle event processing 
 219 // ---------------------------------------------------------------------------- 
 221 bool wxEventLoopImpl::SendIdleMessage() 
 223     return wxTheApp
->ProcessIdle() ; 
 226 // ============================================================================ 
 227 // wxEventLoop implementation 
 228 // ============================================================================ 
 230 wxEventLoop 
*wxEventLoopBase::ms_activeLoop 
= NULL
; 
 232 // ---------------------------------------------------------------------------- 
 233 // wxEventLoop running and exiting 
 234 // ---------------------------------------------------------------------------- 
 236 wxEventLoop::~wxEventLoop() 
 238     wxASSERT_MSG( !m_impl
, _T("should have been deleted in Run()") ); 
 241 ////////////////////////////////////////////////////////////////////////////// 
 243 // Keep trying to process messages until WM_QUIT 
 246 // If there are messages to be processed, they will all be 
 247 // processed and OnIdle will not be called. 
 248 // When there are no more messages, OnIdle is called. 
 249 // If OnIdle requests more time, 
 250 // it will be repeatedly called so long as there are no pending messages. 
 251 // A 'feature' of this is that once OnIdle has decided that no more processing 
 252 // is required, then it won't get processing time until further messages 
 253 // are processed (it'll sit in Dispatch). 
 255 ////////////////////////////////////////////////////////////////////////////// 
 256 class CallEventLoopMethod
 
 259     typedef void (wxEventLoop::*FuncType
)(); 
 261     CallEventLoopMethod(wxEventLoop 
*evtLoop
, FuncType fn
) 
 262         : m_evtLoop(evtLoop
), m_fn(fn
) { } 
 263     ~CallEventLoopMethod() { (m_evtLoop
->*m_fn
)(); } 
 266     wxEventLoop 
*m_evtLoop
; 
 270 int wxEventLoop::Run() 
 272     // event loops are not recursive, you need to create another loop! 
 273     wxCHECK_MSG( !IsRunning(), -1, _T("can't reenter a message loop") ); 
 275     // SendIdleMessage() and Dispatch() below may throw so the code here should 
 276     // be exception-safe, hence we must use local objects for all actions we 
 278     wxEventLoopActivator 
activate(&ms_activeLoop
, this); 
 279     wxEventLoopImplTiedPtr 
impl(&m_impl
, new wxEventLoopImpl
); 
 281     CallEventLoopMethod  
callOnExit(this, &wxEventLoop::OnExit
); 
 286         wxMutexGuiLeaveOrEnter(); 
 287 #endif // wxUSE_THREADS 
 289         // generate and process idle events for as long as we don't have 
 290         // anything else to do 
 291         while ( !Pending() && m_impl
->SendIdleMessage() ) 
 293             wxTheApp
->HandleSockets(); 
 297         wxTheApp
->HandleSockets(); 
 310     return m_impl
->GetExitCode(); 
 313 void wxEventLoop::Exit(int rc
) 
 315     wxCHECK_RET( IsRunning(), _T("can't call Exit() if not running") ); 
 317     m_impl
->SetExitCode(rc
); 
 319     ::WinPostMsg(NULL
, WM_QUIT
, 0, 0); 
 322 // ---------------------------------------------------------------------------- 
 323 // wxEventLoop message processing dispatching 
 324 // ---------------------------------------------------------------------------- 
 326 bool wxEventLoop::Pending() const 
 329     return ::WinPeekMsg(vHabmain
, &msg
, 0, 0, 0, PM_NOREMOVE
) != 0; 
 332 bool wxEventLoop::Dispatch() 
 334     wxCHECK_MSG( IsRunning(), FALSE
, _T("can't call Dispatch() if not running") ); 
 337     BOOL bRc 
= ::WinGetMsg(vHabmain
, &msg
, (HWND
) NULL
, 0, 0); 
 346     wxASSERT_MSG( wxThread::IsMain(), 
 347                   wxT("only the main thread can process Windows messages") ); 
 349     static bool s_hadGuiLock 
= TRUE
; 
 350     static wxMsgArray s_aSavedMessages
; 
 352     // if a secondary thread owning the mutex is doing GUI calls, save all 
 353     // messages for later processing - we can't process them right now because 
 354     // it will lead to recursive library calls (and we're not reentrant) 
 355     if ( !wxGuiOwnedByMainThread() ) 
 357         s_hadGuiLock 
= FALSE
; 
 359         // leave out WM_COMMAND messages: too dangerous, sometimes 
 360         // the message will be processed twice 
 361         if ( !wxIsWaitingForThread() || msg
.msg 
!= WM_COMMAND 
) 
 363             s_aSavedMessages
.Add(msg
); 
 370         // have we just regained the GUI lock? if so, post all of the saved 
 373         // FIXME of course, it's not _exactly_ the same as processing the 
 374         //       messages normally - expect some things to break... 
 379             size_t count 
= s_aSavedMessages
.Count(); 
 380             for ( size_t n 
= 0; n 
< count
; n
++ ) 
 382                 QMSG
& msg 
= s_aSavedMessages
[n
]; 
 383                 m_impl
->ProcessMessage(&msg
); 
 386             s_aSavedMessages
.Empty(); 
 389 #endif // wxUSE_THREADS 
 391     m_impl
->ProcessMessage(&msg
);