1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/motif/evtloop.cpp 
   3 // Purpose:     implements wxEventLoop for Motif 
   4 // Author:      Mattia Barbon 
   8 // Copyright:   (c) 2002 Mattia Barbon 
   9 // License:     wxWindows licence 
  10 /////////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  20 // For compilers that support precompilation, includes "wx.h". 
  21 #include "wx/wxprec.h" 
  26     #include "wx/window.h" 
  27     #include "wx/module.h" 
  30 #include "wx/evtloop.h" 
  31 #include "wx/thread.h" 
  34     #pragma message disable nosimpint 
  39     #pragma message enable nosimpint 
  42 #include "wx/unix/private.h" 
  43 #include "wx/motif/private.h" 
  45 #ifdef HAVE_SYS_SELECT_H 
  46 #   include <sys/select.h> 
  49 static bool CheckForKeyUp(XEvent
* event
); 
  50 static bool CheckForKeyDown(XEvent
* event
); 
  51 static bool CheckForAccelerator(XEvent
* event
); 
  52 static void ProcessXEvent(XEvent
* event
); 
  53 static void wxBreakDispatch(); 
  55 // ---------------------------------------------------------------------------- 
  57 // ---------------------------------------------------------------------------- 
  59 class WXDLLEXPORT wxEventLoopImpl
 
  63     wxEventLoopImpl() { SetExitCode(0); } 
  65     // set/get the exit code 
  66     void SetExitCode(int exitcode
) { m_exitcode 
= exitcode
; } 
  67     int GetExitCode() const { return m_exitcode
; } 
  69     bool SendIdleMessage(); 
  70     bool GetKeepGoing() const { return m_keepGoing
; } 
  71     void SetKeepGoing(bool keepGoing
) { m_keepGoing 
= keepGoing
; } 
  73     // the exit code of the event loop 
  78 // ---------------------------------------------------------------------------- 
  79 // wxEventLoopImpl idle event processing 
  80 // ---------------------------------------------------------------------------- 
  82 static bool SendIdleMessage() 
  84     return wxTheApp
->ProcessIdle(); 
  87 bool wxEventLoopImpl::SendIdleMessage() 
  89     return ::SendIdleMessage(); 
  92 // ============================================================================ 
  93 // wxEventLoop implementation 
  94 // ============================================================================ 
  96 // ---------------------------------------------------------------------------- 
  97 // wxEventLoop running and exiting 
  98 // ---------------------------------------------------------------------------- 
 100 wxGUIEventLoop::~wxGUIEventLoop() 
 102     wxASSERT_MSG( !m_impl
, _T("should have been deleted in Run()") ); 
 105 int wxGUIEventLoop::Run() 
 107     // event loops are not recursive, you need to create another loop! 
 108     wxCHECK_MSG( !IsRunning(), -1, _T("can't reenter a message loop") ); 
 110     wxEventLoopActivator 
activate(this); 
 112     m_impl 
= new wxEventLoopImpl
; 
 113     m_impl
->SetKeepGoing( true ); 
 117         if( !wxDoEventLoopIteration( *this ) ) 
 123     int exitcode 
= m_impl
->GetExitCode(); 
 130 void wxGUIEventLoop::Exit(int rc
) 
 132     wxCHECK_RET( IsRunning(), _T("can't call Exit() if not running") ); 
 134     m_impl
->SetExitCode(rc
); 
 135     m_impl
->SetKeepGoing( false ); 
 140 // ---------------------------------------------------------------------------- 
 141 // wxEventLoop message processing dispatching 
 142 // ---------------------------------------------------------------------------- 
 144 bool wxGUIEventLoop::Pending() const 
 146     return XtAppPending( (XtAppContext
)wxTheApp
->GetAppContext() ) != 0; 
 149 bool wxGUIEventLoop::Dispatch() 
 152     XtAppContext context 
= (XtAppContext
)wxTheApp
->GetAppContext(); 
 154     if( XtAppPeekEvent( context
, &event 
) != 0 ) 
 156         XtAppNextEvent( context
, &event 
); 
 157         ProcessXEvent( &event 
); 
 161         XtAppProcessEvent( context
, XtIMTimer 
| XtIMAlternateInput
 
 168     return m_impl 
? m_impl
->GetKeepGoing() : true; 
 171 // ---------------------------------------------------------------------------- 
 172 // Static functions (originally in app.cpp) 
 173 // ---------------------------------------------------------------------------- 
 175 void ProcessXEvent(XEvent
* event
) 
 177     if (event
->type 
== KeyPress
) 
 179         if (CheckForAccelerator(event
)) 
 181             // Do nothing! We intercepted and processed the event as an 
 185         // It seemed before that this hack was redundant and 
 186         // key down events were being generated by wxCanvasInputEvent. 
 187         // But no longer - why ??? 
 189         else if (CheckForKeyDown(event
)) 
 191             // We intercepted and processed the key down event 
 196             XtDispatchEvent(event
); 
 200     else if (event
->type 
== KeyRelease
) 
 202         // TODO: work out why we still need this !  -michael 
 204         if (::CheckForKeyUp(event
)) 
 206             // We intercepted and processed the key up event 
 211             XtDispatchEvent(event
); 
 215     else if (event
->type 
== PropertyNotify
) 
 217         wxTheApp
->HandlePropertyChange(event
); 
 220     else if (event
->type 
== ResizeRequest
) 
 222         /* Terry Gitnick <terryg@scientech.com> - 1/21/98 
 223          * If resize event, don't resize until the last resize event for this 
 224          * window is recieved. Prevents flicker as windows are resized. 
 227         Display 
*disp 
= event
->xany
.display
; 
 228         Window win 
= event
->xany
.window
; 
 233         while( XCheckTypedWindowEvent (disp
, win
, ResizeRequest
, &report
)); 
 235         // TODO: when implementing refresh optimization, we can use 
 236         // XtAddExposureToRegion to expand the window's paint region. 
 238         XtDispatchEvent(event
); 
 242         XtDispatchEvent(event
); 
 246 // Returns true if an accelerator has been processed 
 247 bool CheckForAccelerator(XEvent
* event
) 
 249     if (event
->xany
.type 
== KeyPress
) 
 251         // Find a wxWindow for this window 
 252         // TODO: should get display for the window, not the current display 
 253         Widget widget 
= XtWindowToWidget(event
->xany
.display
, 
 255         wxWindow
* win 
= NULL
; 
 257         // Find the first wxWindow that corresponds to this event window 
 258         while (widget 
&& ((win 
= wxGetWindowFromTable(widget
))!=NULL
)) 
 259             widget 
= XtParent(widget
); 
 264         wxKeyEvent 
keyEvent(wxEVT_CHAR
); 
 265         wxTranslateKeyEvent(keyEvent
, win
, (Widget
) 0, event
); 
 267         // Now we have a wxKeyEvent and we have a wxWindow. 
 268         // Go up the hierarchy until we find a matching accelerator, 
 269         // or we get to the top. 
 272             if (win
->ProcessAccelerator(keyEvent
)) 
 274             win 
= win
->GetParent(); 
 281 // bool wxApp::CheckForKeyDown(WXEvent* event) { wxFAIL; return false; } 
 283 bool CheckForKeyDown(XEvent
* event
) 
 285     if (event
->xany
.type 
== KeyPress
) 
 287         Widget widget 
= XtWindowToWidget(event
->xany
.display
, 
 289         wxWindow
* win 
= NULL
; 
 291         // Find the first wxWindow that corresponds to this event window 
 292         while (widget 
&& ((win 
= wxGetWindowFromTable(widget
))!=NULL
)) 
 293             widget 
= XtParent(widget
); 
 298         wxKeyEvent 
keyEvent(wxEVT_KEY_DOWN
); 
 299         wxTranslateKeyEvent(keyEvent
, win
, (Widget
) 0, event
); 
 301         return win
->HandleWindowEvent( keyEvent 
); 
 307 // bool wxApp::CheckForKeyUp(WXEvent* event) { wxFAIL; return false; } 
 309 bool CheckForKeyUp(XEvent
* event
) 
 311     if (event
->xany
.type 
== KeyRelease
) 
 313         Widget widget 
= XtWindowToWidget(event
->xany
.display
, 
 315         wxWindow
* win 
= NULL
; 
 317         // Find the first wxWindow that corresponds to this event window 
 318         while (widget 
&& ((win 
= wxGetWindowFromTable(widget
))!=NULL
)) 
 319                 widget 
= XtParent(widget
); 
 324         wxKeyEvent 
keyEvent(wxEVT_KEY_UP
); 
 325         wxTranslateKeyEvent(keyEvent
, win
, (Widget
) 0, event
); 
 327         return win
->HandleWindowEvent( keyEvent 
); 
 333 // ---------------------------------------------------------------------------- 
 334 // executes one main loop iteration (declared in include/wx/motif/private.h) 
 335 // ---------------------------------------------------------------------------- 
 337 bool wxDoEventLoopIteration( wxGUIEventLoop
& evtLoop 
) 
 339     bool moreRequested
, pendingEvents
; 
 343         pendingEvents 
= evtLoop
.Pending(); 
 344         if( pendingEvents 
) break; 
 345         moreRequested 
= ::SendIdleMessage(); 
 346         if( !moreRequested 
) break; 
 350     if( !pendingEvents 
&& !moreRequested 
) 
 352         // leave the main loop to give other threads a chance to 
 353         // perform their GUI work 
 360     if( !evtLoop
.Dispatch() ) 
 366 // ---------------------------------------------------------------------------- 
 367 // ::wxWakeUpIdle implementation 
 368 // ---------------------------------------------------------------------------- 
 370 // As per Vadim's suggestion, we open a pipe, and XtAppAddInputSource it; 
 371 // writing a single byte to the pipe will cause wxEventLoop::Pending 
 372 // to return true, and wxEventLoop::Dispatch to dispatch an input handler 
 373 // that simply removes the byte(s), and to return, which will cause 
 374 // an idle event to be sent 
 376 // also wxEventLoop::Exit is implemented that way, so that exiting an 
 377 // event loop won't require an event being in the queue 
 379 #include <sys/types.h> 
 380 #include <sys/time.h> 
 383 static int idleFds
[2] = { -1, -1 }; 
 385 class wxIdlePipeModule 
: public wxModule
 
 388     wxIdlePipeModule() {}; 
 390     virtual bool OnInit() 
 392         // Must be done before modules are initialized 
 394         if( pipe(idleFds
) != 0 ) 
 400     virtual void OnExit() 
 406     DECLARE_DYNAMIC_CLASS(wxIdlePipeModule
) 
 409 IMPLEMENT_DYNAMIC_CLASS(wxIdlePipeModule
, wxModule
) 
 411 static void wxInputCallback( XtPointer
, int* fd
, XtInputId
* ) 
 415     // wxWakeUpIdle may have been called more than once 
 419         struct timeval timeout
; 
 425         wxFD_SET( *fd
, &in 
); 
 427         if( select( *fd 
+ 1, &in
, NULL
, NULL
, &timeout 
) <= 0 ) 
 429         if( read( *fd
, buffer
, sizeof(buffer
) - 1 ) != sizeof(buffer
) - 1 ) 
 434 static void wxBreakDispatch() 
 436     char dummy 
= 0; // for valgrind 
 438     // check if wxWakeUpIdle has already been called 
 440     struct timeval timeout
; 
 446     wxFD_SET( idleFds
[0], &in 
); 
 448     if( select( idleFds
[0] + 1, &in
, NULL
, NULL
, &timeout 
) > 0 ) 
 451     // write a single byte 
 452     write( idleFds
[1], &dummy
, 1 ); 
 455 void wxApp::WakeUpIdle() 
 462     if( pipe(idleFds
) != 0 ) 
 467 bool wxAddIdleCallback() 
 469     if (!wxInitIdleFds()) 
 472     // install input handler for wxWakeUpIdle 
 473     XtAppAddInput((XtAppContext
) wxTheApp
->GetAppContext(), 
 475                   (XtPointer
)XtInputReadMask
,