Skip to content

Conversation

@yixinshark
Copy link
Contributor

include minisize luancher, tray plugin popup and tray menu

fix: prevent dock screen switch if any popup is showing
Pms: BUG-288701

Copy link

@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.

Sorry @yixinshark, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@deepin-ci-robot
Copy link

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: 18202781743, 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

include minisize luancher, tray plugin popup and tray menu

fix: prevent dock screen switch if any popup is showing
Pms: BUG-288701
@deepin-ci-robot
Copy link

deepin pr auto review

这段代码主要是为了在 Dock(任务栏)切换屏幕时,检查是否存在弹窗或临时的子窗口(Transient Child Window)。如果存在,则阻止屏幕切换,并强制显示 Dock。

以下是对这段代码的审查意见,涵盖语法逻辑、代码质量、代码性能和代码安全四个方面:

1. 语法逻辑

  • 变量命名与语义

    • m_transientChildShows:变量名暗示这是一个布尔值列表(shows),表示子窗口是否正在显示。逻辑上 if (show) 是成立的。
    • 建议:如果该容器存储的是窗口指针(如 QWidget*),建议重命名为 m_transientChildrenm_activePopups,并检查 isVisible()!isHidden(),而不是检查指针本身是否非空。如果存储的是 bool,命名 m_transientChildShows 是可以的,但通常我们需要知道具体是哪个窗口导致了阻塞,以便调试。
  • 逻辑控制

    • 代码逻辑是:如果有任何子窗口处于显示状态,就设置父窗口状态为 Show 并直接 return,不再执行后续的 QTimer 延迟切换逻辑。
    • 潜在问题:如果 m_transientChildShows 中的状态没有及时更新(例如窗口关闭了但列表里的 bool 依然是 true),会导致 Dock 永远无法切换屏幕。需要确保窗口关闭时能同步更新该列表。

2. 代码质量

  • 魔法数字

    • QTimer::singleShot(200, ...):这里的 200 毫秒是一个硬编码的延迟。
    • 建议:定义一个常量,例如 static constexpr int kScreenSwitchDelayMs = 200;,或者将其作为可配置参数,以便后续调整动画或响应速度。
  • 代码可读性与注释

    • 注释 // Do not switch screen if any popup/transient child window is showing 写得很清楚,这点很好。
    • 建议:可以补充说明为什么需要这样做(例如:防止弹窗跟随 Dock 瞬移导致用户体验不佳或坐标错乱)。
  • Lambda 捕获

    • [this, screen]:使用了值捕获 screen。如果 screen 是指针,且在 200ms 内对象被销毁(虽然 QScreen 生命周期通常由 QGuiApplication 管理,较稳定),可能会导致悬空指针。
    • 建议:确认 screen 的生命周期,或者确保逻辑安全。

3. 代码性能

  • 循环遍历
    • for (auto show : m_transientChildShows):这是一个线性遍历。
    • 影响:如果 m_transientChildShows 容量非常大(例如成百上千个),可能会有轻微的性能开销。但在 GUI 场景下,弹窗数量通常很少(<10),所以性能影响可以忽略不计。
    • 优化建议:如果对性能极其敏感,且此函数调用极其频繁,可以在状态改变时维护一个计数器或标志位(如 m_hasActivePopup),这样可以将检查操作从 O(N) 降为 O(1)。但在此场景下,目前的实现是可以接受的。

4. 代码安全

  • 空指针检查

    • parent()->setHideState(Show);:代码调用了 parent()
    • 风险:虽然 Qt 的对象树机制通常保证 parent() 存在,但为了防御性编程,建议在调用前添加断言或空指针检查:
      Q_ASSERT(parent());
      if (parent()) {
          parent()->setHideState(Show);
      }
    • 此外,parent() 返回的是 QObject*,直接调用 setHideState 暗示进行了 static_castqobject_cast。如果类型不匹配,会导致编译错误或运行时崩溃(如果是 C 风格转换)。确保 parent() 指向的类型确实有 setHideState 方法。
  • 竞态条件

    • QTimer::singleShot 是异步的。如果在 200ms 延迟期间,m_transientChildShows 的状态发生了变化,或者 screen 失效了,可能会产生不一致的行为。
    • 建议:目前的逻辑是“如果有弹窗就不切换,没弹窗就延迟切换”。如果在延迟期间弹出了窗口,目前的逻辑无法取消已经发出的定时器。
    • 改进思路:如果这是一个高频触发的函数(例如鼠标快速划过屏幕边缘),可能会在短时间内创建多个定时器。需要考虑是否需要防抖处理,或者在定时器回调中再次检查当前状态是否依然合法。

改进后的代码建议

结合以上建议,代码可以优化如下:

// 定义常量
static constexpr int kScreenSwitchDelayMs = 200;

void DockHelper::enterScreen(QScreen *screen)
{
    if (!screen) {
        return;
    }

    // Do not switch screen if any popup/transient child window is showing
    // 使用 std::any_of 或范围 for 循环,保持逻辑清晰
    bool hasActivePopup = false;
    for (auto isVisible : m_transientChildShows) {
        if (isVisible) {
            hasActivePopup = true;
            break;
        }
    }

    if (hasActivePopup) {
        // 安全检查 parent
        if (auto p = qobject_cast<DockParentType*>(parent())) { // 替换 DockParentType 为实际父类类型
            p->setHideState(Show);
        }
        return;
    }

    // 使用 weak_ptr 或者在回调中再次验证 screen 有效性(如果 QScreen 支持的话)
    // 这里假设 QScreen 生命周期由系统管理,相对安全
    QTimer::singleShot(kScreenSwitchDelayMs, [this, screen]() {
        // 再次检查 screen 是否依然有效(可选,视具体业务逻辑而定)
        if (!screen) return;

        if (auto p = qobject_cast<DockParentType*>(parent())) {
            p->setDockScreen(screen);
            p->setHideState(Show);
        }
    });
}

总结

这段代码逻辑基本正确,能够解决“弹窗存在时不切换屏幕”的需求。主要改进点在于:

  1. 消除魔法数字。
  2. 增加 parent() 的类型安全检查。
  3. 考虑异步操作期间状态变化的影响。
  4. 优化变量命名以提高可读性。

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.

3 participants