Use XRRSetCrtcConfig instead of XRRSetScreenConfig, in order to fix issue #1226. It should also fix issue #1224.

This commit is contained in:
Bloodsword 2017-11-01 19:34:45 +01:00 committed by Lukas Dürrenberger
parent 87aaa9e145
commit 46ce05cd9c
2 changed files with 292 additions and 55 deletions

View File

@ -487,6 +487,7 @@ m_inputMethod (NULL),
m_inputContext (NULL),
m_isExternal (true),
m_oldVideoMode (0),
m_oldRRCrtc (0),
m_hiddenCursor (0),
m_lastCursor (None),
m_keyRepeat (true),
@ -535,6 +536,7 @@ m_inputMethod (NULL),
m_inputContext (NULL),
m_isExternal (false),
m_oldVideoMode (0),
m_oldRRCrtc (0),
m_hiddenCursor (0),
m_lastCursor (None),
m_keyRepeat (true),
@ -556,8 +558,17 @@ m_lastInputTime (0)
m_screen = DefaultScreen(m_display);
// Compute position and size
int left = m_fullscreen ? 0 : (DisplayWidth(m_display, m_screen) - mode.width) / 2;
int top = m_fullscreen ? 0 : (DisplayHeight(m_display, m_screen) - mode.height) / 2;
Vector2i windowPosition;
if(m_fullscreen)
{
windowPosition = getPrimaryMonitorPosition();
}
else
{
windowPosition.x = (DisplayWidth(m_display, m_screen) - mode.width) / 2;
windowPosition.y = (DisplayWidth(m_display, m_screen) - mode.height) / 2;
}
int width = mode.width;
int height = mode.height;
@ -572,7 +583,7 @@ m_lastInputTime (0)
m_window = XCreateWindow(m_display,
DefaultRootWindow(m_display),
left, top,
windowPosition.x, windowPosition.y,
width, height,
0,
visualInfo.depth,
@ -669,9 +680,11 @@ m_lastInputTime (0)
{
m_useSizeHints = true;
XSizeHints* sizeHints = XAllocSizeHints();
sizeHints->flags = PMinSize | PMaxSize;
sizeHints->flags = PMinSize | PMaxSize | USPosition;
sizeHints->min_width = sizeHints->max_width = width;
sizeHints->min_height = sizeHints->max_height = height;
sizeHints->x = windowPosition.x;
sizeHints->y = windowPosition.y;
XSetWMNormalHints(m_display, m_window, sizeHints);
XFree(sizeHints);
}
@ -708,7 +721,15 @@ m_lastInputTime (0)
// Set fullscreen video mode and switch to fullscreen if necessary
if (m_fullscreen)
{
setPosition(Vector2i(0, 0));
// Disable hint for min and max size,
// otherwise some windows managers will not remove window decorations
XSizeHints *sizeHints = XAllocSizeHints();
long flags = 0;
XGetWMNormalHints(m_display, m_window, sizeHints, &flags);
sizeHints->flags &= ~(PMinSize | PMaxSize);
XSetWMNormalHints(m_display, m_window, sizeHints);
XFree(sizeHints);
setVideoMode(mode);
switchToFullscreen();
}
@ -1240,53 +1261,99 @@ void WindowImplX11::setVideoMode(const VideoMode& mode)
return;
// Check if the XRandR extension is present
int version;
if (!XQueryExtension(m_display, "RANDR", &version, &version, &version))
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;
}
RROutput output = getOutputPrimary(rootWindow, res, xRandRMajor, xRandRMinor);
// Get output info from output
XRROutputInfo* outputInfo = XRRGetOutputInfo(m_display, res, output);
if (!outputInfo || outputInfo->connection == RR_Disconnected)
{
XRRFreeScreenResources(res);
// If outputInfo->connection == RR_Disconnected, free output info
if (outputInfo)
XRRFreeOutputInfo(outputInfo);
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;
}
}
if (!modeFound)
{
XRRFreeScreenResources(res);
XRRFreeOutputInfo(outputInfo);
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
Rotation currentRotation;
m_oldVideoMode = XRRConfigCurrentConfiguration(config, &currentRotation);
m_oldVideoMode = crtcInfo->mode;
m_oldRRCrtc = outputInfo->crtc;
// Get the available screen sizes
int nbSizes;
XRRScreenSize* sizes = XRRConfigSizes(config, &nbSizes);
// Search for a matching size
for (int i = 0; (sizes && i < nbSizes); ++i)
{
XRRConfigRotations(config, &currentRotation);
if (currentRotation == RR_Rotate_90 || currentRotation == RR_Rotate_270)
std::swap(sizes[i].height, sizes[i].width);
if ((sizes[i].width == static_cast<int>(mode.width)) && (sizes[i].height == static_cast<int>(mode.height)))
{
// Switch to fullscreen mode
XRRSetScreenConfig(m_display, config, RootWindow(m_display, m_screen), i, currentRotation, CurrentTime);
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;
break;
}
}
// Free the configuration instance
XRRFreeScreenConfigInfo(config);
XRRFreeScreenResources(res);
XRRFreeOutputInfo(outputInfo);
XRRFreeCrtcInfo(crtcInfo);
}
@ -1295,19 +1362,55 @@ 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;
}
// Free the configuration instance
XRRFreeScreenConfigInfo(config);
RROutput output;
// if version >= 1.3 get the primary screen else take the first screen
if ((xRandRMajor == 1 && xRandRMinor >= 3) || xRandRMajor > 1)
{
output = XRRGetOutputPrimary(m_display, DefaultRootWindow(m_display));
// Check if returned output is valid, otherwise use the first screen
if (output == None)
output = res->outputs[0];
}
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
@ -1973,6 +2076,106 @@ 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 too old" << std::endl;
return false;
}
return true;
}
////////////////////////////////////////////////////////////
RROutput WindowImplX11::getOutputPrimary(::Window& rootWindow, XRRScreenResources* res, int xRandRMajor, int xRandRMinor)
{
// if xRandR version >= 1.3 get the primary screen else take the first screen
if ((xRandRMajor == 1 && xRandRMinor >= 3) || xRandRMajor > 1)
{
RROutput output = XRRGetOutputPrimary(m_display, rootWindow);
// Check if returned output is valid, otherwise use the first screen
if (output == None)
return res->outputs[0];
else
return output;
}
// xRandr version can't get the primary screen, use the first screen
return res->outputs[0];
}
////////////////////////////////////////////////////////////
Vector2i WindowImplX11::getPrimaryMonitorPosition()
{
Vector2i monitorPosition;
// Get root window
::Window rootWindow = RootWindow(m_display, m_screen);
// Get the screen resources
XRRScreenResources* res = XRRGetScreenResources(m_display, rootWindow);
if (!res)
{
err() << "Failed to get the current screen resources for.primary monitor position" << std::endl;
return monitorPosition;
}
// Get xRandr version
int xRandRMajor, xRandRMinor;
if (!checkXRandR(xRandRMajor, xRandRMinor))
xRandRMajor = xRandRMinor = 0;
RROutput output = getOutputPrimary(rootWindow, res, xRandRMajor, xRandRMinor);
// Get output info from output
XRROutputInfo* outputInfo = XRRGetOutputInfo(m_display, res, output);
if (!outputInfo || outputInfo->connection == RR_Disconnected)
{
XRRFreeScreenResources(res);
// If outputInfo->connection == RR_Disconnected, free output info
if (outputInfo)
XRRFreeOutputInfo(outputInfo);
err() << "Failed to get output info for.primary monitor position" << std::endl;
return monitorPosition;
}
// 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.primary monitor position" << std::endl;
return monitorPosition;
}
monitorPosition.x = crtcInfo->x;
monitorPosition.y = crtcInfo->y;
XRRFreeCrtcInfo(crtcInfo);
XRRFreeOutputInfo(outputInfo);
XRRFreeScreenResources(res);
return monitorPosition;
}
} // namespace priv
} // namespace sf

View File

@ -34,6 +34,7 @@
#include <SFML/Window/WindowStyle.hpp> // Prevent conflict with macro None from Xlib
#include <X11/Xlib.h>
#include <deque>
#include <X11/extensions/Xrandr.h>
namespace sf
@ -264,6 +265,38 @@ private:
////////////////////////////////////////////////////////////
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);
////////////////////////////////////////////////////////////
/// \brief Get the RROutput of the primary monitor
///
/// \param rootWindow the root window
/// \param res screen resources
/// \param xRandRMajor XRandR major version
/// \param xRandRMinor XRandR minor version
///
/// \return RROutput of the primary monitor
///
////////////////////////////////////////////////////////////
RROutput getOutputPrimary(::Window& rootWindow, XRRScreenResources* res, int xRandRMajor, int xRandRMinor);
////////////////////////////////////////////////////////////
/// \brief Get coordinates of the primary monitor
///
/// \return Position of the primary monitor
///
////////////////////////////////////////////////////////////
Vector2i getPrimaryMonitorPosition();
////////////////////////////////////////////////////////////
// Member data
////////////////////////////////////////////////////////////
@ -275,6 +308,7 @@ private:
std::deque<XEvent> m_events; ///< Queue we use to store pending events for this 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
RRCrtc m_oldRRCrtc; ///< RRCrtc in use before we switch to fullscreen
::Cursor m_hiddenCursor; ///< As X11 doesn't provide cursor hiding, we must create a transparent one
::Cursor m_lastCursor; ///< Last cursor used -- this data is not owned by the window and is required to be always valid
bool m_keyRepeat; ///< Is the KeyRepeat feature enabled?