QApplication: deliver activation events for non-widget windows

Problem: if you create a hybrid Widgets and Quick Controls
application, you would need to use QApplication rather than
QGuiApplication. But in that case, the QQuickWindows would
never receive window activation events from QApplication.
And this causes problems for controls, since, for example,
the palettes in use there will never update upon activation
changes, and instead sometimes get stuck as e.g QPalette::Inactive
after application startup.

This patch will make sure that we send out activation events
also for QWindows that are not QWidgetWindows.

Pick-to: 6.3 6.2
Change-Id: I649f5c653081c0c5249f4faf28a7de2c92f17421
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
Richard Moe Gustavsen 2022-04-21 12:10:21 +02:00
parent 2d6007fa1c
commit 5907a0a944
2 changed files with 62 additions and 1 deletions

View File

@ -1912,7 +1912,6 @@ QWidget *qt_tlw_for_window(QWindow *wnd)
void QApplicationPrivate::notifyActiveWindowChange(QWindow *previous)
{
Q_UNUSED(previous);
#ifndef Q_OS_MACOS
// Some delayed focus event to ignore, unless we are on cocoa where
// popups can be opened via right-click on inactive applications
@ -1929,6 +1928,20 @@ void QApplicationPrivate::notifyActiveWindowChange(QWindow *previous)
if (widget->inherits("QAxHostWidget"))
widget->setFocus(Qt::ActiveWindowFocusReason);
}
// QApplication::setActiveWindow() will deliver window activation events for
// QWidgetWindows. But for other subclasses of QWindow (like QQuickWindow), we
// need to send them explicitly, like we do from the base class implementation.
if (previous && !qobject_cast<QWidgetWindow *>(previous)) {
QEvent de(QEvent::WindowDeactivate);
QCoreApplication::sendEvent(previous, &de);
}
if (focusWindow && !qobject_cast<QWidgetWindow *>(focusWindow)) {
QEvent ae(QEvent::WindowActivate);
QCoreApplication::sendEvent(focusWindow, &ae);
}
// don't call base class to avoid double delivery of WindowActivate/Deactivate events
}

View File

@ -125,6 +125,7 @@ private slots:
void desktopSettingsAware();
void setActiveWindow();
void activateDeactivateEvent();
void focusWidget();
void focusChanged();
@ -1563,6 +1564,53 @@ void tst_QApplication::setActiveWindow()
delete w;
}
void tst_QApplication::activateDeactivateEvent()
{
// Ensure that QWindows (other than QWidgetWindow)
// are activated / deactivated.
class Window : public QWindow
{
public:
using QWindow::QWindow;
int activateCount = 0;
int deactivateCount = 0;
protected:
bool event(QEvent *e)
{
switch (e->type()) {
case QEvent::WindowActivate:
++activateCount;
break;
case QEvent::WindowDeactivate:
++deactivateCount;
break;
default:
break;
}
return QWindow::event(e);
}
};
int argc = 0;
QApplication app(argc, nullptr);
Window w1;
Window w2;
w1.show();
w1.requestActivate();
QVERIFY(QTest::qWaitForWindowActive(&w1));
QCOMPARE(w1.activateCount, 1);
QCOMPARE(w1.deactivateCount, 0);
w2.show();
w2.requestActivate();
QVERIFY(QTest::qWaitForWindowActive(&w2));
QCOMPARE(w1.deactivateCount, 1);
QCOMPARE(w2.activateCount, 1);
}
void tst_QApplication::focusWidget()
{
int argc = 0;