]> git.saurik.com Git - wxWidgets.git/blame - src/x11/evtloop.cpp
correction to last commit: don't test unsetenv() return value, it's void under Darwin
[wxWidgets.git] / src / x11 / evtloop.cpp
CommitLineData
1b0fb34b 1///////////////////////////////////////////////////////////////////////////////
32d4c30a 2// Name: src/x11/evtloop.cpp
1b0fb34b
JS
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
65571936 9// License: wxWindows licence
1b0fb34b
JS
10///////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
32d4c30a
WS
20// for compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
670f9935
WS
23#include "wx/evtloop.h"
24
32d4c30a
WS
25#ifndef WX_PRECOMP
26 #include "wx/hash.h"
670f9935 27 #include "wx/app.h"
cdccdfab 28 #include "wx/window.h"
02761f6c 29 #include "wx/module.h"
32d4c30a
WS
30#endif
31
30c45bdd 32#include "wx/private/selectdispatcher.h"
17a1ebd1 33#include "wx/unix/private.h"
1b0fb34b
JS
34#include "wx/x11/private.h"
35#include "X11/Xlib.h"
c2ca375c 36#include "wx/generic/private/timer.h"
1b0fb34b 37
32d4c30a
WS
38#if wxUSE_THREADS
39 #include "wx/thread.h"
40#endif
41
1016f0de
JS
42#include <sys/time.h>
43#include <unistd.h>
44
bc023abb
MW
45#ifdef HAVE_SYS_SELECT_H
46# include <sys/select.h>
47#endif
48
1b0fb34b
JS
49// ----------------------------------------------------------------------------
50// wxEventLoopImpl
51// ----------------------------------------------------------------------------
52
53class WXDLLEXPORT wxEventLoopImpl
54{
55public:
56 // ctor
32d4c30a 57 wxEventLoopImpl() { SetExitCode(0); m_keepGoing = false; }
1b0fb34b 58
32d4c30a 59 // process an XEvent, return true if it was processed
086fd560 60 bool ProcessEvent(XEvent* event);
1b0fb34b 61
32d4c30a 62 // generate an idle message, return true if more idle time requested
1b0fb34b
JS
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
69public:
32d4c30a 70 // preprocess an event, return true if processed (i.e. no further
1b0fb34b 71 // dispatching required)
7266b672 72 bool PreProcessEvent(XEvent* event);
1b0fb34b
JS
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
086fd560 88bool wxEventLoopImpl::ProcessEvent(XEvent *event)
1b0fb34b
JS
89{
90 // give us the chance to preprocess the message first
086fd560 91 if ( PreProcessEvent(event) )
32d4c30a 92 return true;
3754265e 93
086fd560
JS
94 // if it wasn't done, dispatch it to the corresponding window
95 if (wxTheApp)
96 return wxTheApp->ProcessXEvent((WXEvent*) event);
97
32d4c30a 98 return false;
1b0fb34b
JS
99}
100
101bool wxEventLoopImpl::PreProcessEvent(XEvent *event)
102{
103 // TODO
104#if 0
105 HWND hWnd = msg->hwnd;
106 wxWindow *wndThis = wxGetWindowFromHWND((WXHWND)hWnd);
107
108
109 // try translations first; find the youngest window with a translation
110 // table.
111 wxWindow *wnd;
112 for ( wnd = wndThis; wnd; wnd = wnd->GetParent() )
113 {
114 if ( wnd->MSWTranslateMessage((WXMSG *)msg) )
32d4c30a 115 return true;
1b0fb34b
JS
116 }
117
118 // Anyone for a non-translation message? Try youngest descendants first.
119 for ( wnd = wndThis; wnd; wnd = wnd->GetParent() )
120 {
121 if ( wnd->MSWProcessMessage((WXMSG *)msg) )
32d4c30a 122 return true;
1b0fb34b
JS
123 }
124#endif
125
32d4c30a 126 return false;
1b0fb34b
JS
127}
128
129// ----------------------------------------------------------------------------
130// wxEventLoopImpl idle event processing
131// ----------------------------------------------------------------------------
132
133bool wxEventLoopImpl::SendIdleEvent()
134{
e39af974 135 return wxTheApp->ProcessIdle();
1b0fb34b
JS
136}
137
138// ============================================================================
139// wxEventLoop implementation
140// ============================================================================
141
1b0fb34b
JS
142// ----------------------------------------------------------------------------
143// wxEventLoop running and exiting
144// ----------------------------------------------------------------------------
145
b46b1d59 146wxGUIEventLoop::~wxGUIEventLoop()
1b0fb34b
JS
147{
148 wxASSERT_MSG( !m_impl, _T("should have been deleted in Run()") );
149}
150
b46b1d59 151int wxGUIEventLoop::Run()
1b0fb34b
JS
152{
153 // event loops are not recursive, you need to create another loop!
154 wxCHECK_MSG( !IsRunning(), -1, _T("can't reenter a message loop") );
155
156 m_impl = new wxEventLoopImpl;
3754265e 157
77fb1a02 158 wxEventLoopActivator activate(this);
1b0fb34b 159
32d4c30a 160 m_impl->m_keepGoing = true;
1b0fb34b
JS
161 while ( m_impl->m_keepGoing )
162 {
1b0fb34b
JS
163 // generate and process idle events for as long as we don't have
164 // anything else to do
165 while ( ! Pending() )
166 {
b555c37c 167#if wxUSE_TIMER
c2ca375c 168 wxGenericTimerImpl::NotifyTimers(); // TODO: is this the correct place for it?
b555c37c 169#endif
1b0fb34b
JS
170 if (!m_impl->SendIdleEvent())
171 {
1b0fb34b
JS
172 // Break out of while loop
173 break;
174 }
175 }
176
177 // a message came or no more idle processing to do, sit in Dispatch()
178 // waiting for the next message
179 if ( !Dispatch() )
180 {
181 break;
182 }
183 }
184
16d17da6
VZ
185 OnExit();
186
1b0fb34b
JS
187 int exitcode = m_impl->GetExitCode();
188 delete m_impl;
189 m_impl = NULL;
190
1b0fb34b
JS
191 return exitcode;
192}
193
b46b1d59 194void wxGUIEventLoop::Exit(int rc)
1b0fb34b
JS
195{
196 wxCHECK_RET( IsRunning(), _T("can't call Exit() if not running") );
197
198 m_impl->SetExitCode(rc);
32d4c30a 199 m_impl->m_keepGoing = false;
1b0fb34b
JS
200}
201
202// ----------------------------------------------------------------------------
203// wxEventLoop message processing dispatching
204// ----------------------------------------------------------------------------
205
b46b1d59 206bool wxGUIEventLoop::Pending() const
1b0fb34b 207{
2b5f62a0
VZ
208 XFlush( wxGlobalDisplay() );
209 return (XPending( wxGlobalDisplay() ) > 0);
1b0fb34b
JS
210}
211
b46b1d59 212bool wxGUIEventLoop::Dispatch()
1b0fb34b
JS
213{
214 XEvent event;
215
bd00fe32
VZ
216 // Start off by checking if any of our child processes have finished.
217 wxCheckForFinishedChildren();
218
1b0fb34b
JS
219 // TODO allowing for threads, as per e.g. wxMSW
220
1016f0de
JS
221 // This now waits until either an X event is received,
222 // or the select times out. So we should now process
223 // wxTimers in a reasonably timely fashion. However it
224 // does also mean that idle processing will happen more
225 // often, so we should probably limit idle processing to
226 // not be repeated more than every N milliseconds.
3754265e 227
2b5f62a0 228 if (XPending( wxGlobalDisplay() ) == 0)
1016f0de 229 {
868741e9
JS
230#if wxUSE_NANOX
231 GR_TIMEOUT timeout = 10; // Milliseconds
232 // Wait for next event, or timeout
233 GrGetNextEventTimeout(& event, timeout);
234
235 // Fall through to ProcessEvent.
236 // we'll assume that ProcessEvent will just ignore
237 // the event if there was a timeout and no event.
3754265e 238
868741e9 239#else
1016f0de
JS
240 struct timeval tv;
241 tv.tv_sec=0;
242 tv.tv_usec=10000; // TODO make this configurable
2b5f62a0 243 int fd = ConnectionNumber( wxGlobalDisplay() );
3754265e 244
1016f0de 245 fd_set readset;
52127426 246 fd_set writeset;
17a1ebd1
VZ
247 wxFD_ZERO(&readset);
248 wxFD_ZERO(&writeset);
17a1ebd1 249 wxFD_SET(fd, &readset);
52127426 250
6b44a335 251 if (select( fd+1, &readset, &writeset, NULL, &tv ) != 0)
1016f0de 252 {
6b44a335 253 // An X11 event was pending, get it
17a1ebd1 254 if (wxFD_ISSET( fd, &readset ))
2b5f62a0 255 XNextEvent( wxGlobalDisplay(), &event );
b46b1d59 256 }
868741e9 257#endif
3754265e 258 }
2b5f62a0 259 else
1016f0de 260 {
2b5f62a0 261 XNextEvent( wxGlobalDisplay(), &event );
1016f0de 262 }
3754265e 263
6b44a335
VS
264#if wxUSE_SOCKETS
265 // handle any pending socket events:
b46b1d59 266 wxSelectDispatcher::DispatchPending();
6b44a335 267#endif
3754265e 268
2b5f62a0 269 (void) m_impl->ProcessEvent( &event );
32d4c30a 270 return true;
1b0fb34b 271}