summaryrefslogtreecommitdiffstats
path: root/src/gui/kernel/qguiapplication.cpp
diff options
context:
space:
mode:
authorBradley T. Hughes <bradley.hughes@nokia.com>2012-03-28 15:26:17 +0200
committerQt by Nokia <qt-info@nokia.com>2012-04-11 16:17:59 +0200
commitad1bd1563f3f65d0f7b65687af2ade42f7f9f3d9 (patch)
treecaf53878e581afa44a53458dc5bcc23ea5eea972 /src/gui/kernel/qguiapplication.cpp
parenteff344ab8a509996cab491347aed4a4d8ea5b2ab (diff)
Implement window modality in QtGui
QWindow already has windowModality() and setWindowModality() as part of its API from commit 516f4e283ba4626d7239630397ef867ab0366071. Platform plugins can use this already to setup modality hints on windows that they create, but it's not enough to implement modality fully. QGuiApplication gets a modalWindow() static method, which is similar to QApplication::activeModalWidget() in that it returns the last modal window to be shown. The modal window "stack" moves from QApplicationPrivate to QGuiApplicationPrivate. The enterModal*() and leaveModal*() functions in QApplicationPrivate are removed and replaced by QGuiApplicationPrivate::showModalWindow() and hideModalWindow(), which are called by QWindow::setVisible() just before calling QPlatformWindow::setVisible(). The virtual QGuiApplicationPrivate::isWindowBlocked() will tell us if a window is blocked by a modal window (and tell which modal window for any interested callers). The default implementation works on the QWindow level. QApplicationPrivate reimplements isWindowBlocked() and adds popup and WA_GroupLeader support. QGuiApplication uses the state set from isWindowBlocked() to block user-input events: mouse press, mouse move, mouse release, wheel, key presses, key releases, enter/leave events, close events, and touch begin, update, and end events. Note also that the modality helper functions in QtWidgets and QApplicationPrivate are left in place and working as they always have. The behavior of QWidget in the presence of modal windows/dialogs should not change. Change-Id: I2c89e6026d40160387787a6e009ae1fdc12dfd69 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@nokia.com> Reviewed-by: Lars Knoll <lars.knoll@nokia.com> Reviewed-by: Samuel Rødal <samuel.rodal@nokia.com> Reviewed-by: Morten Johan Sørvig <morten.sorvig@nokia.com>
Diffstat (limited to 'src/gui/kernel/qguiapplication.cpp')
-rw-r--r--src/gui/kernel/qguiapplication.cpp158
1 files changed, 157 insertions, 1 deletions
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp
index e03fd6dba0..8dcd58a51a 100644
--- a/src/gui/kernel/qguiapplication.cpp
+++ b/src/gui/kernel/qguiapplication.cpp
@@ -114,7 +114,6 @@ enum ApplicationResourceFlags
static unsigned applicationResourceFlags = 0;
QString *QGuiApplicationPrivate::platform_name = 0;
-bool QGuiApplicationPrivate::app_do_modal = false;
QPalette *QGuiApplicationPrivate::app_pal = 0; // default application palette
@@ -384,6 +383,132 @@ QGuiApplicationPrivate::QGuiApplicationPrivate(int &argc, char **argv, int flags
}
/*!
+ Returns the most recently shown modal window. If no modal windows are
+ visible, this function returns zero.
+
+ A modal window is a window which has its
+ \l{QWindow::windowModality}{windowModality} property set to Qt::WindowModal
+ or Qt::ApplicationModal. A modal window must be closed before the user can
+ continue with other parts of the program.
+
+ Modal window are organized in a stack. This function returns the modal
+ window at the top of the stack.
+
+ \sa Qt::WindowModality, QWindow::setWindowModality()
+*/
+QWindow *QGuiApplication::modalWindow()
+{
+ if (QGuiApplicationPrivate::self->modalWindowList.isEmpty())
+ return 0;
+ return QGuiApplicationPrivate::self->modalWindowList.first();
+}
+
+void QGuiApplicationPrivate::showModalWindow(QWindow *window)
+{
+ self->modalWindowList.prepend(window);
+
+ QEvent e(QEvent::WindowBlocked);
+ QWindowList windows = QGuiApplication::topLevelWindows();
+ for (int i = 0; i < windows.count(); ++i) {
+ QWindow *window = windows.at(i);
+ if (!window->d_func()->blockedByModalWindow && window->windowType() != Qt::Tool && self->isWindowBlocked(window)) {
+ window->d_func()->blockedByModalWindow = true;
+ QGuiApplication::sendEvent(window, &e);
+ }
+ }
+}
+
+void QGuiApplicationPrivate::hideModalWindow(QWindow *window)
+{
+ self->modalWindowList.removeAll(window);
+
+ QEvent e(QEvent::WindowUnblocked);
+ QWindowList windows = QGuiApplication::topLevelWindows();
+ for (int i = 0; i < windows.count(); ++i) {
+ QWindow *window = windows.at(i);
+ if (window->d_func()->blockedByModalWindow && window->windowType() != Qt::Tool && !self->isWindowBlocked(window)) {
+ window->d_func()->blockedByModalWindow = false;
+ QGuiApplication::sendEvent(window, &e);
+ }
+ }
+}
+
+/*
+ Returns true if \a window is blocked by a modal window. If \a
+ blockingWindow is non-zero, *blockingWindow will be set to the blocking
+ window (or to zero if \a window is not blocked).
+*/
+bool QGuiApplicationPrivate::isWindowBlocked(QWindow *window, QWindow **blockingWindow) const
+{
+ QWindow *unused = 0;
+ if (!blockingWindow)
+ blockingWindow = &unused;
+
+ if (modalWindowList.isEmpty()) {
+ *blockingWindow = 0;
+ return false;
+ }
+
+ for (int i = 0; i < modalWindowList.count(); ++i) {
+ QWindow *modalWindow = modalWindowList.at(i);
+
+ {
+ // check if the modal window is our window or a (transient) parent of our window
+ QWindow *w = window;
+ while (w) {
+ if (w == modalWindow) {
+ *blockingWindow = 0;
+ return false;
+ }
+ QWindow *p = w->parent();
+ if (!p)
+ p = w->transientParent();
+ w = p;
+ }
+ }
+
+ Qt::WindowModality windowModality = modalWindow->windowModality();
+ switch (windowModality) {
+ case Qt::ApplicationModal:
+ {
+ if (modalWindow != window) {
+ *blockingWindow = modalWindow;
+ return true;
+ }
+ break;
+ }
+ case Qt::WindowModal:
+ {
+ QWindow *w = window;
+ do {
+ QWindow *m = modalWindow;
+ do {
+ if (m == w) {
+ *blockingWindow = m;
+ return true;
+ }
+ QWindow *p = m->parent();
+ if (!p)
+ p = m->transientParent();
+ m = p;
+ } while (m);
+ QWindow *p = w->parent();
+ if (!p)
+ p = w->transientParent();
+ w = p;
+ } while (w);
+ break;
+ }
+ default:
+ Q_ASSERT_X(false, "QGuiApplication", "internal error, a modal widget cannot be modeless");
+ break;
+ }
+ }
+ *blockingWindow = 0;
+ return false;
+}
+
+/*!
Returns the QWindow that receives events tied to focus,
such as key events.
*/
@@ -1058,6 +1183,11 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
}
if (window) {
+ if (window->d_func()->blockedByModalWindow) {
+ // a modal window is blocking this window, don't allow mouse events through
+ return;
+ }
+
QMouseEvent ev(type, localPoint, localPoint, globalPoint, button, buttons, e->modifiers);
ev.setTimestamp(e->timestamp);
#ifndef QT_NO_CURSOR
@@ -1120,6 +1250,11 @@ void QGuiApplicationPrivate::processWheelEvent(QWindowSystemInterfacePrivate::Wh
QWindow *window = e->window.data();
if (window) {
+ if (window->d_func()->blockedByModalWindow) {
+ // a modal window is blocking this window, don't allow wheel events through
+ return;
+ }
+
QWheelEvent ev(e->localPos, e->globalPos, e->pixelDelta, e->angleDelta, e->qt4Delta, e->qt4Orientation, buttons, e->modifiers);
ev.setTimestamp(e->timestamp);
QGuiApplication::sendSpontaneousEvent(window, &ev);
@@ -1137,6 +1272,10 @@ void QGuiApplicationPrivate::processKeyEvent(QWindowSystemInterfacePrivate::KeyE
window = QGuiApplication::activeWindow();
if (!window)
return;
+ if (window->d_func()->blockedByModalWindow) {
+ // a modal window is blocking this window, don't allow key events through
+ return;
+ }
QKeyEventEx ev(e->keyType, e->key, e->modifiers, e->unicode, e->repeat, e->repeatCount,
e->nativeScanCode, e->nativeVirtualKey, e->nativeModifiers);
@@ -1148,6 +1287,10 @@ void QGuiApplicationPrivate::processEnterEvent(QWindowSystemInterfacePrivate::En
{
if (!e->enter)
return;
+ if (e->enter.data()->d_func()->blockedByModalWindow) {
+ // a modal window is blocking this window, don't allow enter events through
+ return;
+ }
QEvent event(QEvent::Enter);
QCoreApplication::sendSpontaneousEvent(e->enter.data(), &event);
@@ -1157,6 +1300,10 @@ void QGuiApplicationPrivate::processLeaveEvent(QWindowSystemInterfacePrivate::Le
{
if (!e->leave)
return;
+ if (e->leave.data()->d_func()->blockedByModalWindow) {
+ // a modal window is blocking this window, don't allow leave events through
+ return;
+ }
QEvent event(QEvent::Leave);
QCoreApplication::sendSpontaneousEvent(e->leave.data(), &event);
@@ -1271,6 +1418,10 @@ void QGuiApplicationPrivate::processCloseEvent(QWindowSystemInterfacePrivate::Cl
{
if (e->window.isNull())
return;
+ if (e->window.data()->d_func()->blockedByModalWindow) {
+ // a modal window is blocking this window, don't allow close events through
+ return;
+ }
QCloseEvent event;
QGuiApplication::sendSpontaneousEvent(e->window.data(), &event);
@@ -1459,6 +1610,11 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
break;
}
+ if (w->d_func()->blockedByModalWindow) {
+ // a modal window is blocking this window, don't allow touch events through
+ continue;
+ }
+
QTouchEvent touchEvent(eventType,
e->device,
e->modifiers,