Skip to content

feat(display): integrate ScreenScale service for scale management#3176

Open
fly602 wants to merge 1 commit intolinuxdeepin:masterfrom
fly602:master
Open

feat(display): integrate ScreenScale service for scale management#3176
fly602 wants to merge 1 commit intolinuxdeepin:masterfrom
fly602:master

Conversation

@fly602
Copy link
Copy Markdown
Contributor

@fly602 fly602 commented Apr 15, 2026

Use ScreenScale service as the single source of truth for display scale:

  • Get scale factor, available scales and recommended scale from ScreenScale
  • Set scale via ScreenScale.SetScaleFactor() method
  • Remove XSettings scale interfaces, simplify code structure
  • Add PropertiesChanged signal listener for real-time updates

Log: 集成ScreenScale服务统一管理显示缩放
PMS: BUG-355227
Influence: 缩放数据从ScreenScale服务获取,设置缩放通过ScreenScale接口,简化代码结构
Change-Id: I53aa2c588631543f2d83234adb16c7f2eb2c7b4a

Summary by Sourcery

Integrate the ScreenScale D-Bus service as the unified source of truth for display scaling and expose its data through the display module and QML UI.

New Features:

  • Expose available display scales and recommended scale from the ScreenScale service through DisplayModule properties for use in the UI.
  • Provide real-time updates of screen scale, available scales, and recommended scale via ScreenScale-related D-Bus signals.

Enhancements:

  • Switch global UI scale management to use the ScreenScale D-Bus service instead of XSettings-based scale handling, simplifying scale-related logic.
  • Update the display worker to initialize and set UI scale directly via ScreenScale and to apply scale changes through the ScreenScale interface.
  • Adjust the QML display settings UI to build the scale selection model from ScreenScale-provided data when available, falling back to the previous static model otherwise.

Use ScreenScale service as the single source of truth for display scale:
- Get scale factor, available scales and recommended scale from ScreenScale
- Set scale via ScreenScale.SetScaleFactor() method
- Remove XSettings scale interfaces, simplify code structure
- Add PropertiesChanged signal listener for real-time updates

Log: 集成ScreenScale服务统一管理显示缩放
PMS: BUG-355227
Influence: 缩放数据从ScreenScale服务获取,设置缩放通过ScreenScale接口,简化代码结构
Change-Id: I53aa2c588631543f2d83234adb16c7f2eb2c7b4a
@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented Apr 15, 2026

Reviewer's Guide

Integrates the org.deepin.dde.ScreenScale1 D-Bus service as the single source of truth for UI scaling, wiring its properties and signals into the DisplayDBusProxy/DisplayWorker/DisplayModule stack and QML, while removing the old XSettings-based max scale calculation and asynchronous GetScaleFactor calls.

Sequence diagram for setting global scale via ScreenScale service

sequenceDiagram
    actor User
    participant DisplayMain_qml
    participant DisplayModule
    participant DisplayWorker
    participant DisplayDBusProxy
    participant ScreenScaleService as org.deepin_dde_ScreenScale1
    participant DisplayModel

    User ->> DisplayMain_qml: change scale selection
    DisplayMain_qml ->> DisplayModule: setGlobalScale(scale)
    DisplayModule ->> DisplayWorker: setUiScale(scale)

    alt isTreeland
        DisplayWorker ->> DisplayDBusProxy: SetWaylandUIScale(scale)
        DisplayWorker ->> DisplayModel: setUIScale(scale)
    else X11_or_other
        DisplayWorker ->> DisplayDBusProxy: SetScreenScaleFactor(scale)
        DisplayDBusProxy ->> ScreenScaleService: SetScaleFactor(scale)
        DisplayWorker ->> DisplayModel: setUIScale(scale)
    end

    ScreenScaleService -->> DisplayDBusProxy: PropertiesChanged ScaleFactor
    DisplayDBusProxy ->> DisplayWorker: ScreenScaleFactorChanged(value)
    DisplayWorker ->> DisplayModel: setUIScale(value)
Loading

