Skip to content

fix: Fix secondary screen highlight display anomaly in 90° and 270° rotation#3175

Open
leibn123 wants to merge 4 commits intolinuxdeepin:masterfrom
leibn123:master
Open

fix: Fix secondary screen highlight display anomaly in 90° and 270° rotation#3175
leibn123 wants to merge 4 commits intolinuxdeepin:masterfrom
leibn123:master

Conversation

@leibn123
Copy link
Copy Markdown
Contributor

@leibn123 leibn123 commented Apr 14, 2026

Summary by Sourcery

Fix display configuration UI to correctly track and highlight the selected screen, especially when screens are rotated 90° or 270°, and when the virtual screen list changes.

Bug Fixes:

  • Correct screen matching logic to account for swapped width and height when a screen is rotated 90° or 270°.
  • Ensure the selected screen highlight and preview remain in sync after screen rotation and virtual screen list updates.
  • Fix tab selection logic to rely on screen names instead of direct object equality, avoiding incorrect selection after screen objects change.

Enhancements:

  • Persist the last selected screen by name so the selection can be restored when the virtual screen list changes.

leibn123 and others added 2 commits April 8, 2026 17:27
@deepin-ci-robot
Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: leibn123

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

Hi @leibn123. Thanks for your PR.

I'm waiting for a linuxdeepin member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented Apr 14, 2026

Reviewer's Guide

This PR fixes secondary screen highlight and selection issues when displays are rotated 90°/270° by correcting how Qt screens are matched to virtual screens, ensuring highlight selection reacts to rotation changes, and making screen selection persist across virtual screen list updates.

Sequence diagram for rotated screen selection and highlight update

sequenceDiagram
    actor User
    participant DisplayMainQml as DisplayMainQml
    participant ScreenTabQml as ScreenTabQml
    participant ScreenItemQml as ScreenItemQml
    participant dccData as dccData
    participant QtApplication as QtApplication
    participant Indicator as Indicator

    rect rgb(235,235,255)
        User ->> DisplayMainQml: open display settings
        activate DisplayMainQml
        DisplayMainQml ->> dccData: read virtualScreens[0]
        dccData -->> DisplayMainQml: initial screen
        DisplayMainQml ->> DisplayMainQml: Component.onCompleted
        DisplayMainQml ->> DisplayMainQml: lastScreenName = screen.name
    end

    rect rgb(235,255,235)
        User ->> ScreenItemQml: click secondary screen preview
        ScreenItemQml ->> DisplayMainQml: pressedItem(item)
        DisplayMainQml ->> DisplayMainQml: screen = item.screen
        DisplayMainQml ->> DisplayMainQml: lastScreenName = item.screen.name
        alt dccData.isX11
            DisplayMainQml ->> QtApplication: getQtScreen(screen)
            loop for each s in Qt.application.screens
                DisplayMainQml ->> DisplayMainQml: isRotated = (screen.rotate == 2 or 8)
                DisplayMainQml ->> DisplayMainQml: targetW,targetH based on isRotated
                DisplayMainQml ->> DisplayMainQml: compare s.virtualX,Y and s.width,height
            end
            QtApplication -->> DisplayMainQml: matched screen s or null
            DisplayMainQml ->> Indicator: createObject(screen = matched s)
        end
    end

    rect rgb(255,235,235)
        User ->> dccData: change display rotation 90 or 270
        dccData ->> DisplayMainQml: emit virtualScreensChanged
        DisplayMainQml ->> DisplayMainQml: onVirtualScreensChanged
        alt lastScreenName matches a virtual screen
            DisplayMainQml ->> DisplayMainQml: root.screen = matchedScreen
        else
            DisplayMainQml ->> DisplayMainQml: root.screen = virtualScreens[0]
        end

        DisplayMainQml ->> ScreenItemQml: update delegates
        ScreenItemQml ->> ScreenItemQml: selected = (root.screen === screen and screen.rotate defined)
        ScreenItemQml ->> ScreenItemQml: onScreenRotateChanged -> selected = (root.screen === screen)
        ScreenItemQml ->> ScreenItemQml: Loader.active = selected
        ScreenItemQml ->> ScreenItemQml: Loader.visible = selected
    end

    deactivate DisplayMainQml
Loading

Updated class diagram for display QML components and selection state

