summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gui/kernel/qguiapplication.cpp30
-rw-r--r--src/gui/kernel/qguiapplication_p.h1
-rw-r--r--src/gui/kernel/qwindow.cpp51
-rw-r--r--src/gui/kernel/qwindow_p.h4
-rw-r--r--src/widgets/kernel/qapplication.cpp4
-rw-r--r--src/widgets/kernel/qwidget.cpp26
-rw-r--r--src/widgets/kernel/qwidgetwindow.cpp34
7 files changed, 82 insertions, 68 deletions
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp
index 98b5ea03e6..294684584b 100644
--- a/src/gui/kernel/qguiapplication.cpp
+++ b/src/gui/kernel/qguiapplication.cpp
@@ -1918,6 +1918,8 @@ void QGuiApplicationPrivate::captureGlobalModifierState(QEvent *e)
*/
bool QGuiApplication::notify(QObject *object, QEvent *event)
{
+ Q_D(QGuiApplication);
+
if (object->isWindowType()) {
if (QGuiApplicationPrivate::sendQWindowEventToQPlatformWindow(static_cast<QWindow *>(object), event))
return true; // Platform plugin ate the event
@@ -1925,7 +1927,12 @@ bool QGuiApplication::notify(QObject *object, QEvent *event)
QGuiApplicationPrivate::captureGlobalModifierState(event);
- return QCoreApplication::notify(object, event);
+ bool accepted = QCoreApplication::notify(object, event);
+
+ if (event->type() == QEvent::Close && object->isWindowType() && accepted)
+ d->maybeQuitOnLastWindowClosed(static_cast<QWindow*>(object));
+
+ return accepted;
}
/*! \reimp
@@ -3533,13 +3540,30 @@ void QGuiApplication::setQuitOnLastWindowClosed(bool quit)
QCoreApplication::setQuitLockEnabled(quit);
}
-
-
bool QGuiApplication::quitOnLastWindowClosed()
{
return QCoreApplication::isQuitLockEnabled();
}
+void QGuiApplicationPrivate::maybeQuitOnLastWindowClosed(QWindow *closedWindow)
+{
+ Q_ASSERT(closedWindow);
+
+ if (!qt_window_private(closedWindow)->shouldTriggerQuitOnClose())
+ return;
+
+ // Check if there are any remaining windows that should prevent us from quitting
+ for (auto *topLevelWindow : QGuiApplication::topLevelWindows()) {
+ auto *windowPrivate = qt_window_private(topLevelWindow);
+ if (windowPrivate->shouldCancelQuitOnClose())
+ return;
+ }
+
+ emitLastWindowClosed();
+
+ if (QGuiApplication::quitOnLastWindowClosed())
+ maybeQuit();
+}
/*!
\fn void QGuiApplication::lastWindowClosed()
diff --git a/src/gui/kernel/qguiapplication_p.h b/src/gui/kernel/qguiapplication_p.h
index 7b28c70993..3450c6e36b 100644
--- a/src/gui/kernel/qguiapplication_p.h
+++ b/src/gui/kernel/qguiapplication_p.h
@@ -109,6 +109,7 @@ public:
void quit() override;
bool shouldQuitInternal(const QWindowList &processedWindows);
+ void maybeQuitOnLastWindowClosed(QWindow *closedWindow);
static void captureGlobalModifierState(QEvent *e);
static Qt::KeyboardModifiers modifier_buttons;
diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp
index e1733cbf46..cdb2534b2e 100644
--- a/src/gui/kernel/qwindow.cpp
+++ b/src/gui/kernel/qwindow.cpp
@@ -2268,6 +2268,18 @@ bool QWindow::close()
return d->platformWindow->close();
}
+bool QWindowPrivate::shouldTriggerQuitOnClose() const
+{
+ Q_Q(const QWindow);
+ return q->isTopLevel();
+}
+
+bool QWindowPrivate::shouldCancelQuitOnClose() const
+{
+ Q_Q(const QWindow);
+ return q->isVisible() && !q->transientParent() && q->type() != Qt::ToolTip;
+}
+
/*!
The expose event (\a ev) is sent by the window system when a window moves
between the un-exposed and exposed states.
@@ -2444,17 +2456,8 @@ bool QWindow::event(QEvent *ev)
case QEvent::Close:
closeEvent(static_cast<QCloseEvent*>(ev));
- if (ev->isAccepted()) {
- Q_D(QWindow);
- bool wasVisible = isVisible();
+ if (ev->isAccepted())
destroy();
- if (wasVisible) {
- // FIXME: This check for visibility is a workaround for both QWidgetWindow
- // and QWindow having logic to emit lastWindowClosed, and possibly quit the
- // application. We should find a better way to handle this.
- d->maybeQuitOnLastWindowClosed();
- }
- }
break;
case QEvent::Expose:
@@ -2806,34 +2809,6 @@ Q_GUI_EXPORT QWindowPrivate *qt_window_private(QWindow *window)
return window->d_func();
}
-void QWindowPrivate::maybeQuitOnLastWindowClosed()
-{
- if (!QCoreApplication::instance())
- return;
-
- Q_Q(QWindow);
- if (!q->isTopLevel())
- return;
-
- QWindowList list = QGuiApplication::topLevelWindows();
- bool lastWindowClosed = true;
- for (int i = 0; i < list.size(); ++i) {
- QWindow *w = list.at(i);
- if (!w->isVisible() || w->transientParent() || w->type() == Qt::ToolTip)
- continue;
- lastWindowClosed = false;
- break;
- }
- if (lastWindowClosed) {
- QGuiApplicationPrivate::emitLastWindowClosed();
-
- if (QGuiApplication::quitOnLastWindowClosed()) {
- QCoreApplicationPrivate *applicationPrivate = static_cast<QCoreApplicationPrivate*>(QObjectPrivate::get(QCoreApplication::instance()));
- applicationPrivate->maybeQuit();
- }
- }
-}
-
QWindow *QWindowPrivate::topLevelWindow(QWindow::AncestorMode mode) const
{
Q_Q(const QWindow);
diff --git a/src/gui/kernel/qwindow_p.h b/src/gui/kernel/qwindow_p.h
index fef8b4ca72..3eeafeff86 100644
--- a/src/gui/kernel/qwindow_p.h
+++ b/src/gui/kernel/qwindow_p.h
@@ -81,7 +81,6 @@ public:
void init(QScreen *targetScreen = nullptr);
- void maybeQuitOnLastWindowClosed();
#ifndef QT_NO_CURSOR
void setCursor(const QCursor *c = nullptr);
bool applyCursor();
@@ -119,6 +118,9 @@ public:
virtual void processSafeAreaMarginsChanged() {}
+ virtual bool shouldTriggerQuitOnClose() const;
+ virtual bool shouldCancelQuitOnClose() const;
+
bool isPopup() const { return (windowFlags & Qt::WindowType_Mask) == Qt::Popup; }
void setAutomaticPositionAndResizeEnabled(bool a)
{ positionAutomatic = resizeAutomatic = a; }
diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp
index 9069b9005d..74868077b3 100644
--- a/src/widgets/kernel/qapplication.cpp
+++ b/src/widgets/kernel/qapplication.cpp
@@ -3342,6 +3342,10 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
break;
}
+ // We don't call QGuiApplication::notify here, so we need to duplicate the logic
+ if (e->type() == QEvent::Close && receiver->isWindowType() && res)
+ d->maybeQuitOnLastWindowClosed(static_cast<QWindow *>(receiver));
+
return res;
}
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
index dcd3d1f1d9..a92454547a 100644
--- a/src/widgets/kernel/qwidget.cpp
+++ b/src/widgets/kernel/qwidget.cpp
@@ -8399,8 +8399,6 @@ bool QWidgetPrivate::handleClose(CloseMode mode)
QPointer<QWidget> that = q;
QPointer<QWidget> parentWidget = (q->parentWidget() && !QObjectPrivate::get(q->parentWidget())->wasDeleted) ? q->parentWidget() : nullptr;
- bool quitOnClose = q->testAttribute(Qt::WA_QuitOnClose);
-
if (data.in_destructor)
mode = CloseNoEvent;
@@ -8420,30 +8418,6 @@ bool QWidgetPrivate::handleClose(CloseMode mode)
if (!that.isNull() && !q->isHidden())
q->hide();
- // Attempt to close the application only if this has WA_QuitOnClose set and a non-visible parent
- quitOnClose = quitOnClose && (parentWidget.isNull() || !parentWidget->isVisible());
-
- if (quitOnClose) {
- /* if there is no non-withdrawn primary window left (except
- the ones without QuitOnClose), we emit the lastWindowClosed
- signal */
- QWidgetList list = QApplication::topLevelWidgets();
- bool lastWindowClosed = true;
- for (int i = 0; i < list.size(); ++i) {
- QWidget *w = list.at(i);
- if (!w->isVisible() || w->parentWidget() || !w->testAttribute(Qt::WA_QuitOnClose))
- continue;
- lastWindowClosed = false;
- break;
- }
- if (lastWindowClosed) {
- QGuiApplicationPrivate::emitLastWindowClosed();
- QCoreApplicationPrivate *applicationPrivate = static_cast<QCoreApplicationPrivate*>(QObjectPrivate::get(QCoreApplication::instance()));
- applicationPrivate->maybeQuit();
- }
- }
-
-
if (!that.isNull()) {
data.is_closing = false;
if (q->testAttribute(Qt::WA_DeleteOnClose)) {
diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp
index 80e9b1ab5c..0d73e55719 100644
--- a/src/widgets/kernel/qwidgetwindow.cpp
+++ b/src/widgets/kernel/qwidgetwindow.cpp
@@ -115,6 +115,9 @@ public:
if (QWidget *widget = q->widget())
QWidgetPrivate::get(widget)->updateContentsRect();
}
+
+ bool shouldTriggerQuitOnClose() const override;
+ bool shouldCancelQuitOnClose() const override;
};
QRectF QWidgetWindowPrivate::closestAcceptableGeometry(const QRectF &rect) const
@@ -843,6 +846,37 @@ void QWidgetWindow::handleCloseEvent(QCloseEvent *event)
event->setAccepted(accepted);
}
+bool QWidgetWindowPrivate::shouldTriggerQuitOnClose() const
+{
+ Q_Q(const QWidgetWindow);
+ QWidget *widget = q->widget();
+
+ // Closing a window without WA_QuitOnClose should stop us from even
+ // looking at the other windows. Otherwise we might find that all the
+ // other windows miss WA_QuitOnClose as well, and end up quitting,
+ // but that's not what the user intended.
+ if (!widget->testAttribute(Qt::WA_QuitOnClose))
+ return false;
+
+ // Qt::Tool windows do not have WA_QuitOnClose set by default, which
+ // means that if you open a dialog from one, and the tool window is
+ // the only remaining window, then closing the dialog would result
+ // in quitting the application. To prevent this we check if the
+ // closed widget has a visible parent (the Qt:Tool window in this
+ // case), and if so bail out.
+ if (widget->parentWidget() && widget->parentWidget()->isVisible())
+ return false;
+
+ return true;
+}
+
+bool QWidgetWindowPrivate::shouldCancelQuitOnClose() const
+{
+ Q_Q(const QWidgetWindow);
+ QWidget *w = q->widget();
+ return w->isVisible() && !w->parentWidget() & w->testAttribute(Qt::WA_QuitOnClose);
+}
+
#if QT_CONFIG(wheelevent)
void QWidgetWindow::handleWheelEvent(QWheelEvent *event)