Sequence diagram for initializing scale and available scales from ScreenScale

sequenceDiagram
    participant DisplayWorker
    participant DisplayDBusProxy
    participant ScreenScaleService as org.deepin_dde_ScreenScale1
    participant DisplayModel

    DisplayWorker ->> DisplayDBusProxy: active()
    Note over DisplayWorker,DisplayDBusProxy: non Treeland branch

    DisplayWorker ->> DisplayDBusProxy: screenScaleFactor()
    DisplayDBusProxy ->> ScreenScaleService: read property ScaleFactor
    ScreenScaleService -->> DisplayDBusProxy: ScaleFactor
    DisplayDBusProxy -->> DisplayWorker: double
    DisplayWorker ->> DisplayModel: setUIScale(scaleFactor_or_1_0)

    DisplayWorker ->> DisplayDBusProxy: availableScales()
    DisplayDBusProxy ->> ScreenScaleService: read property AvailableScales
    ScreenScaleService -->> DisplayDBusProxy: AvailableScales

    DisplayWorker ->> DisplayDBusProxy: recommendedScale()
    DisplayDBusProxy ->> ScreenScaleService: read property RecommendedScale
    ScreenScaleService -->> DisplayDBusProxy: RecommendedScale

    ScreenScaleService -->> DisplayDBusProxy: PropertiesChanged AvailableScales RecommendedScale
    DisplayDBusProxy ->> DisplayModule: AvailableScalesChanged
    DisplayDBusProxy ->> DisplayModule: RecommendedScaleChanged
Loading

Class diagram for updated scaling-related classes

classDiagram
    class DisplayDBusProxy {
        +DisplayDBusProxy(QObject *parent)
        +BrightnessMap brightness()
        +QDBusPendingReply~<>~ ApplyChanges()
        +double screenScaleFactor() const
        +double recommendedScale() const
        +QList~double~ availableScales() const
        +QDBusPendingReply~<>~ SetScreenScaleFactor(double factor)
        +void onScreenScalePropertiesChanged(QString interface, QVariantMap changedProperties, QStringList invalidatedProperties)
        +void ScreenScaleFactorChanged(double value) const
        +void AvailableScalesChanged() const
        +void RecommendedScaleChanged() const
        +void BrightnessChanged(BrightnessMap value) const
        +void ColorTemperatureEnabledChanged(bool value) const
        -Dtk::Core::DDBusInterface *m_dBusDisplayInter
        -Dtk::Core::DDBusInterface *m_dBusSystemDisplayInter
        -Dtk::Core::DDBusInterface *m_dBusAppearanceInter
        -Dtk::Core::DDBusInterface *m_dBusPowerInter
        -Dtk::Core::DDBusInterface *m_dBusScreenScaleInter
        -void init()
    }

    class DisplayWorker {
        +DisplayWorker(DisplayModel *model, QObject *parent, bool isSync)
        +~DisplayWorker()
        +void active()
        +void saveChanges()
        +void switchMode(int mode, QString name)
        +void setUiScale(double value)
        +void setIndividualScaling(Monitor *m, double scaling)
        +DisplayDBusProxy *dbusProxy() const
        -void onMonitorListChanged(QList~QDBusObjectPath~ mons)
        -void onMonitorsBrightnessChanged(BrightnessMap brightness)
        -void onGetScreenScalesFinished(QDBusPendingCallWatcher *w)
        -DisplayModel *m_model
        -DisplayDBusProxy *m_displayInter
    }

    class DisplayModule {
        <<QObject>>
        +Q_PROPERTY(bool isX11)
        +Q_PROPERTY(qreal globalScale)
        +Q_PROPERTY(qreal maxGlobalScale)
        +Q_PROPERTY(QList~qreal~ availableScales)
        +Q_PROPERTY(qreal recommendedScale)
        +bool isX11() const
        +qreal globalScale() const
        +void setGlobalScale(qreal scale)
        +qreal maxGlobalScale() const
        +QList~qreal~ availableScales() const
        +qreal recommendedScale() const
        +bool colorTemperatureEnabled() const
        +void setColorTemperatureEnabled(bool enabled)
        +void globalScaleChanged()
        +void maxGlobalScaleChanged()
        +void availableScalesChanged()
        +void recommendedScaleChanged()
        -DisplayModulePrivate *d_ptr
    }

    class DisplayModulePrivate {
        +DisplayModulePrivate(DisplayModule *parent)
        +void init()
        +void updateMonitorList()
        +void updatePrimary()
        +void updateDisplayMode()
        +DccScreen *primary() const
        +QString displayMode() const
        +void setScreenPosition(QList~ScreenData*~ screensData)
        -DisplayWorker *m_worker
        -DisplayModel *m_model
        -QList~DccScreen*~ m_screens
        -QList~DccScreen*~ m_virtualScreens
        -DccScreen *m_primary
        -QString m_displayMode
    }

    class DisplayModel {
        +void setUIScale(double value)
        +void uiscaleChanged()
        +void colorTemperatureChanged()
        +void customColorTempTimePeriodChanged()
        +void adjustCCTmodeChanged()
    }

    class DisplayMain_qml {
        +function getScaleModel(maxScale, scale)
        +property real globalScale
        +property real maxGlobalScale
        +property var availableScales
        +property real recommendedScale
    }

    DisplayWorker --> DisplayDBusProxy : uses
    DisplayWorker --> DisplayModel : updates
    DisplayModulePrivate --> DisplayWorker : holds
    DisplayModulePrivate --> DisplayModel : holds
    DisplayModule --> DisplayModulePrivate : aggregates
    DisplayMain_qml --> DisplayModule : binds_Q_PROPERTY
    DisplayDBusProxy --> DisplayModel : ScreenScaleFactorChanged_to_setUIScale
