]> git.saurik.com Git - wxWidgets.git/blob - src/x11/evtloop.cpp
Support using GetTextExtent() with empty string to get descent in wxOSX.
[wxWidgets.git] / src / x11 / evtloop.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/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 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // for compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #include "wx/evtloop.h"
24
25 #ifndef WX_PRECOMP
26 #include "wx/hash.h"
27 #include "wx/app.h"
28 #include "wx/window.h"
29 #include "wx/module.h"
30 #endif
31
32 #include "wx/private/fdiodispatcher.h"
33 #include "wx/unix/private.h"
34 #include "wx/x11/private.h"
35 #include "wx/generic/private/timer.h"
36
37 #if wxUSE_THREADS
38 #include "wx/thread.h"
39 #endif
40
41 #include <X11/Xlib.h>
42 #include <sys/time.h>
43 #include <unistd.h>
44
45 #ifdef HAVE_SYS_SELECT_H
46 # include <sys/select.h>
47 #endif
48
49 // ----------------------------------------------------------------------------
50 // wxEventLoopImpl
51 // ----------------------------------------------------------------------------
52
53 class WXDLLEXPORT wxEventLoopImpl
54 {
55 public:
56 // ctor
57 wxEventLoopImpl() { SetExitCode(0); m_keepGoing = false; }
58
59 // process an XEvent, return true if it was processed
60 bool ProcessEvent(XEvent* event);
61
62 // generate an idle message, return true if more idle time requested
63 bool SendIdleEvent();
64
65 // set/get the exit code
66 void SetExitCode(int exitcode) { m_exitcode = exitcode; }
67 int GetExitCode() const { return m_exitcode; }
68
69 public:
70 // preprocess an event, return true if processed (i.e. no further
71 // dispatching required)
72 bool PreProcessEvent(XEvent* event);
73
74 // the exit code of the event loop
75 int m_exitcode;
76
77 bool m_keepGoing;
78 };
79
80 // ============================================================================
81 // wxEventLoopImpl implementation
82 // ============================================================================
83
84 // ----------------------------------------------------------------------------
85 // wxEventLoopImpl message processing
86 // ----------------------------------------------------------------------------
87
88 bool wxEventLoopImpl::ProcessEvent(XEvent *event)
89 {
90 // give us the chance to preprocess the message first
91 if ( PreProcessEvent(event) )
92 return true;
93
94 // if it wasn't done, dispatch it to the corresponding window
95 if (wxTheApp)
96 return wxTheApp->ProcessXEvent((WXEvent*) event);
97
98 return false;
99 }
100
101 bool wxEventLoopImpl::PreProcessEvent(XEvent *WXUNUSED(event))
102 {
103 return false;
104 }
105
106 // ----------------------------------------------------------------------------
107 // wxEventLoopImpl idle event processing
108 // ----------------------------------------------------------------------------
109
110 bool wxEventLoopImpl::SendIdleEvent()
111 {
112 return wxTheApp->ProcessIdle();
113 }
114
115 // ============================================================================
116 // wxEventLoop implementation
117 // ============================================================================
118
119 // ----------------------------------------------------------------------------
120 // wxEventLoop running and exiting
121 // ----------------------------------------------------------------------------
122
123 wxGUIEventLoop::~wxGUIEventLoop()
124 {
125 wxASSERT_MSG( !m_impl, wxT("should have been deleted in Run()") );
126 }
127
128 int wxGUIEventLoop::DoRun()
129 {
130 m_impl = new wxEventLoopImpl;
131
132 m_impl->m_keepGoing = true;
133 while ( m_impl->m_keepGoing )
134 {
135 // generate and process idle events for as long as we don't have
136 // anything else to do
137 while ( ! Pending() )
138 {
139 #if wxUSE_TIMER
140 wxGenericTimerImpl::NotifyTimers(); // TODO: is this the correct place for it?
141 #endif
142 if (!m_impl->SendIdleEvent())
143 {
144 // Break out of while loop
145 break;
146 }
147 }
148
149 // a message came or no more idle processing to do, sit in Dispatch()
150 // waiting for the next message
151 if ( !Dispatch() )
152 {
153 break;
154 }
155 }
156
157 OnExit();
158
159 int exitcode = m_impl->GetExitCode();
160 wxDELETE(m_impl);
161
162 return exitcode;
163 }
164
165 void wxGUIEventLoop::ScheduleExit(int rc)
166 {
167 if ( m_impl )
168 {
169 m_impl->SetExitCode(rc);
170 m_impl->m_keepGoing = false;
171 }
172 }
173
174 // ----------------------------------------------------------------------------
175 // wxEventLoop message processing dispatching
176 // ----------------------------------------------------------------------------
177
178 bool wxGUIEventLoop::Pending() const
179 {
180 XFlush( wxGlobalDisplay() );
181 return (XPending( wxGlobalDisplay() ) > 0);
182 }
183
184 bool wxGUIEventLoop::Dispatch()
185 {
186 // see comment in wxEventLoopManual::ProcessEvents()
187 if ( wxTheApp )
188 wxTheApp->ProcessPendingEvents();
189
190 XEvent event;
191
192 // TODO allowing for threads, as per e.g. wxMSW
193
194 // This now waits until either an X event is received,
195 // or the select times out. So we should now process
196 // wxTimers in a reasonably timely fashion. However it
197 // does also mean that idle processing will happen more
198 // often, so we should probably limit idle processing to
199 // not be repeated more than every N milliseconds.
200
201 if (XPending( wxGlobalDisplay() ) == 0)
202 {
203 #if wxUSE_NANOX
204 GR_TIMEOUT timeout = 10; // Milliseconds
205 // Wait for next event, or timeout
206 GrGetNextEventTimeout(& event, timeout);
207
208 // Fall through to ProcessEvent.
209 // we'll assume that ProcessEvent will just ignore
210 // the event if there was a timeout and no event.
211
212 #else
213 struct timeval tv;
214 tv.tv_sec=0;
215 tv.tv_usec=10000; // TODO make this configurable
216 int fd = ConnectionNumber( wxGlobalDisplay() );
217
218 fd_set readset;
219 fd_set writeset;
220 wxFD_ZERO(&readset);
221 wxFD_ZERO(&writeset);
222 wxFD_SET(fd, &readset);
223
224 if (select( fd+1, &readset, &writeset, NULL, &tv ) != 0)
225 {
226 // An X11 event was pending, get it
227 if (wxFD_ISSET( fd, &readset ))
228 XNextEvent( wxGlobalDisplay(), &event );
229 }
230 #endif
231 }
232 else
233 {
234 XNextEvent( wxGlobalDisplay(), &event );
235 }
236
237 #if wxUSE_SOCKETS
238 // handle any pending socket events:
239 wxFDIODispatcher::DispatchPending();
240 #endif
241
242 (void) m_impl->ProcessEvent( &event );
243 return true;
244 }
245
246 bool wxGUIEventLoop::YieldFor(long eventsToProcess)
247 {
248 // Sometimes only 2 yields seem
249 // to do the trick, e.g. in the
250 // progress dialog
251 int i;
252 for (i = 0; i < 2; i++)
253 {
254 m_isInsideYield = true;
255 m_eventsToProcessInsideYield = eventsToProcess;
256
257 // Call dispatch at least once so that sockets
258 // can be tested
259 wxTheApp->Dispatch();
260
261 // TODO: implement event filtering using the eventsToProcess mask
262 while (wxTheApp && wxTheApp->Pending())
263 wxTheApp->Dispatch();
264
265 #if wxUSE_TIMER
266 wxGenericTimerImpl::NotifyTimers();
267 #endif
268 ProcessIdle();
269
270 m_isInsideYield = false;
271 }
272
273 return true;
274 }