1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: motif/evtloop.cpp
3 // Purpose: implements wxEventLoop for Motif
4 // Author: Mattia Barbon
8 // Copyright: (c) 2002 Mattia Barbon
9 // License: wxWindows license
10 ///////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
21 #pragma implementation "evtloop.h"
25 #define XtParent XTPARENT
26 #define XtDisplay XTDISPLAY
29 // For compilers that support precompilation, includes "wx.h".
30 #include "wx/wxprec.h"
35 #include "wx/evtloop.h"
40 #pragma message disable nosimpint
45 #pragma message enable nosimpint
48 #include "wx/motif/private.h"
50 static bool CheckForKeyUp(XEvent
* event
);
51 static bool CheckForKeyDown(XEvent
* event
);
52 static bool CheckForAccelerator(XEvent
* event
);
53 static void ProcessXEvent(XEvent
* event
);
54 static void wxBreakDispatch();
56 // ----------------------------------------------------------------------------
58 // ----------------------------------------------------------------------------
60 class WXDLLEXPORT wxEventLoopImpl
64 wxEventLoopImpl() { SetExitCode(0); }
66 // set/get the exit code
67 void SetExitCode(int exitcode
) { m_exitcode
= exitcode
; }
68 int GetExitCode() const { return m_exitcode
; }
70 bool SendIdleMessage();
71 bool GetKeepGoing() const { return m_keepGoing
; }
72 void SetKeepGoing(bool keepGoing
) { m_keepGoing
= keepGoing
; }
74 // the exit code of the event loop
79 // ----------------------------------------------------------------------------
80 // wxEventLoopImpl idle event processing
81 // ----------------------------------------------------------------------------
83 static bool SendIdleMessage()
87 return wxTheApp
->ProcessEvent(event
) && event
.MoreRequested();
90 bool wxEventLoopImpl::SendIdleMessage()
92 return ::SendIdleMessage();
95 // ============================================================================
96 // wxEventLoop implementation
97 // ============================================================================
99 // ----------------------------------------------------------------------------
100 // wxEventLoop running and exiting
101 // ----------------------------------------------------------------------------
103 wxEventLoop
*wxEventLoop::ms_activeLoop
= NULL
;
105 wxEventLoop::~wxEventLoop()
107 wxASSERT_MSG( !m_impl
, _T("should have been deleted in Run()") );
110 bool wxEventLoop::IsRunning() const
112 return m_impl
!= NULL
;
115 int wxEventLoop::Run()
117 // event loops are not recursive, you need to create another loop!
118 wxCHECK_MSG( !IsRunning(), -1, _T("can't reenter a message loop") );
120 wxEventLoop
*oldLoop
= ms_activeLoop
;
121 ms_activeLoop
= this;
123 m_impl
= new wxEventLoopImpl
;
124 m_impl
->SetKeepGoing( true );
128 if( !wxDoEventLoopIteration( *this ) )
132 int exitcode
= m_impl
->GetExitCode();
136 ms_activeLoop
= oldLoop
;
141 void wxEventLoop::Exit(int rc
)
143 wxCHECK_RET( IsRunning(), _T("can't call Exit() if not running") );
145 m_impl
->SetExitCode(rc
);
146 m_impl
->SetKeepGoing( false );
151 // ----------------------------------------------------------------------------
152 // wxEventLoop message processing dispatching
153 // ----------------------------------------------------------------------------
155 bool wxEventLoop::Pending() const
157 return XtAppPending( (XtAppContext
)wxTheApp
->GetAppContext() ) != 0;
160 bool wxEventLoop::Dispatch()
163 XtAppContext context
= (XtAppContext
)wxTheApp
->GetAppContext();
165 if( XtAppPeekEvent( context
, &event
) != 0 )
167 XtAppNextEvent( context
, &event
);
168 ProcessXEvent( &event
);
172 XtAppProcessEvent( context
, XtIMTimer
|XtIMAlternateInput
);
174 XtAppProcessEvent( context
, XtIMTimer
|XtIMAlternateInput
|XtIMSignal
);
177 return m_impl
? m_impl
->GetKeepGoing() : true;
180 // ----------------------------------------------------------------------------
181 // Static functions (originally in app.cpp)
182 // ----------------------------------------------------------------------------
184 void ProcessXEvent(XEvent
* event
)
186 if (event
->type
== KeyPress
)
188 if (CheckForAccelerator(event
))
190 // Do nothing! We intercepted and processed the event as an
194 // It seemed before that this hack was redundant and
195 // key down events were being generated by wxCanvasInputEvent.
196 // But no longer - why ???
198 else if (CheckForKeyDown(event
))
200 // We intercepted and processed the key down event
205 XtDispatchEvent(event
);
209 else if (event
->type
== KeyRelease
)
211 // TODO: work out why we still need this ! -michael
213 if (::CheckForKeyUp(event
))
215 // We intercepted and processed the key up event
220 XtDispatchEvent(event
);
224 else if (event
->type
== PropertyNotify
)
226 wxTheApp
->HandlePropertyChange(event
);
229 else if (event
->type
== ResizeRequest
)
231 /* Terry Gitnick <terryg@scientech.com> - 1/21/98
232 * If resize event, don't resize until the last resize event for this
233 * window is recieved. Prevents flicker as windows are resized.
236 Display
*disp
= XtDisplay((Widget
) wxTheApp
->GetTopLevelWidget());
237 Window win
= event
->xany
.window
;
242 while( XCheckTypedWindowEvent (disp
, win
, ResizeRequest
, &report
));
244 // TODO: when implementing refresh optimization, we can use
245 // XtAddExposureToRegion to expand the window's paint region.
247 XtDispatchEvent(event
);
251 XtDispatchEvent(event
);
255 // Returns true if an accelerator has been processed
256 bool CheckForAccelerator(XEvent
* event
)
258 if (event
->xany
.type
== KeyPress
)
260 // Find a wxWindow for this window
261 // TODO: should get display for the window, not the current display
262 Widget widget
= XtWindowToWidget((Display
*) wxGetDisplay(),
264 wxWindow
* win
= NULL
;
266 // Find the first wxWindow that corresponds to this event window
267 while (widget
&& !(win
= wxGetWindowFromTable(widget
)))
268 widget
= XtParent(widget
);
273 wxKeyEvent
keyEvent(wxEVT_CHAR
);
274 wxTranslateKeyEvent(keyEvent
, win
, (Widget
) 0, event
);
276 // Now we have a wxKeyEvent and we have a wxWindow.
277 // Go up the hierarchy until we find a matching accelerator,
278 // or we get to the top.
281 if (win
->ProcessAccelerator(keyEvent
))
283 win
= win
->GetParent();
290 // bool wxApp::CheckForKeyDown(WXEvent* event) { wxFAIL; return false; }
292 bool CheckForKeyDown(XEvent
* event
)
294 if (event
->xany
.type
== KeyPress
)
296 Widget widget
= XtWindowToWidget((Display
*) wxGetDisplay(),
298 wxWindow
* win
= NULL
;
300 // Find the first wxWindow that corresponds to this event window
301 while (widget
&& !(win
= wxGetWindowFromTable(widget
)))
302 widget
= XtParent(widget
);
307 wxKeyEvent
keyEvent(wxEVT_KEY_DOWN
);
308 wxTranslateKeyEvent(keyEvent
, win
, (Widget
) 0, event
);
310 return win
->ProcessEvent( keyEvent
);
316 // bool wxApp::CheckForKeyUp(WXEvent* event) { wxFAIL; return false; }
318 bool CheckForKeyUp(XEvent
* event
)
320 if (event
->xany
.type
== KeyRelease
)
322 Widget widget
= XtWindowToWidget((Display
*) wxGetDisplay(),
324 wxWindow
* win
= NULL
;
326 // Find the first wxWindow that corresponds to this event window
327 while (widget
&& !(win
= wxGetWindowFromTable(widget
)))
328 widget
= XtParent(widget
);
333 wxKeyEvent
keyEvent(wxEVT_KEY_UP
);
334 wxTranslateKeyEvent(keyEvent
, win
, (Widget
) 0, event
);
336 return win
->ProcessEvent( keyEvent
);
342 // ----------------------------------------------------------------------------
343 // executes one main loop iteration (declared in include/wx/motif/private.h)
344 // ----------------------------------------------------------------------------
346 bool wxDoEventLoopIteration( wxEventLoop
& evtLoop
)
349 // leave the main loop to give other threads a chance to
350 // perform their GUI work
356 while ( !evtLoop
.Pending() && ::SendIdleMessage() )
359 if( !evtLoop
.Dispatch() )
365 // ----------------------------------------------------------------------------
366 // ::wxWakeUpIdle implementation
367 // ----------------------------------------------------------------------------
369 // As per Vadim's suggestion, we open a pipe, and XtAppAddInputSource it;
370 // writing a single byte to the pipe will cause wxEventLoop::Pending
371 // to return true, and wxEventLoop::Dispatch to dispatch an input handler
372 // that simply removes the byte(s), and to return, which will cause
373 // an idle event to be sent
375 // also wxEventLoop::Exit is implemented that way, so that exiting an
376 // event loop won't require an event being in the queue
378 #include "wx/module.h"
380 #include <sys/types.h>
381 #include <sys/time.h>
384 static XtInputId inputId
;
385 static int idleFds
[2] = { -1, -1 };
387 class wxIdlePipeModule
: public wxModule
390 wxIdlePipeModule() {};
392 virtual bool OnInit()
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
;
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()
438 // check if wxWakeUpIdle has already been called
440 struct timeval timeout
;
446 FD_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 );
460 bool wxAddIdleCallback()
462 // install input handler for wxWakeUpIdle
463 inputId
= XtAppAddInput( (XtAppContext
) wxTheApp
->GetAppContext(),
465 (XtPointer
)XtInputReadMask
,