Loading

File-Level Changes

Change Details Files
Add ScreenScale D-Bus interface wrapper and property/signal handling in DisplayDBusProxy, exposing screen scale factor, available scales, and recommended scale plus a setter.
  • Instantiate a DDBusInterface for org.deepin.dde.ScreenScale1 in DisplayDBusProxy::init and connect to org.freedesktop.DBus.Properties.PropertiesChanged.
  • Implement screenScaleFactor(), availableScales(), recommendedScale(), and SetScreenScaleFactor(double) helpers using direct property access and asyncCallWithArgumentList.
  • Handle PropertiesChanged to emit ScreenScaleFactorChanged, AvailableScalesChanged, and RecommendedScaleChanged signals, including QDBusArgument array unpacking for AvailableScales.
  • Extend DisplayDBusProxy header with the new methods, signals, member pointer, slot declaration, and updated SPDX copyright years.
src/plugin-display/operation/private/displaydbusproxy.cpp
src/plugin-display/operation/private/displaydbusproxy.h
Wire ScreenScale data into the display model layer and remove local computation of maxGlobalScale based on monitor modes.
  • In DisplayWorker::active, initialize DisplayModel::UIScale from DisplayDBusProxy::screenScaleFactor instead of async GetScaleFactor, and trigger availableScales()/recommendedScale() reads.
  • Connect DisplayDBusProxy::ScreenScaleFactorChanged to DisplayModel::setUIScale and remove the onGetScaleFinished path and GetScaleFactor watcher.
  • Expose DisplayDBusProxy* via DisplayWorker::dbusProxy() for higher layers to query scaling info.
  • Remove DisplayModulePrivate::updateMaxGlobalScale, its state member, and related signal connections tied to Monitor changes.
src/plugin-display/operation/private/displayworker.cpp
src/plugin-display/operation/private/displayworker.h
src/plugin-display/operation/private/displaymodule_p.h
src/plugin-display/operation/displaymodule.cpp
Expose ScreenScale-based properties at the DisplayModule/QML layer and adapt the UI to use service-provided available scales.
  • Add Q_PROPERTYs for availableScales and recommendedScale on DisplayModule, their getters, and corresponding NOTIFY signals.
  • Implement DisplayModule::maxGlobalScale(), availableScales(), and recommendedScale() to delegate to DisplayWorker::dbusProxy()->availableScales()/recommendedScale(), and hook DBusProxy AvailableScalesChanged/RecommendedScaleChanged signals to the new NOTIFY signals.
  • Update DisplayMain.qml getScaleModel() to build the scale options list primarily from dccData.availableScales (as percentages), falling back to the old constant model if none are provided.
