Skip to content

fix: activate main window on D-Bus openImageFile - #417

Merged
deepin-bot[bot] merged 1 commit into
linuxdeepin:masterfrom
add-uos:fix-dbus-open-activate-window
Oct 27, 2026
Merged

deepin-bot[bot] merged 1 commit into
linuxdeepin:masterfrom
add-uos:fix-dbus-open-activate-window

Conversation

@add-uos

@add-uos add-uos commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

问题 / Problem

应用已运行时(D-Bus 服务 com.deepin.imageViewer 已注册),外部通过 D-Bus 调用 openImageFile 打开图片:图片正常加载,但已有窗口不会还原/置顶/聚焦,窗口仍埋在后台或保持最小化。

根因 / Root Cause

ApplicationAdaptor::openImageFile → Q_EMIT fileControl->openImageFile(urlPath) → MainStack.qml 的 Connections.onOpenImageFile 仅调用 requestSourcePath() 加载图片,链路上无任何 raise()/requestActivate() 逻辑。

修复 / Fix

  • FileControl 新增 activateMainWindow()(Q_INVOKABLE):遍历 QGuiApplication::topLevelWindows() 取可见主窗口(排除 Popup);
    • 最小化时仅清除 WindowMinimized 标志还原窗口(保留最大化/全屏形态),还原动作经 WM 异步完成,raise()+requestActivate() 推迟到下一轮事件循环执行,避免与 WM 取消最小化/焦点重分配竞态;
    • 非最小化则立即 raise() + requestActivate()。
    • Wayland 说明:X11 下完整置顶聚焦;Wayland 下合成器可能因缺少 xdg-activation 令牌拒绝焦点转移,此时窗口仍会置顶展示,令牌方案需调用方配合传递,已在代码注释中说明。
  • ApplicationAdaptor::openImageFile 成功分支在 Q_EMIT 前调用 fileControl->activateMainWindow();校验不通过分支不激活。
  • 首次启动路径不受影响(新进程由 main/CommandLineProxy 正常创建窗口)。

验证 / Verification

  • 单元测试(新增 5 例,全量 1150/1151 通过;IsCheckOnly_RepeatedLockAttempts_BothSucceed 失败为环境中正在运行的实例持有 single 锁文件所致,与本次改动无关):
    • ActivateMainWindow_NoVisibleWindow_NoActionTaken
    • ActivateMainWindow_VisibleWindow_RaisesAndRequestsActivate
    • ActivateMainWindow_MinimizedWindow_RestoresKeepingOtherStates
    • OpenImageFile_Success_ActivatesMainWindow
    • OpenImageFile_RejectedInput_DoesNotActivateMainWindow
  • 玲珑包环境实测(X11 会话,ll-builder build 构建产物替换层内二进制,测试后已恢复原文件):
    • 修复前:窗口最小化后 dbus-send openImageFile,_NET_WM_STATE 仍为 _NET_WM_STATE_HIDDEN、_NET_ACTIVE_WINDOW 为空 —— 不激活(问题复现)
    • 修复后:最小化 → dbus-send → 3/3 轮 _NET_WM_STATE_HIDDEN 清除且激活窗口 = 看图;窗口在后台 → dbus-send → 置顶并聚焦
    • dbus-send --session --print-reply --dest=com.deepin.imageViewer / com.deepin.imageViewer.openImageFile string:"file:///tmp/dbusfix-test.png"

Summary by Sourcery

Activate the existing main window when handling valid D-Bus image-open requests.

Bug Fixes:

  • Activate the existing main window when a valid image is opened through D-Bus, including restoring minimized windows and requesting focus.

Enhancements:

  • Preserve maximized or fullscreen window state while restoring minimized windows and avoid activating the window for rejected image requests.

Tests:

  • Add coverage for main-window activation, minimized-window restoration, successful D-Bus activation, and rejected-input behavior.

@sourcery-ai

sourcery-ai Bot commented Oct 27, 2026

Copy link
Copy Markdown

Sorry @add-uos, you've used your own review budget of 250,000 diff characters for the last 7 days.

You can request another review in 17 hours and 12 minutes by commenting @sourcery-ai review. Upgrade to get a review now.

@sourcery-ai

sourcery-ai Bot commented Oct 27, 2026

Copy link
Copy Markdown

Reviewer's Guide

Valid D-Bus image-open requests now restore, raise, and request focus for the existing main window, while preserving window state and avoiding activation for invalid requests; the implementation includes deferred minimized-window activation and focused unit/integration coverage.

Sequence diagram for D-Bus image opening and main window activation

