1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/motif/evtloop.cpp 
   3 // Purpose:     implements wxEventLoop for Motif 
   4 // Author:      Mattia Barbon 
   8 // Copyright:   (c) 2002 Mattia Barbon 
   9 // Licence:     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
, wxT("should have been deleted in Run()") ); 
 105 int wxGUIEventLoop::DoRun() 
 107     m_impl 
= new wxEventLoopImpl
; 
 108     m_impl
->SetKeepGoing( true ); 
 112         if( !wxDoEventLoopIteration( *this ) ) 
 118     int exitcode 
= m_impl
->GetExitCode(); 
 124 void wxGUIEventLoop::ScheduleExit(int rc
) 
 126     wxCHECK_RET( IsInsideRun(), wxT("can't call ScheduleExit() if not started") ); 
 128     m_impl
->SetExitCode(rc
); 
 129     m_impl
->SetKeepGoing( false ); 
 134 bool wxGUIEventLoop::YieldFor(long eventsToProcess
) 
 136     m_isInsideYield 
= true; 
 137     m_eventsToProcessInsideYield 
= eventsToProcess
; 
 139     while (wxTheApp 
&& wxTheApp
->Pending()) 
 140         // TODO: implement event filtering using the eventsToProcess mask 
 141         wxTheApp
->Dispatch(); 
 143     m_isInsideYield 
= false; 
 148 // ---------------------------------------------------------------------------- 
 149 // wxEventLoop message processing dispatching 
 150 // ---------------------------------------------------------------------------- 
 152 bool wxGUIEventLoop::Pending() const 
 154     return XtAppPending( (XtAppContext
)wxTheApp
->GetAppContext() ) != 0; 
 157 bool wxGUIEventLoop::Dispatch() 
 160     XtAppContext context 
= (XtAppContext
)wxTheApp
->GetAppContext(); 
 162     if( XtAppPeekEvent( context
, &event 
) != 0 ) 
 164         XtAppNextEvent( context
, &event 
); 
 165         ProcessXEvent( &event 
); 
 169         XtAppProcessEvent( context
, XtIMTimer 
| XtIMAlternateInput
 
 176     return m_impl 
? m_impl
->GetKeepGoing() : true; 
 179 // ---------------------------------------------------------------------------- 
 180 // Static functions (originally in app.cpp) 
 181 // ---------------------------------------------------------------------------- 
 183 void ProcessXEvent(XEvent
* event
) 
 185     if (event
->type 
== KeyPress
) 
 187         if (CheckForAccelerator(event
)) 
 189             // Do nothing! We intercepted and processed the event as an 
 193         // It seemed before that this hack was redundant and 
 194         // key down events were being generated by wxCanvasInputEvent. 
 195         // But no longer - why ??? 
 197         else if (CheckForKeyDown(event
)) 
 199             // We intercepted and processed the key down event 
 204             XtDispatchEvent(event
); 
 208     else if (event
->type 
== KeyRelease
) 
 210         // TODO: work out why we still need this !  -michael 
 212         if (::CheckForKeyUp(event
)) 
 214             // We intercepted and processed the key up event 
 219             XtDispatchEvent(event
); 
 223     else if (event
->type 
== PropertyNotify
) 
 225         wxTheApp
->HandlePropertyChange(event
); 
 228     else if (event
->type 
== ResizeRequest
) 
 230         /* Terry Gitnick <terryg@scientech.com> - 1/21/98 
 231          * If resize event, don't resize until the last resize event for this 
 232          * window is recieved. Prevents flicker as windows are resized. 
 235         Display 
*disp 
= event
->xany
.display
; 
 236         Window win 
= event
->xany
.window
; 
 241         while( XCheckTypedWindowEvent (disp
, win
, ResizeRequest
, &report
)); 
 243         // TODO: when implementing refresh optimization, we can use 
 244         // XtAddExposureToRegion to expand the window's paint region. 
 246         XtDispatchEvent(event
); 
 250         XtDispatchEvent(event
); 
 254 // Returns true if an accelerator has been processed 
 255 bool CheckForAccelerator(XEvent
* event
) 
 257     if (event
->xany
.type 
== KeyPress
) 
 259         // Find a wxWindow for this window 
 260         // TODO: should get display for the window, not the current display 
 261         Widget widget 
= XtWindowToWidget(event
->xany
.display
, 
 263         wxWindow
* win 
= NULL
; 
 265         // Find the first wxWindow that corresponds to this event window 
 266         while (widget 
&& ((win 
= wxGetWindowFromTable(widget
))!=NULL
)) 
 267             widget 
= XtParent(widget
); 
 272         wxKeyEvent 
keyEvent(wxEVT_CHAR
); 
 273         wxTranslateKeyEvent(keyEvent
, win
, (Widget
) 0, event
); 
 275         // Now we have a wxKeyEvent and we have a wxWindow. 
 276         // Go up the hierarchy until we find a matching accelerator, 
 277         // or we get to the top. 
 280             if (win
->ProcessAccelerator(keyEvent
)) 
 282             win 
= win
->GetParent(); 
 289 // bool wxApp::CheckForKeyDown(WXEvent* event) { wxFAIL; return false; } 
 291 bool CheckForKeyDown(XEvent
* event
) 
 293     if (event
->xany
.type 
== KeyPress
) 
 295         Widget widget 
= XtWindowToWidget(event
->xany
.display
, 
 297         wxWindow
* win 
= NULL
; 
 299         // Find the first wxWindow that corresponds to this event window 
 300         while (widget 
&& ((win 
= wxGetWindowFromTable(widget
))!=NULL
)) 
 301             widget 
= XtParent(widget
); 
 306         wxKeyEvent 
keyEvent(wxEVT_KEY_DOWN
); 
 307         wxTranslateKeyEvent(keyEvent
, win
, (Widget
) 0, event
); 
 309         return win
->HandleWindowEvent( keyEvent 
); 
 315 // bool wxApp::CheckForKeyUp(WXEvent* event) { wxFAIL; return false; } 
 317 bool CheckForKeyUp(XEvent
* event
) 
 319     if (event
->xany
.type 
== KeyRelease
) 
 321         Widget widget 
= XtWindowToWidget(event
->xany
.display
, 
 323         wxWindow
* win 
= NULL
; 
 325         // Find the first wxWindow that corresponds to this event window 
 326         while (widget 
&& ((win 
= wxGetWindowFromTable(widget
))!=NULL
)) 
 327                 widget 
= XtParent(widget
); 
 332         wxKeyEvent 
keyEvent(wxEVT_KEY_UP
); 
 333         wxTranslateKeyEvent(keyEvent
, win
, (Widget
) 0, event
); 
 335         return win
->HandleWindowEvent( keyEvent 
); 
 341 // ---------------------------------------------------------------------------- 
 342 // executes one main loop iteration (declared in include/wx/motif/private.h) 
 343 // ---------------------------------------------------------------------------- 
 345 bool wxDoEventLoopIteration( wxGUIEventLoop
& evtLoop 
) 
 347     bool moreRequested
, pendingEvents
; 
 351         pendingEvents 
= evtLoop
.Pending(); 
 352         if( pendingEvents 
) break; 
 353         moreRequested 
= ::SendIdleMessage(); 
 354         if( !moreRequested 
) break; 
 358     if( !pendingEvents 
&& !moreRequested 
) 
 360         // leave the main loop to give other threads a chance to 
 361         // perform their GUI work 
 368     if( !evtLoop
.Dispatch() ) 
 374 // ---------------------------------------------------------------------------- 
 375 // ::wxWakeUpIdle implementation 
 376 // ---------------------------------------------------------------------------- 
 378 // As per Vadim's suggestion, we open a pipe, and XtAppAddInputSource it; 
 379 // writing a single byte to the pipe will cause wxEventLoop::Pending 
 380 // to return true, and wxEventLoop::Dispatch to dispatch an input handler 
 381 // that simply removes the byte(s), and to return, which will cause 
 382 // an idle event to be sent 
 384 // also wxEventLoop::Exit is implemented that way, so that exiting an 
 385 // event loop won't require an event being in the queue 
 387 #include <sys/types.h> 
 388 #include <sys/time.h> 
 391 static int idleFds
[2] = { -1, -1 }; 
 393 class wxIdlePipeModule 
: public wxModule
 
 396     wxIdlePipeModule() {}; 
 398     virtual bool OnInit() 
 400         // Must be done before modules are initialized 
 402         if( pipe(idleFds
) != 0 ) 
 408     virtual void OnExit() 
 414     DECLARE_DYNAMIC_CLASS(wxIdlePipeModule
) 
 417 IMPLEMENT_DYNAMIC_CLASS(wxIdlePipeModule
, wxModule
) 
 419 static void wxInputCallback( XtPointer
, int* fd
, XtInputId
* ) 
 423     // wxWakeUpIdle may have been called more than once 
 427         struct timeval timeout
; 
 433         wxFD_SET( *fd
, &in 
); 
 435         if( select( *fd 
+ 1, &in
, NULL
, NULL
, &timeout 
) <= 0 ) 
 437         if( read( *fd
, buffer
, sizeof(buffer
) - 1 ) != sizeof(buffer
) - 1 ) 
 442 static void wxBreakDispatch() 
 444     char dummy 
= 0; // for valgrind 
 446     // check if wxWakeUpIdle has already been called 
 448     struct timeval timeout
; 
 454     wxFD_SET( idleFds
[0], &in 
); 
 456     if( select( idleFds
[0] + 1, &in
, NULL
, NULL
, &timeout 
) > 0 ) 
 459     // write a single byte 
 460     write( idleFds
[1], &dummy
, 1 ); 
 463 void wxApp::WakeUpIdle() 
 470     if( pipe(idleFds
) != 0 ) 
 475 bool wxAddIdleCallback() 
 477     if (!wxInitIdleFds()) 
 480     // install input handler for wxWakeUpIdle 
 481     XtAppAddInput((XtAppContext
) wxTheApp
->GetAppContext(), 
 483                   (XtPointer
)XtInputReadMask
,