Skip to content

feat: rewrite PopupHandle for Qt6 with Window popupType support#612

Closed
18202781743 wants to merge 1 commit intomasterfrom
popupwindow
Closed

feat: rewrite PopupHandle for Qt6 with Window popupType support#612
18202781743 wants to merge 1 commit intomasterfrom
popupwindow

Conversation

@18202781743
Copy link
Copy Markdown
Contributor

@18202781743 18202781743 commented Apr 24, 2026

  1. Rewrite DPopupWindowHandle to work natively with Qt6
  2. Support Popup.Window popupType with window decorations (radius,
    border, shadow, blur)
  3. Implement screen edge avoidance for popup windows
  4. Add close-on-focus-loss behavior through event filters
  5. Simplify architecture: remove DPopupWindowHandleImpl and DVtableHook
    usage
  6. Remove global PopupMode enum and forceWindowMode property
  7. Update DQuickWindowAttached to support QQuickPopup objects

Log: Rewrite PopupHandle to support popupType Window mode in Qt6

Influence:

  1. Test Popup with popupType: Window – verify window decorations
    (radius, border, shadow, blur)
  2. Test screen edge avoidance: open popups near screen edges and verify
    positioning
  3. Test close-on-click-outside: click outside popup and verify it closes
  4. Test close-on-focus-loss: switch to other window and verify popup
    closes
  5. Test nested popups (submenus) – verify correct screen assignment and
    flipping behavior
  6. Test window properties: windowRadius, borderWidth, borderColor,
    shadowRadius, shadowOffset, shadowColor
  7. Test translucentBackground and enableBlurWindow properties
  8. Test menu popup behavior – ensure no regressions in Menu popup
  9. Test with different screen configurations (multiple monitors,
    different DPI)
  10. Verify no crash when popup is destroyed

feat: 重写PopupHandle以支持Qt6的Window模式

  1. 重写DPopupWindowHandle以原生支持Qt6
  2. 支持Popup.Window弹窗类型,添加窗口装饰(圆角、边框、阴影、模糊)
  3. 实现弹窗窗口的屏幕边缘避让
  4. 通过事件过滤器实现失去焦点自动关闭
  5. 简化架构:移除DPopupWindowHandleImpl和DVtableHook的使用
  6. 移除全局PopupMode枚举和forceWindowMode属性
  7. 更新DQuickWindowAttached以支持QQuickPopup对象

Log: 重写PopupHandle支持popupType为Window模式

Influence:

  1. 测试Popup的popupType: Window模式 – 验证窗口装饰(圆角、边框、阴影、
    模糊)
  2. 测试屏幕边缘避让:在屏幕边缘打开弹窗,验证位置调整
  3. 测试点击外部关闭:点击弹窗外区域,验证弹窗关闭
  4. 测试失去焦点关闭:切换到其他窗口,验证弹窗关闭
  5. 测试嵌套弹窗(子菜单)– 验证正确的屏幕分配和翻转行为
  6. 测试窗口属性:windowRadius、borderWidth、borderColor、shadowRadius、
    shadowOffset、shadowColor
  7. 测试translucentBackground和enableBlurWindow属性
  8. 测试菜单弹窗行为 – 确保菜单弹窗没有回归问题
  9. 测试不同屏幕配置(多显示器、不同DPI)
  10. 验证弹窗销毁时不会崩溃

Summary by Sourcery

Rewrite the popup window handling to integrate natively with Qt 6 popup windows and DQuickWindowAttached, enabling Window-type popups with proper decorations and screen-aware positioning.

New Features:

  • Support Qt 6 Popup.Window popups as real windows with DQuickWindowAttached-based attached properties.
  • Enable window decoration controls (radius, border, shadow, translucency, blur) on popup windows via PopupHandle and DQuickWindowAttached.
  • Add automatic screen edge avoidance and submenu flipping logic for popup windows to keep them within the active screen.

Bug Fixes:

  • Ensure popup windows close correctly on outside clicks and focus loss via event filters on popup and parent windows.
  • Prevent crashes and inconsistent state when popup windows are destroyed or hidden while still marked visible.

