Fixes crash in QWidget::effectiveWinId.
Widgets are left in a transitional (and incosistent) state while being re-parented, which caused QWidget::effectiveWinId() to crash in certain circumstances. See patch for more details. Auto test included. Reviewed-by: ogoffart (cherry picked from commit 6db0153cd7e35e4a919a76ae2aadbf2d2510bfb7)
This commit is contained in:
parent
7ee981a834
commit
1e41e3076a
@ -299,6 +299,7 @@ QWidgetPrivate::QWidgetPrivate(int version)
|
||||
#ifndef QT_NO_IM
|
||||
, inheritsInputMethodHints(0)
|
||||
#endif
|
||||
, inSetParent(0)
|
||||
#if defined(Q_WS_X11)
|
||||
, picture(0)
|
||||
#elif defined(Q_WS_WIN)
|
||||
@ -2599,6 +2600,22 @@ WId QWidget::effectiveWinId() const
|
||||
if (id || !testAttribute(Qt::WA_WState_Created))
|
||||
return id;
|
||||
QWidget *realParent = nativeParentWidget();
|
||||
if (!realParent && d_func()->inSetParent) {
|
||||
// In transitional state. This is really just a workaround. The real problem
|
||||
// is that QWidgetPrivate::setParent_sys (platform specific code) first sets
|
||||
// the window id to 0 (setWinId(0)) before it sets the Qt::WA_WState_Created
|
||||
// attribute to false. The correct way is to do it the other way around, and
|
||||
// in that case the Qt::WA_WState_Created logic above will kick in and
|
||||
// return 0 whenever the widget is in a transitional state. However, changing
|
||||
// the original logic for all platforms is far more intrusive and might
|
||||
// break existing applications.
|
||||
// Note: The widget can only be in a transitional state when changing its
|
||||
// parent -- everything else is an internal error -- hence explicitly checking
|
||||
// against 'inSetParent' rather than doing an unconditional return whenever
|
||||
// 'realParent' is 0 (which may cause strange artifacts and headache later).
|
||||
return 0;
|
||||
}
|
||||
// This widget *must* have a native parent widget.
|
||||
Q_ASSERT(realParent);
|
||||
Q_ASSERT(realParent->internalWinId());
|
||||
return realParent->internalWinId();
|
||||
@ -10111,6 +10128,7 @@ void QWidget::setParent(QWidget *parent)
|
||||
void QWidget::setParent(QWidget *parent, Qt::WindowFlags f)
|
||||
{
|
||||
Q_D(QWidget);
|
||||
d->inSetParent = true;
|
||||
bool resized = testAttribute(Qt::WA_Resized);
|
||||
bool wasCreated = testAttribute(Qt::WA_WState_Created);
|
||||
QWidget *oldtlw = window();
|
||||
@ -10271,6 +10289,8 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f)
|
||||
ancestorProxy->d_func()->embedSubWindow(this);
|
||||
}
|
||||
#endif
|
||||
|
||||
d->inSetParent = false;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -770,6 +770,7 @@ public:
|
||||
#ifndef QT_NO_IM
|
||||
uint inheritsInputMethodHints : 1;
|
||||
#endif
|
||||
uint inSetParent : 1;
|
||||
|
||||
// *************************** Platform specific ************************************
|
||||
#if defined(Q_WS_X11) // <----------------------------------------------------------- X11
|
||||
|
@ -345,6 +345,7 @@ private slots:
|
||||
void immediateRepaintAfterInvalidateBuffer();
|
||||
#endif
|
||||
void effectiveWinId();
|
||||
void effectiveWinId2();
|
||||
void customDpi();
|
||||
void customDpiProperty();
|
||||
|
||||
@ -8495,6 +8496,30 @@ void tst_QWidget::effectiveWinId()
|
||||
QVERIFY(child.effectiveWinId());
|
||||
}
|
||||
|
||||
void tst_QWidget::effectiveWinId2()
|
||||
{
|
||||
QWidget parent;
|
||||
|
||||
class MyWidget : public QWidget {
|
||||
bool event(QEvent *e)
|
||||
{
|
||||
if (e->type() == QEvent::WinIdChange) {
|
||||
// Shouldn't crash.
|
||||
effectiveWinId();
|
||||
}
|
||||
|
||||
return QWidget::event(e);
|
||||
}
|
||||
};
|
||||
|
||||
MyWidget child;
|
||||
child.setParent(&parent);
|
||||
parent.show();
|
||||
|
||||
child.setParent(0);
|
||||
child.setParent(&parent);
|
||||
}
|
||||
|
||||
class CustomWidget : public QWidget
|
||||
{
|
||||
public:
|
||||
|
Loading…
Reference in New Issue
Block a user