1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        msw/evtloop.cpp 
   3 // Purpose:     implements wxEventLoop for MSW 
   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 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  21     #pragma implementation "evtloop.h" 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  32     #include "wx/window.h" 
  36 #include "wx/evtloop.h" 
  38 #include "wx/tooltip.h" 
  39 #include "wx/except.h" 
  40 #include "wx/ptr_scpd.h" 
  42 #include "wx/msw/private.h" 
  45     #include "wx/thread.h" 
  47     // define the array of MSG strutures 
  48     WX_DECLARE_OBJARRAY(MSG
, wxMsgArray
); 
  50     #include "wx/arrimpl.cpp" 
  52     WX_DEFINE_OBJARRAY(wxMsgArray
); 
  53 #endif // wxUSE_THREADS 
  55 // ---------------------------------------------------------------------------- 
  57 // ---------------------------------------------------------------------------- 
  59 // this object sets the wxEventLoop given to the ctor as the currently active 
  60 // one and unsets it in its dtor 
  61 class wxEventLoopActivator
 
  64     wxEventLoopActivator(wxEventLoop 
**pActive
, 
  68         m_evtLoopOld 
= *pActive
; 
  72     ~wxEventLoopActivator() 
  74         // restore the previously active event loop 
  75         *m_pActive 
= m_evtLoopOld
; 
  79     wxEventLoop 
*m_evtLoopOld
; 
  80     wxEventLoop 
**m_pActive
; 
  83 // ============================================================================ 
  84 // wxEventLoop implementation 
  85 // ============================================================================ 
  87 wxEventLoop 
*wxEventLoopBase::ms_activeLoop 
= NULL
; 
  89 // ---------------------------------------------------------------------------- 
  91 // ---------------------------------------------------------------------------- 
  93 wxEventLoop::wxEventLoop() 
  99 // ---------------------------------------------------------------------------- 
 100 // wxEventLoop message processing 
 101 // ---------------------------------------------------------------------------- 
 103 void wxEventLoop::ProcessMessage(WXMSG 
*msg
) 
 105     // give us the chance to preprocess the message first 
 106     if ( !PreProcessMessage(msg
) ) 
 108         // if it wasn't done, dispatch it to the corresponding window 
 109         ::TranslateMessage(msg
); 
 110         ::DispatchMessage(msg
); 
 114 bool wxEventLoop::PreProcessMessage(WXMSG 
*msg
) 
 116     HWND hwnd 
= msg
->hwnd
; 
 117     wxWindow 
*wndThis 
= wxGetWindowFromHWND((WXHWND
)hwnd
); 
 119     // this may happen if the event occured in a standard modeless dialog (the 
 120     // only example of which I know of is the find/replace dialog) - then call 
 121     // IsDialogMessage() to make TAB navigation in it work 
 124         // we need to find the dialog containing this control as 
 125         // IsDialogMessage() just eats all the messages (i.e. returns true for 
 126         // them) if we call it for the control itself 
 127         while ( hwnd 
&& ::GetWindowLong(hwnd
, GWL_STYLE
) & WS_CHILD 
) 
 129             hwnd 
= ::GetParent(hwnd
); 
 132         return hwnd 
&& ::IsDialogMessage(hwnd
, msg
) != 0; 
 136     // we must relay WM_MOUSEMOVE events to the tooltip ctrl if we want it to 
 137     // popup the tooltip bubbles 
 138     if ( msg
->message 
== WM_MOUSEMOVE 
) 
 140         wxToolTip 
*tt 
= wndThis
->GetToolTip(); 
 143             tt
->RelayEvent((WXMSG 
*)msg
); 
 146 #endif // wxUSE_TOOLTIPS 
 148     // allow the window to prevent certain messages from being 
 149     // translated/processed (this is currently used by wxTextCtrl to always 
 150     // grab Ctrl-C/V/X, even if they are also accelerators in some parent) 
 151     if ( !wndThis
->MSWShouldPreProcessMessage((WXMSG 
*)msg
) ) 
 156     // try translations first: the accelerators override everything 
 159     for ( wnd 
= wndThis
; wnd
; wnd 
= wnd
->GetParent() ) 
 161         if ( wnd
->MSWTranslateMessage((WXMSG 
*)msg
)) 
 164         // stop at first top level window, i.e. don't try to process the key 
 165         // strokes originating in a dialog using the accelerators of the parent 
 166         // frame - this doesn't make much sense 
 167         if ( wnd
->IsTopLevel() ) 
 171     // now try the other hooks (kbd navigation is handled here): we start from 
 172     // wndThis->GetParent() because wndThis->MSWProcessMessage() was already 
 174     for ( wnd 
= wndThis
->GetParent(); wnd
; wnd 
= wnd
->GetParent() ) 
 176         if ( wnd
->MSWProcessMessage((WXMSG 
*)msg
) ) 
 180     // no special preprocessing for this message, dispatch it normally 
 184 // ---------------------------------------------------------------------------- 
 185 // wxEventLoop running and exiting 
 186 // ---------------------------------------------------------------------------- 
 188 bool wxEventLoop::IsRunning() const 
 190     return ms_activeLoop 
== this; 
 193 int wxEventLoop::Run() 
 195     // event loops are not recursive, you need to create another loop! 
 196     wxCHECK_MSG( !IsRunning(), -1, _T("can't reenter a message loop") ); 
 198     // ProcessIdle() and Dispatch() below may throw so the code here should 
 199     // be exception-safe, hence we must use local objects for all actions we 
 201     wxEventLoopActivator 
activate(&ms_activeLoop
, this); 
 203     // we must ensure that OnExit() is called even if an exception is thrown 
 204     // from inside Dispatch() but we must call it from Exit() in normal 
 205     // situations because it is supposed to be called synchronously, 
 206     // wxModalEventLoop depends on this (so we can't just use ON_BLOCK_EXIT or 
 207     // something similar here) 
 213 #endif // wxUSE_EXCEPTIONS 
 215             // this is the event loop itself 
 219                     wxMutexGuiLeaveOrEnter(); 
 220                 #endif // wxUSE_THREADS 
 222                 // generate and process idle events for as long as we don't 
 223                 // have anything else to do 
 224                 while ( !Pending() && (wxTheApp 
&& wxTheApp
->ProcessIdle()) ) 
 227                 // if the "should exit" flag is set, the loop should terminate 
 228                 // but not before processing any remaining messages so while 
 229                 // Pending() returns true, do process them 
 238                 // a message came or no more idle processing to do, sit in 
 239                 // Dispatch() waiting for the next message 
 248             // exit the outer loop as well 
 255                 if ( !wxTheApp 
|| !wxTheApp
->OnExceptionInMainLoop() ) 
 260                 //else: continue running the event loop 
 264                 // OnException() throwed, possibly rethrowing the same 
 265                 // exception again: very good, but we still need OnExit() to 
 272 #endif // wxUSE_EXCEPTIONS 
 277 void wxEventLoop::Exit(int rc
) 
 279     wxCHECK_RET( IsRunning(), _T("can't call Exit() if not running") ); 
 286     // all we have to do to exit from the loop is to (maybe) wake it up so that 
 287     // it can notice that Exit() had been called 
 289     // in particular, we do *not* use PostQuitMessage() here because we're not 
 290     // sure that WM_QUIT is going to be processed by the correct event loop: it 
 291     // is possible that another one is started before this one has a chance to 
 293     ::PostMessage(NULL
, WM_NULL
, 0, 0); 
 296 // ---------------------------------------------------------------------------- 
 297 // wxEventLoop message processing dispatching 
 298 // ---------------------------------------------------------------------------- 
 300 bool wxEventLoop::Pending() const 
 303     return ::PeekMessage(&msg
, 0, 0, 0, PM_NOREMOVE
) != 0; 
 306 bool wxEventLoop::Dispatch() 
 308     wxCHECK_MSG( IsRunning(), false, _T("can't call Dispatch() if not running") ); 
 311     BOOL rc 
= ::GetMessage(&msg
, (HWND
) NULL
, 0, 0); 
 321         // should never happen, but let's test for it nevertheless 
 322         wxLogLastError(wxT("GetMessage")); 
 324         // still break from the loop 
 329     wxASSERT_MSG( wxThread::IsMain(), 
 330                   wxT("only the main thread can process Windows messages") ); 
 332     static bool s_hadGuiLock 
= true; 
 333     static wxMsgArray s_aSavedMessages
; 
 335     // if a secondary thread owning the mutex is doing GUI calls, save all 
 336     // messages for later processing - we can't process them right now because 
 337     // it will lead to recursive library calls (and we're not reentrant) 
 338     if ( !wxGuiOwnedByMainThread() ) 
 340         s_hadGuiLock 
= false; 
 342         // leave out WM_COMMAND messages: too dangerous, sometimes 
 343         // the message will be processed twice 
 344         if ( !wxIsWaitingForThread() || msg
.message 
!= WM_COMMAND 
) 
 346             s_aSavedMessages
.Add(msg
); 
 353         // have we just regained the GUI lock? if so, post all of the saved 
 356         // FIXME of course, it's not _exactly_ the same as processing the 
 357         //       messages normally - expect some things to break... 
 362             size_t count 
= s_aSavedMessages
.Count(); 
 363             for ( size_t n 
= 0; n 
< count
; n
++ ) 
 365                 MSG
& msg 
= s_aSavedMessages
[n
]; 
 366                 ProcessMessage(&msg
); 
 369             s_aSavedMessages
.Empty(); 
 372 #endif // wxUSE_THREADS 
 374     ProcessMessage(&msg
);