Skip to content

fix: prevent dock tray popup flicker - #1720

Open
yixinshark wants to merge 1 commit into
linuxdeepin:masterfrom
yixinshark:fix/dock-tray-popup-rendering
Open

fix: prevent dock tray popup flicker#1720
yixinshark wants to merge 1 commit into
linuxdeepin:masterfrom
yixinshark:fix/dock-tray-popup-rendering

Conversation

@yixinshark

@yixinshark yixinshark commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

BUG-375267

Summary

  • Calculate dock tray popup coordinates before the first frame.
  • Wait for committed Wayland content and one rendered frame before revealing the popup.
  • Reset shared popup window opacity during interrupted popup transitions.

Test plan

  • cmake --build build --target dde-shell dock-plugin dock-tray -j2
  • ctest --test-dir build --output-on-failure -j2
  • Verified on the remote UOS machine: the network tray popup opens at the correct position without a transparent first frame.

Summary by Sourcery

Prevent dock tray popup flicker by synchronizing popup positioning, content readiness, and visual reveal timing.

Bug Fixes:

  • Prevent dock tray popups from flickering or showing a transparent first frame during opening.
  • Ensure tray popups open at their updated anchor position and wait for surface content and a rendered frame before becoming visible.

Enhancements:

  • Reset shared popup opacity when interrupted transitions close so subsequent popups cannot inherit an incomplete reveal state.

@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: yixinshark

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

@sourcery-ai

sourcery-ai Bot commented Sep 1, 2026

Copy link
Copy Markdown

Reviewer's Guide

Prevents dock tray popup flicker by calculating its anchor position before the first frame, waiting for Wayland content and a rendered frame before revealing it, and resetting shared popup opacity across interrupted transitions.

Sequence diagram for flicker-free dock tray popup reveal

sequenceDiagram
    participant Tray as TrayItemSurfacePopup
    participant Panel as PanelPopup
    participant Wayland as WaylandSurface
    participant Positioner as DockPositioner
    participant Window as SharedPopupWindow
    participant Frame as RenderFrame

    Tray->>Panel: open()
    Panel->>Wayland: hasSurfaceContent
    alt content not ready
        Panel-->>Panel: contentOpenPending = true
        Wayland-->>Panel: contentReadyChanged
        Panel->>Panel: open()
    end
    Tray->>Positioner: updatePosition()
    Panel->>Window: finalizeOpen()
    Window->>Window: opacity = 0
    Window->>Window: show()
    Window->>Frame: update()
    Frame-->>Window: onFrameSwapped()
    Window->>Window: opacity = 1
    Window->>Window: requestActivate()
Loading

Flow diagram for dock tray popup positioning and reveal

flowchart TD
    A[Tray popup opens] --> B["DockPositioner.updatePosition()"]
    B --> C{Wayland content ready?}
    C -- No --> D[Wait for contentReadyChanged]
    D --> C
    C -- Yes --> E["PanelPopup.finalizeOpen()"]
    E --> F[Set shared popup opacity to 0]
    F --> G[Show popup and render frame]
    G --> H["onFrameSwapped()"]
    H --> I[Set opacity to 1 and activate]
Loading

File-Level Changes

Change Details Files
Coordinates are recalculated immediately when the dock anchor changes, preventing the popup’s initial frame from using a default position.
  • Route bounding changes directly to position updates.
  • Preserve the existing panel and geometry update triggers.
panels/dock/dockpositioner.cpp
Popup opening is gated on committed surface content and delayed until a rendered frame is available before becoming visible.
  • Track content readiness and defer opening when the Wayland surface has no content.
  • Initialize shared popup opacity for every open and reveal after frame swap when requested.
  • Reset pending transitions and opacity when closing an interrupted popup.
  • Expose surface-content readiness through the dock surface proxy and enable the behavior for tray popups.
frame/qml/PanelPopup.qml
panels/dock/ShellSurfaceItemProxy.qml
panels/dock/tray/TrayItemSurfacePopup.qml

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

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've reviewed your changes and they look great!


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.

Calculate the tray popup position synchronously when its anchor changes so the
first frame is placed at the tray item instead of the default origin.

Wait for the Wayland surface to commit content, render one hidden frame, and
only then reveal the shared popup window. This prevents the transparent window
background from being visible before the client texture is ready.

在锚点变化时同步计算托盘弹窗位置,避免首帧使用默认原点坐标而先显示在错误位置。

等待 Wayland surface 提交内容后,以隐藏状态完成一帧渲染,再显示共享弹窗窗口,避免客户端纹理就绪前出现透明窗口背景。

Log: prevent dock tray popup flicker
@yixinshark
yixinshark force-pushed the fix/dock-tray-popup-rendering branch from 6a0d68b to 4977ed7 Compare September 1, 2026 06:29
@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

🤖 AI 代码审查报告

总体评分: 95 分 (通过阈值: 70分)

Pass


📊 总体评价

项目 结果
审查结论 代码审查通过
评分详情 代码变更质量优秀,通过内容就绪门控、同步锚点计算和帧交换延迟显示机制有效修复了 dock 托盘弹窗闪烁问题。无安全漏洞,逻辑清晰,注释完善。
PR 标题 fix: prevent dock tray popup flicker
作者 yixinshark
变更文件 4 个文件(+52 / -3)
分析模式 全量分析(GitHub PR)

📝 需求背景

PR 描述摘要:

  • 在首帧渲染前计算 dock 托盘弹窗坐标
  • 等待 Wayland 内容提交并渲染一帧后再显示弹窗
  • 在中断的弹窗切换过程中重置共享弹窗窗口的透明度

测试计划:

  • cmake 构建 dde-shell、dock-plugin、dock-tray 目标
  • ctest 测试通过
  • 在 UOS 远程机器上验证:网络托盘弹窗在正确位置打开,无透明首帧

🔍 四维度详细分析

维度1:语法逻辑(24/25分)✓ 通过

评价词: 语法正确,逻辑清晰

分析:

本次变更涉及 4 个文件,语法逻辑整体正确,状态管理设计合理:

  1. frame/qml/PanelPopup.qml - 新增 contentReadycontentOpenPendingrevealAfterRenderrevealPending 四个布尔属性用于控制弹窗内容就绪和延迟显示状态。open() 函数中增加 contentReady 门控逻辑,当内容未就绪时设置 contentOpenPending = true 并返回,避免在 Wayland 内容提交前显示弹窗。onContentReadyChanged 处理器通过 Qt.callLater 延迟调用 open(),并在回调中再次检查 contentReady && contentOpenPending,是良好的防御性编程实践。finalizeOpen() 中根据 revealAfterRender 设置 revealPending,并通过 opacity = 0 隐藏首帧,在 onFrameSwapped() 中恢复 opacity = 1 并调用 requestActivate(),逻辑链路完整无遗漏。

  2. panels/dock/ShellSurfaceItemProxy.qml - 新增 readonly property bool hasSurfaceContent,使用三元运算符 impl.surface ? impl.surface.hasContent : false 安全处理 null surface。

  3. panels/dock/dockpositioner.cpp - 将 boundingChanged 信号连接从 update()(启动 0ms 定时器延迟执行)改为直接连接 updatePosition()(同步执行),消除事件循环延迟导致的首帧位置错误。

  4. panels/dock/tray/TrayItemSurfacePopup.qml - 设置 contentReady: popupContent.hasSurfaceContentrevealAfterRender: true,将新增机制与 PanelPopup 集成。

潜在问题:
✅ 未发现明显问题


维度2:代码质量(24/25分)✓ 通过

评价词: 代码结构清晰,注释完整

分析:

  1. 注释完整性(4/5分): dockpositioner.cpp 中新增注释清晰解释了设计原因:"The popup may be opened in the same event-loop turn as its anchor is assigned. Calculate anchor changes immediately so its first frame does not use the default (0, 0) position."。PanelPopup.qmlfinalizeOpen() 的注释解释了共享窗口透明度初始化的必要性。但新增的 contentReadyrevealAfterRenderrevealPending 等属性缺少文档注释。

  2. 代码重复(5/5分): 无重复代码,新增逻辑各司其职。

  3. 结构合理性(5/5分): 状态属性与对应的处理函数组织清晰,open()contentReady 门控 → finalizeOpen()revealPending 延迟 → onFrameSwapped() 显示的流程逻辑清晰。

  4. 调试信息清理(5/5分): 无残留调试代码,无敏感注释。

建议:

  1. 建议在 PanelPopup.qml 中为新增的 contentReady、revealAfterRender、revealAfterRender、revealPending 等属性添加属性文档注释,说明各属性的含义和使用场景,便于其他开发者理解和使用

维度3:代码性能(19/20分)✓ 通过

评价词: 性能良好,资源使用合理

分析:

  1. dockpositioner.cpp 中将 boundingChangedupdate()(0ms 定时器)改为直接调用 updatePosition(),消除了事件循环延迟。这是一个性能与正确性的权衡:直接调用确保首帧位置正确,但可能在高频 bounding 变化场景下增加 CPU 开销。考虑到弹窗定位场景的调用频率较低,该权衡是合理的。

  2. PanelPopup.qmlonFrameSwapped() 回调仅在 revealPending 为 true 时触发一次(回调内立即将 revealPending 置为 false),不会造成重复回调。

  3. Qt.callLater 的使用将延迟操作合并到事件循环中,避免了同步重入问题。

  4. opacity 方式的延迟显示比 visible 切换更轻量,不会触发额外的布局计算。

建议:

  1. dockpositioner.cpp 中将 boundingChanged 信号从 update()(0ms定时器延迟)改为直接调用 updatePosition(),虽然解决了首帧位置问题,但需注意在高频 bounding 变化场景下可能增加 CPU 开销,建议后续关注性能表现

维度4:代码安全(30/30分)✓ 通过

存在0个安全漏洞

安全漏洞详情:
✅ 未发现安全漏洞

安全扫描工具结果审计:

安全扫描工具(security_scanner.py)在 panels/dock/tray/TrayItemSurfacePopup.qml 第 136 行报告了 1 个 Critical 级别的 RCE 漏洞(CWE-78)。经人工审计确认为误报

  • 该行代码 let surfaceId = \${popupSurface.pluginId}::${popupSurface.itemKey}`` 是 JavaScript 模板字符串拼接,用于创建字符串 ID,并非命令执行
  • popupSurface.pluginIdpopupSurface.itemKey 来源于 Wayland 合成器的 popupSurface 对象,非用户可控输入
  • 该行代码为既有代码,不在本次 PR 变更范围内

漏洞对比统计:新增漏洞 0 个,减少漏洞 0 个,持平 0 个


📁 文件级分析

文件 变更类型 评估
frame/qml/PanelPopup.qml 修改 新增内容就绪门控和帧交换延迟显示机制,状态管理设计合理,消除了透明首帧闪烁和共享窗口状态泄漏
panels/dock/ShellSurfaceItemProxy.qml 修改 新增 hasSurfaceContent 只读属性,简洁有效地暴露 surface 内容状态
panels/dock/dockpositioner.cpp 修改 关键修复:将锚点位置计算从异步改为同步,确保首帧使用正确位置;注释清晰
panels/dock/tray/TrayItemSurfacePopup.qml 修改 干净集成:绑定 contentReady 和启用 revealAfterRender,两行代码完成功能对接

💡 改进建议

  1. 属性文档注释: 建议为 PanelPopup.qml 中新增的 contentReadycontentOpenPendingrevealAfterRenderrevealPending 属性添加文档注释,说明各属性的语义、初始值和使用场景

  2. 性能监控: dockpositioner.cppboundingChangedupdatePosition() 的同步调用变更,建议在高频 bounding 变化场景下关注 CPU 性能表现

  3. 状态重置完整性: close() 函数中重置了 contentOpenPendingrevealPending,建议确认在 Component.onDestruction 调用 close() 时这些状态也能被正确清理(当前实现已覆盖此场景)


📊 评分汇总

维度 得分 权重 状态
语法逻辑 24/25 25% ✓ 通过
代码质量 24/25 25% ✓ 通过
代码性能 19/20 20% ✓ 通过
代码安全 30/30 30% ✓ 通过
总分 95/100 100% ✓ 通过

本报告由 AI 代码审查工具自动生成

扫描时间:2026-09-01 14:45:00
分析模式:全量分析(GitHub PR)
项目:linuxdeepin/dde-shell
Commit:4977ed76ae6794fda314ddc36bd19388fbcdf3df

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