summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTor Arne Vestbø <tor.arne.vestbo@qt.io>2022-06-16 12:01:36 +0200
committerTor Arne Vestbø <tor.arne.vestbo@qt.io>2022-06-18 21:08:02 +0200
commitfa0b2ef81c0d22f4038235871fbc1abda55887d1 (patch)
treea8e67e11a00b6319569b7ffe8916e60351db7932
parente457aeec3802e79d33347768cb9c50eb87deed92 (diff)
Windows: Decouple screen change monitoring from top level QWindows
The WM_DISPLAYCHANGE message it sent when displays are added, removed, or update their properties such as the scale/DPI. We were processing this message as part of QWindowsContext::windowsProc(), which meant that we would only react to display changes if there was a QWindow on screen. Just creating a QGuiApplication was insufficient to pick up changes to screens after startup. In addition, despite being documented to post messages to child windows, WM_DISPLAYCHANGE only ends up in top level windows. Presumably it's the top level window's responsibility to post the message to child windows. As a result, if a QWindow was a native child window of a foreign window, such as in audio plugins being hosted in a DAW, we would again fail to pick up display changes. We solve both these cases by decoupling the WM_DISPLAYCHANGE handling from QWindowsContext::windowsProc(), by creating a dedicated window for listening to WM_DISPLAYCHANGE. This is similar to how we already handle tray icons, power notifications, clipboard, etc -- the only difference being that since purely HWND_MESSAGE windows do not receive WM_DISPLAYCHANGE it's an actual invisible WS_TILED window. This also lets us remove the workaround for QTBUG-79248, which was doing screen updates in response to WM_DPICHANGED when detecting that there were no QWindows. Task-number: QTBUG-103383 Task-number: QTBUG-79248 Fixes: QTBUG-102343 Pick-to: 6.4 Change-Id: I905d8253069ec339b193edf05c052d21361ca3e9 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
-rw-r--r--src/plugins/platforms/windows/qtwindowsglobal.h5
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.cpp7
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.h1
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.cpp2
-rw-r--r--src/plugins/platforms/windows/qwindowsscreen.cpp37
-rw-r--r--src/plugins/platforms/windows/qwindowsscreen.h3
-rw-r--r--src/plugins/platforms/windows/qwindowssystemtrayicon.cpp3
7 files changed, 44 insertions, 14 deletions
diff --git a/src/plugins/platforms/windows/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h
index 71a4269a27..9a65603e24 100644
--- a/src/plugins/platforms/windows/qtwindowsglobal.h
+++ b/src/plugins/platforms/windows/qtwindowsglobal.h
@@ -140,8 +140,7 @@ enum WindowsEventType // Simplify event types
InputMethodRequest = InputMethodEventFlag + 6,
ThemeChanged = ThemingEventFlag + 1,
CompositionSettingsChanged = ThemingEventFlag + 2,
- DisplayChangedEvent = 437,
- SettingChangedEvent = DisplayChangedEvent + 1,
+ SettingChangedEvent = 438,
ScrollEvent = GenericEventFlag + 1,
ContextMenu = 123,
GestureEvent = 124,
@@ -258,8 +257,6 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI
// http://msdn.microsoft.com/en-us/library/ms695534(v=vs.85).aspx
case WM_SETTINGCHANGE:
return QtWindows::SettingChangedEvent;
- case WM_DISPLAYCHANGE:
- return QtWindows::DisplayChangedEvent;
case WM_THEMECHANGED:
case WM_SYSCOLORCHANGE: // Handle color change as theme change (QTBUG-34170).
case WM_DWMCOLORIZATIONCOLORCHANGED:
diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp
index 68d2e5d98d..9397c0213e 100644
--- a/src/plugins/platforms/windows/qwindowscontext.cpp
+++ b/src/plugins/platforms/windows/qwindowscontext.cpp
@@ -71,6 +71,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
Q_LOGGING_CATEGORY(lcQpaAccessibility, "qt.qpa.accessibility")
Q_LOGGING_CATEGORY(lcQpaUiAutomation, "qt.qpa.uiautomation")
Q_LOGGING_CATEGORY(lcQpaTrayIcon, "qt.qpa.trayicon")
+Q_LOGGING_CATEGORY(lcQpaScreen, "qt.qpa.screen")
int QWindowsContext::verbose = 0;
@@ -1091,12 +1092,6 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
#else
return false;
#endif
- case QtWindows::DisplayChangedEvent:
- if (QWindowsTheme *t = QWindowsTheme::instance())
- t->displayChanged();
- QWindowsWindow::displayChanged();
- d->m_screenManager.handleScreenChanges();
- return false;
case QtWindows::SettingChangedEvent: {
QWindowsWindow::settingsChanged();
// Only refresh the window theme if the user changes the personalize settings.
diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h
index 4cc47a3ba4..af92690b3b 100644
--- a/src/plugins/platforms/windows/qwindowscontext.h
+++ b/src/plugins/platforms/windows/qwindowscontext.h
@@ -31,6 +31,7 @@ Q_DECLARE_LOGGING_CATEGORY(lcQpaTablet)
Q_DECLARE_LOGGING_CATEGORY(lcQpaAccessibility)
Q_DECLARE_LOGGING_CATEGORY(lcQpaUiAutomation)
Q_DECLARE_LOGGING_CATEGORY(lcQpaTrayIcon)
+Q_DECLARE_LOGGING_CATEGORY(lcQpaScreen)
class QWindow;
class QPlatformScreen;
diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp
index 8e94722565..f1874b37bb 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.cpp
+++ b/src/plugins/platforms/windows/qwindowsintegration.cpp
@@ -264,7 +264,7 @@ QWindowsIntegration::QWindowsIntegration(const QStringList &paramList) :
#if QT_CONFIG(clipboard)
d->m_clipboard.registerViewer();
#endif
- d->m_context.screenManager().handleScreenChanges();
+ d->m_context.screenManager().initialize();
d->m_context.setDetectAltGrModifier((d->m_options & DetectAltGrModifier) != 0);
}
diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp
index 6b60083759..177bff8a12 100644
--- a/src/plugins/platforms/windows/qwindowsscreen.cpp
+++ b/src/plugins/platforms/windows/qwindowsscreen.cpp
@@ -513,8 +513,45 @@ QPlatformScreen::SubpixelAntialiasingType QWindowsScreen::subpixelAntialiasingTy
\internal
*/
+extern "C" LRESULT QT_WIN_CALLBACK qDisplayChangeObserverWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ if (message == WM_DISPLAYCHANGE) {
+ qCDebug(lcQpaScreen) << "Handling WM_DISPLAYCHANGE";
+ if (QWindowsTheme *t = QWindowsTheme::instance())
+ t->displayChanged();
+ QWindowsWindow::displayChanged();
+ QWindowsContext::instance()->screenManager().handleScreenChanges();
+ }
+
+ return DefWindowProc(hwnd, message, wParam, lParam);
+}
+
QWindowsScreenManager::QWindowsScreenManager() = default;
+void QWindowsScreenManager::initialize()
+{
+ qCDebug(lcQpaScreen) << "Initializing screen manager";
+
+ auto className = QWindowsContext::instance()->registerWindowClass(
+ QWindowsContext::classNamePrefix() + QLatin1String("ScreenChangeObserverWindow"),
+ qDisplayChangeObserverWndProc);
+
+ // HWND_MESSAGE windows do not get WM_DISPLAYCHANGE, so we need to create
+ // a real top level window that we never show.
+ m_displayChangeObserver = CreateWindowEx(0, reinterpret_cast<LPCWSTR>(className.utf16()),
+ nullptr, WS_TILED, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+ nullptr, nullptr, GetModuleHandle(nullptr), nullptr);
+ Q_ASSERT(m_displayChangeObserver);
+
+ qCDebug(lcQpaScreen) << "Created display change observer" << m_displayChangeObserver;
+
+ handleScreenChanges();
+}
+
+QWindowsScreenManager::~QWindowsScreenManager()
+{
+ DestroyWindow(m_displayChangeObserver);
+}
bool QWindowsScreenManager::isSingleScreen()
{
diff --git a/src/plugins/platforms/windows/qwindowsscreen.h b/src/plugins/platforms/windows/qwindowsscreen.h
index babb9de758..6c638842fe 100644
--- a/src/plugins/platforms/windows/qwindowsscreen.h
+++ b/src/plugins/platforms/windows/qwindowsscreen.h
@@ -96,6 +96,8 @@ public:
using WindowsScreenList = QList<QWindowsScreen *>;
QWindowsScreenManager();
+ void initialize();
+ ~QWindowsScreenManager();
void clearScreens();
@@ -110,6 +112,7 @@ public:
private:
void removeScreen(int index);
+ HWND m_displayChangeObserver = nullptr;
WindowsScreenList m_screens;
};
diff --git a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp
index 25d29a2302..cf150b5772 100644
--- a/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp
+++ b/src/plugins/platforms/windows/qwindowssystemtrayicon.cpp
@@ -94,9 +94,6 @@ static int indexOfHwnd(HWND hwnd)
extern "C" LRESULT QT_WIN_CALLBACK qWindowsTrayIconWndProc(HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
- // QTBUG-79248: Trigger screen update if there are no other windows.
- if (message == WM_DPICHANGED && QGuiApplication::topLevelWindows().isEmpty())
- QWindowsContext::instance()->screenManager().handleScreenChanges();
if (message == MYWM_TASKBARCREATED || message == MYWM_NOTIFYICON
|| message == WM_INITMENU || message == WM_INITMENUPOPUP
|| message == WM_CLOSE || message == WM_COMMAND) {