Bug#970641: libqtgui4: QDialog randomly misplaced invisible in buster, patches
Package: libqtgui4
Version: 4:4.8.7+dfsg-18
Severity: normal
Tags: patch
Introduction:
After migrating a legacy application from jessie to buster without making major
changes we experienced QDialogs and QMessageBoxes randomly showing up outside
the visible area.
In most of the occurences the invisible dialog didn't have focus despite being
modal, rendering the GUI frozen from the user's perspective.
Bugs:
We finally tracked it down to QDesktopWidget::availableGeometry(int screen)
parsing the response of XGetWindowProperty(_NET_WORKAREA) as array of 4 64 bit
integers despite format==32 clearly guaranteeing 32 bit integers.
This 'compresses' the 4 good values received in the first 2 values of the QRect
workArea c'tor, x and y, and pulls random memory content in the other 2 values,
width and heigth.
As a consequence QMessageBoxPrivate::updateSize() calculated hardLimit,
softLimit, width and height to crazy negative values like -123456789.
That whole method, QMessageBoxPrivate::updateSize(), has some wild heuristics
and should not use negative values, but that's not the root cause.
Depending on the window manager and system configuration the bad code path in
QDesktopWidget::availableGeometry(int) might be used or not.
It's always used in our customer's setup that facilitates matchbox-window-
manager -use_titlebar no for a kiosk-like user experience.
Patches:
Our main patch, qdesktopwidget_fix_availableGeometry.diff, fixes the main error
described above, in src/gui/kernel/qdesktopwidget_x11.cpp:304.
Our side patch qmessagebox_ironize_updatesize.diff makes
QMessageBoxPrivate::updateSize() ignore non-positive softLimits and hardLimits.
We're not 100% sure it's a good idea to apply that. Concerns
src/gui/dialogs/qmessagebox.cpp lines 345, 349, 375, 390.
Non-Patches:
On the assumption that such code is often copied'n'change we grepped for other
uses of XGetWindowProperty() (there are 51), quickly (not too thouroghly)
checked for similar mistakes and found serveral suspicious blocks of code.
This was done after 'apt-get source qt4-x11' to *.cpp under
qt4-x11-4.8.7+dfsg/src/, i.e. after debian patches have been applied to the
source code. Line numbers in upstream tarball might differ.
In QETWidget::translatePropertyEvent(),
src/gui/kernel/qapplication_x11.cpp:5008ff
XGetWindowProperty(_KDE_NET_WM_FRAME_STRUT) seems to make a similar mistake,
but I haven't researched wether the contradiction between '// struts are 4
longs' and the check 'format == 32' is a bug or maybe a legitimate-ish hack.
Other XGetWindowProperty() calls with suspicious result processing can be found
in
src/gui/kernel/qapplication_x11.cpp:2831, which someone has thought about
with // quint32, but seems not in use
src/gui/kernel/qapplication_x11.cpp:5027
src/gui/kernel/qapplication_x11.cpp:5106
src/gui/kernel/qapplication_x11.cpp:5165
src/gui/kernel/qx11embed_x11.cpp:415
src/gui/kernel/qx11embed_x11.cpp:829
src/gui/kernel/qx11embed_x11.cpp:1673
Patched amd64 packages:
Packages that include our 2 patches can be found on https://deb.clazzes.org/debian/pool/buster-xpkg-1/
To use them with apt or the like perform something like this:
wget -O /etc/apt/trusted.gpg.d/pba-archiver.clazzes.org.gpg https://deb.clazzes.org/gpg/pba-archiver.clazzes.org.gpg
cd /etc/apt/sources.list.d
wget https://deb.clazzes.org/debian/sources.list.d/buster/buster-xpkg-1.list
apt-get update
apt-get upgrade
We'd be willing to add armhf packages if anyone's interested.
Our clean room build infrastructure has been relieved from i386 and we don't support other archs.
Regards, Christoph Lechleitner
--
Christoph Lechleitner
Geschäftsführung
------------------------------------------------------------------------
ITEG IT-Engineers GmbH | Salurner Straße 18, A-6020 Innsbruck
FN 365826f | Handelsgericht Innsbruck | Mobiltelefon: +43 676 3674710
Mail: christoph.lechleitner@iteg.at | Web: http://www.iteg.at/
------------------------------------------------------------------------
--- qt4-x11-4.8.7+dfsg.orig/src/gui/kernel/qdesktopwidget_x11.cpp 2015-05-07 16:14:43.000000000 +0200
+++ qt4-x11-4.8.7+dfsg/src/gui/kernel/qdesktopwidget_x11.cpp 2020-09-20 15:49:52.089122544 +0200
@@ -301,7 +301,8 @@
QRect workArea;
if (e == Success && ret == XA_CARDINAL &&
format == 32 && nitems == 4) {
- long *workarea = (long *) data;
+ //long *workarea = (long *) data;
+ qint32 *workarea = (qint32 *) data;
workArea = QRect(workarea[0], workarea[1], workarea[2], workarea[3]);
} else {
workArea = screenGeometry(screen);
--- qt4-x11-4.8.7+dfsg.orig/src/gui/dialogs/qmessagebox.cpp 2015-05-07 16:14:43.000000000 +0200
+++ qt4-x11-4.8.7+dfsg/src/gui/dialogs/qmessagebox.cpp 2020-09-20 15:49:20.787609493 +0200
@@ -342,11 +342,11 @@
label->setWordWrap(false); // makes the label return min size
int width = layoutMinimumWidth();
- if (width > softLimit) {
+ if ((softLimit > 0) && (width > softLimit)) {
label->setWordWrap(true);
width = qMax(softLimit, layoutMinimumWidth());
- if (width > hardLimit) {
+ if ((hardLimit > 0) && (width > hardLimit)) {
label->d_func()->ensureTextControl();
if (QTextControl *control = label->d_func()->control) {
QTextOption opt = control->document()->defaultTextOption();
@@ -372,7 +372,7 @@
policy.setHeightForWidth(true);
informativeLabel->setSizePolicy(policy);
width = qMax(width, layoutMinimumWidth());
- if (width > hardLimit) { // longest word is really big, so wrap anywhere
+ if ((hardLimit > 0) && (width > hardLimit)) { // longest word is really big, so wrap anywhere
informativeLabel->d_func()->ensureTextControl();
if (QTextControl *control = informativeLabel->d_func()->control) {
QTextOption opt = control->document()->defaultTextOption();
@@ -386,7 +386,10 @@
}
QFontMetrics fm(QApplication::font("QWorkspaceTitleBar"));
- int windowTitleWidth = qMin(fm.width(q->windowTitle()) + 50, hardLimit);
+ int windowTitleWidth = fm.width(q->windowTitle()) + 50;
+ if (hardLimit > 0) {
+ windowTitleWidth = qMin(fm.width(q->windowTitle()) + 50, hardLimit);
+ }
if (windowTitleWidth > width)
width = windowTitleWidth;
Reply to: