Windows: Detect lack of WS_CLIPCHILDREN when adding child windows

The lack of WS_CLIPCHILDREN will cause drawing artifacts, so ensure
we have WS_CLIPCHILDREN in our native window manual tests, and warn
if users inadvertently end up reparenting windows into a HWND that
doesn't have WS_CLIPCHILDREN set.

Change-Id: Ic4dac83882167562599d63f46232071c8c21b617
Reviewed-by: Zhao Yuhang <2546789017@qq.com>
Reviewed-by: Wladimir Leuschner <wladimir.leuschner@qt.io>
Reviewed-by: Oliver Wolff <oliver.wolff@qt.io>
Reviewed-by: Pavel Dubsky <pavel.dubsky@qt.io>
This commit is contained in:
Tor Arne Vestbø 2025-05-08 10:22:40 +02:00
parent 312215ba87
commit 33d1ac4095
4 changed files with 22 additions and 11 deletions

View File

@ -1402,6 +1402,24 @@ void QWindowsBaseWindow::setCustomMargins(const QMargins &)
Q_UNIMPLEMENTED();
}
bool QWindowsBaseWindow::windowEvent(QEvent *event)
{
switch (event->type()) {
case QEvent::ChildWindowAdded:
if (!(GetWindowLongPtr(handle(), GWL_STYLE) & WS_CLIPCHILDREN)) {
auto *childWindowEvent = static_cast<QChildWindowEvent*>(event);
qWarning() << childWindowEvent->child() << "added as child to"
<< window() << "which does not have WS_CLIPCHILDREN set."
<< "This will result in drawing artifacts!";
}
break;
default:
break;
}
return QPlatformWindow::windowEvent(event);
}
/*!
\class QWindowsDesktopWindow
\brief Window wrapping GetDesktopWindow not allowing any manipulation.
@ -2928,7 +2946,7 @@ bool QWindowsWindow::windowEvent(QEvent *event)
break;
}
return QPlatformWindow::windowEvent(event);
return QWindowsBaseWindow::windowEvent(event);
}
void QWindowsWindow::propagateSizeHints()

View File

@ -126,6 +126,8 @@ public:
static QWindowsBaseWindow *baseWindowOf(const QWindow *w);
static HWND handleOf(const QWindow *w);
bool windowEvent(QEvent *event) override;
protected:
HWND parentHwnd() const { return GetAncestor(handle(), GA_PARENT); }
bool isTopLevel_sys() const;

View File

@ -93,15 +93,6 @@ int main(int argc, char *argv[])
NativeWindow nativeParentWindow;
if (QWindow *foreignWindow = QWindow::fromWinId(nativeParentWindow)) {
#ifdef Q_OS_WIN
// Native parent windows should have WS_CLIPCHILDREN style set
// to prevent overdrawing child area and cause flickering.
const HWND hwnd = reinterpret_cast<HWND>(foreignWindow->winId());
const LONG_PTR oldStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
SetWindowLongPtr(hwnd, GWL_STYLE, oldStyle | WS_CLIPCHILDREN);
#endif
foreignWindow->setParent(&window);
foreignWindow->setGeometry(50, 350, 100, 100);
foreignWindow->showNormal();

View File

@ -133,7 +133,7 @@ NativeWindow::NativeWindow()
RegisterClass(&wc);
return wc.lpszClassName;
}();
m_handle = CreateWindowEx(0, className, nullptr, WS_POPUP,
m_handle = CreateWindowEx(0, className, nullptr, WS_POPUP | WS_CLIPCHILDREN,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
nullptr, nullptr, GetModuleHandle(nullptr), nullptr);
}