summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gui/kernel/qguiapplication.cpp22
-rw-r--r--src/gui/kernel/qguiapplication.h4
-rw-r--r--src/gui/kernel/qguiapplication_p.h2
-rw-r--r--src/gui/kernel/qwindow.cpp72
-rw-r--r--src/gui/kernel/qwindow.h12
-rw-r--r--src/widgets/kernel/qapplication_qpa.cpp2
-rw-r--r--src/widgets/kernel/qwidgetwindow_qpa.cpp6
-rw-r--r--tests/auto/qfiledialog2/tst_qfiledialog2.cpp2
-rw-r--r--tests/auto/qwindow/tst_qwindow.cpp118
9 files changed, 197 insertions, 43 deletions
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp
index bfa60fa657..986fc5c11d 100644
--- a/src/gui/kernel/qguiapplication.cpp
+++ b/src/gui/kernel/qguiapplication.cpp
@@ -114,7 +114,7 @@ QClipboard *QGuiApplicationPrivate::qt_clipboard = 0;
QList<QScreen *> QGuiApplicationPrivate::screen_list;
QWindowList QGuiApplicationPrivate::window_list;
-QWindow *QGuiApplicationPrivate::active_window = 0;
+QWindow *QGuiApplicationPrivate::focus_window = 0;
Q_GLOBAL_STATIC(QMutex, applicationFontMutex)
QFont *QGuiApplicationPrivate::app_font = 0;
@@ -181,9 +181,9 @@ QGuiApplicationPrivate::QGuiApplicationPrivate(int &argc, char **argv, int flags
self = this;
}
-QWindow *QGuiApplication::activeWindow()
+QWindow *QGuiApplication::focusWindow()
{
- return QGuiApplicationPrivate::active_window;
+ return QGuiApplicationPrivate::focus_window;
}
QWindowList QGuiApplication::topLevelWindows()
@@ -678,8 +678,20 @@ void QGuiApplicationPrivate::processActivatedEvent(QWindowSystemInterfacePrivate
if (!e->activated)
return;
- QWindow *previous = QGuiApplicationPrivate::active_window;
- QGuiApplicationPrivate::active_window = e->activated.data();
+ QWindow *previous = QGuiApplicationPrivate::focus_window;
+ QGuiApplicationPrivate::focus_window = e->activated.data();
+
+ if (previous == QGuiApplicationPrivate::focus_window)
+ return;
+
+ if (previous) {
+ QFocusEvent focusOut(QEvent::FocusOut);
+ QCoreApplication::sendSpontaneousEvent(previous, &focusOut);
+ }
+
+ QFocusEvent focusIn(QEvent::FocusIn);
+ QCoreApplication::sendSpontaneousEvent(QGuiApplicationPrivate::focus_window, &focusIn);
+
if (self)
self->notifyActiveWindowChange(previous);
}
diff --git a/src/gui/kernel/qguiapplication.h b/src/gui/kernel/qguiapplication.h
index 7b8590233e..80c71dfa2a 100644
--- a/src/gui/kernel/qguiapplication.h
+++ b/src/gui/kernel/qguiapplication.h
@@ -85,7 +85,9 @@ public:
static QWindowList topLevelWindows();
static QWindow *topLevelAt(const QPoint &pos);
- static QWindow *activeWindow();
+ static QT_DEPRECATED QWindow *activeWindow() { return focusWindow(); }
+ static QWindow *focusWindow();
+
static QScreen *primaryScreen();
static QList<QScreen *> screens();
diff --git a/src/gui/kernel/qguiapplication_p.h b/src/gui/kernel/qguiapplication_p.h
index 7ee95b777f..ccaf1292ae 100644
--- a/src/gui/kernel/qguiapplication_p.h
+++ b/src/gui/kernel/qguiapplication_p.h
@@ -161,7 +161,7 @@ public:
static QPalette *app_pal;
static QWindowList window_list;
- static QWindow *active_window;
+ static QWindow *focus_window;
#ifndef QT_NO_CURSOR
QList<QCursor> cursor_list;
diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp
index 489a7498f4..b1c26a39f1 100644
--- a/src/gui/kernel/qwindow.cpp
+++ b/src/gui/kernel/qwindow.cpp
@@ -95,8 +95,8 @@ QWindow::QWindow(QWindowPrivate &dd, QWindow *parent)
QWindow::~QWindow()
{
- if (QGuiApplicationPrivate::active_window == this)
- QGuiApplicationPrivate::active_window = 0;
+ if (QGuiApplicationPrivate::focus_window == this)
+ QGuiApplicationPrivate::focus_window = 0;
QGuiApplicationPrivate::window_list.removeAll(this);
destroy();
}
@@ -320,9 +320,32 @@ void QWindow::setOpacity(qreal level)
void QWindow::requestActivateWindow()
{
Q_D(QWindow);
- QGuiApplicationPrivate::active_window = this;
- if (d->platformWindow) {
+ if (d->platformWindow)
d->platformWindow->requestActivateWindow();
+}
+
+/*!
+ Returns true if the window should appear active from a style perspective.
+
+ This is the case for the window that has input focus as well as windows
+ that are in the same parent / transient parent chain as the focus window.
+
+ To get the window that currently has focus, use QGuiApplication::focusWindow().
+*/
+bool QWindow::isActive() const
+{
+ Q_D(const QWindow);
+ if (!d->platformWindow)
+ return false;
+
+ QWindow *focus = QGuiApplication::focusWindow();
+ if (focus == this)
+ return true;
+
+ if (!parent() && !transientParent()) {
+ return isAncestorOf(focus);
+ } else {
+ return (parent() && parent()->isActive()) || (transientParent() && transientParent()->isActive());
}
}
@@ -335,7 +358,7 @@ Qt::WindowState QWindow::windowState() const
void QWindow::setWindowState(Qt::WindowState state)
{
if (state == Qt::WindowActive) {
- requestActivateWindow();
+ qWarning() << "QWindow::setWindowState does not accept Qt::WindowActive";
return;
}
@@ -361,6 +384,29 @@ QWindow *QWindow::transientParent() const
return d->transientParent.data();
}
+/*!
+ \enum QWindow::AncestorMode
+
+ This enum is used to control whether or not transient parents
+ should be considered ancestors.
+
+ \value ExcludeTransients Transient parents are not considered ancestors.
+ \value IncludeTransients Transient parents are considered ancestors.
+*/
+
+/*!
+ Returns true if the window is an ancestor of the given child. If mode is
+ IncludeTransients transient parents are also considered ancestors.
+*/
+bool QWindow::isAncestorOf(const QWindow *child, AncestorMode mode) const
+{
+ if (child->parent() == this || (mode == IncludeTransients && child->transientParent() == this))
+ return true;
+
+ return (child->parent() && isAncestorOf(child->parent(), mode))
+ || (mode == IncludeTransients && child->transientParent() && isAncestorOf(child->transientParent(), mode));
+}
+
QSize QWindow::minimumSize() const
{
Q_D(const QWindow);
@@ -670,6 +716,14 @@ bool QWindow::event(QEvent *event)
keyReleaseEvent(static_cast<QKeyEvent *>(event));
break;
+ case QEvent::FocusIn:
+ focusInEvent(static_cast<QFocusEvent *>(event));
+ break;
+
+ case QEvent::FocusOut:
+ focusOutEvent(static_cast<QFocusEvent *>(event));
+ break;
+
#ifndef QT_NO_WHEELEVENT
case QEvent::Wheel:
wheelEvent(static_cast<QWheelEvent*>(event));
@@ -710,6 +764,14 @@ void QWindow::keyReleaseEvent(QKeyEvent *)
{
}
+void QWindow::focusInEvent(QFocusEvent *)
+{
+}
+
+void QWindow::focusOutEvent(QFocusEvent *)
+{
+}
+
void QWindow::inputMethodEvent(QInputMethodEvent *)
{
}
diff --git a/src/gui/kernel/qwindow.h b/src/gui/kernel/qwindow.h
index fefece1e9e..499582e348 100644
--- a/src/gui/kernel/qwindow.h
+++ b/src/gui/kernel/qwindow.h
@@ -60,6 +60,7 @@ QT_MODULE(Gui)
class QWindowPrivate;
class QExposeEvent;
+class QFocusEvent;
class QMoveEvent;
class QResizeEvent;
class QShowEvent;
@@ -123,12 +124,21 @@ public:
void setOpacity(qreal level);
void requestActivateWindow();
+ bool isActive() const;
+
Qt::WindowState windowState() const;
void setWindowState(Qt::WindowState state);
void setTransientParent(QWindow *parent);
QWindow *transientParent() const;
+ enum AncestorMode {
+ ExcludeTransients,
+ IncludeTransients
+ };
+
+ bool isAncestorOf(const QWindow *child, AncestorMode mode = IncludeTransients) const;
+
QSize minimumSize() const;
QSize maximumSize() const;
QSize baseSize() const;
@@ -205,6 +215,8 @@ protected:
virtual void exposeEvent(QExposeEvent *);
virtual void resizeEvent(QResizeEvent *);
virtual void moveEvent(QMoveEvent *);
+ virtual void focusInEvent(QFocusEvent *);
+ virtual void focusOutEvent(QFocusEvent *);
virtual void showEvent(QShowEvent *);
virtual void hideEvent(QHideEvent *);
diff --git a/src/widgets/kernel/qapplication_qpa.cpp b/src/widgets/kernel/qapplication_qpa.cpp
index 29ac94bfb1..8732a194e8 100644
--- a/src/widgets/kernel/qapplication_qpa.cpp
+++ b/src/widgets/kernel/qapplication_qpa.cpp
@@ -157,7 +157,7 @@ void QApplicationPrivate::notifyActiveWindowChange(QWindow *previous)
{
Q_UNUSED(previous);
Q_Q(QApplication);
- QWindow *wnd = QGuiApplicationPrivate::active_window;
+ QWindow *wnd = QGuiApplicationPrivate::focus_window;
if (inPopupMode()) // some delayed focus event to ignore
return;
QWidget *tlw = qt_tlw_for_window(wnd);
diff --git a/src/widgets/kernel/qwidgetwindow_qpa.cpp b/src/widgets/kernel/qwidgetwindow_qpa.cpp
index ee5cd7482e..2265fb55fb 100644
--- a/src/widgets/kernel/qwidgetwindow_qpa.cpp
+++ b/src/widgets/kernel/qwidgetwindow_qpa.cpp
@@ -79,6 +79,12 @@ bool QWidgetWindow::event(QEvent *event)
handleEnterLeaveEvent(event);
return true;
+ // these should not be sent to QWidget, the corresponding events
+ // are sent by QApplicationPrivate::notifyActiveWindowChange()
+ case QEvent::FocusIn:
+ case QEvent::FocusOut:
+ return false;
+
case QEvent::KeyPress:
case QEvent::KeyRelease:
handleKeyEvent(static_cast<QKeyEvent *>(event));
diff --git a/tests/auto/qfiledialog2/tst_qfiledialog2.cpp b/tests/auto/qfiledialog2/tst_qfiledialog2.cpp
index 282e95313f..0edc028ce6 100644
--- a/tests/auto/qfiledialog2/tst_qfiledialog2.cpp
+++ b/tests/auto/qfiledialog2/tst_qfiledialog2.cpp
@@ -589,7 +589,7 @@ void tst_QFileDialog2::completionOnLevelAfterRoot()
QCOMPARE(edit->text(), QString("completionOnLevelAfterRootTest"));
current.rmdir("completionOnLevelAfterRootTest");
#else
- QCOMPARE(edit->text(), QString("etc"));
+ QTRY_COMPARE(edit->text(), QString("etc"));
#endif
}
diff --git a/tests/auto/qwindow/tst_qwindow.cpp b/tests/auto/qwindow/tst_qwindow.cpp
index 3eedd7cf6f..478bcbe78c 100644
--- a/tests/auto/qwindow/tst_qwindow.cpp
+++ b/tests/auto/qwindow/tst_qwindow.cpp
@@ -52,6 +52,7 @@ class tst_QWindow: public QObject
private slots:
void mapGlobal();
void positioning();
+ void isActive();
};
@@ -78,35 +79,30 @@ class Window : public QWindow
{
public:
Window()
- : gotResizeEvent(false)
- , gotMapEvent(false)
- , gotMoveEvent(false)
{
+ reset();
setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint);
}
+ void reset()
+ {
+ m_received.clear();
+ }
+
bool event(QEvent *event)
{
- switch (event->type()) {
- case QEvent::Map:
- gotMapEvent = true;
- break;
- case QEvent::Resize:
- gotResizeEvent = true;
- break;
- case QEvent::Move:
- gotMoveEvent = true;
- break;
- default:
- break;
- }
+ m_received[event->type()]++;
return QWindow::event(event);
}
- bool gotResizeEvent;
- bool gotMapEvent;
- bool gotMoveEvent;
+ int received(QEvent::Type type)
+ {
+ return m_received.value(type, 0);
+ }
+
+private:
+ QHash<QEvent::Type, int> m_received;
};
void tst_QWindow::positioning()
@@ -118,7 +114,8 @@ void tst_QWindow::positioning()
QCOMPARE(window.geometry(), geometry);
window.show();
- QTRY_VERIFY(window.gotResizeEvent && window.gotMapEvent);
+ QTRY_COMPARE(window.received(QEvent::Resize), 1);
+ QTRY_COMPARE(window.received(QEvent::Map), 1);
QMargins originalMargins = window.frameMargins();
@@ -128,14 +125,11 @@ void tst_QWindow::positioning()
QPoint originalPos = window.pos();
QPoint originalFramePos = window.framePos();
- window.gotResizeEvent = false;
-
window.setWindowState(Qt::WindowFullScreen);
- QTRY_VERIFY(window.gotResizeEvent);
+ QTRY_COMPARE(window.received(QEvent::Resize), 2);
- window.gotResizeEvent = false;
window.setWindowState(Qt::WindowNoState);
- QTRY_VERIFY(window.gotResizeEvent);
+ QTRY_COMPARE(window.received(QEvent::Resize), 3);
QTRY_COMPARE(originalPos, window.pos());
QTRY_COMPARE(originalFramePos, window.framePos());
@@ -146,22 +140,88 @@ void tst_QWindow::positioning()
if (originalPos == geometry.topLeft() && (originalMargins.top() != 0 || originalMargins.left() != 0)) {
QPoint framePos(40, 40);
- window.gotMoveEvent = false;
+ window.reset();
window.setFramePos(framePos);
- QTRY_VERIFY(window.gotMoveEvent);
+ QTRY_VERIFY(window.received(QEvent::Move));
QTRY_COMPARE(framePos, window.framePos());
QTRY_COMPARE(originalMargins, window.frameMargins());
QCOMPARE(window.pos(), window.framePos() + QPoint(originalMargins.left(), originalMargins.top()));
// and back to regular positioning
- window.gotMoveEvent = false;
+ window.reset();
window.setPos(originalPos);
- QTRY_VERIFY(window.gotMoveEvent);
+ QTRY_VERIFY(window.received(QEvent::Move));
QTRY_COMPARE(originalPos, window.pos());
}
}
+void tst_QWindow::isActive()
+{
+ Window window;
+ window.setGeometry(80, 80, 40, 40);
+ window.show();
+
+ QTRY_COMPARE(window.received(QEvent::Map), 1);
+ QTRY_COMPARE(window.received(QEvent::Resize), 1);
+ QTRY_VERIFY(QGuiApplication::focusWindow() == &window);
+ QVERIFY(window.isActive());
+
+ Window child;
+ child.setParent(&window);
+ child.setGeometry(10, 10, 20, 20);
+ child.show();
+
+ QTRY_COMPARE(child.received(QEvent::Map), 1);
+
+ child.requestActivateWindow();
+
+ QTRY_VERIFY(QGuiApplication::focusWindow() == &child);
+ QVERIFY(child.isActive());
+
+ // parent shouldn't receive new map or resize events from child being shown
+ QTRY_COMPARE(window.received(QEvent::Map), 1);
+ QTRY_COMPARE(window.received(QEvent::Resize), 1);
+ QTRY_COMPARE(window.received(QEvent::FocusIn), 1);
+ QTRY_COMPARE(window.received(QEvent::FocusOut), 1);
+ QTRY_COMPARE(child.received(QEvent::FocusIn), 1);
+
+ // child has focus
+ QVERIFY(window.isActive());
+
+ Window dialog;
+ dialog.setTransientParent(&window);
+ dialog.setGeometry(110, 110, 30, 30);
+ dialog.show();
+
+ dialog.requestActivateWindow();
+
+ QTRY_COMPARE(dialog.received(QEvent::Map), 1);
+ QTRY_COMPARE(dialog.received(QEvent::Resize), 1);
+ QTRY_VERIFY(QGuiApplication::focusWindow() == &dialog);
+ QVERIFY(dialog.isActive());
+
+ // transient child has focus
+ QVERIFY(window.isActive());
+
+ // parent is active
+ QVERIFY(child.isActive());
+
+ window.requestActivateWindow();
+
+ QTRY_VERIFY(QGuiApplication::focusWindow() == &window);
+ QTRY_COMPARE(dialog.received(QEvent::FocusOut), 1);
+ QTRY_COMPARE(window.received(QEvent::FocusIn), 2);
+
+ QVERIFY(window.isActive());
+
+ // transient parent has focus
+ QVERIFY(dialog.isActive());
+
+ // parent has focus
+ QVERIFY(child.isActive());
+}
+
#include <tst_qwindow.moc>
QTEST_MAIN(tst_QWindow);