1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/os2/evtloop.cpp 
   3 // Purpose:     implements wxGUIEventLoop 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" 
  39 #include "wx/os2/private/timer.h"       // for wxTimerProc 
  42     // define the array of QMSG strutures 
  43     WX_DECLARE_OBJARRAY(QMSG
, wxMsgArray
); 
  45     #include "wx/arrimpl.cpp" 
  47     WX_DEFINE_OBJARRAY(wxMsgArray
); 
  52 // ---------------------------------------------------------------------------- 
  54 // ---------------------------------------------------------------------------- 
  56 class WXDLLEXPORT wxEventLoopImpl
 
  60     wxEventLoopImpl() { SetExitCode(0); } 
  63     void ProcessMessage(QMSG 
*msg
); 
  65     // generate an idle message, return TRUE if more idle time requested 
  66     bool SendIdleMessage(); 
  68     // set/get the exit code 
  69     void SetExitCode(int exitcode
) { m_exitcode 
= exitcode
; } 
  70     int GetExitCode() const { return m_exitcode
; } 
  73     // preprocess a message, return TRUE if processed (i.e. no further 
  74     // dispatching required) 
  75     bool PreProcessMessage(QMSG 
*msg
); 
  77     // the exit code of the event loop 
  81 // ---------------------------------------------------------------------------- 
  83 // ---------------------------------------------------------------------------- 
  85 wxDEFINE_TIED_SCOPED_PTR_TYPE(wxEventLoopImpl
); 
  87 // ============================================================================ 
  88 // wxEventLoopImpl implementation 
  89 // ============================================================================ 
  91 // ---------------------------------------------------------------------------- 
  92 // wxEventLoopImpl message processing 
  93 // ---------------------------------------------------------------------------- 
  95 void wxEventLoopImpl::ProcessMessage(QMSG 
*msg
) 
  97     // give us the chance to preprocess the message first 
  98     if ( !PreProcessMessage(msg
) ) 
 100         // if it wasn't done, dispatch it to the corresponding window 
 101         ::WinDispatchMsg(vHabmain
, msg
); 
 105 bool wxEventLoopImpl::PreProcessMessage(QMSG 
*pMsg
) 
 107     HWND hWnd 
= pMsg
->hwnd
; 
 108     wxWindow 