sequenceDiagram
    participant Caller as D-Bus caller
    participant Adaptor as ApplicationAdaptor
    participant FileControl
    participant Window as Main window
    participant QML as MainStack

    Caller->>Adaptor: openImageFile(fileName)
    Adaptor->>FileControl: isCanReadable(urlPath)
    Adaptor->>FileControl: isImage(urlPath)
    alt valid image
        Adaptor->>FileControl: activateMainWindow()
        alt window minimized
            FileControl->>Window: setWindowStates(states without WindowMinimized)
            FileControl->>Window: QTimer::singleShot(0)
            QTimer->>Window: raise()
            QTimer->>Window: requestActivate()
        else window not minimized
            FileControl->>Window: raise()
            FileControl->>Window: requestActivate()
        end
        Adaptor-->>FileControl: openImageFile(urlPath)
        FileControl-->>QML: onOpenImageFile
        QML->>QML: requestSourcePath()
        Adaptor-->>Caller: true
    else invalid input
        Adaptor-->>Caller: false
    end
Loading

File-Level Changes

Change Details Files
Activate the existing main window before handling a valid D-Bus image-open request.
  • Call window activation only after readability and image validation succeeds and before emitting the image-open signal.
  • Leave rejected requests and first-launch behavior unchanged.
src/src/dbus/applicationadpator.cpp
Implement platform-aware main-window restoration and activation.
  • Find the first visible non-Popup top-level window.
  • For minimized windows, clear only the minimized state and defer raise/focus until the next event-loop turn.
  • For other windows, immediately raise and request activation, with Wayland focus limitations documented.
  • Expose the behavior as a Q_INVOKABLE FileControl method.
src/src/filecontrol.cpp
src/src/filecontrol.h
Add coverage for activation behavior and D-Bus integration.
  • Test no-window, visible-window, and minimized-window paths, including preservation of maximized state and deferred activation.
  • Verify successful open requests activate the window and rejected input does not.
  • Update the FileControl test method inventory and add required Qt window/test headers.
tests/src/test_filecontrol.cpp
tests/src/test_applicationadpator.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

When the viewer is already running, the D-Bus openImageFile call only
loaded the image without raising or focusing the existing window. Now
the running instance activates the main window (restores it from
minimized, raises, requests focus) before loading the image, so the
window pops up on top and focused.

已运行实例通过 D-Bus openImageFile 打开图片时仅加载图片,不会还原、
置顶或聚焦已有窗口。现在先激活主窗口(最小化则还原,再置顶并请求
焦点)再加载图片,保证窗口置顶弹出。

Log: D-Bus 调用 openImageFile 打开图片时激活主窗口
@add-uos
add-uos force-pushed the fix-dbus-open-activate-window branch from 5df491c to 1de409d Compare October 27, 2026 13:06
@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

🤖 AI 代码审查报告

总体评分: 98 分 (通过阈值: 70分)

Pass


📊 总体评价

项目 结果
审查结论 代码审查通过
评分详情 本次提交在 D-Bus openImageFile 路径中新增主窗口激活逻辑,生产代码语法正确、逻辑清晰、注释详尽、性能良好、无安全漏洞。测试代码存在一个悬空指针风险(ActivationCounter 栈变量被桩 lambda 捕获,TearDown 中 stub.clear() 在对象删除之后执行),建议调整 TearDown 顺序或在使用后及时清理桩;此外集成测试缺少最小化窗口路径覆盖。整体代码质量良好。

🔍 详细分析

1. 语法逻辑 ✅

评价: 语法正确,逻辑清晰 ✅ 通过

潜在问题:
✅ 未发现明显问题

建议: []


2. 代码质量 ✅

评价: 代码结构清晰,注释完整 ✅ 通过

潜在问题:
✅ 未发现明显问题

建议: ['在 TearDown() 开头调用 stub.clear(),确保在 delete m_adaptor / m_fileControl 之前清除所有桩,避免悬空指针', '在集成测试中增加最小化窗口变体:win.setWindowStates(Qt::WindowMinimized) 后调用 openImageFile,再 processEvents() 验证延迟激活路径']


3. 代码性能 ✅

评价: 性能良好,资源使用合理 ✅ 通过

潜在问题:
✅ 未发现明显问题

建议: []


4. 代码安全 🔒

评价: 存在0个安全漏洞 ✅ 通过

🔐 发现 0 个安全漏洞

安全漏洞详情:
✅ 未发现安全漏洞

建议: []


💡 改进建议代码示例

// tests/src/test_applicationadpator.cpp — 修复悬空指针风险
// 方案:在 TearDown() 开头先清除桩,再删除对象

void TearDown() override {
    stub.clear();  // 先清除桩,避免删除对象时桩 lambda 解引用已销毁的栈变量
    if (m_adaptor) {
        delete m_adaptor;
        m_adaptor = nullptr;
    }
    delete m_fileControl;
    m_fileControl = nullptr;
}

本报告由 AI 代码审查工具自动生成

@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: add-uos, lzwind

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

@add-uos

add-uos commented Oct 27, 2026

Copy link
Copy Markdown
Contributor Author

/forcemerge

@deepin-bot
deepin-bot Bot merged commit e58f991 into linuxdeepin:master Oct 27, 2026
17 checks passed
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