1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/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 // ---------------------------------------------------------------------------- 
  20 // For compilers that support precompilation, includes "wx.h". 
  21 #include "wx/wxprec.h" 
  28     #include "wx/window.h" 
  34 #include "wx/evtloop.h" 
  35 #include "wx/tooltip.h" 
  36 #include "wx/ptr_scpd.h" 
  38 #include "wx/os2/private.h" 
  41     // define the array of QMSG strutures 
  42     WX_DECLARE_OBJARRAY(QMSG
, wxMsgArray
); 
  44     #include "wx/arrimpl.cpp" 
  46     WX_DEFINE_OBJARRAY(wxMsgArray
); 
  51 // ---------------------------------------------------------------------------- 
  53 // ---------------------------------------------------------------------------- 
  55 class WXDLLEXPORT wxEventLoopImpl
 
  59     wxEventLoopImpl() { SetExitCode(0); } 
  62     void ProcessMessage(QMSG 
*msg
); 
  64     // generate an idle message, return TRUE if more idle time requested 
  65     bool SendIdleMessage(); 
  67     // set/get the exit code 
  68     void SetExitCode(int exitcode
) { m_exitcode 
= exitcode
; } 
  69     int GetExitCode() const { return m_exitcode
; } 
  72     // preprocess a message, return TRUE if processed (i.e. no further 
  73     // dispatching required) 
  74     bool PreProcessMessage(QMSG 
*msg
); 
  76     // the exit code of the event loop 
  80 // ---------------------------------------------------------------------------- 
  82 // ---------------------------------------------------------------------------- 
  84 wxDEFINE_TIED_SCOPED_PTR_TYPE(wxEventLoopImpl
); 
  86 // ============================================================================ 
  87 // wxEventLoopImpl implementation 
  88 // ============================================================================ 
  90 // ---------------------------------------------------------------------------- 
  91 // wxEventLoopImpl message processing 
  92 // ---------------------------------------------------------------------------- 
  94 void wxEventLoopImpl::ProcessMessage(QMSG 
*msg
) 
  96     // give us the chance to preprocess the message first 
  97     if ( !PreProcessMessage(msg
) ) 
  99         // if it wasn't done, dispatch it to the corresponding window 
 100         ::WinDispatchMsg(vHabmain
, msg
); 
 104 bool wxEventLoopImpl::PreProcessMessage(QMSG 
*pMsg
) 
 106     HWND hWnd 
= pMsg
->hwnd
; 
 107     wxWindow 