classDiagram
    class DisplayMainQml {
        +var screen
        +string lastScreenName
        +var activeDialogs
        +var scaleModelConst
        +getScaleModelIndex(model, scale)
        +getQtScreen(screen)
        +getControlCenterScreen()
        +closeInvalidDialogs()
        +Component_onCompleted()
        +onVirtualScreensChanged()
    }

    class ScreenItemQml {
        +var screen
        +bool selected
        +int width
        +int height
        +int radius
        +int offset
        +updatePosition()
        +onWidthChanged()
        +onHeightChanged()
        +onRotateChanged()
        +Loader_active
        +Loader_visible
        +onScreenChanged()
        +onScreenRotationChanged()
    }

    class ScreenTabQml {
        +var screen
        +Repeater repeater
        +delegate_isSelect
        +delegate_hovered
    }

    class dccData {
        +list virtualScreens
        +bool isX11
        +signal virtualScreensChanged
    }

    class QtApplication {
        +list screens
    }

    DisplayMainQml --> dccData : reads virtualScreens
    DisplayMainQml --> QtApplication : getQtScreen
    DisplayMainQml "1" o-- "many" ScreenItemQml : screen delegates
    DisplayMainQml "1" o-- "many" ScreenTabQml : tab delegates
    dccData --> DisplayMainQml : emits virtualScreensChanged
    ScreenItemQml --> DisplayMainQml : pressedItem sets screen
    ScreenTabQml --> DisplayMainQml : tab click sets screen

    class ScreenTabDelegate {
        +var modelData
        +bool isSelect
        +bool hovered
    }

    ScreenTabQml "1" o-- "many" ScreenTabDelegate : delegate
    ScreenTabDelegate --> dccData : uses modelData.name
    ScreenTabDelegate --> DisplayMainQml : compares with screen.name

    class VirtualScreen {
        +string name
        +int x
        +int y
        +int rotate
        +Resolution currentResolution
    }

    class Resolution {
        +int width
        +int height
    }

    dccData "1" o-- "many" VirtualScreen
    VirtualScreen *-- Resolution
    DisplayMainQml --> VirtualScreen : screen
    ScreenItemQml --> VirtualScreen : screen
    ScreenTabDelegate --> VirtualScreen : modelData

    class QtScreen {
        +int virtualX
        +int virtualY
        +int width
        +int height
        +double devicePixelRatio
    }

    QtApplication "1" o-- "many" QtScreen
    DisplayMainQml --> QtScreen : getQtScreen match
Loading

Flow diagram for rotation aware getQtScreen matching

flowchart TD
    A[Start getQtScreen screen] --> B[Initialize matchedScreen as null]
    B --> C{Any Qt.application.screens remaining}
    C -->|No| Z[Return null]
    C -->|Yes| D[Take next screen s]
    D --> E{screen.rotate is 2 or 8}
    E -->|Yes| F[Set isRotated true
set targetW = screen.currentResolution.height
set targetH = screen.currentResolution.width]
    E -->|No| G[Set isRotated false
set targetW = screen.currentResolution.width
set targetH = screen.currentResolution.height]
    F --> H
    G --> H
    H{Match position and size}
    H -->|Yes| I[Return s as matched Qt screen]
    H -->|No| C
    Z --> J[End]
    I --> J
Loading

Flow diagram for ScreenItem highlight update on rotation

flowchart TD
    A[Start ScreenItem] --> B["Compute selected = (root.screen == screen and screen.rotate defined)"]
    B --> C[Set Loader.active = selected]
    C --> D[Set Loader.visible = selected]
    D --> E{screen property changes}
    E -->|Yes| F[onScreenChanged -> updatePosition]
    E -->|No| G
    G{screen rotation changes} -->|Yes| H[onScreenRotationChanged -> updatePosition]
    G -->|No| I
    H --> J[Recalculate highlight border position]
    F --> J
    J --> K[Highlight border aligned with rotated screen]
    K --> L[End]
Loading

File-Level Changes

Change Details Files
Persist and restore the currently selected virtual screen across virtualScreens updates using screen name instead of relying on object identity.
  • Add lastScreenName property to remember the last selected screen by name
  • Initialize lastScreenName on component completion when screen is available
  • Update lastScreenName whenever the user selects/clicks a screen preview or list item
  • On virtualScreens change, try to re-select the screen with lastScreenName, otherwise fall back to the first virtual screen
src/plugin-display/qml/DisplayMain.qml
Fix Qt screen lookup for rotated screens so indicators and operations bind to the correct physical screen at 90°/270°.
  • Modify getQtScreen to detect 90°/270° rotation using screen.rotate
  • Swap width/height when matching screen resolution for rotated screens while preserving position checks
  • Retain null return if no matching Qt screen is found
src/plugin-display/qml/DisplayMain.qml
Ensure preview screen highlight selection updates correctly when screens rotate so the highlighted monitor matches the active one.
  • Bind ScreenItem.selected to both root.screen and screen.rotate to force update on rotation changes
  • Add onScreenChanged and onScreenRotateChanged handlers in the delegate to recompute selected when the screen reference or rotation changes
  • Propagate selection changes to indicator creation logic by relying on updated root.screen
src/plugin-display/qml/DisplayMain.qml
Force highlight border in ScreenItem to re-render/reposition when the screen rotates or its geometry changes.
  • Keep Loader.active bound to root.selected and also bind Loader.visible to root.selected to ensure the highlight is visible with selection
  • Add onScreenChanged and onScreenRotationChanged handlers on the Loader to trigger updatePosition after rotation/geometry changes
  • Extend implicit geometry update handlers with onRotateChanged to call updatePosition and keep the highlight frame aligned
src/plugin-display/qml/ScreenItem.qml
Make screen tab selection robust to virtual screen object replacement by comparing screen names instead of object equality.
  • Change isSelect property to compare model.modelData.name === screen.name instead of model.modelData === screen
  • Guard against null model.modelData or screen by checking both before comparing names and returning false otherwise
  • Add temporary local variables for modelName and screenName mainly for debugging/readability (not used in the condition)
src/plugin-display/qml/ScreenTab.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
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 ScreenItem.qml, the new onScreenChanged/onScreenRotationChanged handlers on the Loader (and the inner Rectangle) reference signals that don't exist on those types, so they will never fire; consider moving these updates to an object that actually owns a screen/rotation property (e.g., the root Item or an existing Connections to screen).
  • The updated isSelect property in ScreenTab.qml declares modelName and screenName but doesn't use them, and the ternary is redundant; you can simplify this to property bool isSelect: model.modelData && screen && model.modelData.name === screen.name to keep the logic clearer.
  • Several modified QML blocks (e.g., getQtScreen in DisplayMain.qml and the Loader in ScreenItem.qml) lost their previous indentation, which makes the structure harder to read; restoring consistent indentation would significantly improve maintainability.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `ScreenItem.qml`, the new `onScreenChanged`/`onScreenRotationChanged` handlers on the `Loader` (and the inner `Rectangle`) reference signals that don't exist on those types, so they will never fire; consider moving these updates to an object that actually owns a `screen`/`rotation` property (e.g., the root `Item` or an existing `Connections` to `screen`).
- The updated `isSelect` property in `ScreenTab.qml` declares `modelName` and `screenName` but doesn't use them, and the ternary is redundant; you can simplify this to `property bool isSelect: model.modelData && screen && model.modelData.name === screen.name` to keep the logic clearer.
- Several modified QML blocks (e.g., `getQtScreen` in `DisplayMain.qml` and the `Loader` in `ScreenItem.qml`) lost their previous indentation, which makes the structure harder to read; restoring consistent indentation would significantly improve maintainability.

## Individual Comments

### Comment 1
<location path="src/plugin-display/qml/ScreenItem.qml" line_range="127-129" />
<code_context>
+        smooth: true
     }
+
+    // ✅ 关键:旋转后强制重新渲染高亮框
+    onScreenChanged: updatePosition()
+    onScreenRotationChanged: updatePosition()
+}
     MouseArea {
</code_context>
<issue_to_address>
**issue (bug_risk):** `onScreenChanged` / `onScreenRotationChanged` on `Loader` are likely invalid signal handlers.

`Loader` does not provide `screenChanged` or `screenRotationChanged` signals, so these handlers will never run and may emit QML warnings. To react to changes in the parent `ScreenItem`’s `screen`, either bind the geometry directly to `screen`-based values, or use a `Connections { target: root.screen; function onRotateChanged() { updatePosition() } }` block (as you do later in the file).
</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 thread src/plugin-display/qml/ScreenItem.qml Outdated
Comment on lines +127 to +129
// ✅ 关键:旋转后强制重新渲染高亮框
onScreenChanged: updatePosition()
onScreenRotationChanged: updatePosition()
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): onScreenChanged / onScreenRotationChanged on Loader are likely invalid signal handlers.

Loader does not provide screenChanged or screenRotationChanged signals, so these handlers will never run and may emit QML warnings. To react to changes in the parent ScreenItem’s screen, either bind the geometry directly to screen-based values, or use a Connections { target: root.screen; function onRotateChanged() { updatePosition() } } block (as you do later in the file).

@leibn123 leibn123 force-pushed the master branch 3 times, most recently from f4e1ce1 to 20168db Compare April 14, 2026 12:44
…otation

1.修改副屏旋转90度和270度的高亮显示异常问题

PMS: BUG-355449
@deepin-bot
Copy link
Copy Markdown

deepin-bot Bot commented Apr 23, 2026

TAG Bot

New tag: 6.1.82
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #3187

@deepin-bot
Copy link
Copy Markdown

deepin-bot Bot commented Apr 24, 2026

TAG Bot

New tag: 6.1.83
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #3190

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants