Avoid sending X11 sync request if new logical geometry doesn't change the device geometry
There are two mechanisms to throttle ConfigureNotify events during interactive resize: - either using XSync - or by a dummy QTimer The QTimer approach is pretty straightforward: the wm configures the window, blocks the interactive resize operation and arms a timer to unblock it some time later in the future. With the xsync approach, the wm sends an xsync request, makes a call to XConfigureWindow(), and blocks interactive resize until the xsync request is acked by the client. When the client sees the ConfigureNotify event, it is going to repaint and ack the xsync request. When the xsync request is acked, the wm will apply new geometry and unblock interactive resize. After the scaling changes, the logical geometry can have some fractional part, which gets rounded when configuring the X windows. Due to that, it's possible to encounter the case where the logical geometry changes, but the native/device geometry does not due to std::round(). In that case, the wm should not send an xsync request because the client won't ack it because the device geometry has not changed. BUG: 488223
This commit is contained in:
parent
4db2742e96
commit
21a45c2700
2 changed files with 34 additions and 11 deletions
|
@ -1642,6 +1642,10 @@ public:
|
||||||
{
|
{
|
||||||
return m_logicGeometry;
|
return m_logicGeometry;
|
||||||
}
|
}
|
||||||
|
QRect deviceGeometry() const
|
||||||
|
{
|
||||||
|
return m_deviceGeometry;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Configures the window with a new geometry.
|
* Configures the window with a new geometry.
|
||||||
* @param geometry The new window geometry to be used
|
* @param geometry The new window geometry to be used
|
||||||
|
@ -1686,6 +1690,7 @@ private:
|
||||||
xcb_window_t m_window;
|
xcb_window_t m_window;
|
||||||
bool m_destroy;
|
bool m_destroy;
|
||||||
QRectF m_logicGeometry;
|
QRectF m_logicGeometry;
|
||||||
|
QRect m_deviceGeometry;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline Window::Window(xcb_window_t window, bool destroy)
|
inline Window::Window(xcb_window_t window, bool destroy)
|
||||||
|
@ -1744,9 +1749,13 @@ inline void Window::create(const QRectF &geometry, uint32_t mask, const uint32_t
|
||||||
inline xcb_window_t Window::doCreate(const QRectF &geometry, uint16_t windowClass, uint32_t mask, const uint32_t *values, xcb_window_t parent)
|
inline xcb_window_t Window::doCreate(const QRectF &geometry, uint16_t windowClass, uint32_t mask, const uint32_t *values, xcb_window_t parent)
|
||||||
{
|
{
|
||||||
m_logicGeometry = geometry;
|
m_logicGeometry = geometry;
|
||||||
|
m_deviceGeometry = Xcb::toXNative(geometry);
|
||||||
xcb_window_t w = xcb_generate_id(connection());
|
xcb_window_t w = xcb_generate_id(connection());
|
||||||
xcb_create_window(connection(), XCB_COPY_FROM_PARENT, w, parent,
|
xcb_create_window(connection(), XCB_COPY_FROM_PARENT, w, parent,
|
||||||
Xcb::toXNative(geometry.x()), Xcb::toXNative(geometry.y()), Xcb::toXNative(geometry.width()), Xcb::toXNative(geometry.height()),
|
m_deviceGeometry.x(),
|
||||||
|
m_deviceGeometry.y(),
|
||||||
|
m_deviceGeometry.width(),
|
||||||
|
m_deviceGeometry.height(),
|
||||||
0, windowClass, XCB_COPY_FROM_PARENT, mask, values);
|
0, windowClass, XCB_COPY_FROM_PARENT, mask, values);
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
|
@ -1766,11 +1775,12 @@ inline void Window::setGeometry(const QRectF &geometry)
|
||||||
inline void Window::setGeometry(qreal x, qreal y, qreal width, qreal height)
|
inline void Window::setGeometry(qreal x, qreal y, qreal width, qreal height)
|
||||||
{
|
{
|
||||||
m_logicGeometry.setRect(x, y, width, height);
|
m_logicGeometry.setRect(x, y, width, height);
|
||||||
|
m_deviceGeometry = Xcb::toXNative(m_logicGeometry);
|
||||||
if (!isValid()) {
|
if (!isValid()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const uint16_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
|
const uint16_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
|
||||||
const uint32_t values[] = {Xcb::toXNative(x), Xcb::toXNative(y), Xcb::toXNative(width), Xcb::toXNative(height)};
|
const uint32_t values[] = {uint32_t(m_deviceGeometry.x()), uint32_t(m_deviceGeometry.y()), uint32_t(m_deviceGeometry.width()), uint32_t(m_deviceGeometry.height())};
|
||||||
xcb_configure_window(connection(), m_window, mask, values);
|
xcb_configure_window(connection(), m_window, mask, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1782,10 +1792,13 @@ inline void Window::move(const QPointF &pos)
|
||||||
inline void Window::move(qreal x, qreal y)
|
inline void Window::move(qreal x, qreal y)
|
||||||
{
|
{
|
||||||
m_logicGeometry.moveTo(x, y);
|
m_logicGeometry.moveTo(x, y);
|
||||||
|
m_deviceGeometry.moveTo(Xcb::toXNative(x), Xcb::toXNative(y));
|
||||||
if (!isValid()) {
|
if (!isValid()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
moveWindow(m_window, x, y);
|
const uint16_t mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y;
|
||||||
|
const uint32_t values[] = {uint32_t(m_deviceGeometry.x()), uint32_t(m_deviceGeometry.y())};
|
||||||
|
xcb_configure_window(connection(), m_window, mask, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Window::resize(const QSizeF &size)
|
inline void Window::resize(const QSizeF &size)
|
||||||
|
@ -1796,11 +1809,12 @@ inline void Window::resize(const QSizeF &size)
|
||||||
inline void Window::resize(qreal width, qreal height)
|
inline void Window::resize(qreal width, qreal height)
|
||||||
{
|
{
|
||||||
m_logicGeometry.setSize(QSizeF(width, height));
|
m_logicGeometry.setSize(QSizeF(width, height));
|
||||||
|
m_deviceGeometry.setSize(QSize(Xcb::toXNative(width), Xcb::toXNative(height)));
|
||||||
if (!isValid()) {
|
if (!isValid()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const uint16_t mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
|
const uint16_t mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
|
||||||
const uint32_t values[] = {Xcb::toXNative(width), Xcb::toXNative(height)};
|
const uint32_t values[] = {uint32_t(m_deviceGeometry.width()), uint32_t(m_deviceGeometry.height())};
|
||||||
xcb_configure_window(connection(), m_window, mask, values);
|
xcb_configure_window(connection(), m_window, mask, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4784,7 +4784,19 @@ bool X11Window::isWaitingForInteractiveResizeSync() const
|
||||||
|
|
||||||
void X11Window::doInteractiveResizeSync(const QRectF &rect)
|
void X11Window::doInteractiveResizeSync(const QRectF &rect)
|
||||||
{
|
{
|
||||||
setMoveResizeGeometry(rect);
|
const QRectF moveResizeFrameGeometry = Xcb::fromXNative(Xcb::toXNative(rect));
|
||||||
|
const QRectF moveResizeClientGeometry = frameRectToClientRect(moveResizeFrameGeometry);
|
||||||
|
const QRectF moveResizeBufferGeometry = frameRectToBufferRect(moveResizeFrameGeometry);
|
||||||
|
|
||||||
|
const QRectF xFrameGeometry = moveResizeBufferGeometry;
|
||||||
|
const QRectF xWrapperGeometry = moveResizeClientGeometry.translated(-moveResizeBufferGeometry.topLeft());
|
||||||
|
const QRectF xClientGeometry = QRectF(QPointF(0, 0), moveResizeClientGeometry.size());
|
||||||
|
|
||||||
|
if (m_frame.deviceGeometry() == Xcb::toXNative(xFrameGeometry) && m_wrapper.deviceGeometry() == Xcb::toXNative(xWrapperGeometry) && m_client.deviceGeometry() == Xcb::toXNative(xClientGeometry)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setMoveResizeGeometry(moveResizeFrameGeometry);
|
||||||
|
|
||||||
if (!m_syncRequest.timeout) {
|
if (!m_syncRequest.timeout) {
|
||||||
m_syncRequest.timeout = new QTimer(this);
|
m_syncRequest.timeout = new QTimer(this);
|
||||||
|
@ -4804,16 +4816,13 @@ void X11Window::doInteractiveResizeSync(const QRectF &rect)
|
||||||
m_syncRequest.timeout->start(33);
|
m_syncRequest.timeout->start(33);
|
||||||
}
|
}
|
||||||
|
|
||||||
const QRectF moveResizeClientGeometry = frameRectToClientRect(moveResizeGeometry());
|
|
||||||
const QRectF moveResizeBufferGeometry = frameRectToBufferRect(moveResizeGeometry());
|
|
||||||
|
|
||||||
// According to the Composite extension spec, a window will get a new pixmap allocated each time
|
// According to the Composite extension spec, a window will get a new pixmap allocated each time
|
||||||
// it is mapped or resized. Given that we redirect frame windows and not client windows, we have
|
// it is mapped or resized. Given that we redirect frame windows and not client windows, we have
|
||||||
// to resize the frame window in order to forcefully reallocate offscreen storage. If we don't do
|
// to resize the frame window in order to forcefully reallocate offscreen storage. If we don't do
|
||||||
// this, then we might render partially updated client window. I know, it sucks.
|
// this, then we might render partially updated client window. I know, it sucks.
|
||||||
m_frame.setGeometry(moveResizeBufferGeometry);
|
m_frame.setGeometry(xFrameGeometry);
|
||||||
m_wrapper.setGeometry(moveResizeClientGeometry.translated(-moveResizeBufferGeometry.topLeft()));
|
m_wrapper.setGeometry(xWrapperGeometry);
|
||||||
m_client.setGeometry(QRectF(QPointF(0, 0), moveResizeClientGeometry.size()));
|
m_client.setGeometry(xClientGeometry);
|
||||||
}
|
}
|
||||||
|
|
||||||
void X11Window::handleSyncTimeout()
|
void X11Window::handleSyncTimeout()
|
||||||
|
|
Loading…
Reference in a new issue