Skip to content

fix: skip in-use font when disabling via D-Bus StandardFont query#197

Open
JWWTSL wants to merge 1 commit into
linuxdeepin:masterfrom
JWWTSL:bug-347233
Open

fix: skip in-use font when disabling via D-Bus StandardFont query#197
JWWTSL wants to merge 1 commit into
linuxdeepin:masterfrom
JWWTSL:bug-347233

Conversation

@JWWTSL
Copy link
Copy Markdown
Contributor

@JWWTSL JWWTSL commented May 14, 2026

log: Query org.deepin.dde.Appearance1 StandardFont property via D-Bus to detect the system font set through dde-control-center. Skip currently in-use user fonts during multi-select disable and show the font name in the warning message.

pms: bug-347233

Summary by Sourcery

Prevent disabling fonts that are currently in use and align user warnings with the detected active system font.

Bug Fixes:

  • Skip disabling fonts that are currently in use by the application or configured as the system standard font when performing multi-select disable operations.
  • Ensure warning messages correctly name the in-use font, falling back to the system standard font reported by DDE when needed.
  • Always show an appropriate warning message when attempted operations involve in-use or system fonts, even if no fonts were actually disabled.

Enhancements:

  • Query the DDE appearance service over D-Bus to detect the current system standard font for use in font selection and protection logic.
  • Extend font selection logic to treat the application font family and DDE standard font family as protected from disable operations.

@deepin-ci-robot
Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: JWWTSL

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

sourcery-ai Bot commented May 14, 2026

Reviewer's Guide

Adds D-Bus querying of the DDE Appearance1 StandardFont to detect the system font set via dde-control-center, and updates the disable-logic so currently in-use fonts (application font or DDE standard font) are skipped during batch disable while improving the warning messaging logic.

Sequence diagram for batch font disable with D-Bus StandardFont check

sequenceDiagram
    actor User
    participant DFontPreviewListView
    participant DDE_Appearance1
    participant DMessageManager

    User ->> DFontPreviewListView: onEnableBtnClicked(itemIndexes, setValue)
    DFontPreviewListView ->> DDE_Appearance1: QDBusInterface.call(Get, StandardFont)
    DDE_Appearance1 -->> DFontPreviewListView: QDBusReply(StandardFont)
    loop for each font in itemIndexes
        alt setValue is false
            DFontPreviewListView ->> DFontPreviewListView: check in-use
            alt [font is in use (app font or StandardFont)]
                DFontPreviewListView ->> DFontPreviewListView: increment skippedInUse
            else [font not in use]
                alt [font is system font]
                    DFontPreviewListView ->> DFontPreviewListView: set needShowTips
                else [normal font]
                    DFontPreviewListView ->> DFontPreviewListView: disableFont(filePath)
                end
            end
        else setValue is true
            DFontPreviewListView ->> DFontPreviewListView: enableFont(filePath)
        end
    end
    alt needShowTips or count > 0
        DFontPreviewListView ->> DMessageManager: sendMessage(parentWidget, icon, message)
    end
Loading

File-Level Changes

Change Details Files
Detect the current system font via D-Bus and treat it as in-use when selecting and disabling fonts.
  • Include QDBusInterface, QDBusReply, and QDBusConnection to support D-Bus calls.
  • Query org.deepin.dde.Appearance1 StandardFont via org.freedesktop.DBus.Properties.Get in onEnableBtnClicked and selectedFonts, storing the result in a local ddeStandardFont variable.
  • Extend the selectedFonts in-use detection condition to also match the current application font family and the DDE StandardFont, including checking family-style lists from DFontInfoManager.
deepin-font-manager/interfaces/dfontpreviewlistview.cpp
Skip in-use fonts during batch disable and refine the messaging behavior to reflect skipped fonts and system fonts.
  • Introduce skippedInUse counter and increment it whenever a font is detected as in use and therefore skipped during disable iteration.
  • Refine the disable condition to skip in-use fonts based on current font data, file path, app font family, and DDE StandardFont, using DFontInfoManager::getFontFamilyStyle.
  • Account for already-detected in-use fonts (curCnt) by mapping them into skippedInUse when needed so the tips are still shown.
  • Adjust message-selection logic to favor skippedInUse over curCnt, and to show the actual in-use font name (falling back to the DDE StandardFont when current font name is empty).
  • Allow the message to be shown even when no fonts were disabled by changing the send condition from count > 0 to `count > 0

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

  • The D-Bus query for StandardFont is duplicated in both onEnableBtnClicked and selectedFonts; consider extracting it into a small helper (or caching the result) to avoid repetition and keep the logic in sync.
  • The synchronous D-Bus call on the session bus is done directly in UI-related code; if this call can be slow or fail, consider adding basic error/timeout handling or moving it off the hot path to avoid potential UI stalls.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The D-Bus query for `StandardFont` is duplicated in both `onEnableBtnClicked` and `selectedFonts`; consider extracting it into a small helper (or caching the result) to avoid repetition and keep the logic in sync.
- The synchronous D-Bus call on the session bus is done directly in UI-related code; if this call can be slow or fail, consider adding basic error/timeout handling or moving it off the hot path to avoid potential UI stalls.

## Individual Comments

### Comment 1
<location path="deepin-font-manager/interfaces/dfontpreviewlistview.cpp" line_range="1966-1975" />
<code_context>
     QMutexLocker locker(&m_mutex);
     QString fontName;

+    // 通过 D-Bus 查询 DDE 外观服务设置的当前系统字体
+    QString ddeStandardFont;
+    {
+        QDBusInterface iface(QStringLiteral("org.deepin.dde.Appearance1"),
+                             QStringLiteral("/org/deepin/dde/Appearance1"),
+                             QStringLiteral("org.freedesktop.DBus.Properties"),
+                             QDBusConnection::sessionBus());
+        QDBusReply<QVariant> reply = iface.call(QStringLiteral("Get"),
+                                                QStringLiteral("org.deepin.dde.Appearance1"),
+                                                QStringLiteral("StandardFont"));
+        if (reply.isValid())
+            ddeStandardFont = reply.value().toString();
+    }
</code_context>
<issue_to_address>
**issue (performance):** Avoid performing the synchronous D-Bus call while holding m_mutex to prevent UI stalls and lock contention.

In `onEnableBtnClicked`, the D-Bus call runs while `m_mutex` is held via `QMutexLocker`, so a slow or blocked IPC call will stall any code needing this mutex and hurt UI responsiveness. Please move the D-Bus query outside the locked section, or shrink the critical section so only the truly shared state access is protected by `m_mutex`.
</issue_to_address>

### Comment 2
<location path="deepin-font-manager/interfaces/dfontpreviewlistview.cpp" line_range="2659-2667" />
<code_context>
+                   (itemData.fontInfo.familyName == qApp->font().family()) ||
+                   (DFontInfoManager::instance()->getFontFamilyStyle(itemData.fontInfo.filePath)
+                        .contains(qApp->font().family())) ||
+                   (!ddeStandardFont.isEmpty() &&
+                    (itemData.fontInfo.familyName == ddeStandardFont ||
+                     DFontInfoManager::instance()->getFontFamilyStyle(itemData.fontInfo.filePath)
+                         .contains(ddeStandardFont)))) {
             // qDebug() << "Calculate current font";
</code_context>
<issue_to_address>
**suggestion (performance):** Cache the result of getFontFamilyStyle in selectedFonts to avoid redundant work.

`DFontInfoManager::instance()->getFontFamilyStyle(itemData.fontInfo.filePath)` is evaluated twice in this condition and may be relatively expensive. Please store the result in a local `QStringList` (as in `onEnableBtnClicked`) and reuse it for both the app font and `ddeStandardFont` checks.

```suggestion
        } else {
            const QStringList selectedFonts = DFontInfoManager::instance()->getFontFamilyStyle(itemData.fontInfo.filePath);

            if ((itemData.fontData == m_curFontData) ||
                (itemData.fontInfo.filePath == m_dataThread->getFontData(m_curFontData).fontInfo.filePath) ||
                (itemData.fontInfo.familyName == qApp->font().family()) ||
                selectedFonts.contains(qApp->font().family()) ||
                (!ddeStandardFont.isEmpty() &&
                 (itemData.fontInfo.familyName == ddeStandardFont ||
                  selectedFonts.contains(ddeStandardFont)))) {
```
</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 deepin-font-manager/interfaces/dfontpreviewlistview.cpp Outdated
Comment thread deepin-font-manager/interfaces/dfontpreviewlistview.cpp Outdated
@JWWTSL JWWTSL force-pushed the bug-347233 branch 3 times, most recently from 12448c1 to eebd341 Compare May 14, 2026 13:05
// 通过 D-Bus 查询 DDE 外观服务设置的当前系统字体
QString ddeStandardFont;
{
QDBusInterface iface(QStringLiteral("org.deepin.dde.Appearance1"),
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

v20 没得此dbus接口。可以对比v20看下功能是否异常

log: Query org.deepin.dde.Appearance1 StandardFont property via D-Bus to
detect the system font set through dde-control-center. Skip currently
in-use user fonts during multi-select disable and show the font name
in the warning message.

pms: bug-347233
@deepin-ci-robot
Copy link
Copy Markdown

deepin pr auto review

你好!我是CodeGeeX,很高兴为你审查这段代码。

这段代码的主要目的是在禁用字体时,增加对“正在使用中的字体”的保护逻辑,防止用户禁用当前系统界面正在使用的字体(如应用字体、DDE外观标准字体等),并优化了相关的提示信息。同时,修改了底层的 FontConfig 查询逻辑,使其按文件路径精确匹配。

整体来看,代码的业务逻辑是清晰的,但在代码性能、语法健壮性、代码安全和可维护性方面,我有以下改进建议:

1. 代码性能

问题:D-Bus 同步调用阻塞主线程
onEnableBtnClickedselectedFonts 两个方法中,都使用了 iface.call("Get", ...) 进行同步的 D-Bus 调用。虽然你在注释中提到“放在锁外,避免同步 IPC 阻塞其他线程”,但如果这两个函数是在 UI 线程(主线程)中执行的,同步 IPC 依然会阻塞 UI 线程,导致界面卡顿。而且,完全相同的 D-Bus 查询代码出现了两次,违反了 DRY(Don't Repeat Yourself)原则。

改进意见:

  • 将获取 DDE 系统字体的逻辑提取为一个独立的函数。
  • 考虑使用 QDBusInterface::asyncCall 异步获取,或者在应用启动时/焦点切入时获取一次并缓存该值,避免在循环或频繁触发的点击事件中进行同步 IPC 调用。

2. 语法逻辑

问题一:getFontFamilyStyle 中 FontConfig 查询条件不严谨
dfontinfomanager.cpp 中,你添加了 FcPatternAddString(pat, FC_FILE, ...)。这在逻辑上是为了按路径精确查询,但 FcFontList 的匹配默认是模式匹配(Pattern Matching),而非精确相等。如果传入的 filePah 包含 FontConfig 识别为通配符的字符,可能会返回意外结果;更常见的是,它可能会匹配到同目录下的其他字体或产生模糊匹配。

改进意见:

  • 在执行 FcFontList 前,为 FC_FILE 字段添加强绑定,确保是精确匹配。

问题二:大括号嵌套错位(潜在 Bug)
selectedFonts 函数的 diff 末尾:

+        } else {
+            const QStringList fontFamilies = ...
+            if (...) {
             // 旧代码:qDebug() << "Calculate current font";
             // 旧代码:选中字体与当前使用的字体为同一字体文件
@@ -2632,6 +2704,7 @@ void DFontPreviewListView::selectedFonts(const DFontPreviewItemData &curData,
                 *allIndexList << index;
             }
         }
+        }
     }

这里你将原本的 else if 改成了 else { ... if ... },但在闭合时多了一个 }。如果缩进或逻辑没有对齐,极容易导致外层 for 循环提前闭合,或者引发编译/运行时错误。请务必检查此处的括号匹配是否真正符合你的逻辑意图。

问题三:curCnt 逻辑重复计算
onEnableBtnClicked 中,循环内如果 isInUse == trueskippedInUse 会自增并 continue。但在循环外部,又写了:

    if (curCnt > 0) {
        if (skippedInUse == 0) {
            skippedInUse = curCnt;
        }
        needShowTips = true;
    }

curCnt 是在 selectedFonts 中统计的“当前选中字体中包含正在使用字体的数量”。如果 selectedFonts 已经正确识别并把它们放进了 curCnt,而在 onEnableBtnClicked 的循环里又通过新的 isInUse 逻辑拦截了一次,这两者的判断条件并不完全一致(selectedFonts 里也加了类似的判断,但没包含 appFontFamilyfontFamilies.contains 检查)。这会导致提示逻辑混乱。

改进意见:

  • 统一“正在使用”的判断标准。建议将判断逻辑封装为一个函数,如 bool isFontInUse(const ItemData &data, const QString &appFont, const QString &sysFont),在 selectedFontsonEnableBtnClicked 中统一调用,避免两边判断条件不一致导致计数错乱。

3. 代码安全

问题一:C 风格字符串转换缺乏长度保护

FcPatternAddString(pat, FC_FILE, reinterpret_cast<const FcChar8 *>(filePah.toUtf8().data()));

toUtf8().data() 返回的是 const char*,虽然 FontConfig 期望接收 const FcChar8*,但在 C++ 中,toUtf8() 返回的 QByteArray 是一个临时对象。如果编译器没有延长临时对象的生命周期,data() 指针将变成悬空指针,导致内存越界或崩溃。

改进意见:

  • QByteArray 保存在局部变量中,确保其生命周期覆盖 FcFontList 的调用。

问题二:拼写错误
变量名 filePah 应为 filePath。虽然这是旧代码遗留问题,但既然修改了该行,建议顺手修正,提高代码可读性。

4. 综合改进后的代码示例

针对以上问题,我为你提供了修改后的核心代码片段:

1. 提取并优化 D-Bus 调用 (dfontpreviewlistview.cpp)

// 提取为私有成员函数,并考虑未来改为异步+缓存机制
QString DFontPreviewListView::getDDEStandardFont() const
{
    QDBusInterface iface(QStringLiteral("org.deepin.dde.Appearance1"),
                         QStringLiteral("/org/deepin/dde/Appearance1"),
                         QStringLiteral("org.freedesktop.DBus.Properties"),
                         QDBusConnection::sessionBus());
    // 建议后续优化为 asyncCall
    QDBusReply<QVariant> reply = iface.call(QStringLiteral("Get"),
                                            QStringLiteral("org.deepin.dde.Appearance1"),
                                            QStringLiteral("StandardFont"));
    if (reply.isValid()) {
        return reply.value().toString();
    }
    return QString();
}

2. 修复 FontConfig 安全与精确匹配问题 (dfontinfomanager.cpp)

QStringList DFontInfoManager::getFontFamilyStyle(const QString &filePath)
{
    const FcChar8 *format = reinterpret_cast<const FcChar8 *>("%{=fclist}");
    FcObjectSet *os = FcObjectSetBuild(FC_FAMILY, FC_STYLE, FC_FILE, nullptr);
    FcPattern *pat = FcPatternCreate();
    
    // 修复:保存 QByteArray 避免悬空指针,修正拼写 filePath
    const QByteArray utf8Path = filePath.toUtf8();
    FcPatternAddString(pat, FC_FILE, reinterpret_cast<const FcChar8 *>(utf8Path.constData()));
    
    // 增加:确保 FC_FILE 是精确匹配,而不是模糊匹配
    FcPatternAddBool(pat, FC_FILE, FcTrue); 

    FcFontSet *fs = FcFontList(nullptr, pat, os);
    // ... 后续逻辑
}

3. 统一判断逻辑并修复括号嵌套 (dfontpreviewlistview.cpp)

// 在 DFontPreviewListView 中添加统一的判断方法
bool DFontPreviewListView::isFontInUse(const FontData &fontData, const QString &appFontFamily, const QString &ddeStandardFont) const
{
    QStringList fontFamilies = DFontInfoManager::instance()->getFontFamilyStyle(fontData.fontInfo.filePath);
    bool isInUse = (fontData == m_curFontData) ||
                   (fontData.fontInfo.filePath == m_dataThread->getFontData(m_curFontData).fontInfo.filePath) ||
                   (fontData.fontInfo.familyName == appFontFamily) ||
                   fontFamilies.contains(appFontFamily) ||
                   (!ddeStandardFont.isEmpty() && fontData.fontInfo.familyName == ddeStandardFont) ||
                   (!ddeStandardFont.isEmpty() && fontFamilies.contains(ddeStandardFont));
    return isInUse;
}

// 在 selectedFonts 和 onEnableBtnClicked 中调用:
// 例如 selectedFonts 中:
QString ddeStandardFont = getDDEStandardFont();
QString appFontFamily = qApp->font().family();
// ...
} else {
    if (isFontInUse(itemData, appFontFamily, ddeStandardFont)) {
        // 处理正在使用的逻辑
    }
} // 确保这里的括号与外层 for 循环正确对齐

希望这些审查意见对你有所帮助!如果有任何疑问,欢迎随时提问。

@heyumoAi
Copy link
Copy Markdown

heyumoAi commented May 17, 2026 via email

@deepin-bot
Copy link
Copy Markdown
Contributor

deepin-bot Bot commented May 19, 2026

TAG Bot

New tag: 6.5.38
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #199

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.

4 participants