src/plugin-display/operation/displaymodule.h
src/plugin-display/operation/displaymodule.cpp
src/plugin-display/qml/DisplayMain.qml
Use ScreenScale service for setting global UI scale instead of the old SetScaleFactor path, while keeping X11 path unchanged for wlroots.
  • Modify DisplayWorker::setUiScale() so that in the non-wlroots branch it calls DisplayDBusProxy::SetScreenScaleFactor(rv) and immediately updates the model UIScale instead of calling SetScaleFactor and waiting synchronously for completion.
  • Retain existing behavior for wlroots-based compositors via the config file code path.
  • Adjust comments to reflect ScreenScale as the single source of truth propagating to XSettings.
src/plugin-display/operation/private/displayworker.cpp

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 3 issues, and left some high level feedback:

  • In DisplayWorker::setUiScale you switched from a synchronous SetScaleFactor call with error handling to a fire-and-forget SetScreenScaleFactor while unconditionally updating m_model->setUIScale(rv); consider at least checking the QDBusPendingReply for errors or deferring the model update until the DBus call succeeds to avoid UI state diverging from the compositor.
  • In DisplayWorker::active the calls to m_displayInter->availableScales() and recommendedScale() are unused and just perform synchronous DBus property accesses; either use their results (e.g. to initialize related model fields) or remove them to avoid unnecessary blocking calls during activation.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `DisplayWorker::setUiScale` you switched from a synchronous `SetScaleFactor` call with error handling to a fire-and-forget `SetScreenScaleFactor` while unconditionally updating `m_model->setUIScale(rv)`; consider at least checking the `QDBusPendingReply` for errors or deferring the model update until the DBus call succeeds to avoid UI state diverging from the compositor.
- In `DisplayWorker::active` the calls to `m_displayInter->availableScales()` and `recommendedScale()` are unused and just perform synchronous DBus property accesses; either use their results (e.g. to initialize related model fields) or remove them to avoid unnecessary blocking calls during activation.

## Individual Comments

### Comment 1
<location path="src/plugin-display/operation/private/displayworker.cpp" line_range="602" />
<code_context>
void DisplayWorker::setUiScale(const double value)
</code_context>
<issue_to_address>
**issue (bug_risk):** DBus call result is ignored when setting screen scale, which can desync UI state from actual compositor state.

Previously the non-Treeland path only updated `m_model->setUIScale(rv)` after `SetScaleFactor` completed successfully. The new code fire-and-forgets `SetScreenScaleFactor(rv)` and always updates the model, so any DBus failure (missing service, permission error, runtime failure) will leave the UI showing a scale that wasn’t applied. Please either wait on the DBus reply (e.g. via `QDBusPendingCallWatcher`) and update the model only on success, or at least detect errors and revert/refresh the value from `screenScaleFactor()` when the call fails.
</issue_to_address>

### Comment 2
<location path="src/plugin-display/operation/displaymodule.cpp" line_range="361-365" />
<code_context>
 qreal DisplayModule::maxGlobalScale() const
 {
     Q_D(const DisplayModule);
-    return d->m_maxGlobalScale;
+    auto scales = d->m_worker->dbusProxy()->availableScales();
+    return scales.isEmpty() ? 1.0 : scales.last();
+}
+
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Assuming `availableScales()` is sorted may be fragile for deriving `maxGlobalScale`.

This now relies on `availableScales()` returning an ascending list and uses `scales.last()` as the max, but that ordering isn’t guaranteed here. If the backend changes order or returns unsorted data, the max scale in the UI could be incorrect. Consider computing the maximum explicitly with `*std::max_element(scales.cbegin(), scales.cend())` instead of depending on list ordering.

Suggested implementation:

```cpp
qreal DisplayModule::maxGlobalScale() const
{
    Q_D(const DisplayModule);
    const auto scales = d->m_worker->dbusProxy()->availableScales();
    if (scales.isEmpty()) {
        return 1.0;
    }

    return *std::max_element(scales.cbegin(), scales.cend());
}

```

To compile, this file must include the `<algorithm>` header. If it is not already present at the top of `displaymodule.cpp`, add:
`#include <algorithm>`
alongside the other standard library includes.
</issue_to_address>

### Comment 3
<location path="src/plugin-display/operation/private/displayworker.cpp" line_range="85-95" />
<code_context>

-        QDBusPendingCallWatcher *scalewatcher = new QDBusPendingCallWatcher(m_displayInter->GetScaleFactor());
-        connect(scalewatcher, &QDBusPendingCallWatcher::finished, this, &DisplayWorker::onGetScaleFinished);
+        m_displayInter->availableScales();
+        m_displayInter->recommendedScale();

         QDBusPendingCallWatcher *screenscaleswatcher = new QDBusPendingCallWatcher(m_displayInter->GetScreenScaleFactors());
</code_context>
<issue_to_address>
**suggestion (performance):** Calls to `availableScales()` and `recommendedScale()` in `active()` have no observable effect.

These calls fetch values that are never used, so they only introduce extra synchronous DBus traffic during startup. Unless they are intentionally used to force some side-effect (in which case that purpose should be clearly documented), they should be removed or the returned values should be used to initialize or validate related model state (e.g., cache `recommendedScale` or check the current scale against `availableScales`).

```suggestion
        double scaleFactor = m_displayInter->screenScaleFactor();
        if (scaleFactor <= 0) {
            scaleFactor = 1.0;
        }
        m_model->setUIScale(scaleFactor);

        QDBusPendingCallWatcher *screenscaleswatcher = new QDBusPendingCallWatcher(m_displayInter->GetScreenScaleFactors());
        connect(screenscaleswatcher, &QDBusPendingCallWatcher::finished, this, &DisplayWorker::onGetScreenScalesFinished);
```
</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.

}
watcher->deleteLater();
// 通过 ScreenScale 设置缩放(作为唯一事实来源,会同步到 XSettings)
m_displayInter->SetScreenScaleFactor(rv);
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): DBus call result is ignored when setting screen scale, which can desync UI state from actual compositor state.

Previously the non-Treeland path only updated m_model->setUIScale(rv) after SetScaleFactor completed successfully. The new code fire-and-forgets SetScreenScaleFactor(rv) and always updates the model, so any DBus failure (missing service, permission error, runtime failure) will leave the UI showing a scale that wasn’t applied. Please either wait on the DBus reply (e.g. via QDBusPendingCallWatcher) and update the model only on success, or at least detect errors and revert/refresh the value from screenScaleFactor() when the call fails.

