Kaydet (Commit) e770bacc authored tarafından Jan-Marek Glogowski's avatar Jan-Marek Glogowski

Qt5 workaround modal change after show bug

The presentation minimizer dialog calls setVisible before execute.
This results in the dialog being shown before setting the modality
in execute. And this triggers a bug in the Qt / Xcb stack (gtk is
fine because it directly uses XSendEvent to change the state).

The result is an unmapped, modal dialog window: it's invisible and
blocks the GUI. Qt believes it's show; isVisible() returns true.

And my ~/.xsession-errors shows a "qt.qpa.xcb: QXcbConnection: XCB
error: 3 (BadWindow) ... major code: 18 (ChangeProperty)" with an
invalid resource id, according to 'xwininfo -tree -root'.
You can find the window resource of the minimizer by its name in
the full root tree and its unmapped state with 'xwininfo -id'.

I originally thought of a Scheduler bug so enabled debug output
for it. This is already responsible for a delay long enough to
prevent the bug often. Same for doing an additional hide() and
show() sequence. In the end I went with a fixed delay, but that
is just a guess. In theory we could check the mapped state via
Xlib in Qt's show event and manually map it using XMapWindow and
the winId...

I also noted that the minimizer leaks, as there are multiple new
presenter resources after each show and hide...

Change-Id: I2060918aa9c63d385ebb2ffee9e7a3e4196ea766
Reviewed-on: https://gerrit.libreoffice.org/73462
Tested-by: Jenkins
Reviewed-by: 's avatarMichael Weghorn <m.weghorn@posteo.de>
Reviewed-by: 's avatarJan-Marek Glogowski <glogow@fbihome.de>
üst ca69a1e1
......@@ -34,6 +34,7 @@
#include <QtCore/QMimeData>
#include <QtCore/QPoint>
#include <QtCore/QSize>
#include <QtCore/QThread>
#include <QtGui/QIcon>
#include <QtGui/QWindow>
#include <QtGui/QScreen>
......@@ -507,21 +508,27 @@ void Qt5Frame::SetModal(bool bModal)
auto* pSalInst(static_cast<Qt5Instance*>(GetSalData()->m_pInstance));
assert(pSalInst);
pSalInst->RunInMainThread([this, bModal]() {
bool wasVisible = windowHandle()->isVisible();
QWidget* const pChild = asChild();
const bool bWasVisible = pChild->isVisible();
// modality change is only effective if the window is hidden
if (wasVisible)
if (bWasVisible)
{
windowHandle()->hide();
pChild->hide();
if (QGuiApplication::platformName() == "xcb")
{
SAL_WARN("vcl.qt5", "SetModal called after Show - apply delay");
// give QXcbConnection some time to recover from unmap
// ~/.xsession-errors => (BadWindow) (ChangeProperty)
QThread::msleep(250);
}
}
windowHandle()->setModality(bModal ? Qt::WindowModal : Qt::NonModal);
pChild->setWindowModality(bModal ? Qt::WindowModal : Qt::NonModal);
// and shown again if it was visible
if (wasVisible)
{
windowHandle()->show();
}
if (bWasVisible)
pChild->show();
});
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment