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"
24 #define XtParent XTPARENT
25 #define XtDisplay XTDISPLAY
31 #include "wx/window.h"
32 #include "wx/module.h"
35 #include "wx/evtloop.h"
38 #pragma message disable nosimpint
43 #pragma message enable nosimpint
46 #include "wx/unix/private.h"
47 #include "wx/motif/private.h"
49 #ifdef HAVE_SYS_SELECT_H
50 # include <sys/select.h>
53 static bool CheckForKeyUp(XEvent
* event
);
54 static bool CheckForKeyDown(XEvent
* event
);
55 static bool CheckForAccelerator(XEvent
* event
);
56 static void ProcessXEvent(XEvent
* event
);
57 static void wxBreakDispatch();
59 // ----------------------------------------------------------------------------
61 // ----------------------------------------------------------------------------
63 class WXDLLEXPORT wxEventLoopImpl
67 wxEventLoopImpl() { SetExitCode(0); }
69 // set/get the exit code
70 void SetExitCode(int exitcode
) { m_exitcode
= exitcode
; }
71 int GetExitCode() const { return m_exitcode
; }
73 bool SendIdleMessage();
74 bool GetKeepGoing() const { return m_keepGoing
; }
75 void SetKeepGoing(bool keepGoing
) { m_keepGoing
= keepGoing
; }
77 // the exit code of the event loop
82 // ----------------------------------------------------------------------------
83 // wxEventLoopImpl idle event processing
84 // ----------------------------------------------------------------------------
86 static bool SendIdleMessage()
88 return wxTheApp
->ProcessIdle();
91 bool wxEventLoopImpl::SendIdleMessage()
93 return ::SendIdleMessage();
96 // ============================================================================
97 // wxEventLoop implementation
98 // ============================================================================
100 // ----------------------------------------------------------------------------
101 // wxEventLoop running and exiting
102 // ----------------------------------------------------------------------------
104 wxEventLoop::~wxEventLoop()
106 wxASSERT_MSG( !m_impl
, _T("should have been deleted in Run()") );
109 int wxEventLoop::Run()
111 // event loops are not recursive, you need to create another loop!
112 wxCHECK_MSG( !IsRunning(), -1, _T("can't reenter a message loop") );
114 wxEventLoopActivator
activate(this);
116 m_impl
= new wxEventLoopImpl
;
117 m_impl
->SetKeepGoing( true );
121 if( !wxDoEventLoopIteration( *this ) )
127 int exitcode
= m_impl
->GetExitCode();
134 void wxEventLoop::Exit(int rc
)
136 wxCHECK_RET( IsRunning(), _T("can't call Exit() if not running") );
138 m_impl
->SetExitCode(rc
);
139 m_impl
->SetKeepGoing( false );
144 // ----------------------------------------------------------------------------
145 // wxEventLoop message processing dispatching
146 // ----------------------------------------------------------------------------
148 bool wxEventLoop::Pending() const
150 return XtAppPending( (XtAppContext
)wxTheApp
->GetAppContext() ) != 0;
153 bool wxEventLoop::Dispatch()
156 XtAppContext context
= (XtAppContext
)wxTheApp
->GetAppContext();
158 if( XtAppPeekEvent( context
, &event
) != 0 )
160 XtAppNextEvent( context
, &event
);
161 ProcessXEvent( &event
);
165 XtAppProcessEvent( context
, XtIMTimer
| XtIMAlternateInput
172 return m_impl
? m_impl
->GetKeepGoing() : true;
175 // ----------------------------------------------------------------------------
176 // Static functions (originally in app.cpp)
177 // ----------------------------------------------------------------------------
179 void ProcessXEvent(XEvent
* event
)
181 if (event
->type
== KeyPress
)
183 if (CheckForAccelerator(event
))
185 // Do nothing! We intercepted and processed the event as an
189 // It seemed before that this hack was redundant and
190 // key down events were being generated by wxCanvasInputEvent.
191 // But no longer - why ???
193 else if (CheckForKeyDown(event
))
195 // We intercepted and processed the key down event
200 XtDispatchEvent(event
);
204 else if (event
->type
== KeyRelease
)
206 // TODO: work out why we still need this ! -michael
208 if (::CheckForKeyUp(event
))
210 // We intercepted and processed the key up event
215 XtDispatchEvent(event
);
219 else if (event
->type
== PropertyNotify
)
221 wxTheApp
->HandlePropertyChange(event
);
224 else if (event
->type
== ResizeRequest
)
226 /* Terry Gitnick <terryg@scientech.com> - 1/21/98
227 * If resize event, don't resize until the last resize event for this
228 * window is recieved. Prevents flicker as windows are resized.
231 Display
*disp
= event
->xany
.display
;
232 Window win
= event
->xany
.window
;
237 while( XCheckTypedWindowEvent (disp
, win
, ResizeRequest
, &report
));
239 // TODO: when implementing refresh optimization, we can use
240 // XtAddExposureToRegion to expand the window's paint region.
242 XtDispatchEvent(event
);
246 XtDispatchEvent(event
);
250 // Returns true if an accelerator has been processed
251 bool CheckForAccelerator(XEvent
* event
)
253 if (event
->xany
.type
== KeyPress
)
255 // Find a wxWindow for this window
256 // TODO: should get display for the window, not the current display
257 Widget widget
= XtWindowToWidget(event
->xany
.display
,
259 wxWindow
* win
= NULL
;
261 // Find the first wxWindow that corresponds to this event window
262 while (widget
&& ((win
= wxGetWindowFromTable(widget
))!=NULL
))
263 widget
= XtParent(widget
);
268 wxKeyEvent
keyEvent(wxEVT_CHAR
);
269 wxTranslateKeyEvent(keyEvent
, win
, (Widget
) 0, event
);
271 // Now we have a wxKeyEvent and we have a wxWindow.
272 // Go up the hierarchy until we find a matching accelerator,
273 // or we get to the top.
276 if (win
->ProcessAccelerator(keyEvent
))
278 win
= win
->GetParent();
285 // bool wxApp::CheckForKeyDown(WXEvent* event) { wxFAIL; return false; }
287 bool CheckForKeyDown(XEvent
* event
)
289 if (event
->xany
.type
== KeyPress
)
291 Widget widget
= XtWindowToWidget(event
->xany
.display
,
293 wxWindow
* win
= NULL
;
295 // Find the first wxWindow that corresponds to this event window
296 while (widget
&& ((win
= wxGetWindowFromTable(widget
))!=NULL
))
297 widget
= XtParent(widget
);
302 wxKeyEvent
keyEvent(wxEVT_KEY_DOWN
);
303 wxTranslateKeyEvent(keyEvent
, win
, (Widget
) 0, event
);
305 return win
->GetEventHandler()->ProcessEvent( keyEvent
);
311 // bool wxApp::CheckForKeyUp(WXEvent* event) { wxFAIL; return false; }
313 bool CheckForKeyUp(XEvent
* event
)
315 if (event
->xany
.type
== KeyRelease
)
317 Widget widget
= XtWindowToWidget(event
->xany
.display
,
319 wxWindow
* win
= NULL
;
321 // Find the first wxWindow that corresponds to this event window
322 while (widget
&& ((win
= wxGetWindowFromTable(widget
))!=NULL
))
323 widget
= XtParent(widget
);
328 wxKeyEvent
keyEvent(wxEVT_KEY_UP
);
329 wxTranslateKeyEvent(keyEvent
, win
, (Widget
) 0, event
);
331 return win
->GetEventHandler()->ProcessEvent( keyEvent
);
337 // ----------------------------------------------------------------------------
338 // executes one main loop iteration (declared in include/wx/motif/private.h)
339 // ----------------------------------------------------------------------------
341 bool wxDoEventLoopIteration( wxEventLoop
& evtLoop
)
343 bool moreRequested
, pendingEvents
;
347 pendingEvents
= evtLoop
.Pending();
348 if( pendingEvents
) break;
349 moreRequested
= ::SendIdleMessage();
350 if( !moreRequested
) break;
354 if( !pendingEvents
&& !moreRequested
)
356 // leave the main loop to give other threads a chance to
357 // perform their GUI work
364 if( !evtLoop
.Dispatch() )
370 // ----------------------------------------------------------------------------
371 // ::wxWakeUpIdle implementation
372 // ----------------------------------------------------------------------------
374 // As per Vadim's suggestion, we open a pipe, and XtAppAddInputSource it;
375 // writing a single byte to the pipe will cause wxEventLoop::Pending
376 // to return true, and wxEventLoop::Dispatch to dispatch an input handler
377 // that simply removes the byte(s), and to return, which will cause
378 // an idle event to be sent
380 // also wxEventLoop::Exit is implemented that way, so that exiting an
381 // event loop won't require an event being in the queue
383 #include <sys/types.h>
384 #include <sys/time.h>
387 static int idleFds
[2] = { -1, -1 };
389 class wxIdlePipeModule
: public wxModule
392 wxIdlePipeModule() {};
394 virtual bool OnInit()
396 // Must be done before modules are initialized
398 if( pipe(idleFds
) != 0 )
404 virtual void OnExit()
410 DECLARE_DYNAMIC_CLASS(wxIdlePipeModule
)
413 IMPLEMENT_DYNAMIC_CLASS(wxIdlePipeModule
, wxModule
)
415 static void wxInputCallback( XtPointer
, int* fd
, XtInputId
* )
419 // wxWakeUpIdle may have been called more than once
423 struct timeval timeout
;
429 wxFD_SET( *fd
, &in
);
431 if( select( *fd
+ 1, &in
, NULL
, NULL
, &timeout
) <= 0 )
433 if( read( *fd
, buffer
, sizeof(buffer
) - 1 ) != sizeof(buffer
) - 1 )
438 static void wxBreakDispatch()
440 char dummy
= 0; // for valgrind
442 // check if wxWakeUpIdle has already been called
444 struct timeval timeout
;
450 wxFD_SET( idleFds
[0], &in
);
452 if( select( idleFds
[0] + 1, &in
, NULL
, NULL
, &timeout
) > 0 )
455 // write a single byte
456 write( idleFds
[1], &dummy
, 1 );
459 void wxApp::WakeUpIdle()
466 if( pipe(idleFds
) != 0 )
471 bool wxAddIdleCallback()
473 if (!wxInitIdleFds())
476 // install input handler for wxWakeUpIdle
477 XtAppAddInput((XtAppContext
) wxTheApp
->GetAppContext(),
479 (XtPointer
)XtInputReadMask
,