nuclear@0: /******************************************************************************* nuclear@0: nuclear@0: Filename : OVR_Linux_SDKWindow.cpp nuclear@0: Content : SDK generated Linux window. nuclear@0: Created : October 1, 2014 nuclear@0: Authors : James Hughes nuclear@0: nuclear@0: Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. nuclear@0: nuclear@0: Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); nuclear@0: you may not use the Oculus VR Rift SDK except in compliance with the License, nuclear@0: which is provided at the time of installation or download, or which nuclear@0: otherwise accompanies this software in either electronic or hard copy form. nuclear@0: nuclear@0: You may obtain a copy of the License at nuclear@0: nuclear@0: http://www.oculusvr.com/licenses/LICENSE-3.2 nuclear@0: nuclear@0: Unless required by applicable law or agreed to in writing, the Oculus VR SDK nuclear@0: distributed under the License is distributed on an "AS IS" BASIS, nuclear@0: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. nuclear@0: See the License for the specific language governing permissions and nuclear@0: limitations under the License. nuclear@0: nuclear@0: *******************************************************************************/ nuclear@0: nuclear@0: #include "OVR_Linux_SDKWindow.h" nuclear@0: #include "../Kernel/OVR_Log.h" nuclear@0: #include "../Kernel/OVR_Log.h" nuclear@0: #include "../../../3rdParty/EDID/edid.h" nuclear@0: nuclear@0: namespace OVR { nuclear@0: nuclear@0: // Forward declarations nuclear@0: static Window constructWindow(struct _XDisplay* display, int xscreen, nuclear@0: XVisualInfo* xvisual, nuclear@0: const LinuxDeviceScreen& screen); nuclear@0: nuclear@0: static XRRModeInfo* findModeByXID(XRRScreenResources* screen, RRMode xid) nuclear@0: { nuclear@0: for (int m = 0; m < screen->nmode; ++m) nuclear@0: { nuclear@0: XRRModeInfo* mode = &screen->modes[m]; nuclear@0: if (xid == mode->id) nuclear@0: { nuclear@0: return mode; nuclear@0: } nuclear@0: } nuclear@0: return NULL; nuclear@0: } nuclear@0: nuclear@0: /// Retrieves a list of available device screens on which we can build nuclear@0: /// SDK windows. Returns number of devices found. nuclear@0: /// screens Array which this function will populate. nuclear@0: /// maxNumScreens Maximum number of screens to store in screens. nuclear@0: static int getDeviceScreens(LinuxDeviceScreen* screens, int maxNumDevices) nuclear@0: { nuclear@0: struct _XDisplay* disp = XOpenDisplay(NULL); nuclear@0: if (!disp) nuclear@0: { nuclear@0: OVR::LogError("[SDKWindow] Unable to open X Display."); nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: int numDevices = 0; nuclear@0: int numScreens = XScreenCount(disp); nuclear@0: for (int i = 0; i < numScreens; ++i) nuclear@0: { nuclear@0: // Screen root is used to detect what video output the crtc is using. nuclear@0: Window sr = XRootWindow(disp, i); nuclear@0: XRRScreenResources* screen = XRRGetScreenResources(disp, sr); nuclear@0: nuclear@0: for (int ii = 0; ii < screen->ncrtc; ++ii) nuclear@0: { nuclear@0: XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(disp, screen, screen->crtcs[ii]); nuclear@0: nuclear@0: if (0 == crtcInfo->noutput) nuclear@0: { nuclear@0: XRRFreeCrtcInfo(crtcInfo); nuclear@0: continue; nuclear@0: } nuclear@0: nuclear@0: bool foundOutput = false; nuclear@0: RROutput output = crtcInfo->outputs[0]; nuclear@0: for (int k = 0; k < crtcInfo->noutput; ++k) nuclear@0: { nuclear@0: XRROutputInfo* outputInfo = nuclear@0: XRRGetOutputInfo(disp, screen, crtcInfo->outputs[k]); nuclear@0: for (int kk = 0 ; kk < outputInfo->nmode; ++kk) nuclear@0: { nuclear@0: if (outputInfo->modes[kk] == crtcInfo->mode) nuclear@0: { nuclear@0: output = crtcInfo->outputs[k]; nuclear@0: foundOutput = true; nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: XRRFreeOutputInfo(outputInfo); nuclear@0: if (foundOutput) { break; } nuclear@0: } nuclear@0: nuclear@0: if (!foundOutput) nuclear@0: { nuclear@0: XRRFreeCrtcInfo(crtcInfo); nuclear@0: continue; nuclear@0: } nuclear@0: nuclear@0: XRROutputInfo* outputInfo = XRRGetOutputInfo(disp, screen, output); nuclear@0: if (RR_Connected != outputInfo->connection) nuclear@0: { nuclear@0: XRRFreeOutputInfo(outputInfo); nuclear@0: XRRFreeCrtcInfo(crtcInfo); nuclear@0: continue; nuclear@0: } nuclear@0: nuclear@0: // Read EDID associated with crtc. nuclear@0: MonitorInfo* mi = read_edid_data(disp, output); nuclear@0: if (mi == NULL) nuclear@0: { nuclear@0: XRRFreeOutputInfo(outputInfo); nuclear@0: XRRFreeCrtcInfo(crtcInfo); nuclear@0: continue; nuclear@0: } nuclear@0: nuclear@0: if (strcmp(mi->manufacturer_code, "OVR") == 0) nuclear@0: { nuclear@0: XRRModeInfo* modeInfo = findModeByXID(screen, crtcInfo->mode); nuclear@0: nuclear@0: DistortionRotation desiredRot = DistRotateNone; nuclear@0: if (mi->product_code == 3) nuclear@0: { nuclear@0: // This is a DK2, we may have to rotate our output. nuclear@0: // If we don't have to, we should alert the user that nuclear@0: // rotating the display using the DM or graphics nuclear@0: // card settings is highly non-optimal. nuclear@0: desiredRot = DistRotateCCW90; nuclear@0: if (crtcInfo->rotation != RR_Rotate_0) nuclear@0: { nuclear@0: OVR::LogError("Please do not rotate your rift's screen."); nuclear@0: nuclear@0: if (crtcInfo->rotation == RR_Rotate_90) nuclear@0: { nuclear@0: // The user has manually rotated the screen. nuclear@0: // So apply no rotation on our end. nuclear@0: desiredRot = DistRotateNone; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: if (crtcInfo->rotation != RR_Rotate_0) nuclear@0: { nuclear@0: OVR::LogError("Please do not rotate your rift's screen."); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: int width = modeInfo->width; nuclear@0: int height = modeInfo->height; nuclear@0: nuclear@0: // Swap width / height if display is rotated (shouldn't be on linux). nuclear@0: if ( crtcInfo->rotation == RR_Rotate_90 nuclear@0: || crtcInfo->rotation == RR_Rotate_270) nuclear@0: { nuclear@0: width = modeInfo->height; nuclear@0: height = modeInfo->width; nuclear@0: } nuclear@0: nuclear@0: // Push detected monitor. nuclear@0: screens[numDevices].set(i, screen->crtcs[ii], desiredRot, nuclear@0: mi->product_code, width, height, nuclear@0: crtcInfo->x, crtcInfo->y); nuclear@0: ++numDevices; nuclear@0: } nuclear@0: nuclear@0: delete mi; nuclear@0: nuclear@0: if (numDevices == maxNumDevices) nuclear@0: { nuclear@0: XRRFreeOutputInfo(outputInfo); nuclear@0: XRRFreeCrtcInfo(crtcInfo); nuclear@0: XRRFreeScreenResources(screen); nuclear@0: OVR::LogError("[SDKWindow] Maxed out number of devices.."); nuclear@0: XCloseDisplay(disp); nuclear@0: return numDevices; nuclear@0: } nuclear@0: nuclear@0: XRRFreeOutputInfo(outputInfo); nuclear@0: XRRFreeCrtcInfo(crtcInfo); nuclear@0: } nuclear@0: nuclear@0: XRRFreeScreenResources(screen); nuclear@0: } nuclear@0: XCloseDisplay(disp); nuclear@0: return numDevices; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: LinuxDeviceScreen SDKWindow::findDevScreenForHMD(const ovrHmd& hmd) nuclear@0: { nuclear@0: return findDevScreenForDevID(hmd->DisplayDeviceName); nuclear@0: } nuclear@0: nuclear@0: LinuxDeviceScreen SDKWindow::findDevScreenForDevID(const char* deviceIDIn) nuclear@0: { nuclear@0: const int maxNumDevices = 5; nuclear@0: LinuxDeviceScreen screens[maxNumDevices]; nuclear@0: int numDevices = getDeviceScreens(screens, maxNumDevices); nuclear@0: nuclear@0: if (numDevices > 0) nuclear@0: { nuclear@0: // Identify target for SDK window via hmd info. nuclear@0: for (int i = 0; i < numDevices; ++i) nuclear@0: { nuclear@0: LinuxDeviceScreen& screen = screens[i]; nuclear@0: nuclear@0: char deviceID[32]; nuclear@0: OVR_sprintf(deviceID, 32, "OVR%04d-%d", nuclear@0: screen.productCode, screen.crtcid); nuclear@0: nuclear@0: if (strcmp(deviceIDIn, deviceID) == 0) nuclear@0: { nuclear@0: return screen; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: return LinuxDeviceScreen(); nuclear@0: } nuclear@0: nuclear@0: DistortionRotation SDKWindow::getRotation(const ovrHmd& hmd) nuclear@0: { nuclear@0: LinuxDeviceScreen screen = findDevScreenForHMD(hmd); nuclear@0: if (screen.isValid()) nuclear@0: { nuclear@0: return screen.rotation; nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: return DistRotateNone; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: nuclear@0: bool SDKWindow::getVisualFromDrawable(GLXDrawable drawable, XVisualInfo* vinfoOut) nuclear@0: { nuclear@0: struct _XDisplay* display = glXGetCurrentDisplay(); nuclear@0: nuclear@0: unsigned int value; nuclear@0: glXQueryDrawable(display, drawable, GLX_FBCONFIG_ID, &value); nuclear@0: const int attribs[] = {GLX_FBCONFIG_ID, (int)value, None}; nuclear@0: int screen; nuclear@0: glXQueryContext(display, glXGetCurrentContext(), GLX_SCREEN, &screen); nuclear@0: int numElems; nuclear@0: GLXFBConfig* config = glXChooseFBConfig(display, screen, attribs, &numElems); nuclear@0: if (numElems > 0) nuclear@0: { nuclear@0: XVisualInfo* chosen = glXGetVisualFromFBConfig(display, *config); nuclear@0: *vinfoOut = *chosen; nuclear@0: XFree(config); nuclear@0: return true; nuclear@0: } nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: SDKWindow::SDKWindow(const ovrHmd& hmd) : nuclear@0: mXDisplay(NULL), nuclear@0: mXScreen(-1), nuclear@0: mXVisual(NULL), nuclear@0: mXUniqueContext(-1), nuclear@0: mXWindow(0), nuclear@0: mFBConfigID(0) nuclear@0: { nuclear@0: OVR_UNUSED(hmd); nuclear@0: } nuclear@0: nuclear@0: SDKWindow::~SDKWindow() nuclear@0: { nuclear@0: if (mXWindow) nuclear@0: { nuclear@0: XDeleteContext(mXDisplay, mXWindow, mXUniqueContext); nuclear@0: XUnmapWindow(mXDisplay, mXWindow); nuclear@0: XDestroyWindow(mXDisplay, mXWindow); nuclear@0: mXWindow = static_cast(0); nuclear@0: } nuclear@0: nuclear@0: if (mXVisual) nuclear@0: { nuclear@0: XFree(mXVisual); nuclear@0: mXVisual = NULL; nuclear@0: } nuclear@0: nuclear@0: if (mXDisplay) nuclear@0: { nuclear@0: XCloseDisplay(mXDisplay); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: void SDKWindow::buildVisualAndWindow(const LinuxDeviceScreen& devScreen) nuclear@0: { nuclear@0: mXDisplay = XOpenDisplay(NULL); nuclear@0: mXUniqueContext = XUniqueContext(); nuclear@0: mXScreen = devScreen.screen; nuclear@0: mFBConfigID = chooseFBConfigID(mXDisplay, mXScreen); nuclear@0: nuclear@0: mXVisual = getVisual(mXDisplay, mFBConfigID, mXScreen); nuclear@0: if (mXVisual != NULL) nuclear@0: { nuclear@0: mXWindow = constructWindow(mXDisplay, mXScreen, mXVisual, devScreen); nuclear@0: mDeviceScreen = devScreen; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // Used in chooseVisual. May need to expose this to the end use so they can nuclear@0: // choose an appropriate framebuffer configuration. nuclear@0: struct FBConfig nuclear@0: { nuclear@0: FBConfig() : nuclear@0: redBits(8), nuclear@0: greenBits(8), nuclear@0: blueBits(8), nuclear@0: alphaBits(8), nuclear@0: depthBits(8), nuclear@0: stencilBits(-1), nuclear@0: doubleBuffer(true), nuclear@0: auxBuffers(-1) nuclear@0: {} nuclear@0: nuclear@0: int redBits; nuclear@0: int greenBits; nuclear@0: int blueBits; nuclear@0: int alphaBits; nuclear@0: int depthBits; nuclear@0: int stencilBits; nuclear@0: bool doubleBuffer; nuclear@0: int auxBuffers; nuclear@0: nuclear@0: int xcfg; nuclear@0: }; nuclear@0: nuclear@0: static int fbCalcContrib(int desired, int current) nuclear@0: { nuclear@0: int diff = desired - current; nuclear@0: if (current != -1) { return diff * diff; } nuclear@0: else { return 0; } nuclear@0: } nuclear@0: nuclear@0: // Choose frame buffer configuration and return fbConfigID. nuclear@0: int SDKWindow::chooseFBConfigID(struct _XDisplay* display, int xscreen) nuclear@0: { nuclear@0: int nativeCount = 0; nuclear@0: GLXFBConfig* nativeConfigs = nuclear@0: glXGetFBConfigs(display, xscreen, &nativeCount); nuclear@0: if (!nativeCount) nuclear@0: { nuclear@0: OVR::LogError("[SDKWindow] No valid frame buffer configurations found."); nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: FBConfig* usables = static_cast(calloc(nativeCount, sizeof(FBConfig))); nuclear@0: int numUsables = 0; nuclear@0: nuclear@0: for (int i = 0; i < nativeCount; ++i) nuclear@0: { nuclear@0: GLXFBConfig native = nativeConfigs[i]; nuclear@0: FBConfig* usable = &usables[numUsables]; nuclear@0: int v = 0; nuclear@0: nuclear@0: // Only frame buffer configcs with attached visuals. nuclear@0: glXGetFBConfigAttrib(display, native, GLX_VISUAL_ID, &v); nuclear@0: if (!v) { continue; } nuclear@0: nuclear@0: // Only RGBA frame buffers. nuclear@0: glXGetFBConfigAttrib(display, native, GLX_RENDER_TYPE, &v); nuclear@0: if (!(v & GLX_RGBA_BIT)) { continue; } nuclear@0: nuclear@0: glXGetFBConfigAttrib(display, native, GLX_DRAWABLE_TYPE, &v); nuclear@0: if (!(v & GLX_WINDOW_BIT)) { continue; } nuclear@0: nuclear@0: glXGetFBConfigAttrib(display, native, GLX_DEPTH_SIZE, &usable->depthBits); nuclear@0: glXGetFBConfigAttrib(display, native, GLX_STENCIL_SIZE, &usable->stencilBits); nuclear@0: nuclear@0: glXGetFBConfigAttrib(display, native, GLX_RED_SIZE, &usable->redBits); nuclear@0: glXGetFBConfigAttrib(display, native, GLX_GREEN_SIZE, &usable->greenBits); nuclear@0: glXGetFBConfigAttrib(display, native, GLX_BLUE_SIZE, &usable->blueBits); nuclear@0: glXGetFBConfigAttrib(display, native, GLX_ALPHA_SIZE, &usable->alphaBits); nuclear@0: nuclear@0: glXGetFBConfigAttrib(display, native, GLX_ALPHA_SIZE, &usable->auxBuffers); nuclear@0: nuclear@0: glXGetFBConfigAttrib(display, native, GLX_DOUBLEBUFFER, &v); nuclear@0: usable->doubleBuffer = v ? true : false; nuclear@0: nuclear@0: glXGetFBConfigAttrib(display, native, GLX_FBCONFIG_ID, &usable->xcfg); nuclear@0: nuclear@0: ++numUsables; nuclear@0: } nuclear@0: nuclear@0: // We really want std::numeric_limits::max() instead of hardcoded vals. nuclear@0: const int MostMissing = 100; nuclear@0: int leastMissing = MostMissing; nuclear@0: int leastBias = MostMissing; nuclear@0: nuclear@0: const FBConfig* closest = NULL; nuclear@0: nuclear@0: // Desired is currently the default config built by constructor. nuclear@0: FBConfig desired; nuclear@0: nuclear@0: for (int i = 0; i < numUsables; ++i) nuclear@0: { nuclear@0: const FBConfig* cur = &usables[i]; nuclear@0: nuclear@0: if (desired.doubleBuffer != cur->doubleBuffer) { continue; } nuclear@0: nuclear@0: int missing = 0; nuclear@0: if (desired.alphaBits > 0 && cur->alphaBits == 0) { ++missing; } nuclear@0: if (desired.depthBits > 0 && cur->depthBits == 0) { ++missing; } nuclear@0: if (desired.stencilBits > 0 && cur->stencilBits == 0) { ++missing; } nuclear@0: if (desired.redBits > 0 && desired.redBits != cur->redBits) { ++missing; } nuclear@0: if (desired.greenBits > 0 && desired.greenBits != cur->greenBits) { ++missing; } nuclear@0: if (desired.blueBits > 0 && desired.blueBits != cur->blueBits) { ++missing; } nuclear@0: nuclear@0: int bias = fbCalcContrib(desired.redBits, cur->redBits) nuclear@0: + fbCalcContrib(desired.greenBits, cur->greenBits) nuclear@0: + fbCalcContrib(desired.blueBits, cur->blueBits) nuclear@0: + fbCalcContrib(desired.alphaBits, cur->alphaBits) nuclear@0: + fbCalcContrib(desired.depthBits, cur->depthBits) nuclear@0: + fbCalcContrib(desired.stencilBits, cur->stencilBits); nuclear@0: nuclear@0: if (missing < leastMissing) nuclear@0: { nuclear@0: closest = cur; nuclear@0: } nuclear@0: else if (missing == leastMissing) nuclear@0: { nuclear@0: // Now select against squared differences. nuclear@0: if (bias < leastBias) nuclear@0: { nuclear@0: closest = cur; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: if (closest == cur) nuclear@0: { nuclear@0: leastMissing = missing; nuclear@0: leastBias = bias; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: if (closest == NULL) nuclear@0: { nuclear@0: OVR::LogError("[SDKWindow] Failed to select appropriate frame buffer."); nuclear@0: XFree(nativeConfigs); nuclear@0: free(usables); nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: int retVal = closest->xcfg; nuclear@0: nuclear@0: XFree(nativeConfigs); nuclear@0: free(usables); nuclear@0: nuclear@0: return retVal; nuclear@0: } nuclear@0: nuclear@0: // Obtain visual from frame buffer configuration ID. nuclear@0: XVisualInfo* SDKWindow::getVisual(struct _XDisplay* display, nuclear@0: int fbConfigID, int xscreen) nuclear@0: { nuclear@0: GLXFBConfig* cfg = getGLXFBConfig(display, fbConfigID, xscreen); nuclear@0: XVisualInfo* viOut = NULL; nuclear@0: if (cfg != NULL) nuclear@0: { nuclear@0: viOut = glXGetVisualFromFBConfig(display, *cfg); nuclear@0: XFree(cfg); nuclear@0: cfg = NULL; nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: OVR::LogError("Unable to find fb config ID."); nuclear@0: } nuclear@0: return viOut; nuclear@0: } nuclear@0: nuclear@0: // GLXFBConfig pointer from frame buffer configuration ID. You must call nuclear@0: // XFree on the GLXFBConfig pointer. nuclear@0: GLXFBConfig* SDKWindow::getGLXFBConfig(struct _XDisplay* display, nuclear@0: int fbConfigID, int xscreen) nuclear@0: { nuclear@0: const int attribs[] = {GLX_FBCONFIG_ID, (int)fbConfigID, None}; nuclear@0: int numElems; nuclear@0: nuclear@0: GLXFBConfig* config = glXChooseFBConfig(display, xscreen, attribs, &numElems); nuclear@0: if (numElems > 0) nuclear@0: { nuclear@0: return config; nuclear@0: } nuclear@0: else nuclear@0: { nuclear@0: return NULL; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: nuclear@0: static int gXLastError = -1; nuclear@0: static int handleXError(struct _XDisplay* display, XErrorEvent* event) nuclear@0: { nuclear@0: OVR_UNUSED(display); nuclear@0: gXLastError = event->error_code; nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: static void obtainXErrorHandler() nuclear@0: { nuclear@0: gXLastError = Success; nuclear@0: XSetErrorHandler(handleXError); nuclear@0: } nuclear@0: nuclear@0: static void releaseXErrorHandler(struct _XDisplay* display) nuclear@0: { nuclear@0: XSync(display, False); nuclear@0: XSetErrorHandler(NULL); nuclear@0: } nuclear@0: nuclear@0: // Returns 0 on error, otherwise a valid X window is returned. nuclear@0: static Window constructWindow(struct _XDisplay* xDisp, int xScreen, nuclear@0: XVisualInfo* xVisual, nuclear@0: const LinuxDeviceScreen& devScreen) nuclear@0: { nuclear@0: XSetWindowAttributes wa; nuclear@0: nuclear@0: Window root = XRootWindow(xDisp, xScreen); nuclear@0: Window xWindowOut = 0; nuclear@0: nuclear@0: // Create Window nuclear@0: { nuclear@0: Colormap xWinColorMapOut = XCreateColormap( nuclear@0: xDisp, root, xVisual->visual, AllocNone); nuclear@0: unsigned long wamask = CWBorderPixel | CWColormap | CWEventMask; nuclear@0: nuclear@0: wa.colormap = xWinColorMapOut; nuclear@0: wa.border_pixel = 0; nuclear@0: wa.event_mask = StructureNotifyMask | ExposureMask | FocusChangeMask nuclear@0: | VisibilityChangeMask | EnterWindowMask | LeaveWindowMask nuclear@0: | PropertyChangeMask; nuclear@0: nuclear@0: obtainXErrorHandler(); nuclear@0: nuclear@0: xWindowOut = XCreateWindow(xDisp, root, nuclear@0: 0, 0, nuclear@0: devScreen.width, devScreen.height, nuclear@0: 0, nuclear@0: xVisual->depth, nuclear@0: InputOutput, nuclear@0: xVisual->visual, nuclear@0: wamask, nuclear@0: &wa); nuclear@0: nuclear@0: releaseXErrorHandler(xDisp); nuclear@0: nuclear@0: if (!xWindowOut) nuclear@0: { nuclear@0: OVR::LogError("[SDKWindow] Failed to create SDK window."); nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: XFreeColormap(xDisp, xWinColorMapOut); nuclear@0: } nuclear@0: nuclear@0: // OVERRIDE REDIRECT. nuclear@0: XSetWindowAttributes attributes; nuclear@0: attributes.override_redirect = True; nuclear@0: XChangeWindowAttributes(xDisp, xWindowOut, nuclear@0: CWOverrideRedirect, &attributes); nuclear@0: nuclear@0: // Show the window (do this in full screen or windowed). nuclear@0: XMapRaised(xDisp, xWindowOut); nuclear@0: XFlush(xDisp); nuclear@0: nuclear@0: // Position ourselves manually since there should be no WM managing us. nuclear@0: XRaiseWindow(xDisp, xWindowOut); nuclear@0: XMoveWindow(xDisp, xWindowOut, devScreen.offsetX, devScreen.offsetY); nuclear@0: XResizeWindow(xDisp, xWindowOut, devScreen.width, devScreen.height); nuclear@0: nuclear@0: XFlush(xDisp); nuclear@0: nuclear@0: // WM Backup in case there still exists a WM managing us... nuclear@0: Atom NET_WM_BYPASS_COMPOSITOR = nuclear@0: XInternAtom(xDisp, "_NET_WM_BYPASS_COMPOSITOR", False); nuclear@0: Atom NET_WM_STATE = nuclear@0: XInternAtom(xDisp, "_NET_WM_STATE", False); nuclear@0: Atom NET_WM_STATE_FULLSCREEN = nuclear@0: XInternAtom(xDisp, "_NET_WM_STATE_FULLSCREEN", False); nuclear@0: Atom NET_ACTIVE_WINDOW = nuclear@0: XInternAtom(xDisp, "_NET_ACTIVE_WINDOW", False); nuclear@0: nuclear@0: // Bypass compositor if we are under a compositing WM. nuclear@0: // Just in case a WM ignores our override_redirect. nuclear@0: if (NET_WM_BYPASS_COMPOSITOR) nuclear@0: { nuclear@0: const unsigned long bypass = 1; nuclear@0: XChangeProperty(xDisp, xWindowOut, nuclear@0: NET_WM_BYPASS_COMPOSITOR, nuclear@0: XA_CARDINAL, 32, PropModeReplace, nuclear@0: (unsigned char*)&bypass, 1); nuclear@0: } nuclear@0: nuclear@0: if (NET_WM_STATE && NET_WM_STATE_FULLSCREEN) nuclear@0: { nuclear@0: // BACKUP: If we are still managed by a WM we want fullscreen. nuclear@0: const int EWMH_STATE_ADD = 1; nuclear@0: nuclear@0: if (NET_ACTIVE_WINDOW) nuclear@0: { nuclear@0: XEvent event; nuclear@0: memset(&event, 0, sizeof(event)); nuclear@0: nuclear@0: event.type = ClientMessage; nuclear@0: event.xclient.window = xWindowOut; nuclear@0: event.xclient.format = 32; nuclear@0: event.xclient.message_type = NET_ACTIVE_WINDOW; nuclear@0: event.xclient.data.l[0] = 1; nuclear@0: event.xclient.data.l[1] = 0; nuclear@0: nuclear@0: XSendEvent(xDisp, root, False, nuclear@0: SubstructureNotifyMask | SubstructureRedirectMask, nuclear@0: &event); nuclear@0: } nuclear@0: nuclear@0: XEvent event; nuclear@0: memset(&event, 0, sizeof(event)); nuclear@0: nuclear@0: event.type = ClientMessage; nuclear@0: event.xclient.window = xWindowOut; nuclear@0: event.xclient.format = 32; nuclear@0: event.xclient.message_type = NET_WM_STATE; nuclear@0: event.xclient.data.l[0] = EWMH_STATE_ADD; nuclear@0: event.xclient.data.l[1] = NET_WM_STATE_FULLSCREEN; nuclear@0: event.xclient.data.l[2] = 0; nuclear@0: event.xclient.data.l[3] = 1; nuclear@0: nuclear@0: XSendEvent(xDisp, root, False, nuclear@0: SubstructureNotifyMask | SubstructureRedirectMask, nuclear@0: &event); nuclear@0: } nuclear@0: nuclear@0: return xWindowOut; nuclear@0: } nuclear@0: nuclear@0: } // namespace OVR nuclear@0: