/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * OpenSceneGraph Public License for more details. */ /* Note, elements of GraphicsWindowX11 have used Prodcer/RenderSurface_X11.cpp as both * a guide to use of X11/GLX and copiying directly in the case of setBorder(). * These elements are license under OSGPL as above, with Copyright (C) 2001-2004 Don Burns. */ #ifndef OSGVIEWER_GRAPHICSWINDOWX11 #define OSGVIEWER_GRAPHICSWINDOWX11 1 #include #include #include #include #include #include #include #include #define GLX_GLXEXT_PROTOTYPES 1 #include namespace osgViewer { class GraphicsContextX11 : public osg::GraphicsContext { public: GraphicsContextX11(osg::GraphicsContext::Traits* traits): _display(0), _parent(0), _window(0) { _traits = traits; } /** Realise the GraphicsContext implementation, * Pure virtual - must be implemented by concrate implementations of GraphicsContext. */ virtual bool realizeImplementation() { osg::notify(osg::NOTICE)<<"GraphicsWindow::realizeImplementation() not implemented."<setContextID( osg::GraphicsContext::createNewContextID() ); } /** Realise the GraphicsContext.*/ virtual bool realizeImplementation(); /** Return true if the graphics context has been realised and is ready to use.*/ virtual bool isRealizedImplementation() const { return _realized; } /** Close the graphics context.*/ virtual void closeImplementation(); /** Make this graphics context current.*/ virtual void makeCurrentImplementation(); /** Swap the front and back buffers.*/ virtual void swapBuffersImplementation(); /** Check to see if any events have been generated.*/ virtual void checkEvents(); protected: bool createVisualInfo(); void setBorder(bool flag); void init(); void transformMouseXY(float& x, float& y); void adaptKey(XKeyEvent& keyevent, int& keySymbol, unsigned int& modifierMask); Display* _display; Window _parent; Window _window; XVisualInfo* _visualInfo; GLXContext _glxContext; Cursor _defaultCursor; Cursor _nullCursor; Cursor _currentCursor; bool _initialized; bool _realized; }; bool GraphicsWindowX11::createVisualInfo() { typedef std::vector Attributes; Attributes attributes; attributes.push_back(GLX_USE_GL); attributes.push_back(GLX_RGBA); if (_traits->_doubleBuffer) attributes.push_back(GLX_DOUBLEBUFFER); if (_traits->_quadBufferStereo) attributes.push_back(GLX_STEREO); attributes.push_back(GLX_RED_SIZE); attributes.push_back(_traits->_red); attributes.push_back(GLX_GREEN_SIZE); attributes.push_back(_traits->_green); attributes.push_back(GLX_BLUE_SIZE); attributes.push_back(_traits->_blue); attributes.push_back(GLX_DEPTH_SIZE); attributes.push_back(_traits->_depth); if (_traits->_alpha) { attributes.push_back(GLX_ALPHA_SIZE); attributes.push_back(_traits->_alpha); } if (_traits->_stencil) { attributes.push_back(GLX_STENCIL_SIZE); attributes.push_back(_traits->_stencil); } // TODO // GLX_AUX_BUFFERS // GLX_ACCUM_RED_SIZE // GLX_ACCUM_GREEN_SIZE // GLX_SAMPLE_BUFFERS // GLX_SAMPLES attributes.push_back(None); _visualInfo = glXChooseVisual( _display, _traits->_screenNum, &(attributes.front()) ); return _visualInfo != 0; } void GraphicsWindowX11::setBorder(bool flag) { Atom atom; if( (atom = XInternAtom( _display, "_MOTIF_WM_HINTS", 0 )) != None ) { // Hack for sending 64 bit atom to Xserver #if defined( _MIPS_SIM) && (_MIPS_SIM == _MIPS_SIM_ABI64) || defined ( __ia64 ) || defined (__amd64 ) || defined(__x86_64__) struct { CARD32 flags0; CARD32 flags1; CARD32 functions0; CARD32 functions1; CARD32 decorations0; CARD32 decorations1; INT32 input_mode0; INT32 input_mode1; CARD32 status0; CARD32 status1; } wmHints; #if defined( __ia64 ) || defined (__amd64) || defined (__x86_64__) wmHints.flags0 = (1L << 1); wmHints.functions0 = 0; wmHints.decorations0 = flag; wmHints.input_mode0 = 0; #else wmHints.flags1 = (1L << 1); wmHints.functions1 = 0; wmHints.decorations1 = flag; wmHints.input_mode1 = 0; #endif #else struct { CARD32 flags; CARD32 functions; CARD32 decorations; INT32 input_mode; CARD32 status; } wmHints; wmHints.flags = (1L << 1); wmHints.functions = 0; wmHints.decorations = flag; wmHints.input_mode = 0; #endif XUnmapWindow(_display, _window ); XChangeProperty( _display, _window, atom, atom, 32, PropModeReplace, (unsigned char *)&wmHints, 5 ); XMapWindow(_display, _window ); XFlush(_display); XSync(_display,0); } else osg::notify(osg::NOTICE)<<"Error: GraphicsWindowX11::setBorder(" << flag << ") - couldn't change decorations." << std::endl; } void GraphicsWindowX11::init() { if (!_traits || _initialized) return; const char* displayString = _traits->_hostName.c_str(); _display = XOpenDisplay(displayString); unsigned int screen = _traits->_screenNum; if (!_display) { osg::notify(osg::NOTICE)<<"Error: Unable to open display \"" << XDisplayName(displayString) << "\". Is the DISPLAY environmental variable set?"<_x; sh.y = _traits->_y; sh.width = _traits->_width; sh.height = _traits->_height; XSetStandardProperties( _display, _window, _traits->_windowName.c_str(), _traits->_windowName.c_str(), None, 0, 0, &sh); #if 1 setBorder(_traits->_windowDecoration); #else setBorder(true); #endif // Create default Cursor _defaultCursor = XCreateFontCursor( _display, XC_left_ptr ); // Create Null Cursor { Pixmap pixmap; static char buff[2] = {0,0}; static XColor ncol = {0,0,0,0,DoRed|DoGreen|DoBlue,0}; pixmap = XCreateBitmapFromData( _display, _parent, buff, 1, 1); _nullCursor = XCreatePixmapCursor( _display, pixmap, pixmap, &ncol, &ncol, 0, 0 ); } #if 1 _currentCursor = _defaultCursor; #else _currentCursor = _nullCursor; #endif { XDefineCursor( _display, _window, _currentCursor ); XFlush(_display); XSync(_display,0); } XSelectInput( _display, _window, ExposureMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask); XFlush( _display ); XSync( _display, 0 ); _initialized = true; } bool GraphicsWindowX11::realizeImplementation() { if (_realized) return true; if (!_initialized) init(); if (!_initialized) return false; XMapWindow( _display, _window ); Window temp = _window; XSetWMColormapWindows( _display, _window, &temp, 1); makeCurrent(); _realized = true; return true; } void GraphicsWindowX11::makeCurrentImplementation() { glXMakeCurrent( _display, _window, _glxContext ); } void GraphicsWindowX11::closeImplementation() { //glXDestroyContext(_display, _glxContext ); XDestroyWindow(_display, _window); XFlush( _display ); XSync( _display,0 ); _window = 0; _parent = 0; if(_visualInfo) { XFree(_visualInfo); _visualInfo = 0; } _initialized = false; _realized = false; } void GraphicsWindowX11::swapBuffersImplementation() { glXSwapBuffers(_display, _window); } void GraphicsWindowX11::checkEvents() { // osg::notify(osg::NOTICE)<<"Check events"<(_traits->_screenNum); i++ ) { screenOrigin_x -= DisplayWidth(_display, i); } wx += (screenOrigin_x - _traits->_x); wy += (screenOrigin_y - _traits->_y); } float mx = wx; float my = wy; transformMouseXY(mx, my); getEventQueue()->mouseMotion(mx, my); break; } case ButtonPress : { if( ev.xbutton.button == Button4 ) { getEventQueue()->mouseScroll(osgGA::GUIEventAdapter::SCROLL_UP); } else if( ev.xbutton.button == Button5) { getEventQueue()->mouseScroll(osgGA::GUIEventAdapter::SCROLL_DOWN); } else { float mx = ev.xbutton.x; float my = ev.xmotion.y; transformMouseXY(mx, my); getEventQueue()->mouseButtonPress(mx, my, ev.xbutton.button); } break; } case ButtonRelease : { if( ev.xbutton.button == Button4 ) { getEventQueue()->mouseScroll(osgGA::GUIEventAdapter::SCROLL_UP); } else if( ev.xbutton.button == Button5) { getEventQueue()->mouseScroll(osgGA::GUIEventAdapter::SCROLL_DOWN); } else { float mx = ev.xbutton.x; float my = ev.xmotion.y; transformMouseXY(mx, my); getEventQueue()->mouseButtonRelease(mx, my, ev.xbutton.button); } break; } case KeyPress: { int keySymbol = 0; unsigned int modifierMask = 0; adaptKey(ev.xkey, keySymbol, modifierMask); getEventQueue()->keyPress(keySymbol); getEventQueue()->getCurrentEventState()->setModKeyMask(modifierMask); break; } case KeyRelease: { int keySymbol = 0; unsigned int modifierMask = 0; adaptKey(ev.xkey, keySymbol, modifierMask); getEventQueue()->keyRelease(keySymbol); getEventQueue()->getCurrentEventState()->setModKeyMask(modifierMask); break; } default: osg::notify(osg::NOTICE)<<"Other event"<getUseFixedMouseInputRange()) { osgGA::GUIEventAdapter* eventState = getEventQueue()->getCurrentEventState(); x = eventState->getXmin() + (eventState->getXmax()-eventState->getXmin())*x/float(_traits->_width); y = eventState->getYmin() + (eventState->getYmax()-eventState->getYmin())*y/float(_traits->_height); } } void GraphicsWindowX11::adaptKey(XKeyEvent& keyevent, int& keySymbol, unsigned int& modifierMask) { // KeySym ks = XKeycodeToKeysym( _display, keyevent.keycode, 0 ); static XComposeStatus state; unsigned char keybuf[32]; XLookupString( &keyevent, (char *)keybuf, sizeof(keybuf), NULL, &state ); modifierMask = 0; if( keyevent.state & ShiftMask ) { modifierMask |= osgGA::GUIEventAdapter::MODKEY_SHIFT; } if( keyevent.state & LockMask ) { modifierMask |= osgGA::GUIEventAdapter::MODKEY_CAPS_LOCK; } if( keyevent.state & ControlMask ) { modifierMask |= osgGA::GUIEventAdapter::MODKEY_CTRL; } if( keyevent.state & Mod1Mask ) { modifierMask |= osgGA::GUIEventAdapter::MODKEY_ALT; } if( keyevent.state & Mod2Mask ) { modifierMask |= osgGA::GUIEventAdapter::MODKEY_NUM_LOCK; } if( keyevent.state & Mod4Mask ) { modifierMask |= osgGA::GUIEventAdapter::MODKEY_META; } keySymbol = keybuf[0]; } struct X11WindowingSystemInterface : public osg::GraphicsContext::WindowingSystemInterface { X11WindowingSystemInterface() { } virtual unsigned int getNumScreens(const osg::GraphicsContext::ScreenIdentifier& si) { const char* displayString = si._hostName.c_str(); Display* display = XOpenDisplay(displayString); if(display) { unsigned int numScreens = ScreenCount(display); XCloseDisplay(display); return numScreens; } else { osg::notify(osg::NOTICE) << "Unable to open display \"" << XDisplayName(displayString) << "\". Is the DISPLAY environmental variable set?"<_pbuffer) { return new GraphicsContextX11(traits); } else { return new GraphicsWindowX11(traits); } } }; struct RegisterWindowingSystemInterfaceProxy { RegisterWindowingSystemInterfaceProxy() { osg::GraphicsContext::setWindowingSystemInterface(new X11WindowingSystemInterface); } ~RegisterWindowingSystemInterfaceProxy() { osg::GraphicsContext::setWindowingSystemInterface(0); } }; RegisterWindowingSystemInterfaceProxy createWindowingSystemInterfaceProxy; } #endif