*pWndThis 
= wxFindWinFromHandle((WXHWND
)hWnd
); 
 111     // Pass non-system timer messages to the wxTimerProc 
 113     if (pMsg
->msg 
== WM_TIMER 
&& 
 114         (SHORT1FROMMP(pMsg
->mp1
) != TID_CURSOR 
&& 
 115          SHORT1FROMMP(pMsg
->mp1
) != TID_FLASHWINDOW 
&& 
 116          SHORT1FROMMP(pMsg
->mp1
) != TID_SCROLL 
&& 
 117          SHORT1FROMMP(pMsg
->mp1
) != 0x0000 
 119         wxTimerProc(NULL
, 0, (int)pMsg
->mp1
, 0); 
 121     // Allow the window to prevent certain messages from being 
 122     // translated/processed (this is currently used by wxTextCtrl to always 
 123     // grab Ctrl-C/V/X, even if they are also accelerators in some parent) 
 125     if (pWndThis 
&& !pWndThis
->OS2ShouldPreProcessMessage((WXMSG
*)pMsg
)) 
 131     // For some composite controls (like a combobox), wndThis might be NULL 
 132     // because the subcontrol is not a wxWindow, but only the control itself 
 133     // is - try to catch this case 
 135     while (hWnd 
&& !pWndThis
) 
 137         hWnd 
= ::WinQueryWindow(hWnd
, QW_PARENT
); 
 138         pWndThis 
= wxFindWinFromHandle((WXHWND
)hWnd
); 
 143     // Try translations first; find the youngest window with 
 144     // a translation table. OS/2 has case sensiive accels, so 
 145     // this block, coded by BK, removes that and helps make them 
 148     if(pMsg
->msg 
== WM_CHAR
) 
 150        PBYTE                        pChmsg 
= (PBYTE
)&(pMsg
->msg
); 
 151        USHORT                       uSch  
= CHARMSG(pChmsg
)->chr
; 
 155        // Do not process keyup events 
 157        if(!(CHARMSG(pChmsg
)->fs 
& KC_KEYUP
)) 
 159            if((CHARMSG(pChmsg
)->fs 
& (KC_ALT 
| KC_CTRL
)) && CHARMSG(pChmsg
)->chr 
!= 0) 
 160                 CHARMSG(pChmsg
)->chr 
= (USHORT
)wxToupper((UCHAR
)uSch
); 
 163            for(pWnd 
= pWndThis
; pWnd
; pWnd 
= pWnd
->GetParent() ) 
 165                if((bRc 
= pWnd
->OS2TranslateMessage((WXMSG
*)pMsg
)) == TRUE
) 
 167                // stop at first top level window, i.e. don't try to process the 
 168                // key strokes originating in a dialog using the accelerators of 
 169                // the parent frame - this doesn't make much sense 
 170                if ( pWnd
->IsTopLevel() ) 
 174             if(!bRc
)    // untranslated, should restore original value 
 175                 CHARMSG(pChmsg
)->chr 
= uSch
; 
 179     // Anyone for a non-translation message? Try youngest descendants first. 
 181 //  for (pWnd = pWndThis->GetParent(); pWnd; pWnd = pWnd->GetParent()) 
 183 //      if (pWnd->OS2ProcessMessage(pWxmsg)) 
 189 // ---------------------------------------------------------------------------- 
 190 // wxEventLoopImpl idle event processing 
 191 // ---------------------------------------------------------------------------- 
 193 bool wxEventLoopImpl::SendIdleMessage() 
 195     return wxTheApp
->ProcessIdle() ; 
 198 // ============================================================================ 
 199 // wxEventLoop implementation 
 200 // ============================================================================ 
 202 // ---------------------------------------------------------------------------- 
 203 // wxEventLoop running and exiting 
 204 // ---------------------------------------------------------------------------- 
 206 wxEventLoop::~wxEventLoop() 
 208     wxASSERT_MSG( !m_impl
, _T("should have been deleted in Run()") ); 
 211 ////////////////////////////////////////////////////////////////////////////// 
 213 // Keep trying to process messages until WM_QUIT 
 216 // If there are messages to be processed, they will all be 
 217 // processed and OnIdle will not be called. 
 218 // When there are no more messages, OnIdle is called. 
 219 // If OnIdle requests more time, 
 220 // it will be repeatedly called so long as there are no pending messages. 
 221 // A 'feature' of this is that once OnIdle has decided that no more processing 
 222 // is required, then it won't get processing time until further messages 
 223 // are processed (it'll sit in Dispatch). 
 225 ////////////////////////////////////////////////////////////////////////////// 
 226 class CallEventLoopMethod
 
 229     typedef void (wxEventLoop::*FuncType
)(); 
 231     CallEventLoopMethod(wxEventLoop 
*evtLoop
, FuncType fn
) 
 232         : m_evtLoop(evtLoop
), m_fn(fn
) { } 
 233     ~CallEventLoopMethod() { (m_evtLoop
->*m_fn
)(); } 
 236     wxEventLoop 
*m_evtLoop
; 
 240 int wxEventLoop::Run() 
 242     // event loops are not recursive, you need to create another loop! 
 243     wxCHECK_MSG( !IsRunning(), -1, _T("can't reenter a message loop") ); 
 245     // SendIdleMessage() and Dispatch() below may throw so the code here should 
 246     // be exception-safe, hence we must use local objects for all actions we 
 248     wxEventLoopActivator 
activate(this); 
 249     wxEventLoopImplTiedPtr 
impl(&m_impl
, new wxEventLoopImpl
); 
 251     CallEventLoopMethod  
callOnExit(this, &wxEventLoop::OnExit
); 
 256         wxMutexGuiLeaveOrEnter(); 
 257 #endif // wxUSE_THREADS 
 259         // generate and process idle events for as long as we don't have 
 260         // anything else to do 
 261         while ( !Pending() && m_impl
->SendIdleMessage() ) 
 263             wxTheApp
->HandleSockets(); 
 267         wxTheApp
->HandleSockets(); 
 280     return m_impl
->GetExitCode(); 
 283 void wxEventLoop::Exit(int rc
) 
 285     wxCHECK_RET( IsRunning(), _T("can't call Exit() if not running") ); 
 287     m_impl
->SetExitCode(rc
); 
 289     ::WinPostMsg(NULL
, WM_QUIT
, 0, 0); 
 292 // ---------------------------------------------------------------------------- 
 293 // wxEventLoop message processing dispatching 
 294 // ---------------------------------------------------------------------------- 
 296 bool wxEventLoop::Pending() const 
 299     return ::WinPeekMsg(vHabmain
, &msg
, 0, 0, 0, PM_NOREMOVE
) != 0; 
 302 bool wxEventLoop::Dispatch() 
 304     wxCHECK_MSG( IsRunning(), false, _T("can't call Dispatch() if not running") ); 
 307     BOOL bRc 
= ::WinGetMsg(vHabmain
, &msg
, (HWND
) NULL
, 0, 0); 
 316     wxASSERT_MSG( wxThread::IsMain(), 
 317                   wxT("only the main thread can process Windows messages") ); 
 319     static bool s_hadGuiLock 
= true; 
 320     static wxMsgArray s_aSavedMessages
; 
 322     // if a secondary thread owning the mutex is doing GUI calls, save all 
 323     // messages for later processing - we can't process them right now because 
 324     // it will lead to recursive library calls (and we're not reentrant) 
 325     if ( !wxGuiOwnedByMainThread() ) 
 327         s_hadGuiLock 
= false; 
 329         // leave out WM_COMMAND messages: too dangerous, sometimes 
 330         // the message will be processed twice 
 331         if ( !wxIsWaitingForThread() || msg
.msg 
!= WM_COMMAND 
) 
 333             s_aSavedMessages
.Add(msg
); 
 340         // have we just regained the GUI lock? if so, post all of the saved 
 343         // FIXME of course, it's not _exactly_ the same as processing the 
 344         //       messages normally - expect some things to break... 
 349             size_t count 
= s_aSavedMessages
.Count(); 
 350             for ( size_t n 
= 0; n 
< count
; n
++ ) 
 352                 QMSG
& msg 
= s_aSavedMessages
[n
]; 
 353                 m_impl
->ProcessMessage(&msg
); 
 356             s_aSavedMessages
.Empty(); 
 359 #endif // wxUSE_THREADS 
 361     m_impl
->ProcessMessage(&msg
);