*pWndThis 
= wxFindWinFromHandle((WXHWND
)hWnd
); 
 112     // Pass non-system timer messages to the wxTimerProc 
 114     if (pMsg
->msg 
== WM_TIMER 
&& 
 115         (SHORT1FROMMP(pMsg
->mp1
) != TID_CURSOR 
&& 
 116          SHORT1FROMMP(pMsg
->mp1
) != TID_FLASHWINDOW 
&& 
 117          SHORT1FROMMP(pMsg
->mp1
) != TID_SCROLL 
&& 
 118          SHORT1FROMMP(pMsg
->mp1
) != 0x0000 
 120         wxTimerProc(NULL
, 0, (int)pMsg
->mp1
, 0); 
 122     // Allow the window to prevent certain messages from being 
 123     // translated/processed (this is currently used by wxTextCtrl to always 
 124     // grab Ctrl-C/V/X, even if they are also accelerators in some parent) 
 126     if (pWndThis 
&& !pWndThis
->OS2ShouldPreProcessMessage((WXMSG
*)pMsg
)) 
 132     // For some composite controls (like a combobox), wndThis might be NULL 
 133     // because the subcontrol is not a wxWindow, but only the control itself 
 134     // is - try to catch this case 
 136     while (hWnd 
&& !pWndThis
) 
 138         hWnd 
= ::WinQueryWindow(hWnd
, QW_PARENT
); 
 139         pWndThis 
= wxFindWinFromHandle((WXHWND
)hWnd
); 
 144     // Try translations first; find the youngest window with 
 145     // a translation table. OS/2 has case sensiive accels, so 
 146     // this block, coded by BK, removes that and helps make them 
 149     if(pMsg
->msg 
== WM_CHAR
) 
 151        PBYTE                        pChmsg 
= (PBYTE
)&(pMsg
->msg
); 
 152        USHORT                       uSch  
= CHARMSG(pChmsg
)->chr
; 
 156        // Do not process keyup events 
 158        if(!(CHARMSG(pChmsg
)->fs 
& KC_KEYUP
)) 
 160            if((CHARMSG(pChmsg
)->fs 
& (KC_ALT 
| KC_CTRL
)) && CHARMSG(pChmsg
)->chr 
!= 0) 
 161                 CHARMSG(pChmsg
)->chr 
= (USHORT
)wxToupper((UCHAR
)uSch
); 
 164            for(pWnd 
= pWndThis
; pWnd
; pWnd 
= pWnd
->GetParent() ) 
 166                if((bRc 
= pWnd
->OS2TranslateMessage((WXMSG
*)pMsg
)) == TRUE
) 
 168                // stop at first top level window, i.e. don't try to process the 
 169                // key strokes originating in a dialog using the accelerators of 
 170                // the parent frame - this doesn't make much sense 
 171                if ( pWnd
->IsTopLevel() ) 
 175             if(!bRc
)    // untranslated, should restore original value 
 176                 CHARMSG(pChmsg
)->chr 
= uSch
; 
 180     // Anyone for a non-translation message? Try youngest descendants first. 
 182 //  for (pWnd = pWndThis->GetParent(); pWnd; pWnd = pWnd->GetParent()) 
 184 //      if (pWnd->OS2ProcessMessage(pWxmsg)) 
 190 // ---------------------------------------------------------------------------- 
 191 // wxEventLoopImpl idle event processing 
 192 // ---------------------------------------------------------------------------- 
 194 bool wxEventLoopImpl::SendIdleMessage() 
 196     return wxTheApp
->ProcessIdle() ; 
 199 // ============================================================================ 
 200 // wxGUIEventLoop implementation 
 201 // ============================================================================ 
 203 // ---------------------------------------------------------------------------- 
 204 // wxGUIEventLoop running and exiting 
 205 // ---------------------------------------------------------------------------- 
 207 wxGUIEventLoop::~wxGUIEventLoop() 
 209     wxASSERT_MSG( !m_impl
, _T("should have been deleted in Run()") ); 
 212 ////////////////////////////////////////////////////////////////////////////// 
 214 // Keep trying to process messages until WM_QUIT 
 217 // If there are messages to be processed, they will all be 
 218 // processed and OnIdle will not be called. 
 219 // When there are no more messages, OnIdle is called. 
 220 // If OnIdle requests more time, 
 221 // it will be repeatedly called so long as there are no pending messages. 
 222 // A 'feature' of this is that once OnIdle has decided that no more processing 
 223 // is required, then it won't get processing time until further messages 
 224 // are processed (it'll sit in Dispatch). 
 226 ////////////////////////////////////////////////////////////////////////////// 
 227 class CallEventLoopMethod
 
 230     typedef void (wxGUIEventLoop::*FuncType
)(); 
 232     CallEventLoopMethod(wxGUIEventLoop 
*evtLoop
, FuncType fn
) 
 233         : m_evtLoop(evtLoop
), m_fn(fn
) { } 
 234     ~CallEventLoopMethod() { (m_evtLoop
->*m_fn
)(); } 
 237     wxGUIEventLoop 
*m_evtLoop
; 
 241 int wxGUIEventLoop::Run() 
 243     // event loops are not recursive, you need to create another loop! 
 244     wxCHECK_MSG( !IsRunning(), -1, _T("can't reenter a message loop") ); 
 246     // SendIdleMessage() and Dispatch() below may throw so the code here should 
 247     // be exception-safe, hence we must use local objects for all actions we 
 249     wxEventLoopActivator 
activate(this); 
 250     wxEventLoopImplTiedPtr 
impl(&m_impl
, new wxEventLoopImpl
); 
 252     CallEventLoopMethod  
callOnExit(this, &wxGUIEventLoop::OnExit
); 
 257         wxMutexGuiLeaveOrEnter(); 
 258 #endif // wxUSE_THREADS 
 260         // generate and process idle events for as long as we don't have 
 261         // anything else to do 
 262         while ( !Pending() && m_impl
->SendIdleMessage() ) 
 264             wxTheApp
->HandleSockets(); 
 268         wxTheApp
->HandleSockets(); 
 283     return m_impl
->GetExitCode(); 
 286 void wxGUIEventLoop::Exit(int rc
) 
 288     wxCHECK_RET( IsRunning(), _T("can't call Exit() if not running") ); 
 290     m_impl
->SetExitCode(rc
); 
 292     ::WinPostMsg(NULL
, WM_QUIT
, 0, 0); 
 295 // ---------------------------------------------------------------------------- 
 296 // wxGUIEventLoop message processing dispatching 
 297 // ---------------------------------------------------------------------------- 
 299 bool wxGUIEventLoop::Pending() const 
 302     return ::WinPeekMsg(vHabmain
, &msg
, 0, 0, 0, PM_NOREMOVE
) != 0; 
 305 bool wxGUIEventLoop::Dispatch() 
 307     wxCHECK_MSG( IsRunning(), false, _T("can't call Dispatch() if not running") ); 
 310     BOOL bRc 
= ::WinGetMsg(vHabmain
, &msg
, (HWND
) NULL
, 0, 0); 
 319     wxASSERT_MSG( wxThread::IsMain(), 
 320                   wxT("only the main thread can process Windows messages") ); 
 322     static bool s_hadGuiLock 
= true; 
 323     static wxMsgArray s_aSavedMessages
; 
 325     // if a secondary thread owning the mutex is doing GUI calls, save all 
 326     // messages for later processing - we can't process them right now because 
 327     // it will lead to recursive library calls (and we're not reentrant) 
 328     if ( !wxGuiOwnedByMainThread() ) 
 330         s_hadGuiLock 
= false; 
 332         // leave out WM_COMMAND messages: too dangerous, sometimes 
 333         // the message will be processed twice 
 334         if ( !wxIsWaitingForThread() || msg
.msg 
!= WM_COMMAND 
) 
 336             s_aSavedMessages
.Add(msg
); 
 343         // have we just regained the GUI lock? if so, post all of the saved 
 346         // FIXME of course, it's not _exactly_ the same as processing the 
 347         //       messages normally - expect some things to break... 
 352             size_t count 
= s_aSavedMessages
.Count(); 
 353             for ( size_t n 
= 0; n 
< count
; n
++ ) 
 355                 QMSG
& msg 
= s_aSavedMessages
[n
]; 
 356                 m_impl
->ProcessMessage(&msg
); 
 359             s_aSavedMessages
.Empty(); 
 362 #endif // wxUSE_THREADS 
 364     m_impl
->ProcessMessage(&msg
);