1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/x11/evtloop.cpp
3 // Purpose: implements wxEventLoop for X11
4 // Author: Julian Smart
7 // Copyright: (c) 2002 Julian Smart
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
11 // ============================================================================
13 // ============================================================================
15 // ----------------------------------------------------------------------------
17 // ----------------------------------------------------------------------------
19 // for compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
22 #include "wx/evtloop.h"
27 #include "wx/window.h"
28 #include "wx/module.h"
31 #include "wx/private/fdiodispatcher.h"
32 #include "wx/unix/private.h"
33 #include "wx/x11/private.h"
34 #include "wx/generic/private/timer.h"
37 #include "wx/thread.h"
44 #ifdef HAVE_SYS_SELECT_H
45 # include <sys/select.h>
48 // ----------------------------------------------------------------------------
50 // ----------------------------------------------------------------------------
52 class WXDLLEXPORT wxEventLoopImpl
56 wxEventLoopImpl() { SetExitCode(0); m_keepGoing
= false; }
58 // process an XEvent, return true if it was processed
59 bool ProcessEvent(XEvent
* event
);
61 // generate an idle message, return true if more idle time requested
64 // set/get the exit code
65 void SetExitCode(int exitcode
) { m_exitcode
= exitcode
; }
66 int GetExitCode() const { return m_exitcode
; }
69 // preprocess an event, return true if processed (i.e. no further
70 // dispatching required)
71 bool PreProcessEvent(XEvent
* event
);
73 // the exit code of the event loop
79 // ============================================================================
80 // wxEventLoopImpl implementation
81 // ============================================================================
83 // ----------------------------------------------------------------------------
84 // wxEventLoopImpl message processing
85 // ----------------------------------------------------------------------------
87 bool wxEventLoopImpl::ProcessEvent(XEvent
*event
)
89 // give us the chance to preprocess the message first
90 if ( PreProcessEvent(event
) )
93 // if it wasn't done, dispatch it to the corresponding window
95 return wxTheApp
->ProcessXEvent((WXEvent
*) event
);
100 bool wxEventLoopImpl::PreProcessEvent(XEvent
*WXUNUSED(event
))
105 // ----------------------------------------------------------------------------
106 // wxEventLoopImpl idle event processing
107 // ----------------------------------------------------------------------------
109 bool wxEventLoopImpl::SendIdleEvent()
111 return wxTheApp
->ProcessIdle();
114 // ============================================================================
115 // wxEventLoop implementation
116 // ============================================================================
118 // ----------------------------------------------------------------------------
119 // wxEventLoop running and exiting
120 // ----------------------------------------------------------------------------
122 wxGUIEventLoop::~wxGUIEventLoop()
124 wxASSERT_MSG( !m_impl
, wxT("should have been deleted in Run()") );
127 int wxGUIEventLoop::DoRun()
129 m_impl
= new wxEventLoopImpl
;
131 m_impl
->m_keepGoing
= true;
132 while ( m_impl
->m_keepGoing
)
134 // generate and process idle events for as long as we don't have
135 // anything else to do
136 while ( ! Pending() )
139 wxGenericTimerImpl::NotifyTimers(); // TODO: is this the correct place for it?
141 if (!m_impl
->SendIdleEvent())
143 // Break out of while loop
148 // a message came or no more idle processing to do, sit in Dispatch()
149 // waiting for the next message
158 int exitcode
= m_impl
->GetExitCode();
164 void wxGUIEventLoop::ScheduleExit(int rc
)
168 m_impl
->SetExitCode(rc
);
169 m_impl
->m_keepGoing
= false;
173 // ----------------------------------------------------------------------------
174 // wxEventLoop message processing dispatching
175 // ----------------------------------------------------------------------------
177 bool wxGUIEventLoop::Pending() const
179 XFlush( wxGlobalDisplay() );
180 return (XPending( wxGlobalDisplay() ) > 0);
183 bool wxGUIEventLoop::Dispatch()
185 // see comment in wxEventLoopManual::ProcessEvents()
187 wxTheApp
->ProcessPendingEvents();
191 // TODO allowing for threads, as per e.g. wxMSW
193 // This now waits until either an X event is received,
194 // or the select times out. So we should now process
195 // wxTimers in a reasonably timely fashion. However it
196 // does also mean that idle processing will happen more
197 // often, so we should probably limit idle processing to
198 // not be repeated more than every N milliseconds.
200 if (XPending( wxGlobalDisplay() ) == 0)
203 GR_TIMEOUT timeout
= 10; // Milliseconds
204 // Wait for next event, or timeout
205 GrGetNextEventTimeout(& event
, timeout
);
207 // Fall through to ProcessEvent.
208 // we'll assume that ProcessEvent will just ignore
209 // the event if there was a timeout and no event.
214 tv
.tv_usec
=10000; // TODO make this configurable
215 int fd
= ConnectionNumber( wxGlobalDisplay() );
220 wxFD_ZERO(&writeset
);
221 wxFD_SET(fd
, &readset
);
223 if (select( fd
+1, &readset
, &writeset
, NULL
, &tv
) != 0)
225 // An X11 event was pending, get it
226 if (wxFD_ISSET( fd
, &readset
))
227 XNextEvent( wxGlobalDisplay(), &event
);
233 XNextEvent( wxGlobalDisplay(), &event
);
237 // handle any pending socket events:
238 wxFDIODispatcher::DispatchPending();
241 (void) m_impl
->ProcessEvent( &event
);
245 bool wxGUIEventLoop::YieldFor(long eventsToProcess
)
247 // Sometimes only 2 yields seem
248 // to do the trick, e.g. in the
251 for (i
= 0; i
< 2; i
++)
253 m_isInsideYield
= true;
254 m_eventsToProcessInsideYield
= eventsToProcess
;
256 // Call dispatch at least once so that sockets
258 wxTheApp
->Dispatch();
260 // TODO: implement event filtering using the eventsToProcess mask
261 while (wxTheApp
&& wxTheApp
->Pending())
262 wxTheApp
->Dispatch();
265 wxGenericTimerImpl::NotifyTimers();
269 m_isInsideYield
= false;