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

@ -174,7 +174,7 @@ namespace
if (result != Success || actualType != XA_WINDOW || numItems != 1) if (result != Success || actualType != XA_WINDOW || numItems != 1)
{ {
if(result == Success) if (result == Success)
XFree(data); XFree(data);
sf::priv::CloseDisplay(display); sf::priv::CloseDisplay(display);
@ -206,7 +206,7 @@ namespace
if (result != Success || actualType != XA_WINDOW || numItems != 1) if (result != Success || actualType != XA_WINDOW || numItems != 1)
{ {
if(result == Success) if (result == Success)
XFree(data); XFree(data);
sf::priv::CloseDisplay(display); sf::priv::CloseDisplay(display);
@ -270,7 +270,7 @@ namespace
windowManagerName = sf::String::fromUtf8(begin, end); windowManagerName = sf::String::fromUtf8(begin, end);
} }
if(result == Success) if (result == Success)
XFree(data); XFree(data);
sf::priv::CloseDisplay(display); sf::priv::CloseDisplay(display);
@ -487,6 +487,7 @@ m_inputMethod (NULL),
m_inputContext (NULL), m_inputContext (NULL),
m_isExternal (true), m_isExternal (true),
m_oldVideoMode (0), m_oldVideoMode (0),
m_oldRRCrtc (0),
m_hiddenCursor (0), m_hiddenCursor (0),
m_lastCursor (None), m_lastCursor (None),
m_keyRepeat (true), m_keyRepeat (true),
@ -535,6 +536,7 @@ m_inputMethod (NULL),
m_inputContext (NULL), m_inputContext (NULL),
m_isExternal (false), m_isExternal (false),
m_oldVideoMode (0), m_oldVideoMode (0),
m_oldRRCrtc (0),
m_hiddenCursor (0), m_hiddenCursor (0),
m_lastCursor (None), m_lastCursor (None),
m_keyRepeat (true), m_keyRepeat (true),
@ -556,8 +558,17 @@ m_lastInputTime (0)
m_screen = DefaultScreen(m_display); m_screen = DefaultScreen(m_display);
// Compute position and size // Compute position and size
int left = m_fullscreen ? 0 : (DisplayWidth(m_display, m_screen) - mode.width) / 2; Vector2i windowPosition;
int top = m_fullscreen ? 0 : (DisplayHeight(m_display, m_screen) - mode.height) / 2; 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 width = mode.width;
int height = mode.height; int height = mode.height;
@ -572,7 +583,7 @@ m_lastInputTime (0)
m_window = XCreateWindow(m_display, m_window = XCreateWindow(m_display,
DefaultRootWindow(m_display), DefaultRootWindow(m_display),
left, top, windowPosition.x, windowPosition.y,
width, height, width, height,
0, 0,
visualInfo.depth, visualInfo.depth,
@ -669,9 +680,11 @@ m_lastInputTime (0)
{ {
m_useSizeHints = true; m_useSizeHints = true;
XSizeHints* sizeHints = XAllocSizeHints(); XSizeHints* sizeHints = XAllocSizeHints();
sizeHints->flags = PMinSize | PMaxSize; sizeHints->flags = PMinSize | PMaxSize | USPosition;
sizeHints->min_width = sizeHints->max_width = width; sizeHints->min_width = sizeHints->max_width = width;
sizeHints->min_height = sizeHints->max_height = height; sizeHints->min_height = sizeHints->max_height = height;
sizeHints->x = windowPosition.x;
sizeHints->y = windowPosition.y;
XSetWMNormalHints(m_display, m_window, sizeHints); XSetWMNormalHints(m_display, m_window, sizeHints);
XFree(sizeHints); XFree(sizeHints);
} }
@ -708,7 +721,15 @@ m_lastInputTime (0)
// Set fullscreen video mode and switch to fullscreen if necessary // Set fullscreen video mode and switch to fullscreen if necessary
if (m_fullscreen) 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); setVideoMode(mode);
switchToFullscreen(); switchToFullscreen();
} }
@ -722,11 +743,11 @@ WindowImplX11::~WindowImplX11()
cleanup(); cleanup();
// Destroy icon pixmap // Destroy icon pixmap
if(m_iconPixmap) if (m_iconPixmap)
XFreePixmap(m_display, m_iconPixmap); XFreePixmap(m_display, m_iconPixmap);
// Destroy icon mask pixmap // Destroy icon mask pixmap
if(m_iconMaskPixmap) if (m_iconMaskPixmap)
XFreePixmap(m_display, m_iconMaskPixmap); XFreePixmap(m_display, m_iconMaskPixmap);
// Destroy the cursor // Destroy the cursor
@ -960,10 +981,10 @@ void WindowImplX11::setIcon(unsigned int width, unsigned int height, const Uint8
return; return;
} }
if(m_iconPixmap) if (m_iconPixmap)
XFreePixmap(m_display, m_iconPixmap); XFreePixmap(m_display, m_iconPixmap);
if(m_iconMaskPixmap) if (m_iconMaskPixmap)
XFreePixmap(m_display, m_iconMaskPixmap); XFreePixmap(m_display, m_iconMaskPixmap);
m_iconPixmap = XCreatePixmap(m_display, RootWindow(m_display, m_screen), width, height, defDepth); m_iconPixmap = XCreatePixmap(m_display, RootWindow(m_display, m_screen), width, height, defDepth);
@ -1240,53 +1261,99 @@ void WindowImplX11::setVideoMode(const VideoMode& mode)
return; return;
// Check if the XRandR extension is present // Check if the XRandR extension is present
int version; int xRandRMajor, xRandRMinor;
if (!XQueryExtension(m_display, "RANDR", &version, &version, &version)) if (!checkXRandR(xRandRMajor, xRandRMinor))
{ {
// XRandR extension is not supported: we cannot use fullscreen mode // XRandR extension is not supported: we cannot use fullscreen mode
err() << "Fullscreen is not supported, switching to window mode" << std::endl; err() << "Fullscreen is not supported, switching to window mode" << std::endl;
return; return;
} }
// Get the current configuration // Get root window
XRRScreenConfiguration* config = XRRGetScreenInfo(m_display, RootWindow(m_display, m_screen)); ::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 resources for fullscreen mode, switching to window mode" << std::endl;
err() << "Failed to get the current screen configuration 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; return;
} }
// Save the current video mode before we switch to fullscreen // Save the current video mode before we switch to fullscreen
Rotation currentRotation; m_oldVideoMode = crtcInfo->mode;
m_oldVideoMode = XRRConfigCurrentConfiguration(config, &currentRotation); m_oldRRCrtc = outputInfo->crtc;
// Get the available screen sizes // Switch to fullscreen mode
int nbSizes; XRRSetCrtcConfig(m_display,
XRRScreenSize* sizes = XRRConfigSizes(config, &nbSizes); res,
outputInfo->crtc,
CurrentTime,
crtcInfo->x,
crtcInfo->y,
xRandMode,
crtcInfo->rotation,
&output,
1);
// Search for a matching size // Set "this" as the current fullscreen window
for (int i = 0; (sizes && i < nbSizes); ++i) fullscreenWindow = this;
{
XRRConfigRotations(config, &currentRotation);
if (currentRotation == RR_Rotate_90 || currentRotation == RR_Rotate_270) XRRFreeScreenResources(res);
std::swap(sizes[i].height, sizes[i].width); XRRFreeOutputInfo(outputInfo);
XRRFreeCrtcInfo(crtcInfo);
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);
// Set "this" as the current fullscreen window
fullscreenWindow = this;
break;
}
}
// Free the configuration instance
XRRFreeScreenConfigInfo(config);
} }
@ -1295,19 +1362,55 @@ void WindowImplX11::resetVideoMode()
{ {
if (fullscreenWindow == this) if (fullscreenWindow == this)
{ {
// Get current screen info // Try to set old configuration
XRRScreenConfiguration* config = XRRGetScreenInfo(m_display, RootWindow(m_display, m_screen)); // Check if the XRandR extension
if (config) int xRandRMajor, xRandRMinor;
if (checkXRandR(xRandRMajor, xRandRMinor))
{ {
// Get the current rotation XRRScreenResources* res = XRRGetScreenResources(m_display, DefaultRootWindow(m_display));
Rotation currentRotation; if (!res)
XRRConfigCurrentConfiguration(config, &currentRotation); {
err() << "Failed to get the current screen resources to reset the video mode" << std::endl;
return;
}
// Reset the video mode // Retreive current screen position and rotation
XRRSetScreenConfig(m_display, config, RootWindow(m_display, m_screen), m_oldVideoMode, currentRotation, CurrentTime); 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 RROutput output;
XRRFreeScreenConfigInfo(config);
// 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 // Reset the fullscreen window
@ -1503,7 +1606,7 @@ void WindowImplX11::updateLastInputTime(::Time time)
{ {
Atom netWmUserTime = getAtom("_NET_WM_USER_TIME", true); Atom netWmUserTime = getAtom("_NET_WM_USER_TIME", true);
if(netWmUserTime) if (netWmUserTime)
{ {
XChangeProperty(m_display, XChangeProperty(m_display,
m_window, m_window,
@ -1973,6 +2076,106 @@ bool WindowImplX11::processEvent(XEvent& windowEvent)
return true; 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 priv
} // namespace sf } // namespace sf

View File

@ -34,6 +34,7 @@
#include <SFML/Window/WindowStyle.hpp> // Prevent conflict with macro None from Xlib #include <SFML/Window/WindowStyle.hpp> // Prevent conflict with macro None from Xlib
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <deque> #include <deque>
#include <X11/extensions/Xrandr.h>
namespace sf namespace sf
@ -264,6 +265,38 @@ private:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool processEvent(XEvent& windowEvent); 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 // Member data
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -275,6 +308,7 @@ private:
std::deque<XEvent> m_events; ///< Queue we use to store pending events for this window 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 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 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_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 ::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? bool m_keyRepeat; ///< Is the KeyRepeat feature enabled?