glXEventHandler.cpp

00001 
00002 /* Copyright (c) 2006-2009, Stefan Eilemann <eile@equalizergraphics.com> 
00003  *
00004  * This library is free software; you can redistribute it and/or modify it under
00005  * the terms of the GNU Lesser General Public License version 2.1 as published
00006  * by the Free Software Foundation.
00007  *  
00008  * This library is distributed in the hope that it will be useful, but WITHOUT
00009  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00010  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
00011  * details.
00012  * 
00013  * You should have received a copy of the GNU Lesser General Public License
00014  * along with this library; if not, write to the Free Software Foundation, Inc.,
00015  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
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 )) // handle disconnect and interrupt events
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     // Get window coordinates from X11, the event data is relative to window
00195     // parent, but we report pvp relative to root window.
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 ) // Only report last expose event
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; // not a delete message, ignore.
00269         }
00270         // else: delete message, fall through
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     {   // state is state before event
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             // 'Useful' Latin1 characters
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 }
Generated on Mon Aug 10 18:58:39 2009 for Equalizer 0.9 by  doxygen 1.5.8