1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/motif/evtloop.cpp
3 // Purpose: implements wxEventLoop for Motif
4 // Author: Mattia Barbon
7 // Copyright: (c) 2002 Mattia Barbon
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
11 // ============================================================================
13 // ============================================================================
15 // ----------------------------------------------------------------------------
17 // ----------------------------------------------------------------------------
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
25 #include "wx/window.h"
26 #include "wx/module.h"
29 #include "wx/evtloop.h"
30 #include "wx/thread.h"
33 #pragma message disable nosimpint
38 #pragma message enable nosimpint
41 #include "wx/unix/private.h"
42 #include "wx/motif/private.h"
44 #ifdef HAVE_SYS_SELECT_H
45 # include <sys/select.h>
48 static bool CheckForKeyUp(XEvent
* event
);
49 static bool CheckForKeyDown(XEvent
* event
);
50 static bool CheckForAccelerator(XEvent
* event
);
51 static void ProcessXEvent(XEvent
* event
);
52 static void wxBreakDispatch();
54 // ----------------------------------------------------------------------------
56 // ----------------------------------------------------------------------------
58 class WXDLLEXPORT wxEventLoopImpl
62 wxEventLoopImpl() { SetExitCode(0); }
64 // set/get the exit code
65 void SetExitCode(int exitcode
) { m_exitcode
= exitcode
; }
66 int GetExitCode() const { return m_exitcode
; }
68 bool SendIdleMessage();
69 bool GetKeepGoing() const { return m_keepGoing
; }
70 void SetKeepGoing(bool keepGoing
) { m_keepGoing
= keepGoing
; }
72 // the exit code of the event loop
77 // ----------------------------------------------------------------------------
78 // wxEventLoopImpl idle event processing
79 // ----------------------------------------------------------------------------
81 static bool SendIdleMessage()
83 return wxTheApp
->ProcessIdle();
86 bool wxEventLoopImpl::SendIdleMessage()
88 return ::SendIdleMessage();
91 // ============================================================================
92 // wxEventLoop implementation
93 // ============================================================================
95 // ----------------------------------------------------------------------------
96 // wxEventLoop running and exiting
97 // ----------------------------------------------------------------------------
99 wxGUIEventLoop::~wxGUIEventLoop()
101 wxASSERT_MSG( !m_impl
, wxT("should have been deleted in Run()") );
104 int wxGUIEventLoop::DoRun()
106 m_impl
= new wxEventLoopImpl
;
107 m_impl
->SetKeepGoing( true );
111 if( !wxDoEventLoopIteration( *this ) )
117 int exitcode
= m_impl
->GetExitCode();
123 void wxGUIEventLoop::ScheduleExit(int rc
)
125 wxCHECK_RET( IsInsideRun(), wxT("can't call ScheduleExit() if not started") );
127 m_impl
->SetExitCode(rc
);
128 m_impl
->SetKeepGoing( false );
133 bool wxGUIEventLoop::YieldFor(long eventsToProcess
)
135 m_isInsideYield
= true;
136 m_eventsToProcessInsideYield
= eventsToProcess
;
138 while (wxTheApp
&& wxTheApp
->Pending())
139 // TODO: implement event filtering using the eventsToProcess mask
140 wxTheApp
->Dispatch();
142 m_isInsideYield
= false;
147 // ----------------------------------------------------------------------------
148 // wxEventLoop message processing dispatching
149 // ----------------------------------------------------------------------------
151 bool wxGUIEventLoop::Pending() const
153 return XtAppPending( (XtAppContext
)wxTheApp
->GetAppContext() ) != 0;
156 bool wxGUIEventLoop::Dispatch()
159 XtAppContext context
= (XtAppContext
)wxTheApp
->GetAppContext();
161 if( XtAppPeekEvent( context
, &event
) != 0 )
163 XtAppNextEvent( context
, &event
);
164 ProcessXEvent( &event
);
168 XtAppProcessEvent( context
, XtIMTimer
| XtIMAlternateInput
175 return m_impl
? m_impl
->GetKeepGoing() : true;
178 // ----------------------------------------------------------------------------
179 // Static functions (originally in app.cpp)
180 // ----------------------------------------------------------------------------
182 void ProcessXEvent(XEvent
* event
)
184 if (event
->type
== KeyPress
)
186 if (CheckForAccelerator(event
))
188 // Do nothing! We intercepted and processed the event as an
192 // It seemed before that this hack was redundant and
193 // key down events were being generated by wxCanvasInputEvent.
194 // But no longer - why ???
196 else if (CheckForKeyDown(event
))
198 // We intercepted and processed the key down event
203 XtDispatchEvent(event
);
207 else if (event
->type
== KeyRelease
)
209 // TODO: work out why we still need this ! -michael
211 if (::CheckForKeyUp(event
))
213 // We intercepted and processed the key up event
218 XtDispatchEvent(event
);
222 else if (event
->type
== PropertyNotify
)
224 wxTheApp
->HandlePropertyChange(event
);
227 else if (event
->type
== ResizeRequest
)
229 /* Terry Gitnick <terryg@scientech.com> - 1/21/98
230 * If resize event, don't resize until the last resize event for this
231 * window is recieved. Prevents flicker as windows are resized.
234 Display
*disp
= event
->xany
.display
;
235 Window win
= event
->xany
.window
;
240 while( XCheckTypedWindowEvent (disp
, win
, ResizeRequest
, &report
));
242 // TODO: when implementing refresh optimization, we can use
243 // XtAddExposureToRegion to expand the window's paint region.
245 XtDispatchEvent(event
);
249 XtDispatchEvent(event
);
253 // Returns true if an accelerator has been processed
254 bool CheckForAccelerator(XEvent
* event
)
256 if (event
->xany
.type
== KeyPress
)
258 // Find a wxWindow for this window
259 // TODO: should get display for the window, not the current display
260 Widget widget
= XtWindowToWidget(event
->xany
.display
,
262 wxWindow
* win
= NULL
;
264 // Find the first wxWindow that corresponds to this event window
265 while (widget
&& ((win
= wxGetWindowFromTable(widget
))!=NULL
))
266 widget
= XtParent(widget
);
271 wxKeyEvent
keyEvent(wxEVT_CHAR
);
272 wxTranslateKeyEvent(keyEvent
, win
, (Widget
) 0, event
);
274 // Now we have a wxKeyEvent and we have a wxWindow.
275 // Go up the hierarchy until we find a matching accelerator,
276 // or we get to the top.
279 if (win
->ProcessAccelerator(keyEvent
))
281 win
= win
->GetParent();
288 // bool wxApp::CheckForKeyDown(WXEvent* event) { wxFAIL; return false; }
290 bool CheckForKeyDown(XEvent
* event
)
292 if (event
->xany
.type
== KeyPress
)
294 Widget widget
= XtWindowToWidget(event
->xany
.display
,
296 wxWindow
* win
= NULL
;
298 // Find the first wxWindow that corresponds to this event window
299 while (widget
&& ((win
= wxGetWindowFromTable(widget
))!=NULL
))
300 widget
= XtParent(widget
);
305 wxKeyEvent
keyEvent(wxEVT_KEY_DOWN
);
306 wxTranslateKeyEvent(keyEvent
, win
, (Widget
) 0, event
);
308 return win
->HandleWindowEvent( keyEvent
);
314 // bool wxApp::CheckForKeyUp(WXEvent* event) { wxFAIL; return false; }
316 bool CheckForKeyUp(XEvent
* event
)
318 if (event
->xany
.type
== KeyRelease
)
320 Widget widget
= XtWindowToWidget(event
->xany
.display
,
322 wxWindow
* win
= NULL
;
324 // Find the first wxWindow that corresponds to this event window
325 while (widget
&& ((win
= wxGetWindowFromTable(widget
))!=NULL
))
326 widget
= XtParent(widget
);
331 wxKeyEvent
keyEvent(wxEVT_KEY_UP
);
332 wxTranslateKeyEvent(keyEvent
, win
, (Widget
) 0, event
);
334 return win
->HandleWindowEvent( keyEvent
);
340 // ----------------------------------------------------------------------------
341 // executes one main loop iteration (declared in include/wx/motif/private.h)
342 // ----------------------------------------------------------------------------
344 bool wxDoEventLoopIteration( wxGUIEventLoop
& evtLoop
)
346 bool moreRequested
, pendingEvents
;
350 pendingEvents
= evtLoop
.Pending();
351 if( pendingEvents
) break;
352 moreRequested
= ::SendIdleMessage();
353 if( !moreRequested
) break;
357 if( !pendingEvents
&& !moreRequested
)
359 // leave the main loop to give other threads a chance to
360 // perform their GUI work
367 if( !evtLoop
.Dispatch() )
373 // ----------------------------------------------------------------------------
374 // ::wxWakeUpIdle implementation
375 // ----------------------------------------------------------------------------
377 // As per Vadim's suggestion, we open a pipe, and XtAppAddInputSource it;
378 // writing a single byte to the pipe will cause wxEventLoop::Pending
379 // to return true, and wxEventLoop::Dispatch to dispatch an input handler
380 // that simply removes the byte(s), and to return, which will cause
381 // an idle event to be sent
383 // also wxEventLoop::Exit is implemented that way, so that exiting an
384 // event loop won't require an event being in the queue
386 #include <sys/types.h>
387 #include <sys/time.h>
390 static int idleFds
[2] = { -1, -1 };
392 class wxIdlePipeModule
: public wxModule
395 wxIdlePipeModule() {};
397 virtual bool OnInit()
399 // Must be done before modules are initialized
401 if( pipe(idleFds
) != 0 )
407 virtual void OnExit()
413 DECLARE_DYNAMIC_CLASS(wxIdlePipeModule
)
416 IMPLEMENT_DYNAMIC_CLASS(wxIdlePipeModule
, wxModule
)
418 static void wxInputCallback( XtPointer
, int* fd
, XtInputId
* )
422 // wxWakeUpIdle may have been called more than once
426 struct timeval timeout
;
432 wxFD_SET( *fd
, &in
);
434 if( select( *fd
+ 1, &in
, NULL
, NULL
, &timeout
) <= 0 )
436 if( read( *fd
, buffer
, sizeof(buffer
) - 1 ) != sizeof(buffer
) - 1 )
441 static void wxBreakDispatch()
443 char dummy
= 0; // for valgrind
445 // check if wxWakeUpIdle has already been called
447 struct timeval timeout
;
453 wxFD_SET( idleFds
[0], &in
);
455 if( select( idleFds
[0] + 1, &in
, NULL
, NULL
, &timeout
) > 0 )
458 // write a single byte
459 write( idleFds
[1], &dummy
, 1 );
462 void wxApp::WakeUpIdle()
469 if( pipe(idleFds
) != 0 )
474 bool wxAddIdleCallback()
476 if (!wxInitIdleFds())
479 // install input handler for wxWakeUpIdle
480 XtAppAddInput((XtAppContext
) wxTheApp
->GetAppContext(),
482 (XtPointer
)XtInputReadMask
,