Fix virtual output - #1380
Draft
Groveer wants to merge 4 commits into
Draft
Conversation
1. Clamp child resource version to the interface version on create 2. Reject duplicate group names with INVALID_GROUP_NAME protocol error 3. Return an empty proxy for vanished groups instead of a fatal error 4. Notify v3 clients via virtual_output_modified on config changes 5. Restore manager destroy() override; default leaves resource alive 6. Rebind config QPointer to the newest proxy in get_virtual_output Log: Virtual output groups now notify clients on changes; getting a vanished group returns an empty proxy instead of killing the client Influence: 1. Run ctest protocol suites treeland-virtual-output-desktop-v1 and treeland-virtual-output-manager-v1 2. Create two copy groups with the same name; the second create must fail with INVALID_GROUP_NAME and not corrupt the first group 3. Get a group that no longer exists; the client must survive and see an empty outputs event 4. Update copy outputs while test-virtual-output runs; the client receives virtual_output_modified without reconnecting fix(virtual-output): 加固虚拟输出协议层 1. 创建子资源时将版本钳制到接口版本 2. 重名组返回 INVALID_GROUP_NAME 协议错误 3. 已消失的组返回空代理而非致命错误 4. 配置变化时通过 virtual_output_modified 通知 v3 客户端 5. 恢复 manager 的 destroy() 重写;默认实现不会销毁资源 6. get_virtual_output 将配置 QPointer 重新绑定到最新代理 Log: 虚拟输出组变化时通知客户端;获取已消失的组返回空代理而非断开客户端 Influence: 1. 运行 ctest 协议测试 treeland-virtual-output-desktop-v1 与 manager-v1 2. 用同名创建两个复制组;第二次必须报 INVALID_GROUP_NAME 且不影响第一组 3. 获取不存在的组;客户端存活并收到空 outputs 事件 4. test-virtual-output 运行时更新复制输出;客户端无需重连即可收到通知 PMS: TASK-390751 Signed-off-by: groveer <guoyao@uniontech.com>
1. Add WOutputLayout::pin() to freeze settled auto-arranged outputs 2. Restore saved extension positions only when they do not overlap an enabled output; revalidate before expanding from one screen 3. Migrate surfaces stranded on a disabled output back when it is re-enabled 4. Warp the cursor to the closest layout point instead of the primary center when it leaves the output layout 5. Persist the auto-restored primary and copy group ids only after every commit of the configuration succeeds 6. Refuse copy mode restore when a configured id no longer resolves; guard onRestoreCopyOutput against an empty output list Log: Re-enabling a screen no longer strands windows or drags the cursor erratically; stale copy configs no longer restore a partial group Influence: 1. In extension mode, disable then re-enable the primary screen; windows return to it and the cursor does not jump 2. Switch the primary monitor resolution, re-enable; saved stale coordinates are abandoned for auto layout 3. Configure copy mode, unplug one member, reboot; copy mode must not restore and a warning is logged 4. Toggle outputs rapidly in a 3-screen layout; the cursor stays on the nearest enabled output fix(output): 热插拔恢复与复制模式鲁棒性处理 1. 新增 WOutputLayout::pin() 冻结已排定的自动布局输出 2. 扩展模式仅在不与已启用输出重叠时恢复保存位置;单屏扩展前重新校验 3. 禁用的输出重新启用时迁移其上搁浅的窗口 4. 光标离开布局时移动到布局最近点而非主屏中心 5. 仅在该配置全部提交成功后持久化自动恢复的主屏与复制组 ID 6. 配置 ID 失效时拒绝恢复复制模式;onRestoreCopyOutput 增加空列表守卫 Log: 重新启用屏幕不再搁浅窗口或导致光标乱跳;过期的复制配置不再恢复出缺员组 Influence: 1. 扩展模式下禁用再启用主屏;窗口返回原屏且光标不跳动 2. 更换主屏分辨率后再启用;过期的保存坐标被放弃改用自动布局 3. 配置复制模式后拔掉一个成员重启;复制模式不得恢复并输出警告日志 4. 三屏布局下快速开关输出;光标停留在最近的已启用输出上 PMS: TASK-390751 Signed-off-by: groveer <guoyao@uniontech.com>
1. Add wlr-output-management client wrapper for real output discovery 2. Rework VirtualClient to drive copy mode end to end via treeland virtual output protocol and wlr output management events 3. Drop dead connects and redundant comments Log: Example client discovers real outputs via the wlr protocol and drives virtual copy groups end to end Influence: 1. Build the examples target; test-virtual-output compiles and links 2. Create and destroy a copy group from the client; the compositor applies and restores the output topology 3. Toggle real monitor outputs; the client list refreshes through wlr-output-management events feat(test-virtual-output): 扩展示例客户端 1. 新增 wlr-output-management 客户端封装以发现真实输出 2. 重构 VirtualClient,通过 treeland 虚拟输出协议与 wlr 输出管理事件端到端驱动复制模式 3. 清理无效连接与冗余注释 Log: 示例客户端可通过 wlr 协议发现真实输出,并端到端驱动虚拟复制组 Influence: 1. 构建 examples 目标;test-virtual-output 可编译链接 2. 从客户端创建/销毁复制组;合成器正确应用并恢复输出拓扑 3. 切换真实显示器输出;客户端列表通过 wlr-output-management 事件刷新 PMS: TASK-390751 Signed-off-by: groveer <guoyao@uniontech.com>
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: Groveer The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
Reviewer's GuideThe pull request turns the virtual-output example into a full interactive output-management client and expands the virtual-output protocol, while hardening compositor output topology transitions, layout positioning, cursor placement, primary-output persistence, and surface restoration across disable/enable and copy-mode changes. Sequence diagram for copy-source disable and restorationsequenceDiagram
participant Client as OutputManagementClient
participant Helper
participant RootSurfaceContainer
participant OutputManager
participant Wlroots
Client->>Helper: onOutputTestOrApply(config)
Helper->>Helper: handleCopyModeSourceDisabled(disabledSource, requestedDisabled)
alt surviving mirrors remain
Helper->>Helper: promoteCopyOutputToSource(promotedMirror, surfaces, surfacesFrom, shouldRetarget)
Helper->>RootSurfaceContainer: setPrimaryOutput(normalSource)
Helper->>Helper: m_pendingOutputConfig.copyOutputIds = copyOutputIds
else no mirror remains
Helper->>Helper: convertCopyModeToExtension(disabledSource)
end
Helper->>Wlroots: commit output states
Wlroots-->>Helper: commit callback
Helper->>OutputManager: onOutputCommitFinished(config, success)
alt successful re-enable in extension mode
Helper->>Helper: surface->setPosition(savedPosition)
Helper->>RootSurfaceContainer: updateSurfaceOutputs(surface)
end
Sequence diagram for virtual-output updates and protocol notificationssequenceDiagram
participant Client as WaylandClient
participant Manager as VirtualOutputManagerInterfaceV1
participant Binding as VirtualOutputInterfaceV1
participant Config as VirtualOutputConfig
Client->>Manager: create_virtual_output(resource, id, name, outputs)
Manager->>Config: storeVirtualOutput(name, outputs, virtualOutput)
Manager->>Manager: notifyVirtualOutputModified(name)
Manager-->>Client: send_virtual_output_modified(resource, name)
Client->>Manager: get_virtual_output(resource, name, id)
Manager->>Binding: createVirtualOutput(resource, id, name)
alt virtual output exists
Manager->>Config: backfill virtualOutput binding
Manager-->>Binding: sendOutputs(name, outputs)
else virtual output was removed
Manager-->>Binding: sendOutputs(name, empty outputs)
end
Manager->>Manager: updateVirtualOutput(name, outputs)
Manager->>Binding: sendOutputs(name, outputs)
Manager->>Manager: notifyVirtualOutputModified(name)
Client->>Manager: destroy(resource)
Manager->>Manager: wl_resource_destroy(resource)
Flow diagram for safe output layout restorationflowchart TD
A[Output added or layout restored] --> B[Compute effective saved size]
B --> C{Saved position overlaps enabled output?}
C -- Yes --> D[Keep auto-added position]
C -- No --> E["layout.move(output, savedPos)"]
D --> F["layout.pin(output)"]
E --> F
F --> G[Output remains stable during sibling geometry changes]
H[Output-management apply] --> I{Restored states overlap?}
I -- Yes --> J[Reject restored topology]
I -- No --> K[Apply restored states]
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 2 issues
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="src/modules/virtual-output/virtualoutputmanagerinterfacev1.cpp" line_range="256-259" />
<code_context>
- const QByteArray arrSend = config.outputs.join('\0').toLatin1();
- virtualOutput->sendOutputs(name, arrSend);
+ if (it != m_configs.end()) {
+ // Backfill so updateVirtualOutput() pushes to this newest binding
+ // instead of a stale (possibly disconnected) proxy.
+ it.value().virtualOutput = virtualOutput;
+ virtualOutput->sendOutputs(name, it.value().outputs.join('\0').toLatin1());
+ } else {
+ virtualOutput->sendOutputs(name, QByteArray());
</code_context>
<issue_to_address>
**issue (bug_risk):** Rebinding `m_configs[name].virtualOutput` to the newest proxy does not make the destroy cleanup proxy-specific: when the older proxy is later destroyed, its `beforeDestroy` handler unconditionally removes `m_configs[name]`, including the configuration now bound to the newer proxy.
**Triggers:** When a client calls `get_virtual_output` for an existing group more than once and then destroys the older proxy.
**Suggested fix:** Capture the proxy in the cleanup callback and remove the config only when `m_configs[name].virtualOutput` still points to that proxy.
</issue_to_address>
### Comment 2
<location path="src/modules/virtual-output/virtualoutputmanagerinterfacev1.cpp" line_range="261" />
<code_context>
+ it.value().virtualOutput = virtualOutput;
+ virtualOutput->sendOutputs(name, it.value().outputs.join('\0').toLatin1());
+ } else {
+ virtualOutput->sendOutputs(name, QByteArray());
+ }
}
</code_context>
<issue_to_address>
**issue (bug_risk):** The vanished-group path sends an empty outputs array, but the example client's `VirtualOutput::treeland_virtual_output_v1_outputs` handler returns without emitting `outputsReceived` when the array is empty, so the client never observes the required empty outputs event.
**Triggers:** When a listed virtual-output group disappears before the client calls `get_virtual_output`.
**Suggested fix:** Emit `outputsReceived(name, {})` for an empty array instead of returning before the signal emission.
</issue_to_address>…mpty outputs - Only drop the virtual-output config when it is still bound to the destroyed proxy, so a newer get_virtual_output() binding survives the destruction of an older one. - Always emit outputsReceived in the example client, even for an empty outputs array, so a vanished group is observable by the client.
Groveer
marked this pull request as draft
September 8, 2026 09:40
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary by Sourcery
Improve virtual output management and output reconfiguration to provide a complete graphical control tool while keeping display topology, primary selection, layouts, and copy-mode state consistent across output changes.
New Features:
Bug Fixes:
Enhancements:
Build: