]> git.saurik.com Git - wxWidgets.git/blame - src/x11/evtloop.cpp
More changes for better redraw flow under X11.
[wxWidgets.git] / src / x11 / evtloop.cpp
CommitLineData
1b0fb34b
JS
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"
7266b672
JS
28#if wxUSE_THREADS
29#include "wx/thread.h"
30#endif
b513212d 31#include "wx/timer.h"
1b0fb34b
JS
32#include "wx/x11/private.h"
33#include "X11/Xlib.h"
34
1016f0de
JS
35#include <sys/time.h>
36#include <unistd.h>
37
1b0fb34b
JS
38// ----------------------------------------------------------------------------
39// wxEventLoopImpl
40// ----------------------------------------------------------------------------
41
42class WXDLLEXPORT wxEventLoopImpl
43{
44public:
45 // ctor
46 wxEventLoopImpl() { SetExitCode(0); m_keepGoing = FALSE; }
47
086fd560
JS
48 // process an XEvent, return TRUE if it was processed
49 bool ProcessEvent(XEvent* event);
1b0fb34b
JS
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
58public:
59 // preprocess an event, return TRUE if processed (i.e. no further
60 // dispatching required)
7266b672 61 bool PreProcessEvent(XEvent* event);
1b0fb34b
JS
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
086fd560 77bool wxEventLoopImpl::ProcessEvent(XEvent *event)
1b0fb34b
JS
78{
79 // give us the chance to preprocess the message first
086fd560
JS
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;
1b0fb34b
JS
88}
89
90bool 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
122bool 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
134wxEventLoop *wxEventLoop::ms_activeLoop = NULL;
135
136// ----------------------------------------------------------------------------
137// wxEventLoop running and exiting
138// ----------------------------------------------------------------------------
139
140wxEventLoop::~wxEventLoop()
141{
142 wxASSERT_MSG( !m_impl, _T("should have been deleted in Run()") );
143}
144
145bool wxEventLoop::IsRunning() const
146{
147 return m_impl != NULL;
148}
149
150int 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 {
7266b672
JS
163#if 0 // wxUSE_THREADS
164 wxMutexGuiLeaveOrEnter();
1b0fb34b
JS
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 {
b555c37c 171#if wxUSE_TIMER
b513212d 172 wxTimer::NotifyTimers(); // TODO: is this the correct place for it?
b555c37c 173#endif
1b0fb34b
JS
174 if (!m_impl->SendIdleEvent())
175 {
7ded318b 176#if wxUSE_THREADS
1b0fb34b
JS
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
205void 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
217bool wxEventLoop::Pending() const
218{
7266b672
JS
219 XFlush((Display*) wxGetDisplay());
220 return (XPending((Display*) wxGetDisplay()) > 0);
1b0fb34b
JS
221}
222
223bool wxEventLoop::Dispatch()
224{
225 XEvent event;
226
227 // TODO allowing for threads, as per e.g. wxMSW
228
1016f0de 229#if 0
7266b672 230 XNextEvent((Display*) wxGetDisplay(), & event);
1016f0de
JS
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 {
868741e9
JS
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
1016f0de
JS
252 struct timeval tv;
253 tv.tv_sec=0;
254 tv.tv_usec=10000; // TODO make this configurable
333f4ac0 255 int fd = ConnectionNumber((Display*) wxGetDisplay());
1016f0de
JS
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 }
868741e9 269#endif
1016f0de
JS
270 } else
271 {
272 XNextEvent((Display*) wxGetDisplay(), & event);
273 }
274
086fd560 275 (void) m_impl->ProcessEvent(& event);
1b0fb34b
JS
276 return TRUE;
277}
278