# 锁屏信号未触发问题修复指南 ## 问题描述 程序已成功连接到目标系统的 DBus 服务,但是系统锁屏时 `onSessionLocked()` 没有被调用。 此问题在 Ubuntu 和 Deepin 系统上都存在。 ## 问题原因 ### 1. Session 路径问题 原代码使用了固定路径 `/org/freedesktop/login1/session/auto`,但这个路径在大多数 Linux 系统上不起作用。需要使用实际的会话 ID 路径,例如: - `/org/freedesktop/login1/session/c1` - `/org/freedesktop/login1/session/2` ### 2. 信号监听范围太窄 原代码只监听特定路径的信号,如果实际信号从其他路径发出,就无法接收到。 ### 3. 缺少详细调试信息 无法判断到底是哪个环节出了问题:连接失败、信号未发出、还是信号发送者不匹配。 ## 修复方案 ### 主要改进 #### 1. 动态获取 Session 路径 新增 `getCurrentSessionPath()` 方法,通过以下方式获取正确的会话路径: ```cpp QString ScreenLockDetector::getCurrentSessionPath() { // 方法1: 从环境变量获取 QString xdgSessionId = qgetenv("XDG_SESSION_ID"); if (!xdgSessionId.isEmpty()) { return QString("/org/freedesktop/login1/session/%1").arg(xdgSessionId); } // 方法2: 通过 DBus 调用获取 QDBusInterface managerIface( "org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", QDBusConnection::systemBus() ); if (managerIface.isValid()) { QDBusReply reply = managerIface.call("GetSessionByPID", (quint32)QCoreApplication::applicationPid()); if (reply.isValid()) { return reply.value().path(); } } return QString(); } ``` #### 2. 双重信号连接策略 先尝试连接到特定会话路径,如果失败则连接到通用信号(空路径): ```cpp // 方法1: 连接到特定会话 QDBusConnection::systemBus().connect( "org.freedesktop.login1", sessionPath, // 具体路径 "org.freedesktop.login1.Session", "Lock", this, SLOT(onSessionLocked()) ); // 方法2: 连接到所有会话(备用方案) QDBusConnection::systemBus().connect( "org.freedesktop.login1", "", // 空路径 = 监听所有对象 "org.freedesktop.login1.Session", "Lock", this, SLOT(onSessionLocked()) ); ``` #### 3. 增强的调试信息 - 继承 `QDBusContext` 以获取信号发送者详细信息 - 在所有关键点添加详细日志输出 - 显示信号的 service、path、interface 和 member ```cpp void ScreenLockDetector::onSessionLocked() { qDebug() << "##################################################"; qDebug() << "## LOCK SIGNAL RECEIVED"; QDBusMessage msg = QDBusContext::message(); if (msg.type() != QDBusMessage::InvalidMessage) { qDebug() << "## DBus Message Details:"; qDebug() << "## Service:" << msg.service(); qDebug() << "## Path:" << msg.path(); qDebug() << "## Interface:" << msg.interface(); qDebug() << "## Member:" << msg.member(); } qDebug() << "##################################################"; setLockState(true); } ``` #### 4. 改进的状态查询 增强 `queryCurrentLockState()` 方法,正确读取 systemd-logind 的 `LockedHint` 属性: ```cpp QDBusMessage msg = QDBusMessage::createMethodCall( "org.freedesktop.login1", m_loginInterface->path(), "org.freedesktop.DBus.Properties", "Get" ); msg << "org.freedesktop.login1.Session" << "LockedHint"; QDBusReply reply = QDBusConnection::systemBus().call(msg); if (reply.isValid()) { bool locked = reply.value().toBool(); setLockState(locked); } ``` ## 使用修复后的代码 ### 1. 重新编译 ```bash ./build.sh ``` ### 2. 运行程序并观察日志 ```bash ./run.sh ``` 程序启动时会输出详细的连接信息: ``` ================================================= Initializing ScreenLockDetector... ================================================= --- Connecting to Deepin DDE --- Trying Deepin service: com.deepin.dde.lockFront ... --- Connecting to GNOME ScreenSaver --- GNOME ScreenSaver interface is valid GNOME ActiveChanged signal connected: true ... --- Connecting to Login Manager (systemd-logind) --- Session path from XDG_SESSION_ID: /org/freedesktop/login1/session/c1 Current session path: /org/freedesktop/login1/session/c1 Login Manager interface is valid for session: /org/freedesktop/login1/session/c1 Session Lock signal connected: true Session Unlock signal connected: true ... ``` ### 3. 测试锁屏 锁定屏幕后,应该能看到: ``` ################################################## ## LOCK SIGNAL RECEIVED ## Screen is now LOCKED ## DBus Message Details: ## Service: :1.43 ## Path: /org/freedesktop/login1/session/c1 ## Interface: org.freedesktop.login1.Session ## Member: Lock ################################################## ``` ## 调试工具 ### 工具 1: test_lock_signals.sh 这是一个全面的 DBus 信号监听脚本,用于诊断问题: ```bash ./test_lock_signals.sh ``` 功能: 1. 显示当前会话信息(XDG_SESSION_ID 等) 2. 检查可用的锁屏服务 3. 列出会话支持的所有信号 4. 实时监听 session bus 和 system bus 的锁屏信号 5. 保存日志供后续分析 使用方法: 1. 运行脚本 2. 按照提示锁定/解锁屏幕 3. 观察输出的信号 4. 按 Ctrl+C 停止 ### 工具 2: debug_deepin_dbus.sh 专门用于 Deepin 系统的调试脚本: ```bash ./debug_deepin_dbus.sh ``` ## 验证修复 ### 检查列表 - [ ] 程序启动时显示"ScreenLockDetector initialized successfully" - [ ] 至少有一个接口显示"connected: true" - [ ] 显示了正确的 session 路径(不是 "auto") - [ ] 锁屏时看到 "LOCK SIGNAL RECEIVED" 消息 - [ ] 解锁时看到 "UNLOCK SIGNAL RECEIVED" 消息 - [ ] 主窗口状态正确更新 ### 如果仍然无法接收信号 1. **运行 test_lock_signals.sh** ```bash ./test_lock_signals.sh ``` 观察系统实际发出了什么信号 2. **检查会话路径** ```bash echo $XDG_SESSION_ID loginctl show-session $XDG_SESSION_ID ``` 3. **手动测试 DBus 连接** ```bash # 监听 system bus 的 Lock 信号 dbus-monitor --system "type='signal',interface='org.freedesktop.login1.Session',member='Lock'" # 在另一个终端锁屏 loginctl lock-session ``` 4. **检查权限** 确保用户有权限访问 system bus: ```bash groups $USER ``` 用户应该在 `sudo` 或 `wheel` 组中 5. **对于 Deepin 系统** ```bash # 列出所有 Deepin 相关服务 dbus-send --session --print-reply --dest=org.freedesktop.DBus \ /org/freedesktop/DBus org.freedesktop.DBus.ListNames | grep deepin # 查看 lockFront 的接口 dbus-send --session --print-reply --dest=com.deepin.dde.lockFront \ /com/deepin/dde/lockFront org.freedesktop.DBus.Introspectable.Introspect ``` ## 不同系统的特殊情况 ### Ubuntu / GNOME - 主要通过 `org.gnome.ScreenSaver` 的 `ActiveChanged` 信号 - 或通过 systemd-logind 的 `Lock/Unlock` 信号 ### Deepin DDE - 服务名可能是 `com.deepin.dde.lockFront` 或 `org.deepin.dde.lockFront` - 信号名可能是 `Locked/Unlocked` 或 `Lock/Unlock` - 需要通过 session bus 连接 ### KDE Plasma - 使用 `org.freedesktop.ScreenSaver` - 也支持 systemd-logind ### XFCE - 主要依赖 systemd-logind - 或 `org.xfce.ScreenSaver` ## 常见问题 ### Q: 为什么连接显示成功但没有收到信号? A: 可能的原因: 1. 连接到了错误的会话路径 2. 桌面环境使用了不同的锁屏机制 3. 信号签名不匹配(参数类型不对) 解决方法:使用 `test_lock_signals.sh` 查看实际信号。 ### Q: 在虚拟机中测试是否会有问题? A: 可能会。某些虚拟机可能没有完整的 session 管理。建议: - 确保虚拟机安装了完整的桌面环境 - 使用 GUI 登录而不是 SSH - 检查 `loginctl list-sessions` 是否显示你的会话 ### Q: Deepin 系统上还是不工作怎么办? A: Deepin 不同版本的接口可能不同: 1. 运行 `debug_deepin_dbus.sh` 找到正确的服务名 2. 修改 `connectToDeepinDDE()` 中的服务列表 3. 添加找到的服务配置 4. 重新编译测试 ## 技术参考 ### DBus 接口文档 - systemd-logind Session: https://www.freedesktop.org/wiki/Software/systemd/logind/ - GNOME ScreenSaver: https://wiki.gnome.org/Projects/GnomeScreensaver ### Qt DBus 文档 - QDBusConnection: https://doc.qt.io/qt-5/qdbusconnection.html - QDBusContext: https://doc.qt.io/qt-5/qdbuscontext.html - QDBusInterface: https://doc.qt.io/qt-5/qdbusinterface.html ## 总结 修复的核心要点: 1. ✅ **动态获取会话路径** - 不要硬编码 "auto" 2. ✅ **多重连接策略** - 特定路径 + 通用监听 3. ✅ **详细调试日志** - 便于诊断问题 4. ✅ **正确读取属性** - 使用 Properties 接口 5. ✅ **支持多种桌面环境** - Deepin/GNOME/KDE 等 这些修复应该能解决大多数 Linux 系统上的锁屏信号接收问题。