From e7aab83f2c29d0bb81817fb285486c842eac4dbc Mon Sep 17 00:00:00 2001 From: guoyao Date: Fri, 21 Aug 2026 11:49:56 +0800 Subject: [PATCH 1/3] fix(output): sync output item DPR on scale change synchronously MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Remove the devicePixelRatio QML binding that was evaluated lazily, causing a transient mismatch with the window DPR on scale commit. 2. Manage the output item devicePixelRatio from C++ via a direct connection to WOutput::scaleChanged, keeping it in sync with the render window effectiveDevicePixelRatio. 3. Apply the same pattern to both PrimaryOutput and CopyOutput items. Log: Fix greeter login window appearing at the wrong size at startup when screen scaling is not 100%. Influence: 1. Verify greeter/lock screen shows at correct size on startup with fractional scaling (e.g. 150%, 125%). 2. Verify no visual glitch when switching between different scale factors at runtime. 3. Verify copy (mirror) output also renders correctly at non-100% scale. fix(output): 同步输出项缩放比例更新,消除启动时窗口尺寸抖动 1. 移除延迟求值的 devicePixelRatio QML 绑定,该绑定在缩放提交时 与窗口 DPR 存在短暂不一致。 2. 通过 WOutput::scaleChanged 的 C++ 直连信号同步更新输出项缩放。 3. 同时应用于主屏和复制屏输出项。 Log: 修复屏幕缩放非 100% 时启动 greeter 登录窗口先变大再变小的 问题。 Influence: 1. 验证启动时 greeter/锁屏界面在分数缩放下尺寸正确。 2. 验证运行时切换缩放比例无界面抖动。 3. 验证复制屏在非 100% 缩放下显示正常。 Fixes: WM-306 --- src/core/qml/CopyOutput.qml | 2 -- src/core/qml/PrimaryOutput.qml | 2 -- src/output/output.cpp | 16 ++++++++++++++++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/core/qml/CopyOutput.qml b/src/core/qml/CopyOutput.qml index 33eea20e1e..d7f0bcb56f 100644 --- a/src/core/qml/CopyOutput.qml +++ b/src/core/qml/CopyOutput.qml @@ -41,8 +41,6 @@ OutputItem { return rotatedSize; } - devicePixelRatio: output?.scale ?? devicePixelRatio - Rectangle { id: content anchors.fill: parent diff --git a/src/core/qml/PrimaryOutput.qml b/src/core/qml/PrimaryOutput.qml index c8ce8f9f55..6289f1191b 100644 --- a/src/core/qml/PrimaryOutput.qml +++ b/src/core/qml/PrimaryOutput.qml @@ -11,8 +11,6 @@ OutputItem { readonly property OutputViewport screenViewport: outputViewport property bool forceSoftwareCursor: false - devicePixelRatio: output?.scale ?? devicePixelRatio - cursorDelegate: Cursor { id: cursorItem diff --git a/src/output/output.cpp b/src/output/output.cpp index e79dd2c6f0..d4cd81853e 100644 --- a/src/output/output.cpp +++ b/src/output/output.cpp @@ -70,6 +70,16 @@ Output *Output::create(WOutput *output, QQmlEngine *engine, QObject *parent) outputItem->setParentItem(contentItem); outputItem->setOutput(output); + // Keep the item devicePixelRatio in sync with the output scale synchronously. + // The old QML binding (devicePixelRatio: output?.scale) was evaluated lazily, + // so after the scale is committed the render window's effectiveDevicePixelRatio + // (updated in C++ on scaleChanged) already reflected the new scale while the + // output item was still at the old size. That transient mismatch made the + // greeter/lock screen render at the wrong size at startup. + QObject::connect(output, &WOutput::scaleChanged, outputItem, [outputItem, output] { + outputItem->setDevicePixelRatio(output->scale()); + }); + outputItem->setDevicePixelRatio(output->scale()); connect(Helper::instance()->globalConfig(), &TreelandConfig::forceSoftwareCursorChanged, obj, @@ -143,6 +153,12 @@ Output *Output::createCopy(WOutput *output, Output *proxy, QQmlEngine *engine, Q outputItem->setParentItem(contentItem); outputItem->setOutput(output); + // Keep the item devicePixelRatio in sync with the output scale synchronously + // (same as the PrimaryOutput path in Output::create). + QObject::connect(output, &WOutput::scaleChanged, outputItem, [outputItem, output] { + outputItem->setDevicePixelRatio(output->scale()); + }); + outputItem->setDevicePixelRatio(output->scale()); auto o = new Output(outputItem, parent); o->m_type = Type::Proxy; o->m_proxy = proxy; From dc10e4ea1721d4e066c9c856a02f53985ae6c79a Mon Sep 17 00:00:00 2001 From: guoyao Date: Fri, 21 Aug 2026 12:15:58 +0800 Subject: [PATCH 2/3] fix(license): update CopyOutput.qml copyright year to 2024-2026 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The license-check CI verifies that SPDX copyright headers use a year range spanning both the file creation and latest modification year. CopyOutput.qml was created in 2024 and modified in 2026, but its header only listed "2024", causing the license-check workflow to fail. Update the copyright year to "2024-2026" to match PrimaryOutput.qml and pass the check. Log: 修复CopyOutput.qml版权年份不符合license-check要求的问题 --- src/core/qml/CopyOutput.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/qml/CopyOutput.qml b/src/core/qml/CopyOutput.qml index d7f0bcb56f..8779e17bdf 100644 --- a/src/core/qml/CopyOutput.qml +++ b/src/core/qml/CopyOutput.qml @@ -1,4 +1,4 @@ -// Copyright (C) 2024 UnionTech Software Technology Co., Ltd. +// Copyright (C) 2024-2026 UnionTech Software Technology Co., Ltd. // SPDX-License-Identifier: Apache-2.0 OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only import QtQuick From 78cd07a3adec26fa55d24ae8002d518a936aceb4 Mon Sep 17 00:00:00 2001 From: guoyao Date: Fri, 21 Aug 2026 16:17:15 +0800 Subject: [PATCH 3/3] fix(output): sync OutputViewport DPR synchronously on scale change MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The OutputViewport's devicePixelRatio was still set via a lazy QML binding (devicePixelRatio: parent.devicePixelRatio), causing a transient size mismatch at fractional scales. The viewport's implicit size is output->size() / DPR, so a stale DPR makes it larger than its parent OutputItem, and with anchors.centerIn the content is offset — the greeter flashes from bottom-right to center at startup under 1.25 scaling. Remove the QML binding and sync the viewport DPR from C++ in Output::create() and Output::createCopy(), same pattern as the OutputItem DPR fix. Log: 修复greeter在分数缩放下的位置偏移问题 --- src/core/qml/CopyOutput.qml | 1 - src/core/qml/PrimaryOutput.qml | 1 - src/output/output.cpp | 22 ++++++++++++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/core/qml/CopyOutput.qml b/src/core/qml/CopyOutput.qml index 8779e17bdf..969ff8f706 100644 --- a/src/core/qml/CopyOutput.qml +++ b/src/core/qml/CopyOutput.qml @@ -97,7 +97,6 @@ OutputItem { anchors.centerIn: parent depends: [primaryScreenViewport] - devicePixelRatio: outputItem.devicePixelRatio input: content output: outputItem.output diff --git a/src/core/qml/PrimaryOutput.qml b/src/core/qml/PrimaryOutput.qml index 6289f1191b..0cc4922940 100644 --- a/src/core/qml/PrimaryOutput.qml +++ b/src/core/qml/PrimaryOutput.qml @@ -47,7 +47,6 @@ OutputItem { id: outputViewport output: rootOutputItem.output - devicePixelRatio: parent.devicePixelRatio anchors.centerIn: parent RotationAnimation { diff --git a/src/output/output.cpp b/src/output/output.cpp index d4cd81853e..a3c4a0d680 100644 --- a/src/output/output.cpp +++ b/src/output/output.cpp @@ -93,6 +93,20 @@ Output *Output::create(WOutput *output, QQmlEngine *engine, QObject *parent) o->m_type = Type::Primary; obj->setParent(o); + // Keep the OutputViewport's devicePixelRatio in sync with the output scale + // synchronously, for the same reason as the output item above. The viewport's + // implicit size is output->size() / DPR, so a stale (too-small) DPR makes the + // viewport larger than its parent OutputItem. With anchors.centerIn the viewport + // is then offset, and renderMatrix() maps content to the wrong screen position — + // the greeter/lock screen flashes from the bottom-right toward center at startup + // under fractional scales (e.g. 1.25). + if (auto *viewport = o->screenViewport()) { + QObject::connect(output, &WOutput::scaleChanged, viewport, [viewport, output] { + viewport->setDevicePixelRatio(output->scale()); + }); + viewport->setDevicePixelRatio(output->scale()); + } + o->minimizedSurfaces->setFilter([](SurfaceWrapper *s) { return s->isMinimized(); }); @@ -164,6 +178,14 @@ Output *Output::createCopy(WOutput *output, Output *proxy, QQmlEngine *engine, Q o->m_proxy = proxy; obj->setParent(o); + // Same synchronous DPR sync for the copy output's viewport (see Output::create). + if (auto *viewport = o->screenViewport()) { + QObject::connect(output, &WOutput::scaleChanged, viewport, [viewport, output] { + viewport->setDevicePixelRatio(output->scale()); + }); + viewport->setDevicePixelRatio(output->scale()); + } + o->updateOutputHardwareLayers(); connect(proxy->screenViewport(), &WOutputViewport::hardwareLayersChanged,