Comment on lines 361 to +365
qreal DisplayModule::maxGlobalScale() const
{
Q_D(const DisplayModule);
return d->m_maxGlobalScale;
auto scales = d->m_worker->dbusProxy()->availableScales();
return scales.isEmpty() ? 1.0 : scales.last();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

suggestion (bug_risk): Assuming availableScales() is sorted may be fragile for deriving maxGlobalScale.

This now relies on availableScales() returning an ascending list and uses scales.last() as the max, but that ordering isn’t guaranteed here. If the backend changes order or returns unsorted data, the max scale in the UI could be incorrect. Consider computing the maximum explicitly with *std::max_element(scales.cbegin(), scales.cend()) instead of depending on list ordering.

Suggested implementation:

qreal DisplayModule::maxGlobalScale() const
{
    Q_D(const DisplayModule);
    const auto scales = d->m_worker->dbusProxy()->availableScales();
    if (scales.isEmpty()) {
        return 1.0;
    }

    return *std::max_element(scales.cbegin(), scales.cend());
}

To compile, this file must include the <algorithm> header. If it is not already present at the top of displaymodule.cpp, add:
#include <algorithm>
alongside the other standard library includes.

Comment on lines +85 to 95
double scaleFactor = m_displayInter->screenScaleFactor();
if (scaleFactor <= 0) {
scaleFactor = 1.0;
}
m_model->setUIScale(scaleFactor);

QDBusPendingCallWatcher *scalewatcher = new QDBusPendingCallWatcher(m_displayInter->GetScaleFactor());
connect(scalewatcher, &QDBusPendingCallWatcher::finished, this, &DisplayWorker::onGetScaleFinished);
m_displayInter->availableScales();
m_displayInter->recommendedScale();

QDBusPendingCallWatcher *screenscaleswatcher = new QDBusPendingCallWatcher(m_displayInter->GetScreenScaleFactors());
connect(screenscaleswatcher, &QDBusPendingCallWatcher::finished, this, &DisplayWorker::onGetScreenScalesFinished);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

suggestion (performance): Calls to availableScales() and recommendedScale() in active() have no observable effect.

These calls fetch values that are never used, so they only introduce extra synchronous DBus traffic during startup. Unless they are intentionally used to force some side-effect (in which case that purpose should be clearly documented), they should be removed or the returned values should be used to initialize or validate related model state (e.g., cache recommendedScale or check the current scale against availableScales).

Suggested change
double scaleFactor = m_displayInter->screenScaleFactor();
if (scaleFactor <= 0) {
scaleFactor = 1.0;
}
m_model->setUIScale(scaleFactor);
QDBusPendingCallWatcher *scalewatcher = new QDBusPendingCallWatcher(m_displayInter->GetScaleFactor());
connect(scalewatcher, &QDBusPendingCallWatcher::finished, this, &DisplayWorker::onGetScaleFinished);
m_displayInter->availableScales();
m_displayInter->recommendedScale();
QDBusPendingCallWatcher *screenscaleswatcher = new QDBusPendingCallWatcher(m_displayInter->GetScreenScaleFactors());
connect(screenscaleswatcher, &QDBusPendingCallWatcher::finished, this, &DisplayWorker::onGetScreenScalesFinished);
double scaleFactor = m_displayInter->screenScaleFactor();
if (scaleFactor <= 0) {
scaleFactor = 1.0;
}
m_model->setUIScale(scaleFactor);
QDBusPendingCallWatcher *screenscaleswatcher = new QDBusPendingCallWatcher(m_displayInter->GetScreenScaleFactors());
connect(screenscaleswatcher, &QDBusPendingCallWatcher::finished, this, &DisplayWorker::onGetScreenScalesFinished);

@deepin-ci-robot
Copy link
Copy Markdown

deepin pr auto review

这份代码变更主要针对显示模块的缩放功能进行了重构,将原本在本地计算最大缩放比例的逻辑改为直接通过DBus从dde-services获取可用的缩放比例。以下是我的详细审查意见:

1. 语法逻辑

1.1 正确的部分

  • DBus接口连接和信号处理逻辑正确,使用了标准的PropertiesChanged信号监听方式
  • QML中的数据转换逻辑(将小数转换为百分比显示)符合预期
  • 依赖关系添加正确(dde-services(>> 1.0.22)

1.2 潜在问题

  1. displaymodule.cpp中的信号连接位置

    auto dbusProxy = m_worker->dbusProxy();
    q_ptr->connect(dbusProxy, &DisplayDBusProxy::AvailableScalesChanged, q_ptr, &DisplayModule::availableScalesChanged);
    q_ptr->connect(dbusProxy, &DisplayDBusProxy::AvailableScalesChanged, q_ptr, &DisplayModule::maxGlobalScaleChanged);

    AvailableScalesChanged信号连接到maxGlobalScaleChanged信号可能不太合适。虽然maxGlobalScale现在是从availableScales列表中获取的,但这两个信号语义不同。建议保留单独的信号处理或明确注释说明这种连接的意图。

  2. displaydbusproxy.cpp中的类型转换

    if (value.canConvert<QList<double>>()) {
        return qvariant_cast<QList<double>>(value);
    }

    这里假设DBus返回的类型可以直接转换为QList<double>,但DBus通常返回的是QDBusArgument。虽然代码中已经处理了这种情况,但顺序应该调整,先处理QDBusArgument情况更合理。

2. 代码质量

2.1 优点

  • 删除了冗余的updateMaxGlobalScale()函数,简化了代码
  • 代码结构更清晰,将缩放相关的逻辑集中到了DBus代理中
  • 使用了现代C++的lambda表达式,代码更简洁

2.2 改进建议

  1. 魔法数字

    if (scaleFactor <= 0) {
        scaleFactor = 1.0;
    }

    建议将1.0定义为常量,如const double DEFAULT_SCALE_FACTOR = 1.0;

  2. 错误处理
    DisplayDBusProxy::availableScales()中,当转换失败时返回空列表,但调用方(如maxGlobalScale())会使用默认值1.0。建议添加日志记录转换失败的情况,便于调试。

  3. 信号连接

    q_ptr->connect(dbusProxy, &DisplayDBusProxy::AvailableScalesChanged, q_ptr, &DisplayModule::availableScalesChanged);
    q_ptr->connect(dbusProxy, &DisplayDBusProxy::AvailableScalesChanged, q_ptr, &DisplayModule::maxGlobalScaleChanged);

    建议使用Qt5的连接风格,并确保在对象析构时断开连接,避免潜在的资源泄漏。

3. 代码性能

3.1 优点

  • 移除了每次更新监视器列表时都计算最大缩放比例的逻辑,减少了不必要的计算
  • 通过DBus直接获取可用的缩放比例,避免了本地重复计算

3.2 改进建议

  1. 缓存机制

    QList<double> DisplayDBusProxy::availableScales() const
    {
        QVariant value = m_dBusScreenScaleInter->property("AvailableScales");
        // ... 转换逻辑
    }

    这个方法每次调用都会通过DBus获取属性,建议添加缓存机制,只在属性变化时更新缓存。

  2. QML中的循环优化

    for (let scaleValue of availableScales) {
        let percent = Math.round(scaleValue * 100)
        scaleModel.push({...})
    }

    如果availableScales列表很大,可以考虑使用map函数替代循环,代码更简洁且性能可能更好。

4. 代码安全

4.1 潜在问题

  1. DBus接口依赖
    代码新增了对dde-services的依赖,但没有检查该服务是否可用。如果服务未运行或版本不匹配,可能导致功能异常。建议添加服务可用性检查。

  2. 类型转换安全性

    if (value.isValid() && value.canConvert<double>()) {
        return value.toDouble();
    }
    return 1.0;

    虽然有类型检查,但如果DBus返回的值超出预期范围(如负数或极大值),可能会导致UI显示异常。建议添加范围检查。

  3. 信号处理

    void DisplayDBusProxy::onScreenScalePropertiesChanged(const QString &interface, const QVariantMap &changedProperties, const QStringList &invalidatedProperties)
    {
        Q_UNUSED(invalidatedProperties)
        if (interface != ScreenScaleInterface) {
            return;
        }

    虽然检查了接口名称,但没有验证changedProperties中的值是否有效。建议添加值的有效性检查。

5. 其他建议

  1. 文档更新
    代码中新增了公共接口,建议更新相关文档,说明这些接口的用途和使用方法。

  2. 测试覆盖
    建议添加单元测试,特别是针对DBus接口的交互和类型转换逻辑。

  3. 版本兼容性
    代码中修改了SPDX许可证年份范围(2024-2026),请确认这是否符合项目策略。

  4. 日志记录
    建议在关键操作(如DBus调用失败、类型转换失败)处添加日志记录,便于问题排查。

总结

这次代码变更总体上改进了显示模块的缩放功能实现,简化了逻辑,提高了可维护性。主要需要关注的是DBus接口的健壮性和错误处理,以及确保服务依赖的可靠性。建议在合并前进行充分的测试,特别是针对dde-services不可用或返回异常数据的情况。

@deepin-ci-robot
Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: caixr23, fly602

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants