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
);
171 XtAppProcessEvent( context
, XtIMTimer
|XtIMAlternateInput
|XtIMSignal
);
173 return m_impl
? m_impl
->GetKeepGoing() : true;
176 // ----------------------------------------------------------------------------
177 // Static functions (originally in app.cpp)
178 // ----------------------------------------------------------------------------
180 void ProcessXEvent(XEvent
* event
)
182 if (event
->type
== KeyPress
)
184 if (CheckForAccelerator(event
))
186 // Do nothing! We intercepted and processed the event as an
190 // It seemed before that this hack was redundant and
191 // key down events were being generated by wxCanvasInputEvent.
192 // But no longer - why ???
194 else if (CheckForKeyDown(event
))
196 // We intercepted and processed the key down event
201 XtDispatchEvent(event
);
205 else if (event
->type
== KeyRelease
)
207 // TODO: work out why we still need this ! -michael
209 if (::CheckForKeyUp(event
))
211 // We intercepted and processed the key up event
216 XtDispatchEvent(event
);
220 else if (event
->type
== PropertyNotify
)
222 wxTheApp
->HandlePropertyChange(event
);
225 else if (event
->type
== ResizeRequest
)
227 /* Terry Gitnick <terryg@scientech.com> - 1/21/98
228 * If resize event, don't resize until the last resize event for this
229 * window is recieved. Prevents flicker as windows are resized.
232 Display
*disp
= XtDisplay((Widget
) wxTheApp
->GetTopLevelWidget());
233 Window win
= event
->xany
.window
;
238 while( XCheckTypedWindowEvent (disp
, win
, ResizeRequest
, &report
));
240 // TODO: when implementing refresh optimization, we can use
241 // XtAddExposureToRegion to expand the window's paint region.
243 XtDispatchEvent(event
);
247 XtDispatchEvent(event
);
251 // Returns true if an accelerator has been processed
252 bool CheckForAccelerator(XEvent
* event
)
254 if (event
->xany
.type
== KeyPress
)
256 // Find a wxWindow for this window
257 // TODO: should get display for the window, not the current display
258 Widget widget
= XtWindowToWidget((Display
*) wxGetDisplay(),
260 wxWindow
* win
= NULL
;
262 // Find the first wxWindow that corresponds to this event window
263 while (widget
&& !(win
= wxGetWindowFromTable(widget
)))
264 widget
= XtParent(widget
);
269 wxKeyEvent
keyEvent(wxEVT_CHAR
);
270 wxTranslateKeyEvent(keyEvent
, win
, (Widget
) 0, event
);
272 // Now we have a wxKeyEvent and we have a wxWindow.
273 // Go up the hierarchy until we find a matching accelerator,
274 // or we get to the top.
277 if (win
->ProcessAccelerator(keyEvent
))
279 win
= win
->GetParent();
286 // bool wxApp::CheckForKeyDown(WXEvent* event) { wxFAIL; return false; }
288 bool CheckForKeyDown(XEvent
* event
)
290 if (event
->xany
.type
== KeyPress
)
292 Widget widget
= XtWindowToWidget((Display
*) wxGetDisplay(),
294 wxWindow
* win
= NULL
;
296 // Find the first wxWindow that corresponds to this event window
297 while (widget
&& !(win
= wxGetWindowFromTable(widget
)))
298 widget
= XtParent(widget
);
303 wxKeyEvent
keyEvent(wxEVT_KEY_DOWN
);
304 wxTranslateKeyEvent(keyEvent
, win
, (Widget
) 0, event
);
306 return win
->ProcessEvent( keyEvent
);
312 // bool wxApp::CheckForKeyUp(WXEvent* event) { wxFAIL; return false; }
314 bool CheckForKeyUp(XEvent
* event
)
316 if (event
->xany
.type
== KeyRelease
)
318 Widget widget
= XtWindowToWidget((Display
*) wxGetDisplay(),
320 wxWindow
* win
= NULL
;
322 // Find the first wxWindow that corresponds to this event window
323 while (widget
&& !(win
= wxGetWindowFromTable(widget
)))
324 widget
= XtParent(widget
);
329 wxKeyEvent
keyEvent(wxEVT_KEY_UP
);
330 wxTranslateKeyEvent(keyEvent
, win
, (Widget
) 0, event
);
332 return win
->ProcessEvent( keyEvent
);
338 // ----------------------------------------------------------------------------
339 // executes one main loop iteration (declared in include/wx/motif/private.h)
340 // ----------------------------------------------------------------------------
342 bool wxDoEventLoopIteration( wxEventLoop
& evtLoop
)
345 // leave the main loop to give other threads a chance to
346 // perform their GUI work
352 while ( !evtLoop
.Pending() && ::SendIdleMessage() )
355 if( !evtLoop
.Dispatch() )
361 // ----------------------------------------------------------------------------
362 // ::wxWakeUpIdle implementation
363 // ----------------------------------------------------------------------------
365 // As per Vadim's suggestion, we open a pipe, and XtAppAddInputSource it;
366 // writing a single byte to the pipe will cause wxEventLoop::Pending
367 // to return true, and wxEventLoop::Dispatch to dispatch an input handler
368 // that simply removes the byte(s), and to return, which will cause
369 // an idle event to be sent
371 // also wxEventLoop::Exit is implemented that way, so that exiting an
372 // event loop won't require an event being in the queue
374 #include "wx/module.h"
376 #include <sys/types.h>
377 #include <sys/time.h>
380 static XtInputId inputId
;
381 static int idleFds
[2] = { -1, -1 };
383 class wxIdlePipeModule
: public wxModule
386 wxIdlePipeModule() {};
388 virtual bool OnInit()
390 if( pipe(idleFds
) != 0 )
396 virtual void OnExit()
402 DECLARE_DYNAMIC_CLASS(wxIdlePipeModule
);
405 IMPLEMENT_DYNAMIC_CLASS(wxIdlePipeModule
, wxModule
);
407 static void wxInputCallback( XtPointer
, int* fd
, XtInputId
* )
411 // wxWakeUpIdle may have been called more than once
415 struct timeval timeout
;
423 if( select( *fd
+ 1, &in
, NULL
, NULL
, &timeout
) <= 0 )
425 if( read( *fd
, buffer
, sizeof(buffer
) - 1 ) != sizeof(buffer
) - 1 )
430 static void wxBreakDispatch()
434 // check if wxWakeUpIdle has already been called
436 struct timeval timeout
;
442 FD_SET( idleFds
[0], &in
);
444 if( select( idleFds
[0] + 1, &in
, NULL
, NULL
, &timeout
) > 0 )
447 // write a single byte
448 write( idleFds
[1], &dummy
, 1 );
456 bool wxAddIdleCallback()
458 // install input handler for wxWakeUpIdle
459 inputId
= XtAppAddInput( (XtAppContext
) wxTheApp
->GetAppContext(),
461 (XtPointer
)XtInputReadMask
,