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 Change-Id: I905d8253069ec339b193edf05c052d21361ca3e9 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io> (cherry picked from commit fa0b2ef81c0d22f4038235871fbc1abda55887d1) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
d41310a2c4
commit
7a3aa146a5
@ -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:
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -264,7 +264,7 @@ QWindowsIntegration::QWindowsIntegration(const QStringList ¶mList) :
|
||||
#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);
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user