Enhancements:

  • Simplify PopupHandle architecture by removing DPopupWindowHandleImpl, DVtableHook usage, and the global PopupMode/forceWindowMode configuration.
  • Extend DQuickWindowAttached to work with QQuickPopup objects and to manage its target QQuickWindow dynamically.
  • Clean up QML usage of PopupHandle by removing delegate-based window creation and relying on popupType Window behavior instead.

Tests:

  • Update example Popup and Menu QML to exercise Window-type popups, window decoration properties, and to ensure menu popup behavior remains correct across screens.

1. Rewrite DPopupWindowHandle to work natively with Qt6
2. Support Popup.Window popupType with window decorations (radius,
border, shadow, blur)
3. Implement screen edge avoidance for popup windows
4. Add close-on-focus-loss behavior through event filters
5. Simplify architecture: remove DPopupWindowHandleImpl and DVtableHook
usage
6. Remove global PopupMode enum and forceWindowMode property
7. Update DQuickWindowAttached to support QQuickPopup objects

Log: Rewrite PopupHandle to support popupType Window mode in Qt6

Influence:
1. Test Popup with popupType: Window – verify window decorations
(radius, border, shadow, blur)
2. Test screen edge avoidance: open popups near screen edges and verify
positioning
3. Test close-on-click-outside: click outside popup and verify it closes
4. Test close-on-focus-loss: switch to other window and verify popup
closes
5. Test nested popups (submenus) – verify correct screen assignment and
flipping behavior
6. Test window properties: windowRadius, borderWidth, borderColor,
shadowRadius, shadowOffset, shadowColor
7. Test translucentBackground and enableBlurWindow properties
8. Test menu popup behavior – ensure no regressions in Menu popup
9. Test with different screen configurations (multiple monitors,
different DPI)
10. Verify no crash when popup is destroyed

feat: 重写PopupHandle以支持Qt6的Window模式

1. 重写DPopupWindowHandle以原生支持Qt6
2. 支持Popup.Window弹窗类型,添加窗口装饰(圆角、边框、阴影、模糊)
3. 实现弹窗窗口的屏幕边缘避让
4. 通过事件过滤器实现失去焦点自动关闭
5. 简化架构:移除DPopupWindowHandleImpl和DVtableHook的使用
6. 移除全局PopupMode枚举和forceWindowMode属性
7. 更新DQuickWindowAttached以支持QQuickPopup对象

Log: 重写PopupHandle支持popupType为Window模式

Influence:
1. 测试Popup的popupType: Window模式 – 验证窗口装饰(圆角、边框、阴影、
模糊)
2. 测试屏幕边缘避让:在屏幕边缘打开弹窗,验证位置调整
3. 测试点击外部关闭:点击弹窗外区域,验证弹窗关闭
4. 测试失去焦点关闭:切换到其他窗口,验证弹窗关闭
5. 测试嵌套弹窗(子菜单)– 验证正确的屏幕分配和翻转行为
6. 测试窗口属性:windowRadius、borderWidth、borderColor、shadowRadius、
shadowOffset、shadowColor
7. 测试translucentBackground和enableBlurWindow属性
8. 测试菜单弹窗行为 – 确保菜单弹窗没有回归问题
9. 测试不同屏幕配置(多显示器、不同DPI)
10. 验证弹窗销毁时不会崩溃
@18202781743 18202781743 requested review from BLumia and mhduiy April 24, 2026 08:17
@deepin-ci-robot
Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: 18202781743

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@deepin-ci-robot
Copy link
Copy Markdown
Contributor

deepin pr auto review

Git Diff 代码审查报告

总体概述

这次代码改动主要针对 Qt6 中的 Popup 窗口处理进行了重构,移除了旧版的 DPopupWindowHandle 实现,改用 Qt6 原生的 Popup.Window 模式,并优化了窗口位置调整逻辑。整体改动较大,涉及多个文件的修改。

详细审查

1. 语法和逻辑问题

1.1 dpopupwindowhandle.cpp 中的拼写错误

