Skip to content

Commit

Permalink
Use XRRSetCrtcConfig instead of XRRSetScreenConfig, in order to fix i…
Browse files Browse the repository at this point in the history
…ssue #1226.
  • Loading branch information
bloodsword committed Jun 12, 2017
1 parent c43b599 commit 24cf017
Show file tree
Hide file tree
Showing 2 changed files with 177 additions and 48 deletions.
209 changes: 162 additions & 47 deletions src/SFML/Window/Unix/WindowImplX11.cpp
Expand Up @@ -157,7 +157,7 @@ namespace

if (result != Success || actualType != XA_WINDOW || numItems != 1)
{
if(result == Success)
if (result == Success)
XFree(data);

sf::priv::CloseDisplay(display);
Expand Down Expand Up @@ -189,7 +189,7 @@ namespace

if (result != Success || actualType != XA_WINDOW || numItems != 1)
{
if(result == Success)
if (result == Success)
XFree(data);

sf::priv::CloseDisplay(display);
Expand Down Expand Up @@ -253,7 +253,7 @@ namespace
windowManagerName = sf::String::fromUtf8(begin, end);
}

if(result == Success)
if (result == Success)
XFree(data);

sf::priv::CloseDisplay(display);
Expand Down Expand Up @@ -386,6 +386,7 @@ m_inputMethod (NULL),
m_inputContext (NULL),
m_isExternal (true),
m_oldVideoMode (0),
m_oldRRCrtc (0),
m_hiddenCursor (0),
m_keyRepeat (true),
m_previousSize (-1, -1),
Expand Down Expand Up @@ -433,6 +434,7 @@ m_inputMethod (NULL),
m_inputContext (NULL),
m_isExternal (false),
m_oldVideoMode (0),
m_oldRRCrtc (0),
m_hiddenCursor (0),
m_keyRepeat (true),
m_previousSize (-1, -1),
Expand Down Expand Up @@ -619,11 +621,11 @@ WindowImplX11::~WindowImplX11()
cleanup();

// Destroy icon pixmap
if(m_iconPixmap)
if (m_iconPixmap)
XFreePixmap(m_display, m_iconPixmap);

// Destroy icon mask pixmap
if(m_iconMaskPixmap)
if (m_iconMaskPixmap)
XFreePixmap(m_display, m_iconMaskPixmap);

// Destroy the cursor
Expand Down Expand Up @@ -793,10 +795,10 @@ void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8
return;
}

if(m_iconPixmap)
if (m_iconPixmap)
XFreePixmap(m_display, m_iconPixmap);

if(m_iconMaskPixmap)
if (m_iconMaskPixmap)
XFreePixmap(m_display, m_iconMaskPixmap);

m_iconPixmap = XCreatePixmap(m_display, RootWindow(m_display, m_screen), width, height, defDepth);
Expand Down Expand Up @@ -1061,54 +1063,112 @@ void WindowImplX11::setVideoMode(const VideoMode& mode)
if (mode == VideoMode::getDesktopMode())
return;

// Check if the XRandR extension is present
int version;
if (!XQueryExtension(m_display, "RANDR", &version, &version, &version))
// Check if the XRandR extension
int xRandRMajor, xRandRMinor;
if (!checkXRandR(xRandRMajor, xRandRMinor))
{
// XRandR extension is not supported: we cannot use fullscreen mode
err() << "Fullscreen is not supported, switching to window mode" << std::endl;
return;
}

// Get the current configuration
XRRScreenConfiguration* config = XRRGetScreenInfo(m_display, RootWindow(m_display, m_screen));
// Get root window
::Window rootWindow = RootWindow(m_display, m_screen);

if (!config)
// Get the screen resources
XRRScreenResources* res = XRRGetScreenResources(m_display, rootWindow);
if (!res)
{
// Failed to get the screen configuration
err() << "Failed to get the current screen configuration for fullscreen mode, switching to window mode" << std::endl;
err() << "Failed to get the current screen resources for fullscreen mode, switching to window mode" << std::endl;
return;
}

// Save the current video mode before we switch to fullscreen
Rotation currentRotation;
m_oldVideoMode = XRRConfigCurrentConfiguration(config, &currentRotation);

// Get the available screen sizes
int nbSizes;
XRRScreenSize* sizes = XRRConfigSizes(config, &nbSizes);
// If version > 1.2 get the primary screen else take the first screen
RROutput output;
if ((xRandRMajor == 1 && xRandRMinor >= 3) || xRandRMajor > 1)
{
output = XRRGetOutputPrimary(m_display, rootWindow);

// Search for a matching size
for (int i = 0; (sizes && i < nbSizes); ++i)
// Check if output return is valid, otherwise use the first screen
if (output == None)
output = res->outputs[0];
}
else
{
XRRConfigRotations(config, &currentRotation);
output = res->outputs[0];
}

if (currentRotation == RR_Rotate_90 || currentRotation == RR_Rotate_270)
std::swap(sizes[i].height, sizes[i].width);
// Get output info from output
XRROutputInfo* outputInfo = XRRGetOutputInfo(m_display, res, output);
if (!outputInfo || outputInfo->connection == RR_Disconnected)
{
XRRFreeScreenResources(res);

if ((sizes[i].width == static_cast<int>(mode.width)) && (sizes[i].height == static_cast<int>(mode.height)))
// If outputInfo->connection == RR_Disconnected, free output info
if (!outputInfo)
{
// Switch to fullscreen mode
XRRSetScreenConfig(m_display, config, RootWindow(m_display, m_screen), i, currentRotation, CurrentTime);
XRRFreeOutputInfo(outputInfo);
}

// Set "this" as the current fullscreen window
fullscreenWindow = this;
break;
err() << "Failed to get output info for fullscreen mode, switching to window mode" << std::endl;
return;
}

// Retreive current RRMode, screen position and rotation
XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(m_display, res, outputInfo->crtc);
if (!crtcInfo)
{
XRRFreeScreenResources(res);
XRRFreeOutputInfo(outputInfo);
err() << "Failed to get crtc info for fullscreen mode, switching to window mode" << std::endl;
return;
}

// Find RRMode to set
bool modeFound = false;
RRMode xRandMode;

for (int i = 0; (i < res->nmode) && !modeFound; i++)
{
if (crtcInfo->rotation == RR_Rotate_90 || crtcInfo->rotation == RR_Rotate_270)
std::swap(res->modes[i].height, res->modes[i].width);

// Check if screen size match
if (res->modes[i].width == static_cast<int>(mode.width) &&
res->modes[i].height == static_cast<int>(mode.height))
{
xRandMode = res->modes[i].id;
modeFound = true;
}
}

// Free the configuration instance
XRRFreeScreenConfigInfo(config);
if (!modeFound)
{
err() << "Failed to find a matching RRMode for fullscreen mode, switching to window mode" << std::endl;
return;
}

// Save the current video mode before we switch to fullscreen
m_oldVideoMode = crtcInfo->mode;
m_oldRRCrtc = outputInfo->crtc;

// Switch to fullscreen mode
XRRSetCrtcConfig(m_display,
res,
outputInfo->crtc,
CurrentTime,
crtcInfo->x,
crtcInfo->y,
xRandMode,
crtcInfo->rotation,
&output,
1);

// Set "this" as the current fullscreen window
fullscreenWindow = this;

XRRFreeScreenResources(res);
XRRFreeOutputInfo(outputInfo);
XRRFreeCrtcInfo(crtcInfo);
}


Expand All @@ -1117,19 +1177,52 @@ void WindowImplX11::resetVideoMode()
{
if (fullscreenWindow == this)
{
// Get current screen info
XRRScreenConfiguration* config = XRRGetScreenInfo(m_display, RootWindow(m_display, m_screen));
if (config)
// Try to set old configuration
// Check if the XRandR extension
int xRandRMajor, xRandRMinor;
if (checkXRandR(xRandRMajor, xRandRMinor))
{
// Get the current rotation
Rotation currentRotation;
XRRConfigCurrentConfiguration(config, &currentRotation);
XRRScreenResources* res = XRRGetScreenResources(m_display, DefaultRootWindow(m_display));
if (!res)
{
err() << "Failed to get the current screen resources to reset the video mode" << std::endl;
return;
}

// Reset the video mode
XRRSetScreenConfig(m_display, config, RootWindow(m_display, m_screen), m_oldVideoMode, currentRotation, CurrentTime);
// Retreive current screen position and rotation
XRRCrtcInfo* crtcInfo = XRRGetCrtcInfo(m_display, res, m_oldRRCrtc);
if (!crtcInfo)
{
XRRFreeScreenResources(res);
err() << "Failed to get crtc info to reset the video mode" << std::endl;
return;
}

RROutput output;

// Free the configuration instance
XRRFreeScreenConfigInfo(config);
// If version > 1.2 get the primary screen else take the first screen
if ((xRandRMajor == 1 && xRandRMinor >= 3) || xRandRMajor > 1)
{
output = XRRGetOutputPrimary(m_display, DefaultRootWindow(m_display));
}
else
{
output = res->outputs[0];
}

XRRSetCrtcConfig(m_display,
res,
m_oldRRCrtc,
CurrentTime,
crtcInfo->x,
crtcInfo->y,
m_oldVideoMode,
crtcInfo->rotation,
&output,
1);

XRRFreeCrtcInfo(crtcInfo);
XRRFreeScreenResources(res);
}

// Reset the fullscreen window
Expand Down Expand Up @@ -1325,7 +1418,7 @@ void WindowImplX11::updateLastInputTime(::Time time)
{
Atom netWmUserTime = getAtom("_NET_WM_USER_TIME", true);

if(netWmUserTime)
if (netWmUserTime)
{
XChangeProperty(m_display,
m_window,
Expand Down Expand Up @@ -1801,6 +1894,28 @@ bool WindowImplX11::processEvent(XEvent& windowEvent)
return true;
}


////////////////////////////////////////////////////////////
bool WindowImplX11::checkXRandR(int& xRandRMajor, int& xRandRMinor)
{
// Check if the XRandR extension is present
int version;
if (!XQueryExtension(m_display, "RANDR", &version, &version, &version))
{
err() << "XRandR extension is not supported" << std::endl;
return false;
}

// Check XRandR version, 1.2 required
if (!XRRQueryVersion(m_display, &xRandRMajor, &xRandRMinor) || xRandRMajor < 1 || (xRandRMajor == 1 && xRandRMinor < 2 ))
{
err() << "XRandR is to old" << std::endl;
return false;
}

return true;
}

} // namespace priv

} // namespace sf
16 changes: 15 additions & 1 deletion src/SFML/Window/Unix/WindowImplX11.hpp
Expand Up @@ -33,6 +33,7 @@
#include <SFML/System/String.hpp>
#include <X11/Xlib.h>
#include <deque>
#include <X11/extensions/Xrandr.h>


namespace sf
Expand Down Expand Up @@ -255,6 +256,18 @@ class WindowImplX11 : public WindowImpl
////////////////////////////////////////////////////////////
bool processEvent(XEvent& windowEvent);

////////////////////////////////////////////////////////////
/// \brief Check if a valid version of XRandR extension is present
///
/// \param xRandRMajor XRandR major version
///
/// \param xRandRMinor XRandR minor version
///
/// \return True if a valid XRandR version found, false otherwise
///
////////////////////////////////////////////////////////////
bool checkXRandR(int& xRandRMajor, int& xRandRMinor);

////////////////////////////////////////////////////////////
// Member data
////////////////////////////////////////////////////////////
Expand All @@ -264,7 +277,8 @@ class WindowImplX11 : public WindowImpl
XIM m_inputMethod; ///< Input method linked to the X display
XIC m_inputContext; ///< Input context used to get unicode input in our window
bool m_isExternal; ///< Tell whether the window has been created externally or by SFML
int m_oldVideoMode; ///< Video mode in use before we switch to fullscreen
RRMode m_oldVideoMode; ///< Video mode in use before we switch to fullscreen
RRCrtc m_oldRRCrtc; ///< RRCrtc in use before we switch to fullscreen
Cursor m_hiddenCursor; ///< As X11 doesn't provide cursor hidding, we must create a transparent one
bool m_keyRepeat; ///< Is the KeyRepeat feature enabled?
Vector2i m_previousSize; ///< Previous size of the window, to find if a ConfigureNotify event is a resize event (could be a move event only)
Expand Down

0 comments on commit 24cf017

Please sign in to comment.