home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2233.zip / wxOS2-2_3_3.zip / wxWindows-2.3.3 / src / os2 / evtloop.cpp < prev    next >
C/C++ Source or Header  |  2001-10-17  |  9KB  |  297 lines

  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Name:        os2/evtloop.cpp
  3. // Purpose:     implements wxEventLoop for PM
  4. // Author:      Vadim Zeitlin
  5. // Modified by:
  6. // Created:     01.06.01
  7. // RCS-ID:      $Id: evtloop.cpp,v 1.1 2001/10/17 22:31:57 KLB Exp $
  8. // Copyright:   (c) 2001 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
  9. // License:     wxWindows license
  10. ///////////////////////////////////////////////////////////////////////////////
  11.  
  12. // ============================================================================
  13. // declarations
  14. // ============================================================================
  15.  
  16. // ----------------------------------------------------------------------------
  17. // headers
  18. // ----------------------------------------------------------------------------
  19.  
  20. #ifdef __GNUG__
  21.     #pragma implementation "evtloop.h"
  22. #endif
  23.  
  24. // For compilers that support precompilation, includes "wx.h".
  25. #include "wx/wxprec.h"
  26.  
  27. #ifdef __BORLANDC__
  28.     #pragma hdrstop
  29. #endif
  30.  
  31. #ifndef WX_PRECOMP
  32.     #include "wx/window.h"
  33.     #include "wx/app.h"
  34. #endif //WX_PRECOMP
  35.  
  36. #include "wx/evtloop.h"
  37. #include "wx/tooltip.h"
  38.  
  39. #include "wx/os2/private.h"
  40.  
  41. #if wxUSE_THREADS
  42.     // define the array of QMSG strutures
  43.     WX_DECLARE_OBJARRAY(QMSG, wxMsgArray);
  44.     // VS: this is a bit dirty - it duplicates same declaration in app.cpp
  45.     //     (and there's no WX_DEFINE_OBJARRAY for that reason - it is already
  46.     //     defined in app.cpp).
  47. #endif
  48.  
  49. extern HAB vHabMain;
  50.  
  51. // ----------------------------------------------------------------------------
  52. // wxEventLoopImpl
  53. // ----------------------------------------------------------------------------
  54.  
  55. class WXDLLEXPORT wxEventLoopImpl
  56. {
  57. public:
  58.     // ctor
  59.     wxEventLoopImpl() { SetExitCode(0); }
  60.  
  61.     // process a message
  62.     void ProcessMessage(QMSG *msg);
  63.  
  64.     // generate an idle message, return TRUE if more idle time requested
  65.     bool SendIdleMessage();
  66.  
  67.     // set/get the exit code
  68.     void SetExitCode(int exitcode) { m_exitcode = exitcode; }
  69.     int GetExitCode() const { return m_exitcode; }
  70.  
  71. private:
  72.     // preprocess a message, return TRUE if processed (i.e. no further
  73.     // dispatching required)
  74.     bool PreProcessMessage(QMSG *msg);
  75.  
  76.     // the exit code of the event loop
  77.     int m_exitcode;
  78. };
  79.  
  80. // ============================================================================
  81. // wxEventLoopImpl implementation
  82. // ============================================================================
  83.  
  84. // ----------------------------------------------------------------------------
  85. // wxEventLoopImpl message processing
  86. // ----------------------------------------------------------------------------
  87.  
  88. void wxEventLoopImpl::ProcessMessage(QMSG *msg)
  89. {
  90.     // give us the chance to preprocess the message first
  91.     if ( !PreProcessMessage(msg) )
  92.     {
  93.         // if it wasn't done, dispatch it to the corresponding window
  94.         ::WinDispatchMsg(vHabMain, msg);
  95.     }
  96. }
  97.  
  98. bool wxEventLoopImpl::PreProcessMessage(QMSG *msg)
  99. {
  100.     HWND hWnd = msg->hwnd;
  101.     wxWindow *wndThis = wxFindWinFromHandle((WXHWND)hWnd);
  102.  
  103. #if wxUSE_TOOLTIPS
  104.     // we must relay WM_MOUSEMOVE events to the tooltip ctrl if we want it to
  105.     // popup the tooltip bubbles
  106.     if ( wndThis && (msg->message == WM_MOUSEMOVE) )
  107.     {
  108.         wxToolTip *tt = wndThis->GetToolTip();
  109.         if ( tt )
  110.         {
  111.             tt->RelayEvent((WXMSG *)msg);
  112.         }
  113.     }
  114. #endif // wxUSE_TOOLTIPS
  115.  
  116.     // try translations first; find the youngest window with a translation
  117.     // table.
  118.     wxWindow *wnd;
  119.     for ( wnd = wndThis; wnd; wnd = wnd->GetParent() )
  120.     {
  121.         if ( wnd->OS2TranslateMessage((WXMSG *)msg) )
  122.             return TRUE;
  123.     }
  124.  
  125.     // Anyone for a non-translation message? Try youngest descendants first.
  126.     for ( wnd = wndThis; wnd; wnd = wnd->GetParent() )
  127.     {
  128.         if ( wnd->OS2ProcessMessage((WXMSG *)msg) )
  129.             return TRUE;
  130.     }
  131.  
  132.     return FALSE;
  133. }
  134.  
  135. // ----------------------------------------------------------------------------
  136. // wxEventLoopImpl idle event processing
  137. // ----------------------------------------------------------------------------
  138.  
  139. bool wxEventLoopImpl::SendIdleMessage()
  140. {
  141.     wxIdleEvent event;
  142.  
  143.     return wxTheApp->ProcessEvent(event) && event.MoreRequested();
  144. }
  145.  
  146. // ============================================================================
  147. // wxEventLoop implementation
  148. // ============================================================================
  149.  
  150. wxEventLoop *wxEventLoop::ms_activeLoop = NULL;
  151.  
  152. // ----------------------------------------------------------------------------
  153. // wxEventLoop running and exiting
  154. // ----------------------------------------------------------------------------
  155.  
  156. wxEventLoop::~wxEventLoop()
  157. {
  158.     wxASSERT_MSG( !m_impl, _T("should have been deleted in Run()") );
  159. }
  160.  
  161. bool wxEventLoop::IsRunning() const
  162. {
  163.     return m_impl != NULL;
  164. }
  165.  
  166. int wxEventLoop::Run()
  167. {
  168.     // event loops are not recursive, you need to create another loop!
  169.     wxCHECK_MSG( !IsRunning(), -1, _T("can't reenter a message loop") );
  170.  
  171.     m_impl = new wxEventLoopImpl;
  172.  
  173.     wxEventLoop *oldLoop = ms_activeLoop;
  174.     ms_activeLoop = this;
  175.  
  176.     for ( ;; )
  177.     {
  178. #if wxUSE_THREADS
  179.         wxMutexGuiLeaveOrEnter();
  180. #endif // wxUSE_THREADS
  181.  
  182.         // generate and process idle events for as long as we don't have
  183.         // anything else to do
  184.         while ( !Pending() && m_impl->SendIdleMessage() )
  185.             ;
  186.  
  187.         // a message came or no more idle processing to do, sit in Dispatch()
  188.         // waiting for the next message
  189.         if ( !Dispatch() )
  190.         {
  191.             // we got WM_QUIT
  192.             break;
  193.         }
  194.     }
  195.  
  196.     int exitcode = m_impl->GetExitCode();
  197.     delete m_impl;
  198.     m_impl = NULL;
  199.  
  200.     ms_activeLoop = oldLoop;
  201.  
  202.     return exitcode;
  203. }
  204.  
  205. void wxEventLoop::Exit(int rc)
  206. {
  207.     wxCHECK_RET( IsRunning(), _T("can't call Exit() if not running") );
  208.  
  209.     m_impl->SetExitCode(rc);
  210.  
  211.     ::WinPostMsg(NULL, WM_QUIT, 0, 0);
  212. }
  213.  
  214. // ----------------------------------------------------------------------------
  215. // wxEventLoop message processing dispatching
  216. // ----------------------------------------------------------------------------
  217.  
  218. bool wxEventLoop::Pending() const
  219. {
  220.     QMSG msg;
  221.     return ::WinPeekMsg(vHabMain, &msg, 0, 0, 0, PM_NOREMOVE) != 0;
  222. }
  223.  
  224. bool wxEventLoop::Dispatch()
  225. {
  226.     wxCHECK_MSG( IsRunning(), FALSE, _T("can't call Dispatch() if not running") );
  227.  
  228.     QMSG msg;
  229.     BOOL rc = ::WinGetMsg(vHabMain, &msg, (HWND) NULL, 0, 0);
  230.  
  231.     if ( rc == 0 )
  232.     {
  233.         // got WM_QUIT
  234.         return FALSE;
  235.     }
  236.  
  237.     if ( rc == -1 )
  238.     {
  239.         // should never happen, but let's test for it nevertheless
  240.         wxLogLastError(wxT("GetMessage"));
  241.  
  242.         // still break from the loop
  243.         return FALSE;
  244.     }
  245.  
  246. #if wxUSE_THREADS
  247.     wxASSERT_MSG( wxThread::IsMain(),
  248.                   wxT("only the main thread can process Windows messages") );
  249.  
  250.     static bool s_hadGuiLock = TRUE;
  251.     static wxMsgArray s_aSavedMessages;
  252.  
  253.     // if a secondary thread owning the mutex is doing GUI calls, save all
  254.     // messages for later processing - we can't process them right now because
  255.     // it will lead to recursive library calls (and we're not reentrant)
  256.     if ( !wxGuiOwnedByMainThread() )
  257.     {
  258.         s_hadGuiLock = FALSE;
  259.  
  260.         // leave out WM_COMMAND messages: too dangerous, sometimes
  261.         // the message will be processed twice
  262.         if ( !wxIsWaitingForThread() || msg.message != WM_COMMAND )
  263.         {
  264.             s_aSavedMessages.Add(msg);
  265.         }
  266.  
  267.         return TRUE;
  268.     }
  269.     else
  270.     {
  271.         // have we just regained the GUI lock? if so, post all of the saved
  272.         // messages
  273.         //
  274.         // FIXME of course, it's not _exactly_ the same as processing the
  275.         //       messages normally - expect some things to break...
  276.         if ( !s_hadGuiLock )
  277.         {
  278.             s_hadGuiLock = TRUE;
  279.  
  280.             size_t count = s_aSavedMessages.Count();
  281.             for ( size_t n = 0; n < count; n++ )
  282.             {
  283.                 MSG& msg = s_aSavedMessages[n];
  284.                 m_impl->ProcessMessage(&msg);
  285.             }
  286.  
  287.             s_aSavedMessages.Empty();
  288.         }
  289.     }
  290. #endif // wxUSE_THREADS
  291.  
  292.     m_impl->ProcessMessage(&msg);
  293.  
  294.     return TRUE;
  295. }
  296.  
  297.