Add QDeferredDeleteEvent

Use this to store the loop-level counter needed by QCoreApplication
when determining when it is safe to delete an object.

This removes the hack to hijack the QEvent::d pointer (even though
the pointer is unused).

Change-Id: I91c0b1aa00235ec6e13feb30bf928e56d2f80026
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Bradley T. Hughes 2012-05-14 13:27:28 +02:00 committed by Qt by Nokia
parent 00f88bd090
commit 9b07fd0d5c
5 changed files with 39 additions and 13 deletions

View File

@ -1105,13 +1105,7 @@ void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority)
if (event->type() == QEvent::DeferredDelete && data == QThreadData::current()) {
// remember the current running eventloop for DeferredDelete
// events posted in the receiver's thread
// check that QEvent's d pointer is unused before we store the loop level
// if further updates to QEvent have made the use of the d pointer necessary,
// then update this code to store the loop level somewhere else
Q_ASSERT_X(event->d == 0, "QCoreApplication::postEvent",
"Internal error: this code relies on QEvent::d being null");
event->d = reinterpret_cast<QEventPrivate *>(quintptr(data->loopLevel));
static_cast<QDeferredDeleteEvent *>(event)->level = data->loopLevel;
}
// delete the event on exceptions to protect against memory leaks till the event is
@ -1280,11 +1274,12 @@ void QCoreApplicationPrivate::sendPostedEvents(QObject *receiver, int event_type
// DeferredDelete events are only sent when we are explicitly asked to
// (s.a. QEvent::DeferredDelete), and then only if the event loop that
// posted the event has returned.
int loopLevel = static_cast<QDeferredDeleteEvent *>(pe.event)->loopLevel();
const bool allowDeferredDelete =
(quintptr(pe.event->d) > unsigned(data->loopLevel)
|| (!quintptr(pe.event->d) && data->loopLevel > 0)
(loopLevel > data->loopLevel
|| (!loopLevel && data->loopLevel > 0)
|| (event_type == QEvent::DeferredDelete
&& quintptr(pe.event->d) == unsigned(data->loopLevel)));
&& loopLevel == data->loopLevel));
if (!allowDeferredDelete) {
// cannot send deferred delete
if (!event_type && !receiver) {

View File

@ -116,7 +116,7 @@ QT_BEGIN_NAMESPACE
\value ContentsRectChange The margins of the widget's content rect changed.
\value ContextMenu Context popup menu (QContextMenuEvent).
\value CursorChange The widget's cursor has changed.
\value DeferredDelete The object will be deleted after it has cleaned up.
\value DeferredDelete The object will be deleted after it has cleaned up (QDeferredDeleteEvent).
\value DragEnter The cursor enters a widget during a drag and drop operation (QDragEnterEvent).
\value DragLeave The cursor leaves a widget during a drag and drop operation (QDragLeaveEvent).
\value DragMove A drag and drop operation is in progress (QDragMoveEvent).
@ -580,4 +580,24 @@ QDynamicPropertyChangeEvent::~QDynamicPropertyChangeEvent()
\sa QObject::setProperty(), QObject::dynamicPropertyNames()
*/
/*!
Constructs a deferred delete event with an initial loopLevel() of zero.
*/
QDeferredDeleteEvent::QDeferredDeleteEvent()
: QEvent(QEvent::DeferredDelete)
, level(0)
{ }
/*! \internal */
QDeferredDeleteEvent::~QDeferredDeleteEvent()
{ }
/*! \fn int QDeferredDeleteEvent::loopLevel() const
Returns the loop-level in which the event was posted. The
loop-level is set by QCoreApplication::postEvent().
\sa QObject::deleteLater()
*/
QT_END_NAMESPACE

View File

@ -360,6 +360,17 @@ private:
QByteArray n;
};
class Q_CORE_EXPORT QDeferredDeleteEvent : public QEvent
{
public:
explicit QDeferredDeleteEvent();
~QDeferredDeleteEvent();
int loopLevel() const { return level; }
private:
int level;
friend class QCoreApplication;
};
QT_END_NAMESPACE
QT_END_HEADER

View File

@ -1907,7 +1907,7 @@ void QObject::removeEventFilter(QObject *obj)
*/
void QObject::deleteLater()
{
QCoreApplication::postEvent(this, new QEvent(QEvent::DeferredDelete));
QCoreApplication::postEvent(this, new QDeferredDeleteEvent());
}
/*!

View File

@ -1045,7 +1045,7 @@ void SendPostedEventsTester::doTest()
QPointer<SendPostedEventsTester> p = this;
QApplication::postEvent(this, new QEvent(QEvent::User));
// DeferredDelete should not be delivered until returning from this function
QApplication::postEvent(this, new QEvent(QEvent::DeferredDelete));
QApplication::postEvent(this, new QDeferredDeleteEvent());
QEventLoop eventLoop;
QMetaObject::invokeMethod(&eventLoop, "quit", Qt::QueuedConnection);