]> git.saurik.com Git - wxWidgets.git/blob - src/x11/evtloop.cpp
More changes for better redraw flow under X11.
[wxWidgets.git] / src / x11 / evtloop.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: x11/evtloop.cpp
3 // Purpose: implements wxEventLoop for X11
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 01.06.01
7 // RCS-ID: $Id$
8 // Copyright: (c) 2002 Julian Smart
9 // License: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "evtloop.h"
22 #endif
23
24 #include "wx/window.h"
25 #include "wx/app.h"
26 #include "wx/evtloop.h"
27 #include "wx/tooltip.h"
28 #if wxUSE_THREADS
29 #include "wx/thread.h"
30 #endif
31 #include "wx/timer.h"
32 #include "wx/x11/private.h"
33 #include "X11/Xlib.h"
34
35 #include <sys/time.h>
36 #include <unistd.h>
37
38 // ----------------------------------------------------------------------------
39 // wxEventLoopImpl
40 // ----------------------------------------------------------------------------
41
42 class WXDLLEXPORT wxEventLoopImpl
43 {
44 public:
45 // ctor
46 wxEventLoopImpl() { SetExitCode(0); m_keepGoing = FALSE; }
47
48 // process an XEvent, return TRUE if it was processed
49 bool ProcessEvent(XEvent* event);
50
51 // generate an idle message, return TRUE if more idle time requested
52 bool SendIdleEvent();
53
54 // set/get the exit code
55 void SetExitCode(int exitcode) { m_exitcode = exitcode; }
56 int GetExitCode() const { return m_exitcode; }
57
58 public:
59 // preprocess an event, return TRUE if processed (i.e. no further
60 // dispatching required)
61 bool PreProcessEvent(XEvent* event);
62
63 // the exit code of the event loop
64 int m_exitcode;
65
66 bool m_keepGoing;
67 };
68
69 // ============================================================================
70 // wxEventLoopImpl implementation
71 // ============================================================================
72
73 // ----------------------------------------------------------------------------
74 // wxEventLoopImpl message processing
75 // ----------------------------------------------------------------------------
76
77 bool wxEventLoopImpl::ProcessEvent(XEvent *event)
78 {
79 // give us the chance to preprocess the message first
80 if ( PreProcessEvent(event) )
81 return TRUE;
82
83 // if it wasn't done, dispatch it to the corresponding window
84 if (wxTheApp)
85 return wxTheApp->ProcessXEvent((WXEvent*) event);
86
87 return FALSE;
88 }
89
90 bool wxEventLoopImpl::PreProcessEvent(XEvent *event)
91 {
92 // TODO
93 #if 0
94 HWND hWnd = msg->hwnd;
95 wxWindow *wndThis = wxGetWindowFromHWND((WXHWND)hWnd);
96
97
98 // try translations first; find the youngest window with a translation
99 // table.
100 wxWindow *wnd;
101 for ( wnd = wndThis; wnd; wnd = wnd->GetParent() )
102 {
103 if ( wnd->MSWTranslateMessage((WXMSG *)msg) )
104 return TRUE;
105 }
106
107 // Anyone for a non-translation message? Try youngest descendants first.
108 for ( wnd = wndThis; wnd; wnd = wnd->GetParent() )
109 {
110 if ( wnd->MSWProcessMessage((WXMSG *)msg) )
111 return TRUE;
112 }
113 #endif
114
115 return FALSE;
116 }
117
118 // ----------------------------------------------------------------------------
119 // wxEventLoopImpl idle event processing
120 // ----------------------------------------------------------------------------
121
122 bool wxEventLoopImpl::SendIdleEvent()
123 {
124 wxIdleEvent event;
125 event.SetEventObject(wxTheApp);
126
127 return wxTheApp->ProcessEvent(event) && event.MoreRequested();
128 }
129
130 // ============================================================================
131 // wxEventLoop implementation
132 // ============================================================================
133
134 wxEventLoop *wxEventLoop::ms_activeLoop = NULL;
135
136 // ----------------------------------------------------------------------------
137 // wxEventLoop running and exiting
138 // ----------------------------------------------------------------------------
139
140 wxEventLoop::~wxEventLoop()
141 {
142 wxASSERT_MSG( !m_impl, _T("should have been deleted in Run()") );
143 }
144
145 bool wxEventLoop::IsRunning() const
146 {
147 return m_impl != NULL;
148 }
149
150 int wxEventLoop::Run()
151 {
152 // event loops are not recursive, you need to create another loop!
153 wxCHECK_MSG( !IsRunning(), -1, _T("can't reenter a message loop") );
154
155 m_impl = new wxEventLoopImpl;
156
157 wxEventLoop *oldLoop = ms_activeLoop;
158 ms_activeLoop = this;
159
160 m_impl->m_keepGoing = TRUE;
161 while ( m_impl->m_keepGoing )
162 {
163 #if 0 // wxUSE_THREADS
164 wxMutexGuiLeaveOrEnter();
165 #endif // wxUSE_THREADS
166
167 // generate and process idle events for as long as we don't have
168 // anything else to do
169 while ( ! Pending() )
170 {
171 #if wxUSE_TIMER
172 wxTimer::NotifyTimers(); // TODO: is this the correct place for it?
173 #endif
174 if (!m_impl->SendIdleEvent())
175 {
176 #if wxUSE_THREADS
177 // leave the main loop to give other threads a chance to
178 // perform their GUI work
179 wxMutexGuiLeave();
180 wxUsleep(20);
181 wxMutexGuiEnter();
182 #endif
183 // Break out of while loop
184 break;
185 }
186 }
187
188 // a message came or no more idle processing to do, sit in Dispatch()
189 // waiting for the next message
190 if ( !Dispatch() )
191 {
192 break;
193 }
194 }
195
196 int exitcode = m_impl->GetExitCode();
197 delete m_impl;
198 m_impl = NULL;
199
200 ms_activeLoop = oldLoop;
201
202 return exitcode;
203 }
204
205 void wxEventLoop::Exit(int rc)
206 {
207 wxCHECK_RET( IsRunning(), _T("can't call Exit() if not running") );
208
209 m_impl->SetExitCode(rc);
210 m_impl->m_keepGoing = FALSE;
211 }
212
213 // ----------------------------------------------------------------------------
214 // wxEventLoop message processing dispatching
215 // ----------------------------------------------------------------------------
216
217 bool wxEventLoop::Pending() const
218 {
219 XFlush((Display*) wxGetDisplay());
220 return (XPending((Display*) wxGetDisplay()) > 0);
221 }
222
223 bool wxEventLoop::Dispatch()
224 {
225 XEvent event;
226
227 // TODO allowing for threads, as per e.g. wxMSW
228
229 #if 0
230 XNextEvent((Display*) wxGetDisplay(), & event);
231 #endif
232
233 // This now waits until either an X event is received,
234 // or the select times out. So we should now process
235 // wxTimers in a reasonably timely fashion. However it
236 // does also mean that idle processing will happen more
237 // often, so we should probably limit idle processing to
238 // not be repeated more than every N milliseconds.
239
240 if (XPending((Display*) wxGetDisplay()) == 0)
241 {
242 #if wxUSE_NANOX
243 GR_TIMEOUT timeout = 10; // Milliseconds
244 // Wait for next event, or timeout
245 GrGetNextEventTimeout(& event, timeout);
246
247 // Fall through to ProcessEvent.
248 // we'll assume that ProcessEvent will just ignore
249 // the event if there was a timeout and no event.
250
251 #else
252 struct timeval tv;
253 tv.tv_sec=0;
254 tv.tv_usec=10000; // TODO make this configurable
255 int fd = ConnectionNumber((Display*) wxGetDisplay());
256 fd_set readset;
257 FD_ZERO(&readset);
258 FD_SET(fd, &readset);
259 if (select(fd+1, &readset, NULL, NULL, & tv) == 0)
260 {
261 // Timed out, so no event to process
262 return TRUE;
263 }
264 else
265 {
266 // An event was pending, so get it
267 XNextEvent((Display*) wxGetDisplay(), & event);
268 }
269 #endif
270 } else
271 {
272 XNextEvent((Display*) wxGetDisplay(), & event);
273 }
274
275 (void) m_impl->ProcessEvent(& event);
276 return TRUE;
277 }
278