Use the same logic to configure window during normal resize and interactive resize

X11Window::doInteractiveResizeSync() configures the x windows but it only
does a half of the things that should be done. The rest of it is assumed
to be performed by X11Window::updateServerGeometry() when XSync request is
acked later. The current state is not ideal and error prone.

This change makes X11Window::moveResizeInternal() and X11Window::doInteractiveResizeSync()
share the same code to configure the x windows to simplify the code.

It also drops X11Window::m_last{Frame,Client,Buffer}Geometry to further
simplify the code and make X window geometry tracking even more robust.
This commit is contained in:
Vlad Zahorodnii 2024-06-16 22:39:12 +03:00
parent 706d604305
commit 3f7b26cd9a
2 changed files with 28 additions and 52 deletions

View file

@ -4315,9 +4315,10 @@ void X11Window::blockGeometryUpdates(bool block)
++m_blockGeometryUpdates;
} else {
if (--m_blockGeometryUpdates == 0) {
if (m_lastBufferGeometry != m_bufferGeometry || m_lastFrameGeometry != m_frameGeometry || m_lastClientGeometry != m_clientGeometry) {
updateServerGeometry();
}
const QRect nativeFrameGeometry = Xcb::toXNative(m_bufferGeometry);
const QRect nativeWrapperGeometry = Xcb::toXNative(m_clientGeometry.translated(-m_bufferGeometry.topLeft()));
const QRect nativeClientGeometry = QRect(0, 0, nativeWrapperGeometry.width(), nativeWrapperGeometry.height());
configure(nativeFrameGeometry, nativeWrapperGeometry, nativeClientGeometry);
}
}
}
@ -4375,7 +4376,13 @@ void X11Window::moveResizeInternal(const QRectF &rect, MoveResizeMode mode)
m_bufferGeometry = bufferGeometry;
m_output = workspace()->outputAt(frameGeometry.center());
updateServerGeometry();
if (!areGeometryUpdatesBlocked()) {
const QRect nativeFrameGeometry = Xcb::toXNative(m_bufferGeometry);
const QRect nativeWrapperGeometry = Xcb::toXNative(m_clientGeometry.translated(-m_bufferGeometry.topLeft()));
const QRect nativeClientGeometry = QRect(0, 0, nativeWrapperGeometry.width(), nativeWrapperGeometry.height());
configure(nativeFrameGeometry, nativeWrapperGeometry, nativeClientGeometry);
}
updateWindowRules(Rules::Position | Rules::Size);
if (isActive()) {
@ -4398,37 +4405,19 @@ void X11Window::moveResizeInternal(const QRectF &rect, MoveResizeMode mode)
Q_EMIT shapeChanged();
}
void X11Window::updateServerGeometry()
void X11Window::configure(const QRect &nativeFrame, const QRect &nativeWrapper, const QRect &nativeClient)
{
if (areGeometryUpdatesBlocked()) {
return;
}
const QRectF oldBufferGeometry = m_lastBufferGeometry;
// Compute the old client rect, the client geometry is always inside the buffer geometry.
const QRectF oldClientRect = m_lastClientGeometry.translated(-m_lastBufferGeometry.topLeft());
const QRectF clientRect = m_clientGeometry.translated(-m_bufferGeometry.topLeft());
if (oldBufferGeometry.size() != m_bufferGeometry.size() || oldClientRect != clientRect) {
// If the client is being interactively resized, then the frame window, the wrapper window,
// and the client window have correct geometry at this point, so we don't have to configure
// them again.
const QRect xFrameGeometry = Xcb::toXNative(m_bufferGeometry);
if (m_frame.geometry() != xFrameGeometry) {
m_frame.setGeometry(xFrameGeometry);
if (m_frame.size() != nativeFrame.size() || m_wrapper.geometry() != nativeWrapper) {
if (m_frame.geometry() != nativeFrame) {
m_frame.setGeometry(nativeFrame);
}
if (!isShade()) {
const QRect xWrapperGeometry = Xcb::toXNative(clientRect);
if (m_wrapper.geometry() != xWrapperGeometry) {
m_wrapper.setGeometry(xWrapperGeometry);
if (m_wrapper.geometry() != nativeWrapper) {
m_wrapper.setGeometry(nativeWrapper);
}
const QRect xClientGeometry = Xcb::toXNative(QRectF(QPointF(0, 0), clientRect.size()));
if (m_client.geometry() != xClientGeometry) {
m_client.setGeometry(xClientGeometry);
if (m_client.geometry() != nativeClient) {
m_client.setGeometry(nativeClient);
}
// SELI - won't this be too expensive?
// THOMAS - yes, but gtk+ clients will not resize without ...
sendSyntheticConfigureNotify();
}
@ -4442,17 +4431,13 @@ void X11Window::updateServerGeometry()
updateInputShape();
updateInputWindow();
} else {
m_frame.move(Xcb::toXNative(m_bufferGeometry.topLeft()));
sendSyntheticConfigureNotify();
} else if (m_frame.position() != nativeFrame.topLeft()) {
m_frame.move(nativeFrame.topLeft());
if (m_decoInputExtent.isValid()) {
m_decoInputExtent.move(m_frame.position() + input_offset);
}
sendSyntheticConfigureNotify();
}
m_lastBufferGeometry = m_bufferGeometry;
m_lastFrameGeometry = m_frameGeometry;
m_lastClientGeometry = m_clientGeometry;
}
static bool changeMaximizeRecursion = false;
@ -4811,11 +4796,11 @@ void X11Window::doInteractiveResizeSync(const QRectF &rect)
const QRectF moveResizeClientGeometry = frameRectToClientRect(moveResizeFrameGeometry);
const QRectF moveResizeBufferGeometry = frameRectToBufferRect(moveResizeFrameGeometry);
const QRect xFrameGeometry = Xcb::toXNative(moveResizeBufferGeometry);
const QRect xWrapperGeometry = Xcb::toXNative(moveResizeClientGeometry.translated(-moveResizeBufferGeometry.topLeft()));
const QRect xClientGeometry = Xcb::toXNative(QRectF(QPointF(0, 0), moveResizeClientGeometry.size()));
const QRect nativeFrameGeometry = Xcb::toXNative(moveResizeBufferGeometry);
const QRect nativeWrapperGeometry = Xcb::toXNative(moveResizeClientGeometry.translated(-moveResizeBufferGeometry.topLeft()));
const QRect nativeClientGeometry = Xcb::toXNative(QRectF(QPointF(0, 0), moveResizeClientGeometry.size()));
if (m_frame.geometry() == xFrameGeometry && m_wrapper.geometry() == xWrapperGeometry && m_client.geometry() == xClientGeometry) {
if (m_frame.geometry() == nativeFrameGeometry && m_wrapper.geometry() == nativeWrapperGeometry && m_client.geometry() == nativeClientGeometry) {
return;
}
@ -4839,13 +4824,7 @@ void X11Window::doInteractiveResizeSync(const QRectF &rect)
m_syncRequest.timeout->start(33);
}
// 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
// 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.
m_frame.setGeometry(xFrameGeometry);
m_wrapper.setGeometry(xWrapperGeometry);
m_client.setGeometry(xClientGeometry);
configure(nativeFrameGeometry, nativeWrapperGeometry, nativeClientGeometry);
}
void X11Window::handleSyncTimeout()

View file

@ -409,7 +409,7 @@ private:
void updateHiddenPreview();
void updateInputShape();
void updateServerGeometry();
void configure(const QRect &nativeFrame, const QRect &nativeWrapper, const QRect &nativeClient);
void discardWindowPixmap();
void updateWindowPixmap();
@ -521,9 +521,6 @@ private:
QMetaObject::Connection m_edgeGeometryTrackingConnection;
QMarginsF m_clientFrameExtents;
QRectF m_lastBufferGeometry;
QRectF m_lastFrameGeometry;
QRectF m_lastClientGeometry;
int m_blockGeometryUpdates = 0; // > 0 = New geometry is remembered, but not actually set
std::unique_ptr<X11DecorationRenderer> m_decorationRenderer;