From 47146017ae9d2295a65d0a2890ac0d0c512d0b93 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Mon, 20 Jun 2011 09:22:57 +0000 Subject: [PATCH] Introduced a workaround for fullscreen toggle issues under modern X11 window managers. --- src/osgViewer/GraphicsWindowX11.cpp | 161 ++++++++++++++++++---------- 1 file changed, 104 insertions(+), 57 deletions(-) diff --git a/src/osgViewer/GraphicsWindowX11.cpp b/src/osgViewer/GraphicsWindowX11.cpp index c95b2f399..59b23b300 100644 --- a/src/osgViewer/GraphicsWindowX11.cpp +++ b/src/osgViewer/GraphicsWindowX11.cpp @@ -18,7 +18,6 @@ // TODO: // implement http://www.opengl.org/registry/specs/OML/glx_swap_method.txt -// Fix toggling of fullscreen to window mode as it does enable window decoration with recent linux window managers #include #include @@ -360,6 +359,45 @@ bool GraphicsWindowX11::createVisualInfo() return _visualInfo != 0; } + +bool GraphicsWindowX11::checkAndSendEventFullScreenIfNeeded(Display* display, int x, int y, int width, int height, bool windowDecoration) +{ + osg::GraphicsContext::WindowingSystemInterface *wsi = osg::GraphicsContext::getWindowingSystemInterface(); + if (wsi == NULL) + { + OSG_NOTICE << "Error, no WindowSystemInterface available, cannot toggle window fullscreen." << std::endl; + return false; + } + + unsigned int screenWidth; + unsigned int screenHeight; + + wsi->getScreenResolution(*_traits, screenWidth, screenHeight); + bool isFullScreen = x == 0 && y == 0 && width == (int)screenWidth && height == (int)screenHeight && !windowDecoration; + + Atom netWMStateAtom = XInternAtom(display, "_NET_WM_STATE", True); + Atom netWMStateFullscreenAtom = XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", True); + + if (netWMStateAtom != None && netWMStateFullscreenAtom != None) + { + XEvent xev; + xev.xclient.type = ClientMessage; + xev.xclient.serial = 0; + xev.xclient.send_event = True; + xev.xclient.window = _window; + xev.xclient.message_type = netWMStateAtom; + xev.xclient.format = 32; + xev.xclient.data.l[0] = isFullScreen ? 1 : 0; + xev.xclient.data.l[1] = netWMStateFullscreenAtom; + xev.xclient.data.l[2] = 0; + + XSendEvent(display, RootWindow(display, DefaultScreen(display)), + False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); + return true; + } + return false; +} + #define MWM_HINTS_FUNCTIONS (1L << 0) #define MWM_HINTS_DECORATIONS (1L << 1) #define MWM_HINTS_INPUT_MODE (1L << 2) @@ -380,44 +418,6 @@ bool GraphicsWindowX11::createVisualInfo() #define MWM_FUNC_MAXIMIZE (1L<<4) #define MWM_FUNC_CLOSE (1L<<5) - -bool GraphicsWindowX11::checkAndSendEventFullScreenIfNeeded(Display* display, int x, int y, int width, int height, bool windowDecoration) -{ - osg::GraphicsContext::WindowingSystemInterface *wsi = osg::GraphicsContext::getWindowingSystemInterface(); - if (wsi == NULL) { - OSG_NOTICE << "Error, no WindowSystemInterface available, cannot toggle window fullscreen." << std::endl; - return false; - } - - unsigned int screenWidth; - unsigned int screenHeight; - - wsi->getScreenResolution(*_traits, screenWidth, screenHeight); - bool isFullScreen = x == 0 && y == 0 && width == (int)screenWidth && height == (int)screenHeight && !windowDecoration; - - Atom netWMStateAtom = XInternAtom(display, "_NET_WM_STATE", True); - Atom netWMStateFullscreenAtom = XInternAtom(display, - "_NET_WM_STATE_FULLSCREEN", True); - - if (netWMStateAtom != None && netWMStateFullscreenAtom != None) { - XEvent xev; - xev.xclient.type = ClientMessage; - xev.xclient.serial = 0; - xev.xclient.send_event = True; - xev.xclient.window = _window; - xev.xclient.message_type = netWMStateAtom; - xev.xclient.format = 32; - xev.xclient.data.l[0] = isFullScreen ? 1 : 0; - xev.xclient.data.l[1] = netWMStateFullscreenAtom; - xev.xclient.data.l[2] = 0; - - XSendEvent(display, RootWindow(display, DefaultScreen(display)), - False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); - return true; - } - return false; -} - bool GraphicsWindowX11::setWindowDecorationImplementation(bool flag) { Display* display = getDisplayToUse(); @@ -439,28 +439,34 @@ bool GraphicsWindowX11::setWindowDecorationImplementation(bool flag) if( (atom = XInternAtom( display, "_MOTIF_WM_HINTS", 0 )) != None ) { - wmHints.flags = 0; - wmHints.functions = MWM_FUNC_ALL; - wmHints.decorations = MWM_DECOR_ALL; - wmHints.inputMode = 0; - wmHints.status = 0; - - if (!flag) + if (flag) { - wmHints.flags = MWM_HINTS_DECORATIONS; - wmHints.decorations = 0; + wmHints.flags = MWM_HINTS_DECORATIONS | MWM_HINTS_FUNCTIONS; + wmHints.functions = MWM_FUNC_ALL; + wmHints.decorations = MWM_DECOR_ALL; + wmHints.inputMode = 0; + wmHints.status = 0; + + // if traits says not resize we want to set the functions to exlude MWM_FUNC_RESIZE, + // but this bitmask needs to be set if the MWM_FUNC_ALL bit is already set in order to toggle it off. + if (_traits.valid() && !_traits->supportsResize) wmHints.functions = wmHints.functions | MWM_FUNC_RESIZE; + } else { - wmHints.flags |= MWM_HINTS_FUNCTIONS; - if (_traits.valid() && !_traits->supportsResize) wmHints.functions |= MWM_FUNC_RESIZE; + wmHints.flags = MWM_HINTS_DECORATIONS; + wmHints.functions = 0; + wmHints.decorations = 0; + wmHints.inputMode = 0; + wmHints.status = 0; } + XChangeProperty( display, _window, atom, atom, 32, PropModeReplace, (unsigned char *)&wmHints, 5 ); result = true; } else { - OSG_NOTICE<<"Error: GraphicsWindowX11::setBorder(" << flag << ") - couldn't change decorations." << std::endl; + OSG_NOTICE<<"Error: GraphicsWindowX11::setWindowDecorationImplementation(" << flag << ") - couldn't change decorations." << std::endl; result = false; } @@ -479,13 +485,13 @@ bool GraphicsWindowX11::setWindowRectangleImplementation(int x, int y, int width Display* display = getDisplayToUse(); + checkAndSendEventFullScreenIfNeeded(display, x, y, width, height, _traits->windowDecoration); + XMoveResizeWindow(display, _window, x, y, width, height); XFlush(display); XSync(display, 0); - - checkAndSendEventFullScreenIfNeeded(display, x, y, width, height, _traits->windowDecoration); - + // add usleep here to give window manager a chance to handle the request, if // we don't add this sleep then any X11 calls right afterwards can produce // X11 errors. @@ -854,10 +860,51 @@ bool GraphicsWindowX11::createWindow() OSG_INFO<<"Setting override redirect"<x; + int y = _traits->y; + int width = _traits->width; + int height = _traits->height; + + + unsigned int screenWidth; + unsigned int screenHeight; + wsi->getScreenResolution(*_traits, screenWidth, screenHeight); + + bool isFullScreen = x == 0 && y == 0 && width == (int)screenWidth && height == (int)screenHeight && !_traits->windowDecoration; + if (isFullScreen) + { + // follows is hack to get around problems with toggling off full screen with modern X11 window + // managers that try to be too clever when toggling off full screen and ignore the window size + // calls made by the OSG when the initial window size is full screen. + + Atom netWMStateAtom = XInternAtom(_display, "_NET_WM_STATE", True); + Atom netWMStateFullscreenAtom = XInternAtom(_display, "_NET_WM_STATE_FULLSCREEN", True); + + // we have a modern X11 server so assume we need the do the full screen hack. + if (netWMStateAtom != None && netWMStateFullscreenAtom != None) + { + // artifically reduce the initial window size so that the windowing + // system has a size to go back to when toggling off full screen, + // we don't have to worry about the window being initially smaller as the + // setWindowDecoration(..) implementation with enable full screen for us + x = width/4; + y = height/4; + width /= 2; + height /= 2; + } + } + _window = XCreateWindow( _display, _parent, - _traits->x, - _traits->y, - _traits->width, _traits->height, 0, + x, + y, + width, height, 0, _visualInfo->depth, InputOutput, _visualInfo->visual, mask, &swatt );