Fixes handling of native / alien widgets when (un)docking (#820)
* Initial plan * Fix drawing artifacts when content widgets call winId() When a content widget (e.g. VTK/OpenGL) calls winId() to get a native window handle, Qt propagates native-window creation up the ancestor chain. This makes CDockWidget, CDockAreaWidget, and CDockContainerWidget all become native OS windows unexpectedly. Reparenting these native dock widgets during floating or resizing then causes drawing artifacts. Fix: set Qt::WA_DontCreateNativeAncestors on the content widget in CDockWidget::setWidget() to stop native-window creation from propagating up into the dock hierarchy. Co-authored-by: RubendeBruin <34062862+RubendeBruin@users.noreply.github.com> * Fix docking system to handle mix of native and alien Qt widgets Three targeted fixes for the native/alien widget mixing problem: 1. Revert WA_DontCreateNativeAncestors from CDockWidget::setWidget(). Setting it on the content widget created a broken native-inside-alien hierarchy: the QScrollArea (alien) could not clip its native child, so content escaped the scrollbox bounds; and alien CAutoHideDockContainer could not appear above the native content widget. Allowing natural propagation means QScrollArea also goes native, and OS parent/child window clipping works correctly. 2. Fix CDockContainerWidget::removeDockArea to use internalWinId() instead of testAttribute(WA_NativeWindow). WA_NativeWindow is only set when a widget is explicitly made native; widgets that became native through upward propagation from a descendant calling winId() have a real native window handle (internalWinId() != 0) but WA_NativeWindow may be unset. Setting their parent to nullptr would create a free-floating invisible OS window and cause drawing artifacts. 3. Fix CAutoHideDockContainer::collapseView: when the parent dock container is native but the auto-hide panel is still alien, promote the panel to a native window (winId()) before raise(). The OS always renders native child windows above a parent window's painted alien content, so an alien auto-hide panel can never appear above native sibling dock areas. Once the panel has its own OS-level window, raise() operates on OS Z-order and correctly places it above native content siblings. Co-authored-by: RubendeBruin <34062862+RubendeBruin@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -482,6 +482,17 @@ void CAutoHideDockContainer::collapseView(bool Enable)
|
|||||||
{
|
{
|
||||||
updateSize();
|
updateSize();
|
||||||
d->updateResizeHandleSizeLimitMax();
|
d->updateResizeHandleSizeLimitMax();
|
||||||
|
// If the parent dock container has native child windows (e.g. because
|
||||||
|
// an OpenGL or VTK content widget called winId()), this panel is an
|
||||||
|
// alien (non-native) widget and will always be obscured by those native
|
||||||
|
// sibling windows regardless of Qt's paint order. Native OS windows are
|
||||||
|
// rendered above the parent's painted (alien) content by the windowing
|
||||||
|
// system. To allow raise() to use OS-level Z-order and appear on top,
|
||||||
|
// this panel must first be promoted to a native window itself.
|
||||||
|
if (parentWidget() && parentWidget()->internalWinId() && !internalWinId())
|
||||||
|
{
|
||||||
|
winId();
|
||||||
|
}
|
||||||
raise();
|
raise();
|
||||||
show();
|
show();
|
||||||
d->DockWidget->dockManager()->setDockWidgetFocused(d->DockWidget);
|
d->DockWidget->dockManager()->setDockWidgetFocused(d->DockWidget);
|
||||||
|
|||||||
@@ -1573,9 +1573,18 @@ void CDockContainerWidget::removeDockArea(CDockAreaWidget* area)
|
|||||||
d->DockAreas.removeAll(area);
|
d->DockAreas.removeAll(area);
|
||||||
auto Splitter = area->parentSplitter();
|
auto Splitter = area->parentSplitter();
|
||||||
|
|
||||||
// Remove are from parent splitter and recursively hide tree of parent
|
// Remove area from parent splitter and recursively hide tree of parent
|
||||||
// splitters if it has no visible content
|
// splitters if it has no visible content.
|
||||||
if (area->testAttribute(Qt::WA_NativeWindow))
|
// Use internalWinId() rather than testAttribute(WA_NativeWindow) because
|
||||||
|
// WA_NativeWindow is only set when a widget is *explicitly* made native
|
||||||
|
// (e.g. winId() called directly on it). Widgets that became native through
|
||||||
|
// propagation from a child calling winId() (e.g. a VTK/OpenGL widget) also
|
||||||
|
// hold a real native window handle but may not have WA_NativeWindow set.
|
||||||
|
// Setting the parent of such a native window to nullptr would make it an
|
||||||
|
// invisible top-level OS window, causing drawing artifacts. Reparent to
|
||||||
|
// the dock manager instead so the window stays off-screen but within the
|
||||||
|
// application's window hierarchy.
|
||||||
|
if (area->internalWinId())
|
||||||
area->setParent(d->DockManager);
|
area->setParent(d->DockManager);
|
||||||
else
|
else
|
||||||
area->setParent(nullptr);
|
area->setParent(nullptr);
|
||||||
|
|||||||
Reference in New Issue
Block a user