glXEventHandler.cpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "glXEventHandler.h"
00019
00020 #include "commands.h"
00021 #include "event.h"
00022 #include "glXWindow.h"
00023 #include "glXWindowEvent.h"
00024 #include "global.h"
00025 #include "log.h"
00026 #include "packets.h"
00027 #include "pipe.h"
00028 #include "window.h"
00029 #include "X11Connection.h"
00030
00031 #include <eq/base/perThreadRef.h>
00032
00033 #include <X11/keysym.h>
00034
00035 using namespace eq::base;
00036 using namespace std;
00037
00038 namespace eq
00039 {
00040 namespace
00041 {
00042 static PerThreadRef< GLXEventHandler::EventSet > _pipeConnections;
00043 }
00044
00045 GLXEventHandler::GLXEventHandler( GLXPipe* pipe )
00046 : _pipe( pipe )
00047 {
00048 if( !_pipeConnections )
00049 {
00050 _pipeConnections = new GLXEventHandler::EventSet;
00051 }
00052
00053 _pipeConnections->addConnection( new X11Connection( pipe ));
00054 }
00055
00056 GLXEventHandler::~GLXEventHandler()
00057 {
00058 EQASSERT( _pipeConnections.isValid( ));
00059
00060 const net::ConnectionVector& connections =
00061 _pipeConnections->getConnections();
00062
00063 for( net::ConnectionVector::const_iterator i = connections.begin();
00064 i != connections.end(); ++i )
00065 {
00066 net::ConnectionPtr connection = *i;
00067 X11ConnectionPtr x11Connection = static_cast< X11Connection* >(
00068 connection.get( ));
00069 if( x11Connection->pipe == _pipe )
00070 {
00071 _pipeConnections->removeConnection( connection );
00072 x11Connection = 0;
00073 EQASSERTINFO( connection->getRefCount() == 1,
00074 connection->getRefCount( ));
00075 break;
00076 }
00077 }
00078 }
00079
00080 GLXEventSetPtr GLXEventHandler::getEventSet()
00081 {
00082 return _pipeConnections.get();
00083 }
00084
00085 void GLXEventHandler::clearEventSet()
00086 {
00087 EQASSERTINFO( !_pipeConnections || _pipeConnections->empty(),
00088 _pipeConnections->getConnections().size( ));
00089 #if 0 // Asserts with more than one non-threaded pipe
00090 EQASSERTINFO( !_pipeConnections || _pipeConnections->getRefCount() == 1,
00091 _pipeConnections->getRefCount( ));
00092 #endif
00093
00094 _pipeConnections = 0;
00095 EQINFO << "Cleared glX event set" << endl;
00096 }
00097
00098 void GLXEventHandler::dispatchOne()
00099 {
00100 _dispatch( -1 );
00101 }
00102
00103 bool GLXEventHandler::_dispatch( const int timeout )
00104 {
00105 GLXEventSetPtr connections = _pipeConnections.get();
00106 if( !connections )
00107 return false;
00108
00109 const net::ConnectionSet::Event event = connections->select( timeout );
00110 switch( event )
00111 {
00112 case net::ConnectionSet::EVENT_DISCONNECT:
00113 {
00114 net::ConnectionPtr connection = connections->getConnection();
00115 connections->removeConnection( connection );
00116 EQERROR << "Display connection shut down" << endl;
00117 break;
00118 }
00119
00120 case net::ConnectionSet::EVENT_DATA:
00121 GLXEventHandler::dispatchAll();
00122 break;
00123
00124 case net::ConnectionSet::EVENT_INTERRUPT:
00125 break;
00126
00127 case net::ConnectionSet::EVENT_CONNECT:
00128 case net::ConnectionSet::EVENT_ERROR:
00129 default:
00130 EQWARN << "Error during select" << endl;
00131 break;
00132
00133 case net::ConnectionSet::EVENT_TIMEOUT:
00134 return false;
00135 }
00136
00137 return true;
00138 }
00139
00140 void GLXEventHandler::dispatchAll()
00141 {
00142 GLXEventSetPtr pipeConnections = _pipeConnections.get();
00143 if( !pipeConnections )
00144 return;
00145
00146 const net::ConnectionVector& connections =pipeConnections->getConnections();
00147
00148 for( net::ConnectionVector::const_iterator i = connections.begin();
00149 i != connections.end(); ++i )
00150 {
00151 net::ConnectionPtr connection = *i;
00152 X11ConnectionPtr x11Connection = static_cast< X11Connection* >(
00153 connection.get( ));
00154
00155 _handleEvents( x11Connection );
00156 }
00157
00158 while( _dispatch( 0 ))
00159 ;
00160 }
00161
00162 void GLXEventHandler::_handleEvents( X11ConnectionPtr connection )
00163 {
00164 Display* display = connection->getDisplay();
00165 GLXPipe* glXPipe = connection->pipe;
00166 Pipe* pipe = glXPipe->getPipe();
00167 GLXEventHandler* handler = glXPipe->getGLXEventHandler();
00168 EQASSERT( handler );
00169
00170 while( XPending( display ))
00171 {
00172 GLXWindowEvent event;
00173 XEvent& xEvent = event.xEvent;
00174 XNextEvent( display, &xEvent );
00175
00176 handler->_processEvent( event, pipe );
00177 }
00178 }
00179
00180 namespace
00181 {
00182 static GLXWindowIF* _getGLXWindow( Window* window )
00183 {
00184 OSWindow* osWindow = window->getOSWindow();
00185 if( !osWindow )
00186 return 0;
00187
00188 EQASSERT( dynamic_cast< GLXWindowIF* >( osWindow ));
00189 return static_cast< GLXWindowIF* >( osWindow );
00190 }
00191
00192 void _getWindowSize( Display* display, XID drawable, ResizeEvent& event )
00193 {
00194
00195
00196 XWindowAttributes windowAttrs;
00197 XGetWindowAttributes( display, drawable, &windowAttrs );
00198
00199 XID child;
00200 XTranslateCoordinates( display, drawable,
00201 RootWindowOfScreen( windowAttrs.screen ),
00202 windowAttrs.x, windowAttrs.y,
00203 &event.x, &event.y, &child );
00204
00205 event.w = windowAttrs.width;
00206 event.h = windowAttrs.height;
00207 }
00208 }
00209
00210 void GLXEventHandler::_processEvent( GLXWindowEvent& event, Pipe* pipe )
00211 {
00212 XEvent& xEvent = event.xEvent;
00213 XID drawable = xEvent.xany.window;
00214 const WindowVector& windows = pipe->getWindows();
00215 GLXWindowIF* glXWindow = 0;
00216
00217 Window* window = 0;
00218 for( WindowVector::const_iterator i = windows.begin();
00219 i != windows.end(); ++i )
00220 {
00221 Window* const candidate = *i;
00222 glXWindow = _getGLXWindow( candidate );
00223
00224 if( glXWindow && glXWindow->getXDrawable() == drawable )
00225 {
00226 window = candidate;
00227 break;
00228 }
00229 }
00230
00231 if( !window )
00232 {
00233 EQWARN << "Can't match window to received X event" << endl;
00234 return;
00235 }
00236 EQASSERT( glXWindow );
00237
00238 switch( xEvent.type )
00239 {
00240 case Expose:
00241 if( xEvent.xexpose.count )
00242 return;
00243
00244 event.type = Event::WINDOW_EXPOSE;
00245 break;
00246
00247 case ConfigureNotify:
00248 event.type = Event::WINDOW_RESIZE;
00249 _getWindowSize( xEvent.xany.display, drawable, event.resize );
00250 break;
00251
00252 case UnmapNotify:
00253 event.type = Event::WINDOW_HIDE;
00254 _getWindowSize( xEvent.xany.display, drawable, event.resize );
00255 break;
00256
00257 case MapNotify:
00258 event.type = Event::WINDOW_SHOW;
00259 _getWindowSize( xEvent.xany.display, drawable, event.resize );
00260 break;
00261
00262 case ClientMessage:
00263 {
00264 Atom deleteAtom = XInternAtom( xEvent.xany.display,
00265 "WM_DELETE_WINDOW", False );
00266
00267 if( static_cast<Atom>( xEvent.xclient.data.l[0] ) != deleteAtom )
00268 return;
00269 }
00270
00271 case DestroyNotify:
00272 event.type = Event::WINDOW_CLOSE;
00273 break;
00274
00275 case MotionNotify:
00276 event.type = Event::POINTER_MOTION;
00277 event.pointerMotion.x = xEvent.xmotion.x;
00278 event.pointerMotion.y = xEvent.xmotion.y;
00279 event.pointerMotion.buttons = _getButtonState( xEvent );
00280 event.pointerMotion.button = PTR_BUTTON_NONE;
00281
00282 _computePointerDelta( window, event );
00283 _getRenderContext( window, event );
00284 break;
00285
00286 case ButtonPress:
00287 event.type = Event::POINTER_BUTTON_PRESS;
00288 event.pointerButtonPress.x = xEvent.xbutton.x;
00289 event.pointerButtonPress.y = xEvent.xbutton.y;
00290 event.pointerButtonPress.buttons = _getButtonState( xEvent );
00291 event.pointerButtonPress.button = _getButtonAction( xEvent );
00292
00293 _computePointerDelta( window, event );
00294 _getRenderContext( window, event );
00295 break;
00296
00297 case ButtonRelease:
00298 event.type = Event::POINTER_BUTTON_RELEASE;
00299 event.pointerButtonRelease.x = xEvent.xbutton.x;
00300 event.pointerButtonRelease.y = xEvent.xbutton.y;
00301 event.pointerButtonRelease.buttons = _getButtonState( xEvent );
00302 event.pointerButtonRelease.button = _getButtonAction( xEvent);
00303
00304 _computePointerDelta( window, event );
00305 _getRenderContext( window, event );
00306 break;
00307
00308 case KeyPress:
00309 event.type = Event::KEY_PRESS;
00310 event.keyPress.key = _getKey( xEvent );
00311 break;
00312
00313 case KeyRelease:
00314 event.type = Event::KEY_RELEASE;
00315 event.keyPress.key = _getKey( xEvent );
00316 break;
00317
00318 case ReparentNotify:
00319 case VisibilityNotify:
00320 event.type = Event::UNKNOWN;
00321 EQINFO << "Ignored X event, type " << xEvent.type << endl;
00322 break;
00323
00324 default:
00325 event.type = Event::UNKNOWN;
00326 EQWARN << "Unhandled X event, type " << xEvent.type << endl;
00327 break;
00328 }
00329
00330 event.originator = window->getID();
00331
00332 EQLOG( LOG_EVENTS ) << "received event: " << event << endl;
00333
00334 glXWindow->processEvent( event );
00335 }
00336
00337 uint32_t GLXEventHandler::_getButtonState( XEvent& event )
00338 {
00339 const int xState = event.xbutton.state;
00340 uint32_t state = 0;
00341
00342 if( xState & Button1Mask ) state |= PTR_BUTTON1;
00343 if( xState & Button2Mask ) state |= PTR_BUTTON2;
00344 if( xState & Button3Mask ) state |= PTR_BUTTON3;
00345 if( xState & Button4Mask ) state |= PTR_BUTTON4;
00346 if( xState & Button5Mask ) state |= PTR_BUTTON5;
00347
00348 switch( event.type )
00349 {
00350 case ButtonPress:
00351 state |= _getButtonAction( event );
00352 break;
00353
00354 case ButtonRelease:
00355 state &= ~_getButtonAction( event );
00356 break;
00357
00358 default:
00359 break;
00360 }
00361 return state;
00362 }
00363
00364 uint32_t GLXEventHandler::_getButtonAction( XEvent& event )
00365 {
00366 switch( event.xbutton.button )
00367 {
00368 case Button1: return PTR_BUTTON1;
00369 case Button2: return PTR_BUTTON2;
00370 case Button3: return PTR_BUTTON3;
00371 case Button4: return PTR_BUTTON4;
00372 case Button5: return PTR_BUTTON5;
00373 default: return PTR_BUTTON_NONE;
00374 }
00375 }
00376
00377
00378 uint32_t GLXEventHandler::_getKey( XEvent& event )
00379 {
00380 const KeySym key = XKeycodeToKeysym( event.xany.display,
00381 event.xkey.keycode, 0);
00382 switch( key )
00383 {
00384 case XK_Escape: return KC_ESCAPE;
00385 case XK_BackSpace: return KC_BACKSPACE;
00386 case XK_Return: return KC_RETURN;
00387 case XK_Tab: return KC_TAB;
00388 case XK_Home: return KC_HOME;
00389 case XK_Left: return KC_LEFT;
00390 case XK_Up: return KC_UP;
00391 case XK_Right: return KC_RIGHT;
00392 case XK_Down: return KC_DOWN;
00393 case XK_Page_Up: return KC_PAGE_UP;
00394 case XK_Page_Down: return KC_PAGE_DOWN;
00395 case XK_End: return KC_END;
00396 case XK_F1: return KC_F1;
00397 case XK_F2: return KC_F2;
00398 case XK_F3: return KC_F3;
00399 case XK_F4: return KC_F4;
00400 case XK_F5: return KC_F5;
00401 case XK_F6: return KC_F6;
00402 case XK_F7: return KC_F7;
00403 case XK_F8: return KC_F8;
00404 case XK_F9: return KC_F9;
00405 case XK_F10: return KC_F10;
00406 case XK_F11: return KC_F11;
00407 case XK_F12: return KC_F12;
00408 case XK_F13: return KC_F13;
00409 case XK_F14: return KC_F14;
00410 case XK_F15: return KC_F15;
00411 case XK_F16: return KC_F16;
00412 case XK_F17: return KC_F17;
00413 case XK_F18: return KC_F18;
00414 case XK_F19: return KC_F19;
00415 case XK_F20: return KC_F20;
00416 case XK_Shift_L: return KC_SHIFT_L;
00417 case XK_Shift_R: return KC_SHIFT_R;
00418 case XK_Control_L: return KC_CONTROL_L;
00419 case XK_Control_R: return KC_CONTROL_R;
00420 case XK_Alt_L: return KC_ALT_L;
00421 case XK_Alt_R: return KC_ALT_R;
00422
00423 default:
00424
00425 if( (key >= XK_space && key <= XK_asciitilde ) ||
00426 (key >= XK_nobreakspace && key <= XK_ydiaeresis))
00427
00428 return key;
00429
00430 EQWARN << "Unrecognized X11 key code " << key << endl;
00431 return KC_VOID;
00432 }
00433 }
00434
00435 }