Skip to content

Conversation

@wjyrich
Copy link
Contributor

@wjyrich wjyrich commented Nov 28, 2025

  1. Replaced simple windowMargin function with comprehensive updateMargins function
  2. Added proper handling for dock visibility and position
  3. Implemented device pixel ratio conversion for accurate geometry calculations
  4. Added special handling for bottom dock to prevent flickering
  5. Added properties to store margin values instead of recalculating each time
  6. Connected to frontendWindowRectChanged signal for dynamic updates

Log: Fixed notification center positioning issues when dock is visible

fix: 改进通知中心边距计算

  1. 将简单的 windowMargin 函数替换为全面的 updateMargins 函数
  2. 添加对任务栏可见性和位置的正确处理
  3. 实现设备像素比转换以确保几何计算准确
  4. 为底部任务栏添加特殊处理以防止闪烁
  5. 添加属性存储边距值而不是每次都重新计算
  6. 连接 frontendWindowRectChanged 信号以实现动态更新

Log: 修复任务栏可见时通知中心定位问题

PMS: BUG-340799

剪切板相关修复: #1308 linuxdeepin/dde-clipboard#215

@deepin-ci-robot
Copy link

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: wjyrich

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
Copy link

sourcery-ai bot commented Nov 28, 2025

Reviewer's Guide

Refactors notification center margin handling to use dynamic, screen-aware dock geometry with device-pixel–aware calculations and stored margin properties, fixing positioning issues and flicker when the dock is shown/hidden or moved.

Sequence diagram for dynamic dock geometry margin updates

sequenceDiagram
    actor User
    participant DockApplet
    participant NotificationCenterWindow as RootWindow
    participant DLayerShellWindow
    participant Screen

    User->>DockApplet: Change dock visibility/position
    DockApplet->>DockApplet: Update frontendWindowRect
    DockApplet-->>NotificationCenterWindow: frontendWindowRectChanged(frontendWindowRect)
    NotificationCenterWindow->>NotificationCenterWindow: updateMargins(frontendRect)
    NotificationCenterWindow->>DockApplet: Read screenName, position, hideState, dockSize
    NotificationCenterWindow->>Screen: Read name, devicePixelRatio, virtualX, virtualY, width, height
    NotificationCenterWindow->>NotificationCenterWindow: Compute dockGeometry and screenGeometry
    alt Dock on same screen and visible
        alt DockPositionTop
            NotificationCenterWindow->>NotificationCenterWindow: Set topMarginValue
        else DockPositionRight
            NotificationCenterWindow->>NotificationCenterWindow: Set rightMarginValue
        else DockPositionBottom
            NotificationCenterWindow->>DockApplet: Read hideState and dockSize
            NotificationCenterWindow->>NotificationCenterWindow: Set bottomMarginValue with anti_flicker_logic
        end
    else Dock on other screen or not valid
        NotificationCenterWindow->>NotificationCenterWindow: Reset all margin values to 0
    end
    NotificationCenterWindow-->>DLayerShellWindow: topMargin, rightMargin, bottomMargin bindings updated
    DLayerShellWindow->>User: Notification center repositions without flicker
Loading

Class diagram for updated notification center margin handling

classDiagram
    class RootWindow {
        +int topMarginValue
        +int rightMarginValue
        +int bottomMarginValue
        +updateMargins(frontendRect)
        +onRequestClosePopup()
        +onFrontendWindowRectChanged(frontendWindowRect)
    }

    class DockApplet {
        +string screenName
        +int hideState
        +int position
        +int dockSize
        +rect frontendWindowRect
        +frontendWindowRectChanged(frontendWindowRect)
    }

    class Screen {
        +string name
        +double devicePixelRatio
        +int virtualX
        +int virtualY
        +int width
        +int height
    }

    class DLayerShellWindow {
        +int topMargin
        +int rightMargin
        +int bottomMargin
        +int exclusionZone
        +int keyboardInteractivity
    }

    RootWindow --> DockApplet : reads_properties_and_listens_to_signal
    RootWindow --> Screen : uses_for_geometry_and_dpr
    RootWindow --> DLayerShellWindow : binds_margin_properties
    DLayerShellWindow ..> Screen : positioned_on
Loading

File-Level Changes

Change Details Files
Replace simple dock-based margin calculation with a comprehensive, geometry-based updateMargins function and stored margin properties.
  • Introduce topMarginValue, rightMarginValue, and bottomMarginValue properties on the root Window to hold current margins instead of recomputing them in bindings.
  • Replace windowMargin(position) helper with updateMargins(frontendRect) that initializes margins to zero when dock/screen are unavailable or mismatched.
  • Within updateMargins, fetch dockApplet.frontendWindowRect (if no rect is provided) and early-return with zero margins when absent.
panels/notification/center/package/main.qml
Make margin calculation device-pixel–aware and dependent on actual dock geometry for each edge of the screen.
  • Convert dock frontendWindowRect from device pixels to logical pixels using root.screen.devicePixelRatio before calculations.
  • Construct screenGeometry from root.screen virtual coordinates and logical width/height to compare with dock geometry.
  • Compute top, right, and bottom margins based on dock position and visible overlap between dockGeometry and screenGeometry, guarding for zero/invalid dock size.
panels/notification/center/package/main.qml
Add special handling for bottom dock hide behavior and wire margins to DLayerShellWindow and dock signals for dynamic, flicker-free updates.
  • For DOCK_BOTTOM, avoid geometry-based computation and instead set bottom margin to 0 when dockApplet.hideState is Dock.Hide, otherwise use dockApplet.dockSize to prevent flicker.
  • Bind DLayerShellWindow.topMargin/rightMargin/bottomMargin to the new margin properties instead of calling a function per-binding.
  • Handle onFrontendWindowRectChanged(frontendWindowRect) in the dock notification to call root.updateMargins(frontendWindowRect), ensuring margins are updated when the dock frontend rect changes.
panels/notification/center/package/main.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

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.

Hey there - I've reviewed your changes - here's some feedback:

  • The updateMargins function repeats the pattern of resetting all margin values to 0 in several early-return branches; consider extracting this into a small helper (e.g. resetMargins()) to reduce duplication and make the intent clearer.
  • The switch (dockPosition) uses raw numeric values (0/1/2) with comments for DOCK_TOP/RIGHT/BOTTOM; if the dock API exposes an enum or constants for these positions, using them instead of magic numbers would make the code more self-documenting and less error-prone.
  • For the bottom dock you explicitly gate the margin on hideState === Dock.Hide, but for top and right positions the hide state is not considered (only geometry); it may be worth clarifying or aligning this behavior so that margin handling for hidden/auto-hidden docks is consistent across all positions.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `updateMargins` function repeats the pattern of resetting all margin values to 0 in several early-return branches; consider extracting this into a small helper (e.g. `resetMargins()`) to reduce duplication and make the intent clearer.
- The `switch (dockPosition)` uses raw numeric values (0/1/2) with comments for `DOCK_TOP/RIGHT/BOTTOM`; if the dock API exposes an enum or constants for these positions, using them instead of magic numbers would make the code more self-documenting and less error-prone.
- For the bottom dock you explicitly gate the margin on `hideState === Dock.Hide`, but for top and right positions the hide state is not considered (only geometry); it may be worth clarifying or aligning this behavior so that margin handling for hidden/auto-hidden docks is consistent across all positions.

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.

@deepin-bot
Copy link

deepin-bot bot commented Dec 4, 2025

TAG Bot

New tag: 2.0.21
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #1364

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR improves the notification center's margin calculation to properly account for the dock's position and visibility. The change replaces a simple position-based margin calculation with a comprehensive geometry-based approach that handles device pixel ratios and dynamic dock state changes.

Key changes:

  • Replaced windowMargin(position) function with updateMargins(frontendRect) that uses dock geometry instead of simple position checks
  • Added property storage for margin values (topMarginValue, rightMarginValue, bottomMarginValue) to avoid recalculation on every access
  • Implemented device pixel ratio conversion to translate dock geometry from device pixels to logical pixels for accurate positioning

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

newRightMargin = visibleWidth
break
}
//特殊处理:因为会上述计算会导致抖动
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

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

The comment has a grammatical error. It says "因为会上述计算会导致抖动" which contains "会" twice. It should be "因为上述计算会导致抖动" (remove the first "会").

Suggested change
//特殊处理:因为会上述计算会导致抖动
//特殊处理:因为上述计算会导致抖动

Copilot uses AI. Check for mistakes.
let dockSize = dockApplet.dockSize
let dockPosition = dockApplet.position
return dockPosition === position ? dockSize : 0
let screen = root.screen ? root.screen.name : ""
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

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

The screen name check on line 31 is redundant. Line 23 already checks if root.screen is falsy and returns early, so by this point root.screen is guaranteed to be non-null. The ternary operator "root.screen ? root.screen.name : ''" can be simplified to just "root.screen.name".

Suggested change
let screen = root.screen ? root.screen.name : ""
let screen = root.screen.name

Copilot uses AI. Check for mistakes.
topMarginValue = newTopMargin
rightMarginValue = newRightMargin
bottomMarginValue = newBottomMargin

Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

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

There is trailing whitespace at the end of this line. This should be removed to maintain code cleanliness.

Suggested change

Copilot uses AI. Check for mistakes.
Comment on lines 153 to 115
function onFrontendWindowRectChanged(frontendWindowRect) {
root.updateMargins(frontendWindowRect)
}
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

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

The updateMargins function is only called when frontendWindowRectChanged signal is emitted, but it's never called during component initialization or when the screen changes. This means the notification center may have incorrect margins when first displayed or when moved to a different screen. Consider calling updateMargins in a Component.onCompleted handler and in the onScreenChanged handler.

Copilot uses AI. Check for mistakes.
Comment on lines +62 to +44
let screenGeometry = Qt.rect(
root.screen.virtualX,
root.screen.virtualY,
root.screen.width,
root.screen.height
)
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

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

The screen geometry is recalculated every time updateMargins is called, even when only the dock's frontendRect changes. Since screen geometry changes are rare, consider caching the screen geometry and only recalculating it when the screen actually changes to improve performance.

Copilot uses AI. Check for mistakes.
@deepin-bot
Copy link

deepin-bot bot commented Dec 11, 2025

TAG Bot

New tag: 2.0.22
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #1366

@deepin-bot
Copy link

deepin-bot bot commented Dec 18, 2025

TAG Bot

New tag: 2.0.23
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #1371

@deepin-bot
Copy link

deepin-bot bot commented Dec 25, 2025

TAG Bot

New tag: 2.0.24
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #1380

@deepin-bot
Copy link

deepin-bot bot commented Jan 7, 2026

TAG Bot

New tag: 2.0.25
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #1394

@deepin-bot
Copy link

deepin-bot bot commented Jan 14, 2026

TAG Bot

New tag: 2.0.26
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #1396

@deepin-bot
Copy link

deepin-bot bot commented Jan 23, 2026

TAG Bot

New tag: 2.0.27
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #1401

@deepin-bot
Copy link

deepin-bot bot commented Jan 29, 2026

TAG Bot

New tag: 2.0.28
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #1415

@wjyrich wjyrich force-pushed the fix-bug-340795 branch 2 times, most recently from 1c076fd to 4f2f176 Compare February 2, 2026 08:21
@wjyrich wjyrich requested a review from 18202781743 February 2, 2026 08:22
1. Fixed notification center window positioning logic to use
frontendWindowRect for accurate dock geometry
2. Added special handling for bottom dock to avoid jitter by checking
hideState
3. Improved margin calculation by considering actual visible dock area
on screen edges
4. Added property binding for frontendRect updates when dock geometry
changes

Log: Fixed notification center positioning issues near dock edges

Influence:
1. Test notification center positioning when dock is at top/right/bottom
positions
2. Verify no jitter when dock is at bottom with hide/show states
3. Test positioning accuracy when dock spans multiple screens
4. Verify correct margin calculation when dock is partially off-screen
5. Test notification center behavior during dock position changes
6. Verify frontendRect updates properly when dock geometry changes

fix: 修复通知中心窗口定位问题

1. 修复通知中心窗口定位逻辑,使用 frontendWindowRect 获取准确的 dock 几
何信息
2. 为底部 dock 添加特殊处理,通过检查 hideState 避免抖动问题
3. 改进边距计算,考虑屏幕边缘 dock 的实际可见区域
4. 添加 frontendRect 属性绑定,在 dock 几何信息变化时更新

Log: 修复通知中心在 dock 边缘的定位问题

Influence:
1. 测试通知中心在 dock 位于顶部/右侧/底部时的定位
2. 验证 dock 在底部隐藏/显示状态时无抖动
3. 测试 dock 跨多个屏幕时的定位准确性
4. 验证 dock 部分超出屏幕时的边距计算正确性
5. 测试 dock 位置变化时通知中心的行为
6. 验证 dock 几何信息变化时 frontendRect 正确更新

PMS: BUG-340795
@deepin-ci-robot
Copy link

deepin pr auto review

这段代码主要实现了通知中心面板根据任务栏(Dock)的位置和状态计算窗口边距的功能。以下是对该代码的详细审查和改进建议:

1. 语法与逻辑审查

  • 导入语句
    • 增加了 import org.deepin.ds.dock 1.0,这是合理的,因为代码中使用了 Dock.Hide 枚举。
  • 属性定义
    • property rect frontendRect: dockApplet ? dockApplet.frontendWindowRect : Qt.rect(0, 0, 0, 0)
    • 问题:这行代码位于 Window 根元素下,但在定义时引用了 dockApplet。然而,dockApplet 是在 windowMargin 函数内部通过 DS.applet("org.deepin.ds.dock") 获取的局部变量。在属性初始化时,全局作用域中并不存在 dockApplet 变量,这会导致 ReferenceError。
    • 修正:该属性的初始值应设为 Qt.rect(0, 0, 0, 0),其值由 onFrontendWindowRectChanged 信号处理器更新。
  • 变量获取
    • let dockApplet = DS.applet("org.deepin.ds.dock")windowMargin 函数中重复调用。
    • 问题:频繁调用 DS.applet 可能会有性能开销,且逻辑上 Dock 实例通常是唯一的。
    • 建议:虽然 QML 的属性绑定机制会自动处理依赖,但将 dockApplet 提升为组件属性或使用 Loader 来管理可能更清晰。不过考虑到 windowMargin 是一个函数而非属性绑定,函数内部获取是必要的。
  • Switch 语句完整性
    • switch (position) 处理了 0 (Top), 1 (Right), 2 (Bottom)。
    • 问题:缺少 case 3 (DOCK_LEFT) 的处理。如果 Dock 在左侧,函数将返回 undefined,这可能导致布局计算错误。
    • 修正:必须补充左侧 Dock 的逻辑。
  • 底部 Dock 逻辑
    • 底部 Dock 使用了 hideState 判断,而左右上使用了几何计算。这种不一致性在注释中解释为"避免抖动",这可能是业务逻辑的妥协,但在代码维护上容易引起混淆。
  • 坐标计算 (DPR)
    • 代码中显式处理了 devicePixelRatio (dpr),将 frontendRect 的坐标除以 dpr。
    • 逻辑:这通常意味着 frontendRect 是物理像素坐标,而 QML 的 Screen 属性通常是逻辑像素。这种转换是必要的,但需要确保 frontendRect 的来源确实总是物理像素。

2. 代码质量

  • 魔法数字
    • case 0, case 1, case 2 以及 hideState === 2 (旧代码) 或 hideState === Dock.Hide (新代码)。
    • 建议:应使用枚举类型(如 Dock.Position.Top, Dock.Hide)代替硬编码的数字,以提高可读性。虽然代码中已使用了 Dock.Hide,但 Position 仍使用数字。
  • 代码复用
    • case 1 (Right) 的计算逻辑是 screenGeometry.x + screenGeometry.width - dockGeometry.x,即 screenRight - dockLeft
    • case 0 (Top) 的逻辑是 dockGeometry.y + dockGeometry.height - screenGeometry.y,即 dockBottom - screenTop
    • case 2 (Bottom) 完全不同。
    • 建议:目前的写法虽然直观,但如果 Dock 有复杂的遮挡逻辑,建议封装成辅助函数。

3. 代码性能

  • 重复计算
    • 每次调用 windowMargin 都会重新计算 dockGeometryscreenGeometry。如果此函数被高频触发(例如动画过程中),可能会造成轻微性能压力。
    • 建议:考虑到 Screen 属性和 frontendRect 变化频率不高,目前的性能影响通常可以忽略。但如果出现性能瓶颈,可以考虑将这些计算结果缓存为属性,并在 onScreenChangedonFrontendWindowRectChanged 时更新。
  • 除法运算
    • frontendRect.x / dpr 等涉及浮点除法。在 UI 渲染循环中应尽量减少不必要的运算,但在此处是必要的坐标转换。

4. 代码安全

  • 空指针检查
    • if (!dockApplet) return 0 做了很好的空值检查。
  • 边界检查
    • Math.max(0, ...) 确保了边距不会为负数,这是一个很好的防御性编程实践。
  • 数据一致性
    • 混合使用几何计算和状态属性(如 hideState)可能导致边缘情况下的不一致。例如,如果 Dock 正在执行隐藏动画,几何坐标可能还没变,但 hideState 已经变了(反之亦然)。代码中对底部 Dock 的特殊处理正是为了应对这种同步问题。

改进后的代码建议

import QtQuick 2.12
import QtQuick.Window 2.12
import org.deepin.dtk 1.0
import org.deepin.ds 1.0
import org.deepin.ds.notification
import org.deepin.ds.notificationcenter
import org.deepin.ds.dock 1.0

Window {
    id: root

    // 修正:初始化时不引用不存在的变量,由信号更新
    property rect frontendRect: Qt.rect(0, 0, 0, 0)

    function windowMargin(position) {
        let dockApplet = DS.applet("org.deepin.ds.dock")
        if (!dockApplet)
            return 0

        let dockScreen = dockApplet.screenName
        let screen = root.screen.name
        if (dockScreen !== screen)
            return 0

        let dockPosition = dockApplet.position
        if (dockPosition !== position)
            return 0

        // 底部Dock特殊处理:使用hideState判断,避免动画或状态切换时的抖动
        if (dockPosition === Dock.Position.Bottom) {
            if (dockApplet.hideState === Dock.Hide)
                return 0
            return dockApplet.dockSize
        }

        let dpr = root.screen.devicePixelRatio
        // 确保dpr不为0,防止除以零错误
        if (dpr === 0) dpr = 1.0

        let dockGeometry = Qt.rect(
            frontendRect.x / dpr,
            frontendRect.y / dpr,
            frontendRect.width / dpr,
            frontendRect.height / dpr
        )

        let screenGeometry = Qt.rect(
            root.screen.virtualX,
            root.screen.virtualY,
            root.screen.width,
            root.screen.height
        )

        switch (dockPosition) {
            case Dock.Position.Top: {
                // 计算Dock在屏幕内的可见高度
                let visibleHeight = Math.max(0, dockGeometry.y + dockGeometry.height - screenGeometry.y)
                return Math.min(visibleHeight, dockGeometry.height)
            }
            case Dock.Position.Right: {
                // 计算Dock在屏幕内的可见宽度
                let visibleWidth = Math.max(0, screenGeometry.x + screenGeometry.width - dockGeometry.x)
                return Math.min(visibleWidth, dockGeometry.width)
            }
            case Dock.Position.Left: { // 新增:左侧Dock的处理
                // 计算Dock在屏幕内的可见宽度
                let visibleWidth = Math.max(0, dockGeometry.x + dockGeometry.width - screenGeometry.x)
                return Math.min(visibleWidth, dockGeometry.width)
            }
            default:
                return 0
        }
    }

    // ... 其他代码 ...

    Connections {
        target: DS.applet("org.deepin.ds.dock")
        function onFrontendWindowRectChanged(frontendWindowRect) {
            root.frontendRect = frontendWindowRect
        }
    }
}

总结

这段代码的主要改进点在于:

  1. 修复了属性初始化时的作用域错误
  2. 补全了左侧 Dock 的处理逻辑,避免潜在的布局 Bug。
  3. 使用了枚举代替魔法数字,提高了可读性。
  4. 增加了对 DPR 的防御性检查
  5. 优化了代码结构,将底部 Dock 的特殊逻辑前置,使 Switch 结构更清晰。

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