diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp index f5bcf3596f7643bd31c66ad3172429a6ba8fa9f1..7f80697f3c733522f93944edcaadbf6bda38eeca 100644 --- a/src/quick/items/qquickitemsmodule.cpp +++ b/src/quick/items/qquickitemsmodule.cpp @@ -167,6 +167,7 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) qmlRegisterType<QQuickKeyEvent>(); qmlRegisterType<QQuickMouseEvent>(); qmlRegisterType<QQuickWheelEvent>(); + qmlRegisterType<QQuickCloseEvent>(); qmlRegisterType<QQuickTransform>(); qmlRegisterType<QQuickPathElement>(); qmlRegisterType<QQuickCurve>(); diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index ad13489983a4573f516686cdd27eae2e6b9fa36b..4a34adabe8921b533c6bf44c9e121af3358a02ad 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -840,6 +840,11 @@ void QQuickWindowPrivate::cleanup(QSGNode *n) Alternatively you can set or bind \l x and \l y to position the Window explicitly on the screen. + + When the user attempts to close a window, the \a closing signal will be + emitted. You can force the window to stay open (for example to prompt the + user to save changes) by writing an onClosing handler and setting + close.accepted = false. */ /*! \class QQuickWindow @@ -1174,6 +1179,14 @@ bool QQuickWindow::event(QEvent *e) case QEvent::WindowDeactivate: contentItem()->windowDeactivateEvent(); break; + case QEvent::Close: { + // TOOD Qt 6 (binary incompatible) + // closeEvent(static_cast<QCloseEvent *>(e)); + QQuickCloseEvent qev; + qev.setAccepted(e->isAccepted()); + emit closing(&qev); + e->setAccepted(qev.isAccepted()); + } break; case QEvent::FocusAboutToChange: #ifndef QT_NO_IM if (d->activeFocusItem) @@ -2558,6 +2571,57 @@ QOpenGLContext *QQuickWindow::openglContext() const This signal will be emitted from the scene graph rendering thread. */ +/*! + \class QQuickCloseEvent + \internal + \since QtQuick 2.1 + + \inmodule QtQuick.Window + + \brief Notification that a \l QQuickWindow is about to be closed +*/ +/*! + \qmltype CloseEvent + \instantiates QQuickCloseEvent + \inqmlmodule QtQuick.Window 2 + \ingroup qtquick-visual + \brief Notification that a \l Window is about to be closed + \since Qt 5.1 + + Notification that a window is about to be closed by the windowing system + (e.g. the user clicked the titlebar close button). The CloseEvent contains + an accepted property which can be set to false to abort closing the window. + + \sa Window.closing() +*/ + +/*! + \qmlproperty bool QtQuick.Window2::CloseEvent::accepted + + This property indicates whether the application will allow the user to + close the window. It is true by default. +*/ + +/*! + \fn void QQuickWindow::closing() + \since QtQuick 2.1 + + This signal is emitted when the window receives a QCloseEvent from the + windowing system. +*/ + +/*! + \qmlsignal QtQuick.Window2::closing(CloseEvent close) + \since Qt 5.1 + + This signal is emitted when the user tries to close the window. + + This signal includes a closeEvent parameter. The \a close \l accepted + property is true by default so that the window is allowed to close; but you + can implement an onClosing() handler and set close.accepted = false if + you need to do something else before the window can be closed. + */ + /*! Sets the render target for this window to be \a fbo. diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h index 3adc0be83ba86c0b5d82a0f2a90bbb86863c38b5..fc148aabe6893000fa55bd3caa32cf478b8be456 100644 --- a/src/quick/items/qquickwindow.h +++ b/src/quick/items/qquickwindow.h @@ -57,6 +57,7 @@ class QQuickWindowPrivate; class QOpenGLFramebufferObject; class QQmlIncubationController; class QInputMethodEvent; +class QQuickCloseEvent; class Q_QUICK_EXPORT QQuickWindow : public QWindow { @@ -129,6 +130,7 @@ Q_SIGNALS: void beforeSynchronizing(); void beforeRendering(); void afterRendering(); + Q_REVISION(1) void closing(QQuickCloseEvent *close); void colorChanged(const QColor &); Q_REVISION(1) void activeFocusItemChanged(); @@ -144,6 +146,7 @@ protected: virtual void showEvent(QShowEvent *); virtual void hideEvent(QHideEvent *); + // TODO Qt 6: reimplement QWindow::closeEvent to emit closing virtual void focusInEvent(QFocusEvent *); virtual void focusOutEvent(QFocusEvent *); diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h index afcf4a995a211f67087723891f080b7085ce1c93..9e3251b240f622131c22d30715b10865f5d2e0b4 100644 --- a/src/quick/items/qquickwindow_p.h +++ b/src/quick/items/qquickwindow_p.h @@ -231,9 +231,26 @@ private: static void cleanupNodesOnShutdown(QQuickItem *); }; +class Q_QUICK_PRIVATE_EXPORT QQuickCloseEvent : public QObject +{ + Q_OBJECT + Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted) + +public: + QQuickCloseEvent() + : _accepted(true) {} + + bool isAccepted() { return _accepted; } + void setAccepted(bool accepted) { _accepted = accepted; } + +private: + bool _accepted; +}; Q_DECLARE_OPERATORS_FOR_FLAGS(QQuickWindowPrivate::FocusOptions) QT_END_NAMESPACE +QML_DECLARE_TYPE(QQuickCloseEvent) + #endif // QQUICKWINDOW_P_H diff --git a/tests/auto/quick/qquickwindow/data/ucantclosethis.qml b/tests/auto/quick/qquickwindow/data/ucantclosethis.qml new file mode 100644 index 0000000000000000000000000000000000000000..aa68cf5105e26f59fee0b42ea769fa2440a102b7 --- /dev/null +++ b/tests/auto/quick/qquickwindow/data/ucantclosethis.qml @@ -0,0 +1,32 @@ +import QtQuick 2.1 +import QtQuick.Window 2.1 + +Window { + width: 240 + height: 75 + title: "Hammer sez" + color: "#e0c31e" + property bool canCloseThis: false; + Rectangle { + color: "#14148c" + width: parent.width * 0.85 + height: parent.height * 0.7 + anchors.horizontalCenter: parent.horizontalCenter + Text { + id: text + anchors.centerIn: parent + color: "white" + textFormat: Text.StyledText + text: "whoa-oa-oa-oh<br/>U can't <font color='#b40000' size='+1'>close</font> this" + } + } + onClosing: { + if (canCloseThis) { + text.text = "uncle! I give up" + // the event is accepted by default + } else { + close.accepted = false + text.text = "...but you still can't close this" + } + } +} diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp index c3308bfd7d159e58833ed77fac33675a0230b690..e2bb6b431c518df41d065d281c2d39741ecc4225 100644 --- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp +++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp @@ -326,6 +326,8 @@ private slots: void requestActivate(); + void blockClosing(); + #ifndef QT_NO_CURSOR void cursor(); #endif @@ -1466,6 +1468,25 @@ void tst_qquickwindow::requestActivate() QVERIFY(windows.at(0)->isActive()); } +void tst_qquickwindow::blockClosing() +{ + QQmlEngine engine; + QQmlComponent component(&engine); + component.loadUrl(testFileUrl("ucantclosethis.qml")); + QQuickWindow* window = qobject_cast<QQuickWindow *>(component.create()); + QVERIFY(window); + window->show(); + QTest::qWaitForWindowExposed(window); + QVERIFY(window->isVisible()); + QWindowSystemInterface::handleCloseEvent(window); + QVERIFY(window->isVisible()); + QWindowSystemInterface::handleCloseEvent(window); + QVERIFY(window->isVisible()); + window->setProperty("canCloseThis", true); + QWindowSystemInterface::handleCloseEvent(window); + QTRY_VERIFY(!window->isVisible()); +} + QTEST_MAIN(tst_qquickwindow) #include "tst_qquickwindow.moc"