mirror of
https://github.com/SFML/SFML.git
synced 2024-11-28 22:31:09 +08:00
Window/Unix: fix SFML issue #1228, getPosition() returns incorrect results on Linux depending on the used WM,
as well as not returning values that are in-sync with what was given to setPosition(x, y).
This commit is contained in:
parent
93a2e9502d
commit
58b7c2c48a
@ -66,6 +66,8 @@ namespace
|
|||||||
sf::Mutex allWindowsMutex;
|
sf::Mutex allWindowsMutex;
|
||||||
sf::String windowManagerName;
|
sf::String windowManagerName;
|
||||||
|
|
||||||
|
sf::String wmAbsPosGood[] = { "Enlightenment", "FVWM", "i3" };
|
||||||
|
|
||||||
static const unsigned long eventMask = FocusChangeMask | ButtonPressMask |
|
static const unsigned long eventMask = FocusChangeMask | ButtonPressMask |
|
||||||
ButtonReleaseMask | ButtonMotionMask |
|
ButtonReleaseMask | ButtonMotionMask |
|
||||||
PointerMotionMask | KeyPressMask |
|
PointerMotionMask | KeyPressMask |
|
||||||
@ -260,6 +262,90 @@ namespace
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the parent window.
|
||||||
|
::Window getParentWindow(::Display* disp, ::Window win)
|
||||||
|
{
|
||||||
|
::Window root, parent;
|
||||||
|
::Window* children = NULL;
|
||||||
|
unsigned int numChildren;
|
||||||
|
|
||||||
|
XQueryTree(disp, win, &root, &parent, &children, &numChildren);
|
||||||
|
|
||||||
|
// Children information is not used, so must be freed.
|
||||||
|
if (children != NULL)
|
||||||
|
XFree(children);
|
||||||
|
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the Frame Extents from EWMH WMs that support it.
|
||||||
|
bool getEWMHFrameExtents(::Display* disp, ::Window win,
|
||||||
|
long& xFrameExtent, long& yFrameExtent)
|
||||||
|
{
|
||||||
|
if (!ewmhSupported())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Atom frameExtents = sf::priv::getAtom("_NET_FRAME_EXTENTS", true);
|
||||||
|
|
||||||
|
if (frameExtents == None)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool gotFrameExtents = false;
|
||||||
|
Atom actualType;
|
||||||
|
int actualFormat;
|
||||||
|
unsigned long numItems;
|
||||||
|
unsigned long numBytesLeft;
|
||||||
|
unsigned char* data = NULL;
|
||||||
|
|
||||||
|
int result = XGetWindowProperty(disp,
|
||||||
|
win,
|
||||||
|
frameExtents,
|
||||||
|
0,
|
||||||
|
4,
|
||||||
|
False,
|
||||||
|
XA_CARDINAL,
|
||||||
|
&actualType,
|
||||||
|
&actualFormat,
|
||||||
|
&numItems,
|
||||||
|
&numBytesLeft,
|
||||||
|
&data);
|
||||||
|
|
||||||
|
if ((result == Success) && (actualType == XA_CARDINAL) &&
|
||||||
|
(actualFormat == 32) && (numItems == 4) && (numBytesLeft == 0) &&
|
||||||
|
(data != NULL))
|
||||||
|
{
|
||||||
|
gotFrameExtents = true;
|
||||||
|
|
||||||
|
long* extents = (long*) data;
|
||||||
|
|
||||||
|
xFrameExtent = extents[0]; // Left.
|
||||||
|
yFrameExtent = extents[2]; // Top.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always free data.
|
||||||
|
if (data != NULL)
|
||||||
|
XFree(data);
|
||||||
|
|
||||||
|
return gotFrameExtents;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the current WM is in the list of good WMs that provide
|
||||||
|
// a correct absolute position for the window when queried.
|
||||||
|
bool isWMAbsolutePositionGood()
|
||||||
|
{
|
||||||
|
// This can only work with EWMH, to get the name.
|
||||||
|
if (!ewmhSupported())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < (sizeof(wmAbsPosGood) / sizeof(wmAbsPosGood[0])); i++)
|
||||||
|
{
|
||||||
|
if (wmAbsPosGood[i] == windowManagerName)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
sf::Keyboard::Key keysymToSF(KeySym symbol)
|
sf::Keyboard::Key keysymToSF(KeySym symbol)
|
||||||
{
|
{
|
||||||
switch (symbol)
|
switch (symbol)
|
||||||
@ -676,14 +762,67 @@ void WindowImplX11::processEvents()
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
Vector2i WindowImplX11::getPosition() const
|
Vector2i WindowImplX11::getPosition() const
|
||||||
{
|
{
|
||||||
::Window root, child;
|
// Get absolute position of our window relative to root window. This
|
||||||
int localX, localY, x, y;
|
// takes into account all information that X11 has, including X11
|
||||||
unsigned int width, height, border, depth;
|
// border widths and any decorations. It corresponds to where the
|
||||||
|
// window actually is, but not necessarily to where we told it to
|
||||||
|
// go using setPosition() and XMoveWindow(). To have the two match
|
||||||
|
// as expected, we may have to subtract decorations and borders.
|
||||||
|
::Window child;
|
||||||
|
int xAbsRelToRoot, yAbsRelToRoot;
|
||||||
|
|
||||||
XGetGeometry(m_display, m_window, &root, &localX, &localY, &width, &height, &border, &depth);
|
XTranslateCoordinates(m_display, m_window, DefaultRootWindow(m_display),
|
||||||
XTranslateCoordinates(m_display, m_window, root, localX, localY, &x, &y, &child);
|
0, 0, &xAbsRelToRoot, &yAbsRelToRoot, &child);
|
||||||
|
|
||||||
return Vector2i(x, y);
|
// CASE 1: some rare WMs actually put the window exactly where we tell
|
||||||
|
// it to, even with decorations and such, which get shifted back.
|
||||||
|
// In these rare cases, we can use the absolute value directly.
|
||||||
|
if (isWMAbsolutePositionGood())
|
||||||
|
return Vector2i(xAbsRelToRoot, yAbsRelToRoot);
|
||||||
|
|
||||||
|
// CASE 2: most modern WMs support EWMH and can define _NET_FRAME_EXTENTS
|
||||||
|
// with the exact frame size to subtract, so if present, we prefer it and
|
||||||
|
// query it first. According to spec, this already includes any borders.
|
||||||
|
long xFrameExtent, yFrameExtent;
|
||||||
|
|
||||||
|
if (getEWMHFrameExtents(m_display, m_window, xFrameExtent, yFrameExtent))
|
||||||
|
{
|
||||||
|
// Get final X/Y coordinates: subtract EWMH frame extents from
|
||||||
|
// absolute window position.
|
||||||
|
return Vector2i((xAbsRelToRoot - xFrameExtent), (yAbsRelToRoot - yFrameExtent));
|
||||||
|
}
|
||||||
|
|
||||||
|
// CASE 3: EWMH frame extents were not available, use geometry.
|
||||||
|
// We climb back up to the window before the root and use its
|
||||||
|
// geometry information to extract X/Y position. This because
|
||||||
|
// re-parenting WMs may re-parent the window multiple times, so
|
||||||
|
// we'd have to climb up to the furthest ancestor and sum the
|
||||||
|
// relative differences and borders anyway; and doing that to
|
||||||
|
// subtract those values from the absolute coordinates of the
|
||||||
|
// window is equivalent to going up the tree and asking the
|
||||||
|
// furthest ancestor what it's relative distance to the root is.
|
||||||
|
// So we use that approach because it's simpler.
|
||||||
|
// This approach assumes that any window between the root and
|
||||||
|
// our window is part of decorations/borders in some way. This
|
||||||
|
// seems to hold true for most reasonable WM implementations.
|
||||||
|
::Window ancestor = m_window;
|
||||||
|
::Window root = DefaultRootWindow(m_display);
|
||||||
|
|
||||||
|
while (getParentWindow(m_display, ancestor) != root)
|
||||||
|
{
|
||||||
|
// Next window up (parent window).
|
||||||
|
ancestor = getParentWindow(m_display, ancestor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get final X/Y coordinates: take the relative position to
|
||||||
|
// the root of the furthest ancestor window.
|
||||||
|
int xRelToRoot, yRelToRoot;
|
||||||
|
unsigned int width, height, borderWidth, depth;
|
||||||
|
|
||||||
|
XGetGeometry(m_display, ancestor, &root, &xRelToRoot, &yRelToRoot,
|
||||||
|
&width, &height, &borderWidth, &depth);
|
||||||
|
|
||||||
|
return Vector2i(xRelToRoot, yRelToRoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user