// examples/qml-inspect/Example_Popup.qml
id: popupWindow; objectName: "pupup window"  // "pupup" 应为 "popup"

建议: 修正拼写错误为 "popup window"。

1.2 dpopupwindowhandle.cpp 中的条件判断

void DPopupWindowHandle::adjustPopupPosition()
{
    if (!isEnabled() ||!m_popupWin)  // 缺少空格
        return;

建议: 在 || 后添加空格,提高可读性:if (!isEnabled() || !m_popupWin)

2. 代码质量问题

2.1 魔法数字的使用

// dpopupwindowhandle.cpp
bool closeOnPressOutside = closePolicy & 0x01;
bool closeOnPressOutsideParent = closePolicy & 0x02;

建议: 使用命名常量替代魔法数字,提高代码可读性和维护性:

enum ClosePolicyFlag {
    CloseOnPressOutside = 0x01,
    CloseOnPressOutsideParent = 0x02
};
bool closeOnPressOutside = closePolicy & CloseOnPressOutside;
bool closeOnPressOutsideParent = closePolicy & CloseOnPressOutsideParent;

2.2 函数复杂度

adjustPopupPosition() 函数较为复杂,包含了多个嵌套的条件判断和位置计算逻辑。

建议: 考虑将函数拆分为更小的函数,例如:

  • getPopupScreen() - 获取弹出窗口所在的屏幕
  • adjustHorizontalPosition() - 处理水平位置调整
  • adjustVerticalPosition() - 处理垂直位置调整

2.3 注释不一致

// dpopupwindowhandle.cpp
// Nested popup (submenu) detection:
// A submenu's popupWindow uses the parent menu's popupWindow as its transientParent.

有些地方有详细注释,而有些关键逻辑缺少注释。

建议: 为关键逻辑添加更多注释,特别是位置调整算法的部分,以便其他开发者理解。

3. 代码性能问题

3.1 频繁的属性访问

// dpopupwindowhandle.cpp
QVariant popupTypeVar = m_popup->property("popupType");
bool shouldEnable = popupTypeVar.isValid() && popupTypeVar.toInt() == 1;

建议: 如果 popupType 是频繁访问的属性,考虑缓存其值或使用更高效的访问方式。

3.2 重复计算

// dpopupwindowhandle.cpp
const bool overflowsRight = rect.right() > bounds.right();
const bool overflowsLeft  = rect.left()  < bounds.left();

这些计算在每次调整位置时都会执行。

建议: 如果窗口大小和屏幕边界不常变化,可以考虑缓存部分计算结果。

4. 代码安全问题

4.1 指针未检查

// dpopupwindowhandle.cpp
void DPopupWindowHandle::itemVisibilityChanged(QQuickItem *item)
{
    if (!item->isVisible())
        return;
    
    adjustPopupPosition();
}

虽然检查了 item 是否可见,但没有检查 item 是否为 nullptr

建议: 添加空指针检查:

void DPopupWindowHandle::itemVisibilityChanged(QQuickItem *item)
{
    if (!item || !item->isVisible())
        return;
    
    adjustPopupPosition();
}

4.2 事件过滤器中的类型转换

// dpopupwindowhandle.cpp
if (QQuickWindow *main = qobject_cast<QQuickWindow *>(window->transientParent())) {
    m_parentWindow = main;
    m_parentWindow->installEventFilter(this);
}

建议: 确保在 m_parentWindow 上安装事件过滤器前检查其有效性,并在析构函数中正确移除事件过滤器。

5. 其他建议

5.1 版本兼容性

代码中移除了 Qt5 的支持,完全转向 Qt6。如果项目需要同时支持 Qt5 和 Qt6,建议使用条件编译。

5.2 测试覆盖

由于这是对核心窗口管理逻辑的重构,建议增加单元测试和集成测试,特别是针对:

  • 窗口位置调整逻辑
  • 多显示器支持
  • 嵌套弹出窗口行为
  • 窗口关闭策略

5.3 文档更新

由于 DPopupWindowHandle 的接口和行为发生了重大变化,建议更新相关文档和示例代码。

总结

这次代码改动主要是为了适配 Qt6 的窗口管理机制,整体方向是正确的。但代码中存在一些小问题,如拼写错误、魔法数字使用、函数复杂度高等,建议在合并前进行修复。同时,由于这是核心功能的重构,建议进行充分的测试,确保不会引入新的问题。

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented Apr 24, 2026

Reviewer's Guide

Rewrites the PopupHandle/DPopupWindowHandle integration for Qt6 to work natively with QQuickPopup popupType Window, removes the old delegate/PopupMode/vtable-hook based architecture, and routes popup windows through DQuickWindowAttached to provide window decorations, edge-avoidance positioning, and close-on-focus-loss/press-outside behavior while updating QML usages accordingly.

Sequence diagram for QQuickPopup Window popupType with PopupHandle and DQuickWindowAttached

sequenceDiagram
    actor QMLApp
    participant QQuickPopup as QQuickPopup_popup
    participant DQuickWindow as DQuickWindow
    participant DQuickWindowAttached as DQuickWindowAttached_attached
    participant DPopupWindowHandle as PopupHandle
    participant QQuickWindow as PopupWindow
    participant ParentWindow as Parent_QQuickWindow
    participant QGuiApplication as QGuiApp
    participant QScreen as Screen
    participant QQuickItem
    participant QQuickPopupItem

    QMLApp->>QQuickPopup: create Popup { D.PopupHandle attached }
    QQuickPopup->>DPopupWindowHandle: qmlAttachedProperties(object)
    activate DPopupWindowHandle
    DPopupWindowHandle->>DQuickWindow: qmlAttachedProperties(popup)
    DQuickWindow-->>DQuickWindowAttached: new DQuickWindowAttached(popup)
    DQuickWindowAttached-->>DPopupWindowHandle: pointer stored as m_attached

    DPopupWindowHandle->>DPopupWindowHandle: updateEnabled()
    DPopupWindowHandle->>QQuickPopup: property(popupType)
    QQuickPopup-->>DPopupWindowHandle: popupType == Window
    DPopupWindowHandle->>DQuickWindowAttached: setEnabled(true)

    DPopupWindowHandle->>DPopupWindowHandle: popupItemReparented()
    DPopupWindowHandle->>QQuickPopup: findChildren<QQuickItem>()
    QQuickPopup-->>DPopupWindowHandle: QQuickPopupItem
    DPopupWindowHandle->>QQuickItem: addItemChangeListener(Geometry|Visibility)
    DPopupWindowHandle->>QQuickItem: connect windowChanged(...)

    QQuickPopup->>PopupWindow: open() creates QQuickPopupWindow
    QQuickPopup->>DPopupWindowHandle: popupTypeChanged()
    DPopupWindowHandle->>DPopupWindowHandle: updateEnabled()

    QQuickPopupItem->>DPopupWindowHandle: onWindowChanged(PopupWindow)
    DPopupWindowHandle->>DQuickWindowAttached: setWindow(PopupWindow)
    DPopupWindowHandle->>PopupWindow: installEventFilter(this)
    PopupWindow->>ParentWindow: setTransientParent(parent)
    DPopupWindowHandle->>ParentWindow: installEventFilter(this)

    Note over PopupWindow,QGuiApp: During move or initial show
    PopupWindow-->>DPopupWindowHandle: QEvent::Move via eventFilter
    DPopupWindowHandle->>DPopupWindowHandle: adjustPopupPosition()
    DPopupWindowHandle->>PopupWindow: position(), size()
    DPopupWindowHandle->>PopupWindow: transientParent()
    alt nested popup
        DPopupWindowHandle->>ParentWindow: screen()
        ParentWindow-->>DPopupWindowHandle: Screen
    else top level
        DPopupWindowHandle->>QGuiApp: screenAt(windowCenter)
        QGuiApp-->>DPopupWindowHandle: Screen
    end
    DPopupWindowHandle->>Screen: availableGeometry()
    DPopupWindowHandle->>PopupWindow: setPosition(adjustedWithinScreen)

    Note over ParentWindow,DPopupWindowHandle: Close on press outside
    ParentWindow-->>DPopupWindowHandle: QEvent::MouseButtonPress via eventFilter
    DPopupWindowHandle->>QQuickPopup: property(visible), property(closePolicy)
    alt closePolicy allows press outside
        DPopupWindowHandle->>QQuickPopup: invokeMethod("close")
    else do nothing
    end

    Note over PopupWindow,DPopupWindowHandle: Close on focus loss is handled by Qt6 popup window
Loading

Class diagram for rewritten DPopupWindowHandle and DQuickWindowAttached integration

classDiagram
    direction LR

    class DPopupWindowHandle {
        +DPopupWindowHandle(QObject *popup)
        +~DPopupWindowHandle()
        +static DQuickWindowAttached *qmlAttachedProperties(QObject *object)
        +DQuickWindowAttached *windowAttached() const
        +bool eventFilter(QObject *watched, QEvent *event)
        +void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &oldGeometry)
        +void itemVisibilityChanged(QQuickItem *item)
        +void itemParentChanged(QQuickItem *item, QQuickItem *oldParent)
        -void updateEnabled()
        -void onWindowChanged(QQuickWindow *window)
        -QQuickWindow *popupWindow() const
        -QQuickItem *popupItem() const
        -void popupItemReparented()
        -bool isEnabled() const
        -void adjustPopupPosition()
        -members
        -QObject *m_popup
        -bool m_enabled
        -DQuickWindowAttached *m_attached
        -QPointer~QQuickWindow~ m_parentWindow
        -QPointer~QQuickWindow~ m_popupWin
        -QPointer~QQuickItem~ m_trackedItem
    }

    class QQuickItemChangeListener {
        <<interface>>
        +void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &oldGeometry)
        +void itemVisibilityChanged(QQuickItem *item)
        +void itemParentChanged(QQuickItem *item, QQuickItem *oldParent)
    }

    class DQuickWindowAttached {
        +DQuickWindowAttached(QWindow *window)
        +DQuickWindowAttached(QObject *popupObject)
        +QQuickWindow *window() const
        +void setWindow(QQuickWindow *window)
        +bool isEnabled() const
        +int windowRadius() const
        +int borderWidth() const
        +QColor borderColor() const
        +int shadowRadius() const
        +QPointF shadowOffset() const
        +QColor shadowColor() const
        +bool translucentBackground() const
        +bool enableBlurWindow() const
    }

    class DQuickWindowAttachedPrivate {
        +DQuickWindowAttachedPrivate(QQuickWindow *window, DQuickWindowAttached *q)
        +bool ensurePlatformHandle()
        +void destoryPlatformHandle()
        +void setWindow(QWindow *newWindow)
        +void _q_onWindowMotifHintsChanged(quint32 winId)
        -QWindow *window
        -DPlatformHandle *handle
        -DTK_CORE_NAMESPACE::DObject::ExplicitEnable explicitEnable
    }

    class DQuickWindow {
        +static DQuickWindowAttached *qmlAttachedProperties(QObject *object)
    }

    %% relationships
    DPopupWindowHandle ..|> QObject
    DPopupWindowHandle ..|> QQuickItemChangeListener

    DPopupWindowHandle --> DQuickWindowAttached : uses m_attached
    DQuickWindowAttached o--> DQuickWindowAttachedPrivate : d_ptr
    DQuickWindowAttachedPrivate --> QWindow : window

    DQuickWindow ..> DQuickWindowAttached : returns

    %% removed classes (for context)
    class DPopupWindowHandleImpl {
        -QQuickWindow *m_window
        -QObject *m_popup
        -bool m_positioning
    }

    DPopupWindowHandleImpl .. DPopupWindowHandle : removed composition
Loading

File-Level Changes

Change Details Files
Rewrite DPopupWindowHandle to be a Qt6-native attached property that works directly with QQuickPopup and DQuickWindowAttached instead of a delegate-based helper window and vtable hooks.
  • Replace DPopupWindowHandleImpl/vtable-hook mechanism with a single DPopupWindowHandle class that implements QQuickItemChangeListener and tracks the internal QQuickPopupItem geometry/visibility.
  • Detect the popup item as a direct child QQuickPopupItem of the popup object and use its window() as the popup window instead of constructing a separate QQuickWindow from a delegate.
  • Introduce an enabled flag tied to popupType == Window and propagate that state into the attached DQuickWindowAttached instance so window-specific styling properties are only active when appropriate.
  • Add lifecycle cleanup for item change listeners and event filters in the DPopupWindowHandle destructor to prevent leaks and crashes.
src/private/dpopupwindowhandle.cpp
src/private/dpopupwindowhandle_p.h
Integrate popup windows with DQuickWindowAttached so PopupHandle reuses the shared window-attached API for radius, blur, and platform handle setup, and so QQuickPopup objects can obtain a DQuickWindowAttached instance.
  • Change PopupHandle’s QML attached type to be DQuickWindowAttached instead of DPopupWindowHandle so QML code accesses window decoration properties through the same API.
  • Extend DQuickWindow::qmlAttachedProperties to return a DQuickWindowAttached for QQuickPopup instances (initially without a window), enabling use of D.PlatformHandle/PopupHandle on popups.
  • Add a DQuickWindowAttached constructor that accepts a generic QObject (for QQuickPopup) and refactor DQuickWindowAttachedPrivate to store a QWindow pointer independent of the QObject parent.
  • Add DQuickWindowAttached::setWindow and DQuickWindowAttachedPrivate::setWindow to update the tracked QWindow, install event filters, hook motif hint notifications, and conditionally create/destroy the platform handle when the popup window appears or changes.
  • Guard motif hint handling so it safely returns when there is no active window, avoiding null dereferences for popup objects before their window exists.
src/dquickwindow.cpp
src/dquickwindow.h
src/private/dquickwindow_p.h
src/private/dpopupwindowhandle.cpp
src/private/dpopupwindowhandle_p.h
Implement screen edge avoidance and submenu flipping logic for popup windows, and hook it into popup window and popup item geometry changes.
  • Add a helper to detect whether a QWindow is a QQuickPopupWindow and treat popup windows with a popupWindow->transientParent() that is also a popup window as nested popups (submenus).
  • Track the popup window and its transient parent via event filters; adjust popup position when the popup window moves or when the popup item’s geometry/visibility/parent changes.
  • Compute the appropriate screen for the popup window (using the transient parent’s screen for nested popups and QGuiApplication::screenAt for others) and clamp the popup rectangle to the screen’s available geometry.
  • Implement horizontal flipping for nested popups: if the submenu overflows the right edge, try moving it to the left of the parent menu, and vice versa, with fallbacks to clamping against the screen if neither side fits.
  • Ensure vertical and horizontal clamping is applied after flipping so popups remain fully visible within the selected screen bounds.
src/private/dpopupwindowhandle.cpp
src/private/dpopupwindowhandle_p.h
Add close-on-focus-loss and close-on-press-outside behavior for popup windows using event filters rather than relying on Qt5-era popup window hacks.
  • Install an event filter on popup windows to monitor QEvent::Move and on their transient parent windows to monitor QEvent::MouseButtonPress when popupType Window is enabled.
  • On parent window mouse press, inspect the popup’s closePolicy bitmask (closeOnPressOutside and closeOnPressOutsideParent bits) and invoke the popup’s close() method via queued connection when appropriate, respecting the popup’s visible property.
  • Remove the previous Qt5 workaround that connected QWindow::activeChanged to a close slot and manually synced popup visibility when the helper window hid.
  • Centralize cleanup of event filters when the popup window or parent window changes or when the handle is destroyed to prevent stale filters from referencing deleted objects.
src/private/dpopupwindowhandle.cpp
src/private/dpopupwindowhandle_p.h
Remove the global PopupMode enum, forceWindowMode property, and delegate-based window creation from the public API and QML examples, simplifying PopupHandle usage for Qt6.
  • Delete DQMLGlobalObject::PopupMode enum and the static setPopupMode function, and remove the corresponding forwarding implementation to DPopupWindowHandle.
  • Remove PopupHandle.forceWindowMode, PopupHandle.delegate, and the internal static popupMode from DPopupWindowHandle, along with all logic around shouldCreatePopupWindowForMode and delegate-based QQuickWindow construction.
  • Stop registering DPopupWindowHandle as an uncreatable QML type in qmlplugin_plugin.cpp; the PopupHandle attached type is now provided via DQuickWindowAttached.
  • Clean up QML usages: remove D.PopupHandle.delegate and PopupHandle.forceWindowMode assignments in Menu.qml and Example_Popup.qml, and simplify background Loader activation conditions that previously depended on PopupHandle.window.
  • Adjust the CMake source list so dpopupwindowhandle.{h,cpp} are included in the DTK5 build branch instead of being removed, aligning with the new Qt6-specific implementation.
src/private/dqmlglobalobject_p.h
src/private/dqmlglobalobject.cpp
src/private/dpopupwindowhandle_p.h
src/private/dpopupwindowhandle.cpp
qmlplugin/qmlplugin_plugin.cpp
src/qml/Menu.qml
qt6/src/qml/Menu.qml
examples/qml-inspect/Example_Popup.qml
src/qml/Popup.qml
src/src.cmake

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • In DPopupWindowHandle::popupItemReparented() you call QQuickItemPrivate::get(item) without checking if item is null, which will dereference a null pointer when the popup currently has no QQuickPopupItem child; add a null check after updating m_trackedItem.
  • DQuickWindowAttachedPrivate::setWindow() updates the tracked window but does not remove the event filter, motif-hints connection, or any existing platform handle from the previous window, which can lead to stale callbacks and resources; consider explicitly disconnecting and calling destoryPlatformHandle() when the window changes or becomes null.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In DPopupWindowHandle::popupItemReparented() you call QQuickItemPrivate::get(item) without checking if item is null, which will dereference a null pointer when the popup currently has no QQuickPopupItem child; add a null check after updating m_trackedItem.
- DQuickWindowAttachedPrivate::setWindow() updates the tracked window but does not remove the event filter, motif-hints connection, or any existing platform handle from the previous window, which can lead to stale callbacks and resources; consider explicitly disconnecting and calling destoryPlatformHandle() when the window changes or becomes null.

## Individual Comments

### Comment 1
<location path="src/private/dpopupwindowhandle.cpp" line_range="82-91" />
<code_context>
+    QQuickItem *item = popupItem();
</code_context>
<issue_to_address>
**issue (bug_risk):** Guard against popupItem() returning null before using QQuickItemPrivate::get(item).

After `m_trackedItem = item;`, add an early return when `item` is null before calling `QQuickItemPrivate::get(item)` or connecting signals, e.g.:

```cpp
m_trackedItem = item;
if (!item)
    return;

QQuickItemPrivate::get(item)->addItemChangeListener(...);
connect(item, &QQuickItem::windowChanged, ...);
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +82 to +91
QQuickItem *item = popupItem();
if (m_trackedItem == item)
return;

m_forceWindowMode = forceWindowMode;
if (!m_forceWindowMode && m_handle) {
m_handle.reset();
Q_EMIT windowChanged();
if (m_trackedItem) {
QQuickItemPrivate::get(m_trackedItem)->removeItemChangeListener(this, QQuickItemPrivate::Geometry);
disconnect(m_trackedItem, &QQuickItem::windowChanged, this, &DPopupWindowHandle::onWindowChanged);
}
if (m_forceWindowMode) {
// try to create handle.
createHandle();
}
}

void DPopupWindowHandle::createHandle()
{
if (!needCreateHandle())
return;
m_trackedItem = item;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Guard against popupItem() returning null before using QQuickItemPrivate::get(item).

After m_trackedItem = item;, add an early return when item is null before calling QQuickItemPrivate::get(item) or connecting signals, e.g.:

m_trackedItem = item;
if (!item)
    return;

QQuickItemPrivate::get(item)->addItemChangeListener(...);
connect(item, &QQuickItem::windowChanged, ...);

@18202781743 18202781743 deleted the popupwindow branch April 24, 2026 08:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants