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: evtloop.cpp 43976 2006-12-14 14:13:57Z VS $ 8// Copyright: (c) 2002 Julian Smart 9// License: 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/timer.h" 30 #include "wx/module.h" 31#endif 32 33#include "wx/private/socketevtdispatch.h" 34#include "wx/unix/private.h" 35#include "wx/x11/private.h" 36#include "X11/Xlib.h" 37 38#if wxUSE_THREADS 39 #include "wx/thread.h" 40#endif 41 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 53class WXDLLEXPORT wxEventLoopImpl 54{ 55public: 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 69public: 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 88bool 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 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) ) 115 return true; 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) ) 122 return true; 123 } 124#endif 125 126 return false; 127} 128 129// ---------------------------------------------------------------------------- 130// wxEventLoopImpl idle event processing 131// ---------------------------------------------------------------------------- 132 133bool wxEventLoopImpl::SendIdleEvent() 134{ 135 return wxTheApp->ProcessIdle(); 136} 137 138// ============================================================================ 139// wxEventLoop implementation 140// ============================================================================ 141 142// ---------------------------------------------------------------------------- 143// wxEventLoop running and exiting 144// ---------------------------------------------------------------------------- 145 146wxEventLoop::~wxEventLoop() 147{ 148 wxASSERT_MSG( !m_impl, _T("should have been deleted in Run()") ); 149} 150 151int wxEventLoop::Run() 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; 157 158 wxEventLoopActivator activate(this); 159 160 m_impl->m_keepGoing = true; 161 while ( m_impl->m_keepGoing ) 162 { 163 // generate and process idle events for as long as we don't have 164 // anything else to do 165 while ( ! Pending() ) 166 { 167#if wxUSE_TIMER 168 wxTimer::NotifyTimers(); // TODO: is this the correct place for it? 169#endif 170 if (!m_impl->SendIdleEvent()) 171 { 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 185 OnExit(); 186 187 int exitcode = m_impl->GetExitCode(); 188 delete m_impl; 189 m_impl = NULL; 190 191 return exitcode; 192} 193 194void wxEventLoop::Exit(int rc) 195{ 196 wxCHECK_RET( IsRunning(), _T("can't call Exit() if not running") ); 197 198 m_impl->SetExitCode(rc); 199 m_impl->m_keepGoing = false; 200} 201 202// ---------------------------------------------------------------------------- 203// wxEventLoop message processing dispatching 204// ---------------------------------------------------------------------------- 205 206bool wxEventLoop::Pending() const 207{ 208 XFlush( wxGlobalDisplay() ); 209 return (XPending( wxGlobalDisplay() ) > 0); 210} 211 212bool wxEventLoop::Dispatch() 213{ 214 XEvent event; 215 216 // Start off by checking if any of our child processes have finished. 217 wxCheckForFinishedChildren(); 218 219 // TODO allowing for threads, as per e.g. wxMSW 220 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. 227 228 if (XPending( wxGlobalDisplay() ) == 0) 229 { 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. 238 239#else 240 struct timeval tv; 241 tv.tv_sec=0; 242 tv.tv_usec=10000; // TODO make this configurable 243 int fd = ConnectionNumber( wxGlobalDisplay() ); 244 245 fd_set readset; 246 fd_set writeset; 247 wxFD_ZERO(&readset); 248 wxFD_ZERO(&writeset); 249 wxFD_SET(fd, &readset); 250 251 if (select( fd+1, &readset, &writeset, NULL, &tv ) != 0) 252 { 253 // An X11 event was pending, get it 254 if (wxFD_ISSET( fd, &readset )) 255 XNextEvent( wxGlobalDisplay(), &event ); 256 } 257#endif 258 } 259 else 260 { 261 XNextEvent( wxGlobalDisplay(), &event ); 262 } 263 264#if wxUSE_SOCKETS 265 // handle any pending socket events: 266 wxSocketEventDispatcher::Get().RunLoop(); 267#endif 268 269 (void) m_impl->ProcessEvent( &event ); 270 return true; 271} 272