x11: Handle late sync request

X11Client implicitly relied on the finishInteractiveMoveResize() function
to call moveResize() to synchronize the move resize geometry with the
server geometry. However, after removing that moveResize(), X11Client
got slightly broken.

A resize sync request may arrive shortly after finishing resize. In
order to properly handle it, this change makes X11Client handle late
sync requests.

It also makes handling interactive resize on x11 similar to how it's
done on wayland.

The main problem with not letting X11Client finish interactive resize
is that the Toplevel::bufferGeometry() may end up with an outdated value
and SurfacePixmapX11 will fail to create due to a mismatch between
Toplevel::bufferGeometry() and the server side geometry of the frame
window.
This commit is contained in:
Vlad Zahorodnii 2022-01-11 22:32:58 +02:00
parent b4f2bc3898
commit 9a4a960886
2 changed files with 25 additions and 19 deletions

View file

@ -193,6 +193,7 @@ X11Client::X11Client()
m_syncRequest.timeout = m_syncRequest.failsafeTimeout = nullptr;
m_syncRequest.lastTimestamp = xTime();
m_syncRequest.isPending = false;
m_syncRequest.interactiveResize = false;
// Set the initial mapping state
mapping_state = Withdrawn;
@ -2290,6 +2291,7 @@ void X11Client::sendSyncRequest()
}
// failed during resize
m_syncRequest.isPending = false;
m_syncRequest.interactiveResize = false;
m_syncRequest.counter = XCB_NONE;
m_syncRequest.alarm = XCB_NONE;
delete m_syncRequest.timeout;
@ -2321,6 +2323,7 @@ void X11Client::sendSyncRequest()
sendClientMessage(window(), atoms->wm_protocols, atoms->net_wm_sync_request,
m_syncRequest.value.lo, m_syncRequest.value.hi);
m_syncRequest.isPending = true;
m_syncRequest.interactiveResize = isInteractiveResize();
m_syncRequest.lastTimestamp = xTime();
}
@ -2766,21 +2769,21 @@ void X11Client::handleSync()
if (m_syncRequest.failsafeTimeout) {
m_syncRequest.failsafeTimeout->stop();
}
if (isInteractiveResize()) {
// Sync request can be acknowledged shortly after finishing resize.
if (m_syncRequest.interactiveResize) {
m_syncRequest.interactiveResize = false;
if (m_syncRequest.timeout) {
m_syncRequest.timeout->stop();
}
performInteractiveResize();
updateWindowPixmap();
} else // setReadyForPainting does as well, but there's a small chance for resize syncs after the resize ended
addRepaintFull();
}
}
void X11Client::performInteractiveResize()
{
if (isInteractiveResize()) {
resize(moveResizeGeometry().size());
}
resize(moveResizeGeometry().size());
}
bool X11Client::belongToSameApplication(const X11Client *c1, const X11Client *c2, SameApplicationChecks checks)
@ -4544,17 +4547,12 @@ void X11Client::leaveInteractiveMoveResize()
move_resize_has_keyboard_grab = false;
xcb_ungrab_pointer(connection(), xTime());
m_moveResizeGrabWindow.reset();
if (m_syncRequest.counter == XCB_NONE) { // don't forget to sanitize since the timeout will no more fire
m_syncRequest.isPending = false;
}
delete m_syncRequest.timeout;
m_syncRequest.timeout = nullptr;
AbstractClient::leaveInteractiveMoveResize();
}
bool X11Client::isWaitingForInteractiveMoveResizeSync() const
{
return m_syncRequest.isPending && isInteractiveResize();
return m_syncRequest.isPending && m_syncRequest.interactiveResize;
}
void X11Client::doInteractiveResizeSync()
@ -4564,13 +4562,19 @@ void X11Client::doInteractiveResizeSync()
connect(m_syncRequest.timeout, &QTimer::timeout, this, &X11Client::handleSyncTimeout);
m_syncRequest.timeout->setSingleShot(true);
}
if (m_syncRequest.counter != XCB_NONE) {
m_syncRequest.timeout->start(250);
sendSyncRequest();
} else { // for clients not supporting the XSYNC protocol, we
m_syncRequest.isPending = true; // limit the resizes to 30Hz to take pointless load from X11
m_syncRequest.timeout->start(33); // and the client, the mouse is still moved at full speed
} // and no human can control faster resizes anyway
} else {
// For clients not supporting the XSYNC protocol, we limit the resizes to 30Hz
// to take pointless load from X11 and the client, the mouse is still moved at
// full speed and no human can control faster resizes anyway.
m_syncRequest.isPending = true;
m_syncRequest.interactiveResize = true;
m_syncRequest.timeout->start(33);
}
const QRect moveResizeClientGeometry = frameRectToClientRect(moveResizeGeometry());
const QRect moveResizeBufferGeometry = frameRectToBufferRect(moveResizeGeometry());
@ -4585,9 +4589,10 @@ void X11Client::doInteractiveResizeSync()
void X11Client::handleSyncTimeout()
{
if (m_syncRequest.counter == XCB_NONE) { // client w/o XSYNC support. allow the next resize event
m_syncRequest.isPending = false; // NEVER do this for clients with a valid counter
} // (leads to sync request races in some clients)
if (m_syncRequest.counter == XCB_NONE) { // client w/o XSYNC support. allow the next resize event
m_syncRequest.isPending = false; // NEVER do this for clients with a valid counter
m_syncRequest.interactiveResize = false; // (leads to sync request races in some clients)
}
performInteractiveResize();
}

View file

@ -291,6 +291,7 @@ public:
xcb_timestamp_t lastTimestamp;
QTimer *timeout, *failsafeTimeout;
bool isPending;
bool interactiveResize;
};
const SyncRequest &syncRequest() const {
return m_syncRequest;