// Created on: 2013-04-06 // Created by: Kirill Gavrilov // Copyright (c) 2013-2014 OPEN CASCADE SAS // // This file is part of Open CASCADE Technology software library. // // This library is free software; you can redistribute it and/or modify it under // the terms of the GNU Lesser General Public License version 2.1 as published // by the Free Software Foundation, with special exception defined in the file // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT // distribution for complete text of the license and disclaimer of any warranty. // // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement. #include #if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX)) && !defined(__ANDROID__) && !defined(__QNX__) #include #include #include #include #if defined(HAVE_EGL) || defined(HAVE_GLES2) #include #else #include namespace { //! Search for RGBA double-buffered visual with stencil buffer. static int TheDoubleBuffVisual[] = { GLX_RGBA, GLX_DEPTH_SIZE, 16, GLX_STENCIL_SIZE, 1, GLX_DOUBLEBUFFER, None }; //! Search for RGBA double-buffered visual with stencil buffer. static int TheDoubleBuffFBConfig[] = { GLX_X_RENDERABLE, True, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, GLX_DEPTH_SIZE, 16, GLX_STENCIL_SIZE, 1, GLX_DOUBLEBUFFER, True, None }; } #endif IMPLEMENT_STANDARD_RTTIEXT(Xw_Window, Aspect_Window) // ======================================================================= // function : Xw_Window // purpose : // ======================================================================= Xw_Window::Xw_Window (const Handle(Aspect_DisplayConnection)& theXDisplay, const Standard_CString theTitle, const Standard_Integer thePxLeft, const Standard_Integer thePxTop, const Standard_Integer thePxWidth, const Standard_Integer thePxHeight, const Aspect_FBConfig theFBConfig) : Aspect_Window(), myDisplay (theXDisplay), myXWindow (0), myFBConfig (theFBConfig), myXLeft (thePxLeft), myYTop (thePxTop), myXRight (thePxLeft + thePxWidth), myYBottom (thePxTop + thePxHeight), myIsOwnWin (Standard_True) { if (thePxWidth <= 0 || thePxHeight <= 0) { throw Aspect_WindowDefinitionError("Xw_Window, Coordinate(s) out of range"); } else if (theXDisplay.IsNull()) { throw Aspect_WindowDefinitionError("Xw_Window, X Display connection is undefined"); return; } Display* aDisp = myDisplay->GetDisplay(); int aScreen = DefaultScreen(aDisp); Window aParent = RootWindow (aDisp, aScreen); XVisualInfo* aVisInfo = NULL; #if defined(HAVE_EGL) || defined(HAVE_GLES2) EGLDisplay anEglDisplay = eglGetDisplay (aDisp); EGLint aVerMajor = 0; EGLint aVerMinor = 0; XVisualInfo aVisInfoTmp; memset (&aVisInfoTmp, 0, sizeof(aVisInfoTmp)); if (anEglDisplay != EGL_NO_DISPLAY && eglInitialize (anEglDisplay, &aVerMajor, &aVerMinor) == EGL_TRUE) { EGLint aConfigAttribs[] = { EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 0, EGL_DEPTH_SIZE, 24, EGL_STENCIL_SIZE, 8, #if defined(HAVE_GLES2) EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, #else EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, #endif EGL_NONE }; EGLint aNbConfigs = 0; void* anEglConfig = NULL; if (eglChooseConfig (anEglDisplay, aConfigAttribs, &anEglConfig, 1, &aNbConfigs) != EGL_TRUE || anEglConfig == NULL) { eglGetError(); aConfigAttribs[4 * 2 + 1] = 16; // try config with smaller depth buffer if (eglChooseConfig (anEglDisplay, aConfigAttribs, &anEglConfig, 1, &aNbConfigs) != EGL_TRUE || anEglConfig == NULL) { anEglConfig = NULL; } } if (anEglConfig != NULL && eglGetConfigAttrib (anEglDisplay, anEglConfig, EGL_NATIVE_VISUAL_ID, (EGLint* )&aVisInfoTmp.visualid) == EGL_TRUE) { int aNbVisuals = 0; aVisInfoTmp.screen = DefaultScreen (aDisp); aVisInfo = XGetVisualInfo (aDisp, VisualIDMask | VisualScreenMask, &aVisInfoTmp, &aNbVisuals); } } if (aVisInfo == NULL) { Message::DefaultMessenger()->Send ("Warning: cannot choose Visual using EGL while creating Xw_Window", Message_Warning); } #else int aDummy = 0; if (!glXQueryExtension (myDisplay->GetDisplay(), &aDummy, &aDummy)) { throw Aspect_WindowDefinitionError("Xw_Window, GLX extension is unavailable"); return; } if (myFBConfig == NULL) { // FBConfigs were added in GLX version 1.3 int aGlxMajor = 0; int aGlxMinor = 0; const bool hasFBCfg = glXQueryVersion (aDisp, &aGlxMajor, &aGlxMinor) && ((aGlxMajor == 1 && aGlxMinor >= 3) || (aGlxMajor > 1)); if (hasFBCfg) { int aFBCount = 0; GLXFBConfig* aFBCfgList = NULL; if (hasFBCfg) { aFBCfgList = glXChooseFBConfig (aDisp, aScreen, TheDoubleBuffFBConfig, &aFBCount); } if(aFBCfgList != NULL && aFBCount >= 1) { myFBConfig = aFBCfgList[0]; aVisInfo = glXGetVisualFromFBConfig (aDisp, myFBConfig); } XFree (aFBCfgList); } } if (aVisInfo == NULL) { aVisInfo = glXChooseVisual (aDisp, aScreen, TheDoubleBuffVisual); } if (aVisInfo == NULL) { throw Aspect_WindowDefinitionError("Xw_Window, couldn't find compatible Visual (RGBA, double-buffered)"); return; } #endif unsigned long aMask = 0; XSetWindowAttributes aWinAttr; memset(&aWinAttr, 0, sizeof(XSetWindowAttributes)); aWinAttr.event_mask = ExposureMask | StructureNotifyMask; aMask |= CWEventMask; if (aVisInfo != NULL) { aWinAttr.colormap = XCreateColormap(aDisp, aParent, aVisInfo->visual, AllocNone); } aWinAttr.border_pixel = 0; aWinAttr.override_redirect = False; myXWindow = XCreateWindow(aDisp, aParent, myXLeft, myYTop, thePxWidth, thePxHeight, 0, aVisInfo != NULL ? aVisInfo->depth : CopyFromParent, InputOutput, aVisInfo != NULL ? aVisInfo->visual : CopyFromParent, CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect, &aWinAttr); if (aVisInfo != NULL) { XFree (aVisInfo); aVisInfo = NULL; } if (myXWindow == 0) { throw Aspect_WindowDefinitionError("Xw_Window, Unable to create window"); return; } // if parent - desktop XSizeHints aSizeHints; aSizeHints.x = myXLeft; aSizeHints.y = myYTop; aSizeHints.flags = PPosition; aSizeHints.width = thePxWidth; aSizeHints.height = thePxHeight; aSizeHints.flags |= PSize; XSetStandardProperties (aDisp, myXWindow, theTitle, theTitle, None, NULL, 0, &aSizeHints); /*XTextProperty aTitleProperty; aTitleProperty.encoding = None; char* aTitle = (char* )theTitle; Xutf8TextListToTextProperty(aDisp, &aTitle, 1, XUTF8StringStyle, &aTitleProperty); XSetWMName (aDisp, myXWindow, &aTitleProperty); XSetWMProperties(aDisp, myXWindow, &aTitleProperty, &aTitleProperty, NULL, 0, NULL, NULL, NULL);*/ XFlush (aDisp); } // ======================================================================= // function : Xw_Window // purpose : // ======================================================================= Xw_Window::Xw_Window (const Handle(Aspect_DisplayConnection)& theXDisplay, const Window theXWin, const Aspect_FBConfig theFBConfig) : Aspect_Window(), myDisplay (theXDisplay), myXWindow (theXWin), myFBConfig (theFBConfig), myXLeft (0), myYTop (0), myXRight (512), myYBottom (512), myIsOwnWin (Standard_False) { if (theXWin == 0) { throw Aspect_WindowDefinitionError("Xw_Window, given invalid X window"); return; } else if (theXDisplay.IsNull()) { throw Aspect_WindowDefinitionError("Xw_Window, X Display connection is undefined"); return; } #if !defined(HAVE_EGL) && !defined(HAVE_GLES2) int aDummy = 0; if (!glXQueryExtension (myDisplay->GetDisplay(), &aDummy, &aDummy)) { myXWindow = 0; throw Aspect_WindowDefinitionError("Xw_Window, GLX extension is unavailable"); return; } #endif Display* aDisp = myDisplay->GetDisplay(); XWindowAttributes aWinAttr; XGetWindowAttributes (aDisp, myXWindow, &aWinAttr); XVisualInfo aVisInfoTmp; aVisInfoTmp.visualid = aWinAttr.visual->visualid; aVisInfoTmp.screen = DefaultScreen (aDisp); int aNbItems = 0; XVisualInfo* aVisInfo = XGetVisualInfo (aDisp, VisualIDMask | VisualScreenMask, &aVisInfoTmp, &aNbItems); if (aVisInfo == NULL) { throw Aspect_WindowDefinitionError("Xw_Window, Visual is unavailable"); return; } XFree (aVisInfo); DoResize(); } // ======================================================================= // function : ~Xw_Window // purpose : // ======================================================================= Xw_Window::~Xw_Window() { if (myIsOwnWin && myXWindow != 0 && !myDisplay.IsNull()) { XDestroyWindow (myDisplay->GetDisplay(), myXWindow); } } // ======================================================================= // function : XWindow // purpose : // ======================================================================= Window Xw_Window::XWindow() const { return myXWindow; } // ======================================================================= // function : IsMapped // purpose : // ======================================================================= Standard_Boolean Xw_Window::IsMapped() const { if (myXWindow == 0) { return false; } else if (IsVirtual()) { return Standard_True; } XFlush (myDisplay->GetDisplay()); XWindowAttributes aWinAttr; XGetWindowAttributes (myDisplay->GetDisplay(), myXWindow, &aWinAttr); return aWinAttr.map_state == IsUnviewable || aWinAttr.map_state == IsViewable; } // ======================================================================= // function : Map // purpose : // ======================================================================= void Xw_Window::Map() const { if (IsVirtual() || myXWindow == 0) { return; } XMapWindow (myDisplay->GetDisplay(), myXWindow); XFlush (myDisplay->GetDisplay()); } // ======================================================================= // function : Unmap // purpose : // ======================================================================= void Xw_Window::Unmap() const { if (IsVirtual() || myXWindow == 0) { return; } XIconifyWindow (myDisplay->GetDisplay(), myXWindow, DefaultScreen(myDisplay->GetDisplay())); } // ======================================================================= // function : DoResize // purpose : // ======================================================================= Aspect_TypeOfResize Xw_Window::DoResize() const { if (myXWindow == 0) { return Aspect_TOR_UNKNOWN; } XFlush (myDisplay->GetDisplay()); XWindowAttributes aWinAttr; XGetWindowAttributes (myDisplay->GetDisplay(), myXWindow, &aWinAttr); if (aWinAttr.map_state == IsUnmapped) { return Aspect_TOR_UNKNOWN; } Standard_Integer aMask = 0; Aspect_TypeOfResize aMode = Aspect_TOR_UNKNOWN; if (Abs (aWinAttr.x - myXLeft ) > 2) aMask |= 1; if (Abs ((aWinAttr.x + aWinAttr.width) - myXRight ) > 2) aMask |= 2; if (Abs (aWinAttr.y - myYTop ) > 2) aMask |= 4; if (Abs ((aWinAttr.y + aWinAttr.height) - myYBottom) > 2) aMask |= 8; switch (aMask) { case 0: aMode = Aspect_TOR_NO_BORDER; break; case 1: aMode = Aspect_TOR_LEFT_BORDER; break; case 2: aMode = Aspect_TOR_RIGHT_BORDER; break; case 4: aMode = Aspect_TOR_TOP_BORDER; break; case 5: aMode = Aspect_TOR_LEFT_AND_TOP_BORDER; break; case 6: aMode = Aspect_TOR_TOP_AND_RIGHT_BORDER; break; case 8: aMode = Aspect_TOR_BOTTOM_BORDER; break; case 9: aMode = Aspect_TOR_BOTTOM_AND_LEFT_BORDER; break; case 10: aMode = Aspect_TOR_RIGHT_AND_BOTTOM_BORDER; break; default: break; } *((Standard_Integer* )&myXLeft ) = aWinAttr.x; *((Standard_Integer* )&myXRight ) = aWinAttr.x + aWinAttr.width; *((Standard_Integer* )&myYTop ) = aWinAttr.y; *((Standard_Integer* )&myYBottom ) = aWinAttr.y + aWinAttr.height; return aMode; } // ======================================================================= // function : DoMapping // purpose : // ======================================================================= Standard_Boolean Xw_Window::DoMapping() const { return Standard_True; // IsMapped() } // ======================================================================= // function : Ratio // purpose : // ======================================================================= Standard_Real Xw_Window::Ratio() const { if (myXWindow == 0) { return 1.0; } XFlush (myDisplay->GetDisplay()); XWindowAttributes aWinAttr; XGetWindowAttributes (myDisplay->GetDisplay(), myXWindow, &aWinAttr); return Standard_Real(aWinAttr.width) / Standard_Real(aWinAttr.height); } // ======================================================================= // function : Position // purpose : // ======================================================================= void Xw_Window::Position (Standard_Integer& X1, Standard_Integer& Y1, Standard_Integer& X2, Standard_Integer& Y2) const { if (myXWindow == 0) { return; } XFlush (myDisplay->GetDisplay()); XWindowAttributes anAttributes; XGetWindowAttributes (myDisplay->GetDisplay(), myXWindow, &anAttributes); Window aChild; XTranslateCoordinates (myDisplay->GetDisplay(), anAttributes.root, myXWindow, 0, 0, &anAttributes.x, &anAttributes.y, &aChild); X1 = -anAttributes.x; X2 = X1 + anAttributes.width; Y1 = -anAttributes.y; Y2 = Y1 + anAttributes.height; } // ======================================================================= // function : Size // purpose : // ======================================================================= void Xw_Window::Size (Standard_Integer& theWidth, Standard_Integer& theHeight) const { if (myXWindow == 0) { return; } XFlush (myDisplay->GetDisplay()); XWindowAttributes aWinAttr; XGetWindowAttributes (myDisplay->GetDisplay(), myXWindow, &aWinAttr); theWidth = aWinAttr.width; theHeight = aWinAttr.height; } // ======================================================================= // function : InvalidateContent // purpose : // ======================================================================= void Xw_Window::InvalidateContent (const Handle(Aspect_DisplayConnection)& theDisp) { if (myXWindow == 0) { return; } const Handle(Aspect_DisplayConnection)& aDisp = !theDisp.IsNull() ? theDisp : myDisplay; Display* aDispX = aDisp->GetDisplay(); XEvent anEvent; memset (&anEvent, 0, sizeof(anEvent)); anEvent.type = Expose; anEvent.xexpose.window = myXWindow; XSendEvent (aDispX, myXWindow, False, ExposureMask, &anEvent); XFlush (aDispX); } #endif // Win32 or Mac OS X