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 licence
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
)
348 bool moreRequested
, pendingEvents
;
352 pendingEvents
= evtLoop
.Pending();
353 if( pendingEvents
) break;
354 moreRequested
= ::SendIdleMessage();
355 if( !moreRequested
) break;
359 if( !pendingEvents
&& !moreRequested
)
361 // leave the main loop to give other threads a chance to
362 // perform their GUI work
369 if( !evtLoop
.Dispatch() )
375 // ----------------------------------------------------------------------------
376 // ::wxWakeUpIdle implementation
377 // ----------------------------------------------------------------------------
379 // As per Vadim's suggestion, we open a pipe, and XtAppAddInputSource it;
380 // writing a single byte to the pipe will cause wxEventLoop::Pending
381 // to return true, and wxEventLoop::Dispatch to dispatch an input handler
382 // that simply removes the byte(s), and to return, which will cause
383 // an idle event to be sent
385 // also wxEventLoop::Exit is implemented that way, so that exiting an
386 // event loop won't require an event being in the queue
388 #include "wx/module.h"
390 #include <sys/types.h>
391 #include <sys/time.h>
394 static XtInputId inputId
;
395 static int idleFds
[2] = { -1, -1 };
397 class wxIdlePipeModule
: public wxModule
400 wxIdlePipeModule() {};
402 virtual bool OnInit()
404 if( pipe(idleFds
) != 0 )
410 virtual void OnExit()
416 DECLARE_DYNAMIC_CLASS(wxIdlePipeModule
);
419 IMPLEMENT_DYNAMIC_CLASS(wxIdlePipeModule
, wxModule
);
421 static void wxInputCallback( XtPointer
, int* fd
, XtInputId
* )
425 // wxWakeUpIdle may have been called more than once
429 struct timeval timeout
;
437 if( select( *fd
+ 1, &in
, NULL
, NULL
, &timeout
) <= 0 )
439 if( read( *fd
, buffer
, sizeof(buffer
) - 1 ) != sizeof(buffer
) - 1 )
444 static void wxBreakDispatch()
448 // check if wxWakeUpIdle has already been called
450 struct timeval timeout
;
456 FD_SET( idleFds
[0], &in
);
458 if( select( idleFds
[0] + 1, &in
, NULL
, NULL
, &timeout
) > 0 )
461 // write a single byte
462 write( idleFds
[1], &dummy
, 1 );
470 bool wxAddIdleCallback()
472 // install input handler for wxWakeUpIdle
473 inputId
= XtAppAddInput( (XtAppContext
) wxTheApp
->GetAppContext(),
475 (XtPointer
)XtInputReadMask
,