Improve DBus screen lock detection and debugging

This commit is contained in:
ubuntu1804 2025-11-07 15:47:48 +08:00
parent 778a697336
commit fa4514d4eb
6 changed files with 1295 additions and 63 deletions

331
LOCK_SIGNAL_FIX.md Normal file
View File

@ -0,0 +1,331 @@
# 锁屏信号未触发问题修复指南
## 问题描述
程序已成功连接到目标系统的 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<QDBusObjectPath> 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<QVariant> 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 系统上的锁屏信号接收问题。

355
QUICKFIX_LOCK_SIGNALS.md Normal file
View File

@ -0,0 +1,355 @@
# 锁屏信号问题快速修复指南
## 问题症状
✗ 程序显示"已成功连接到目标系统的服务"
✗ 但锁屏时 `onSessionLocked()` 没有被调用
✗ Ubuntu 和 Deepin 系统都有此问题
## 快速解决方案
### 🚀 一键验证修复
已经重新编译,直接运行验证脚本:
```bash
./verify_fix.sh
```
这个脚本会:
1. 检查编译状态
2. 显示系统环境信息
3. 检测可用的 DBus 服务
4. 启动程序并提示如何测试
### 📋 核心修复内容
#### 修复 1: 动态获取会话路径
**问题**: 原代码使用固定路径 `/org/freedesktop/login1/session/auto`,在大多数系统上不工作
**修复**: 新增方法动态获取实际会话路径
```cpp
QString getCurrentSessionPath() {
// 从环境变量 XDG_SESSION_ID 获取
// 或通过 DBus 调用 GetSessionByPID 获取
}
```
#### 修复 2: 广播式信号监听
**问题**: 只监听特定路径的信号
**修复**: 添加空路径监听(监听所有会话)
```cpp
// 监听所有 session 的 Lock/Unlock 信号
QDBusConnection::systemBus().connect(
"org.freedesktop.login1",
"", // 空路径 = 监听所有对象
"org.freedesktop.login1.Session",
"Lock",
this,
SLOT(onSessionLocked())
);
```
#### 修复 3: 增强调试信息
**问题**: 无法判断问题出在哪个环节
**修复**:
- 继承 `QDBusContext` 获取信号详情
- 在关键点添加详细日志
- 显示信号的来源路径和接口
## 验证修复是否生效
### 预期的启动日志
```
=================================================
Initializing ScreenLockDetector...
=================================================
--- 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: ...
Session Lock signal connected: true ← ✓ 应该是 true
Session Unlock signal connected: true ← ✓ 应该是 true
=================================================
ScreenLockDetector initialized successfully
Login Manager connected: true ← ✓ 至少一个为 true
=================================================
```
### 预期的锁屏日志
当你按 `Super+L``Ctrl+Alt+L` 锁屏后:
```
##################################################
## 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: 检查实际发送的信号
运行监听脚本:
```bash
./test_lock_signals.sh
```
按提示锁屏/解锁,观察哪些信号被发出。
#### 步骤 2: 手动测试 DBus
在一个终端运行:
```bash
dbus-monitor --system "type='signal',interface='org.freedesktop.login1.Session'"
```
在另一个终端锁屏:
```bash
# GNOME/Ubuntu
gnome-screensaver-command -l
# 或通用方法
loginctl lock-session
# Deepin
dde-lock
```
观察是否有 `Lock` 信号出现。
#### 步骤 3: 检查会话状态
```bash
# 查看会话 ID
echo $XDG_SESSION_ID
# 查看会话详情
loginctl show-session $XDG_SESSION_ID
# 列出所有会话
loginctl list-sessions
```
确保你的会话是活动的,类型是 `x11``wayland`
#### 步骤 4: 检查权限
```bash
# 当前用户的组
groups
# 测试是否能访问 systemd-logind
dbus-send --system --print-reply \
--dest=org.freedesktop.login1 \
/org/freedesktop/login1 \
org.freedesktop.DBus.Introspectable.Introspect
```
### 🔧 特定系统的额外步骤
#### Ubuntu / GNOME 系统
如果 systemd-logind 不工作,检查 GNOME ScreenSaver
```bash
# 检查服务是否存在
dbus-send --session --print-reply \
--dest=org.gnome.ScreenSaver \
/org/gnome/ScreenSaver \
org.freedesktop.DBus.Introspectable.Introspect
# 监听 GNOME 信号
dbus-monitor --session "interface='org.gnome.ScreenSaver'"
# 锁屏
gnome-screensaver-command -l
```
#### Deepin 系统
运行 Deepin 专用调试脚本:
```bash
./debug_deepin_dbus.sh
```
这会显示所有可用的 Deepin 锁屏服务,然后实时监听信号。
常见的 Deepin 服务名:
- `com.deepin.dde.lockFront`
- `org.deepin.dde.lockFront`
- `com.deepin.ScreenSaver`
#### Wayland 会话
Wayland 可能有不同的行为:
```bash
# 检查会话类型
echo $XDG_SESSION_TYPE
# 如果是 wayland可能需要使用不同的方法
# 某些 Wayland 合成器使用自己的锁屏协议
```
## 常见问题解答
### Q: 为什么连接显示成功但收不到信号?
**A**: 可能原因:
1. **路径不对**: 连接到了错误的会话路径
2. **时机问题**: 信号在连接之前就发送了
3. **权限问题**: 没有权限监听 system bus 信号
4. **桌面环境**: 使用了非标准的锁屏机制
**解决**: 使用 `test_lock_signals.sh` 查看实际信号
### Q: 在虚拟机中测试有问题吗?
**A**: 可能会有。确保:
- ✓ 使用完整的桌面环境(不是最小化安装)
- ✓ 通过图形界面登录(不是 SSH
- ✓ 虚拟机有足够的资源
- ✓ 安装了 Guest Additions / Tools
### Q: 日志显示 "connected: true" 但还是没反应?
**A**: 这说明连接成功了,但信号可能:
1. 使用了不同的信号名(如 `Locked` vs `Lock`
2. 从不同的路径发出
3. 带有额外的参数
运行 `dbus-monitor` 直接查看:
```bash
# 监听所有 session bus 信号
dbus-monitor --session "type='signal'" | grep -i lock
# 监听所有 system bus 信号
dbus-monitor --system "type='signal'" | grep -i lock
```
### Q: Deepin 系统上完全不工作?
**A**: Deepin 不同版本的接口差异很大:
1. 找到正确的服务名:
```bash
dbus-send --session --print-reply \
--dest=org.freedesktop.DBus \
/org/freedesktop/DBus \
org.freedesktop.DBus.ListNames | grep -i deepin
```
2. 查看服务接口:
```bash
dbus-send --session --print-reply \
--dest=com.deepin.dde.lockFront \
/com/deepin/dde/lockFront \
org.freedesktop.DBus.Introspectable.Introspect
```
3. 修改 `screenlockdetector.cpp``connectToDeepinDDE()` 的服务列表
## 技术细节
### 为什么需要空路径监听?
DBus 信号连接时指定路径会限制只接收该对象的信号。使用空路径 `""` 表示监听该接口的所有对象的信号。
```cpp
// 只监听特定会话
connect("service", "/path/to/session1", "interface", "signal", ...)
// 监听所有会话(推荐)
connect("service", "", "interface", "signal", ...)
```
### QDBusContext 的作用
继承 `QDBusContext` 后,在 slot 函数中可以调用 `message()` 获取触发信号的详细信息:
```cpp
QDBusMessage msg = QDBusContext::message();
qDebug() << "Signal from:" << msg.service() << msg.path();
```
这对调试非常有用。
### systemd-logind Session 接口
标准接口应该有这些信号:
- `Lock` - 会话锁定
- `Unlock` - 会话解锁
- `PauseDevice` - 设备暂停
- `ResumeDevice` - 设备恢复
和这些属性:
- `LockedHint` - 布尔值,指示会话是否锁定
- `Active` - 会话是否活动
- `Type` - 会话类型x11, wayland, tty 等)
## 获取帮助
如果以上方法都不行,请提供以下信息:
1. **系统信息**:
```bash
cat /etc/os-release
echo "Desktop: $XDG_CURRENT_DESKTOP"
echo "Session: $XDG_SESSION_TYPE"
```
2. **会话信息**:
```bash
loginctl show-session $XDG_SESSION_ID
```
3. **程序输出**: 运行 `./run.sh` 的完整输出
4. **信号监听结果**: 运行 `./test_lock_signals.sh` 的输出
5. **手动测试结果**:
```bash
dbus-monitor --system "type='signal'" | grep -i lock
# 然后锁屏,记录输出
```
## 相关文档
- 📖 详细修复说明: `LOCK_SIGNAL_FIX.md`
- 🔧 Deepin 支持: `DEEPIN_SUPPORT.md`
- 🏗️ 架构文档: `ARCHITECTURE.md`
- 📝 项目概览: `PROJECT_OVERVIEW.md`
## 总结
核心修复点:
1. ✅ 动态获取会话路径(不硬编码 "auto"
2. ✅ 空路径监听(接收所有会话信号)
3. ✅ 详细调试日志(便于诊断)
4. ✅ 多重连接策略(提高兼容性)
大多数情况下,这些修复应该能解决问题。如果还有问题,使用提供的调试工具找出系统实际使用的信号机制。

View File

@ -2,6 +2,7 @@
#include <QDBusMessage>
#include <QDBusConnection>
#include <QDBusConnectionInterface>
#include <QDBusReply>
ScreenLockDetector::ScreenLockDetector(QObject *parent)
: QObject(parent)
@ -40,7 +41,9 @@ bool ScreenLockDetector::isScreenLocked() const
bool ScreenLockDetector::initialize()
{
qDebug() << "=================================================";
qDebug() << "Initializing ScreenLockDetector...";
qDebug() << "=================================================";
// 尝试连接到不同的DBus接口
bool deepinOk = connectToDeepinDDE();
@ -56,10 +59,12 @@ bool ScreenLockDetector::initialize()
// 查询当前锁屏状态
queryCurrentLockState();
qDebug() << "=================================================";
qDebug() << "ScreenLockDetector initialized successfully";
qDebug() << "Deepin DDE connected:" << m_deepinConnected;
qDebug() << "GNOME ScreenSaver connected:" << m_gnomeConnected;
qDebug() << "Login Manager connected:" << m_loginConnected;
qDebug() << "=================================================";
return true;
}
@ -69,7 +74,9 @@ void ScreenLockDetector::setLockState(bool locked)
if (m_isLocked != locked) {
m_isLocked = locked;
qDebug() << "Screen lock state changed:" << (locked ? "LOCKED" : "UNLOCKED");
qDebug() << "##################################################";
qDebug() << "## Screen lock state changed:" << (locked ? "LOCKED" : "UNLOCKED");
qDebug() << "##################################################";
emit lockStateChanged(locked);
@ -83,11 +90,9 @@ void ScreenLockDetector::setLockState(bool locked)
bool ScreenLockDetector::connectToGnomeScreenSaver()
{
// 连接到GNOME屏幕保护程序的DBus接口
// Service: org.gnome.ScreenSaver
// Path: /org/gnome/ScreenSaver
// Interface: org.gnome.ScreenSaver
qDebug() << "\n--- Connecting to GNOME ScreenSaver ---";
// 连接到GNOME屏幕保护程序的DBus接口
m_gnomeInterface = new QDBusInterface(
"org.gnome.ScreenSaver",
"/org/gnome/ScreenSaver",
@ -104,6 +109,8 @@ bool ScreenLockDetector::connectToGnomeScreenSaver()
return false;
}
qDebug() << "GNOME ScreenSaver interface is valid";
// 连接ActiveChanged信号
bool connected = QDBusConnection::sessionBus().connect(
"org.gnome.ScreenSaver",
@ -114,6 +121,8 @@ bool ScreenLockDetector::connectToGnomeScreenSaver()
SLOT(onScreenSaverActiveChanged(bool))
);
qDebug() << "GNOME ActiveChanged signal connected:" << connected;
if (!connected) {
qWarning() << "Failed to connect to GNOME ScreenSaver ActiveChanged signal";
delete m_gnomeInterface;
@ -128,65 +137,134 @@ bool ScreenLockDetector::connectToGnomeScreenSaver()
bool ScreenLockDetector::connectToLoginManager()
{
// 连接到systemd-logind或其他登录管理器
// Service: org.freedesktop.login1
// Path: /org/freedesktop/login1/session/auto
// Interface: org.freedesktop.login1.Session
qDebug() << "\n--- Connecting to Login Manager (systemd-logind) ---";
m_loginInterface = new QDBusInterface(
"org.freedesktop.login1",
"/org/freedesktop/login1/session/auto",
"org.freedesktop.login1.Session",
QDBusConnection::systemBus(),
this
);
if (!m_loginInterface->isValid()) {
qDebug() << "Login1 interface not available:"
<< m_loginInterface->lastError().message();
delete m_loginInterface;
m_loginInterface = nullptr;
return false;
// 首先获取当前会话的路径
QString sessionPath = getCurrentSessionPath();
if (sessionPath.isEmpty()) {
qWarning() << "Could not determine current session path";
qWarning() << "Will try to connect to generic session signals";
} else {
qDebug() << "Current session path:" << sessionPath;
}
// 连接Lock信号
// 方法1: 连接到特定会话路径(如果获取到了)
if (!sessionPath.isEmpty()) {
m_loginInterface = new QDBusInterface(
"org.freedesktop.login1",
sessionPath,
"org.freedesktop.login1.Session",
QDBusConnection::systemBus(),
this
);
if (m_loginInterface->isValid()) {
qDebug() << "Login Manager interface is valid for session:" << sessionPath;
// 连接Lock和Unlock信号到特定会话
bool lockConnected = QDBusConnection::systemBus().connect(
"org.freedesktop.login1",
sessionPath,
"org.freedesktop.login1.Session",
"Lock",
this,
SLOT(onSessionLocked())
);
bool unlockConnected = QDBusConnection::systemBus().connect(
"org.freedesktop.login1",
sessionPath,
"org.freedesktop.login1.Session",
"Unlock",
this,
SLOT(onSessionUnlocked())
);
qDebug() << "Session Lock signal connected:" << lockConnected;
qDebug() << "Session Unlock signal connected:" << unlockConnected;
if (lockConnected || unlockConnected) {
m_loginConnected = true;
qDebug() << "Successfully connected to Login Manager via session path";
return true;
}
} else {
qDebug() << "Login Manager interface not valid:" << m_loginInterface->lastError().message();
delete m_loginInterface;
m_loginInterface = nullptr;
}
}
// 方法2: 监听所有会话的Lock/Unlock信号不指定具体路径
qDebug() << "Attempting to connect to all login1 Session signals...";
bool lockConnected = QDBusConnection::systemBus().connect(
"org.freedesktop.login1",
"/org/freedesktop/login1/session/auto",
"", // 空路径表示监听所有对象
"org.freedesktop.login1.Session",
"Lock",
this,
SLOT(onSessionLocked())
);
// 连接Unlock信号
bool unlockConnected = QDBusConnection::systemBus().connect(
"org.freedesktop.login1",
"/org/freedesktop/login1/session/auto",
"", // 空路径表示监听所有对象
"org.freedesktop.login1.Session",
"Unlock",
this,
SLOT(onSessionUnlocked())
);
if (!lockConnected || !unlockConnected) {
qWarning() << "Failed to connect to Login Manager signals";
delete m_loginInterface;
m_loginInterface = nullptr;
return false;
qDebug() << "Generic Lock signal connected:" << lockConnected;
qDebug() << "Generic Unlock signal connected:" << unlockConnected;
if (lockConnected || unlockConnected) {
m_loginConnected = true;
qDebug() << "Successfully connected to Login Manager via generic signals";
return true;
}
m_loginConnected = true;
qDebug() << "Successfully connected to Login Manager";
return true;
qWarning() << "Failed to connect to Login Manager signals";
return false;
}
QString ScreenLockDetector::getCurrentSessionPath()
{
// 尝试从环境变量获取
QString xdgSessionId = qgetenv("XDG_SESSION_ID");
if (!xdgSessionId.isEmpty()) {
QString path = QString("/org/freedesktop/login1/session/%1").arg(xdgSessionId);
qDebug() << "Session path from XDG_SESSION_ID:" << path;
return path;
}
// 尝试通过DBus调用获取当前会话
QDBusInterface managerIface(
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
QDBusConnection::systemBus()
);
if (managerIface.isValid()) {
// 获取当前用户的会话列表
QDBusReply<QDBusObjectPath> reply = managerIface.call("GetSessionByPID", (quint32)QCoreApplication::applicationPid());
if (reply.isValid()) {
QString path = reply.value().path();
qDebug() << "Session path from GetSessionByPID:" << path;
return path;
} else {
qDebug() << "GetSessionByPID failed:" << reply.error().message();
}
}
return QString();
}
bool ScreenLockDetector::connectToDeepinDDE()
{
// 尝试连接到多个可能的Deepin DDE DBus接口
// Deepin不同版本可能使用不同的服务名称和信号
qDebug() << "Attempting to connect to Deepin DDE lock services...";
qDebug() << "\n--- Connecting to Deepin DDE ---";
// 可能的服务配置列表
struct DeepinService {
@ -211,7 +289,7 @@ bool ScreenLockDetector::connectToDeepinDDE()
};
for (const auto& svc : services) {
qDebug() << "Trying service:" << svc.service;
qDebug() << "Trying Deepin service:" << svc.service;
m_deepinInterface = new QDBusInterface(
svc.service,
@ -222,13 +300,13 @@ bool ScreenLockDetector::connectToDeepinDDE()
);
if (!m_deepinInterface->isValid()) {
qDebug() << " - Interface not available:" << m_deepinInterface->lastError().message();
qDebug() << " Interface not available:" << m_deepinInterface->lastError().message();
delete m_deepinInterface;
m_deepinInterface = nullptr;
continue;
}
qDebug() << " - Interface is valid, connecting signals...";
qDebug() << " Interface is valid, connecting signals...";
// 尝试连接锁屏信号
bool lockedConnected = QDBusConnection::sessionBus().connect(
@ -249,8 +327,8 @@ bool ScreenLockDetector::connectToDeepinDDE()
SLOT(onSessionUnlocked())
);
qDebug() << " - Lock signal (" << svc.lockSignal << ") connected:" << lockedConnected;
qDebug() << " - Unlock signal (" << svc.unlockSignal << ") connected:" << unlockedConnected;
qDebug() << " Lock signal (" << svc.lockSignal << ") connected:" << lockedConnected;
qDebug() << " Unlock signal (" << svc.unlockSignal << ") connected:" << unlockedConnected;
if (lockedConnected || unlockedConnected) {
m_deepinConnected = true;
@ -259,44 +337,44 @@ bool ScreenLockDetector::connectToDeepinDDE()
return true;
}
// 如果信号连接失败,清理接口
qWarning() << " - Failed to connect signals for" << svc.service;
qWarning() << " Failed to connect signals for" << svc.service;
delete m_deepinInterface;
m_deepinInterface = nullptr;
}
qWarning() << "Failed to connect to any Deepin DDE lock service";
qWarning() << "Please run debug_deepin_dbus.sh to find the correct service";
return false;
}
void ScreenLockDetector::queryCurrentLockState()
{
qDebug() << "\n--- Querying current lock state ---";
// 尝试从Deepin DDE查询当前状态
if (m_deepinInterface && m_deepinInterface->isValid()) {
qDebug() << "Deepin DDE interface available, attempting to query lock state...";
qDebug() << "Querying Deepin DDE lock state...";
// 尝试可能的查询方法
QStringList possibleMethods = {"GetLocked", "IsLocked", "GetActive", "GetSessionLocked"};
for (const QString& method : possibleMethods) {
QDBusReply<bool> reply = m_deepinInterface->call(method);
if (reply.isValid()) {
bool locked = reply.value();
qDebug() << "Successfully queried state via" << method << ":" << (locked ? "LOCKED" : "UNLOCKED");
qDebug() << " Method" << method << "returned:" << (locked ? "LOCKED" : "UNLOCKED");
setLockState(locked);
return;
}
}
qDebug() << "No query method available, waiting for signals";
qDebug() << " No query method worked, waiting for signals";
}
// 尝试从GNOME屏幕保护程序查询当前状态
if (m_gnomeInterface && m_gnomeInterface->isValid()) {
qDebug() << "Querying GNOME ScreenSaver state...";
QDBusReply<bool> reply = m_gnomeInterface->call("GetActive");
if (reply.isValid()) {
bool active = reply.value();
qDebug() << "Current GNOME ScreenSaver state:" << (active ? "ACTIVE" : "INACTIVE");
qDebug() << " Current GNOME ScreenSaver state:" << (active ? "ACTIVE/LOCKED" : "INACTIVE/UNLOCKED");
setLockState(active);
return;
}
@ -304,32 +382,78 @@ void ScreenLockDetector::queryCurrentLockState()
// 尝试从登录管理器查询锁定状态
if (m_loginInterface && m_loginInterface->isValid()) {
QDBusReply<QString> reply = m_loginInterface->call("GetProperty", "LockedHint");
qDebug() << "Querying Login Manager lock state...";
// 尝试读取 LockedHint 属性
QDBusMessage msg = QDBusMessage::createMethodCall(
"org.freedesktop.login1",
m_loginInterface->path(),
"org.freedesktop.DBus.Properties",
"Get"
);
msg << "org.freedesktop.login1.Session" << "LockedHint";
QDBusReply<QVariant> reply = QDBusConnection::systemBus().call(msg);
if (reply.isValid()) {
// 注意这个方法可能需要根据实际DBus接口调整
qDebug() << "Queried login manager lock state";
bool locked = reply.value().toBool();
qDebug() << " LockedHint property:" << (locked ? "LOCKED" : "UNLOCKED");
setLockState(locked);
return;
} else {
qDebug() << " Could not read LockedHint:" << reply.error().message();
}
}
qDebug() << "Could not query initial lock state, will detect on next lock/unlock event";
}
void ScreenLockDetector::onScreenSaverActiveChanged(bool active)
{
qDebug() << "GNOME ScreenSaver ActiveChanged signal received:" << active;
qDebug() << "##################################################";
qDebug() << "## GNOME ScreenSaver ActiveChanged signal received";
qDebug() << "## New state:" << (active ? "ACTIVE (LOCKED)" : "INACTIVE (UNLOCKED)");
qDebug() << "##################################################";
setLockState(active);
}
void ScreenLockDetector::onSessionLocked()
{
qDebug() << "==================================================";
qDebug() << "LOCK SIGNAL RECEIVED - Screen is now LOCKED";
qDebug() << "==================================================";
qDebug() << "##################################################";
qDebug() << "## LOCK SIGNAL RECEIVED";
qDebug() << "## Screen is now LOCKED";
qDebug() << "## Sender:" << sender();
// 获取信号发送者的详细信息
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);
}
void ScreenLockDetector::onSessionUnlocked()
{
qDebug() << "==================================================";
qDebug() << "UNLOCK SIGNAL RECEIVED - Screen is now UNLOCKED";
qDebug() << "==================================================";
qDebug() << "##################################################";
qDebug() << "## UNLOCK SIGNAL RECEIVED";
qDebug() << "## Screen is now UNLOCKED";
qDebug() << "## Sender:" << sender();
// 获取信号发送者的详细信息
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(false);
}

View File

@ -5,6 +5,8 @@
#include <QDBusConnection>
#include <QDBusInterface>
#include <QDBusReply>
#include <QDBusContext>
#include <QCoreApplication>
#include <QDebug>
/**
@ -13,7 +15,7 @@
* Linux系统的DBus信号来检测屏幕锁定/
* Deepin DDE, GNOME, KDE, XFCE等
*/
class ScreenLockDetector : public QObject
class ScreenLockDetector : public QObject, protected QDBusContext
{
Q_OBJECT
@ -99,6 +101,12 @@ private:
*/
void queryCurrentLockState();
/**
* @brief DBus
* @return
*/
QString getCurrentSessionPath();
private:
bool m_isLocked; // 当前锁屏状态
QDBusInterface *m_gnomeInterface; // GNOME屏幕保护程序接口

251
test_lock_signals.sh Executable file
View File

@ -0,0 +1,251 @@
#!/bin/bash
# ========================================
# DBus 锁屏信号测试脚本
# 用于诊断为什么锁屏信号没有被接收到
# ========================================
echo "========================================"
echo "DBus Lock Signal Test Script"
echo "========================================"
echo ""
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
# 检查必要的工具
echo "Checking required tools..."
if ! command -v dbus-monitor &> /dev/null; then
echo -e "${RED}${NC} dbus-monitor not found. Please install: sudo apt install dbus-x11"
exit 1
fi
if ! command -v dbus-send &> /dev/null; then
echo -e "${RED}${NC} dbus-send not found. Please install: sudo apt install dbus-x11"
exit 1
fi
echo -e "${GREEN}${NC} All required tools available"
echo ""
# ========================================
# 1. 检查当前会话信息
# ========================================
echo "========================================"
echo "Step 1: Session Information"
echo "========================================"
echo ""
echo "Environment Variables:"
echo " XDG_SESSION_ID: ${XDG_SESSION_ID:-<not set>}"
echo " XDG_SESSION_TYPE: ${XDG_SESSION_TYPE:-<not set>}"
echo " XDG_CURRENT_DESKTOP: ${XDG_CURRENT_DESKTOP:-<not set>}"
echo " DESKTOP_SESSION: ${DESKTOP_SESSION:-<not set>}"
echo " GDMSESSION: ${GDMSESSION:-<not set>}"
echo ""
# 尝试获取当前会话路径
if [ -n "$XDG_SESSION_ID" ]; then
SESSION_PATH="/org/freedesktop/login1/session/$XDG_SESSION_ID"
echo "Calculated session path: $SESSION_PATH"
echo ""
# 验证会话路径是否有效
echo "Verifying session path..."
if dbus-send --system --print-reply --dest=org.freedesktop.login1 \
"$SESSION_PATH" \
org.freedesktop.DBus.Introspectable.Introspect &>/dev/null; then
echo -e "${GREEN}${NC} Session path is valid"
else
echo -e "${RED}${NC} Session path is not valid"
fi
echo ""
fi
# ========================================
# 2. 检查可用的锁屏相关服务
# ========================================
echo "========================================"
echo "Step 2: Available Lock Services"
echo "========================================"
echo ""
echo "Checking Session Bus Services:"
echo "-------------------------------"
# GNOME ScreenSaver
echo -n " org.gnome.ScreenSaver: "
if dbus-send --session --print-reply --dest=org.gnome.ScreenSaver \
/org/gnome/ScreenSaver \
org.freedesktop.DBus.Introspectable.Introspect &>/dev/null; then
echo -e "${GREEN}Available${NC}"
else
echo -e "${RED}Not available${NC}"
fi
# Deepin 相关服务
DEEPIN_SERVICES=(
"com.deepin.dde.lockFront"
"com.deepin.ScreenSaver"
"com.deepin.SessionManager"
"org.deepin.dde.lockFront"
)
for service in "${DEEPIN_SERVICES[@]}"; do
echo -n " $service: "
if dbus-send --session --print-reply --dest="$service" / \
org.freedesktop.DBus.Introspectable.Introspect &>/dev/null; then
echo -e "${GREEN}Available${NC}"
else
echo -e "${RED}Not available${NC}"
fi
done
echo ""
echo "Checking System Bus Services:"
echo "-----------------------------"
# systemd-logind
echo -n " org.freedesktop.login1: "
if dbus-send --system --print-reply --dest=org.freedesktop.login1 \
/org/freedesktop/login1 \
org.freedesktop.DBus.Introspectable.Introspect &>/dev/null; then
echo -e "${GREEN}Available${NC}"
else
echo -e "${RED}Not available${NC}"
fi
echo ""
# ========================================
# 3. 列出当前会话的所有可用信号
# ========================================
if [ -n "$SESSION_PATH" ]; then
echo "========================================"
echo "Step 3: Session Signals"
echo "========================================"
echo ""
echo "Available signals on $SESSION_PATH:"
echo ""
dbus-send --system --print-reply --dest=org.freedesktop.login1 \
"$SESSION_PATH" \
org.freedesktop.DBus.Introspectable.Introspect 2>/dev/null | \
grep -E "signal name" | sed 's/^[[:space:]]*/ /'
echo ""
fi
# ========================================
# 4. 创建临时监听脚本
# ========================================
echo "========================================"
echo "Step 4: Signal Monitoring Setup"
echo "========================================"
echo ""
TEMP_DIR="/tmp/lock_signal_test_$$"
mkdir -p "$TEMP_DIR"
# Session bus monitor
cat > "$TEMP_DIR/monitor_session.sh" << 'EOF'
#!/bin/bash
echo "=== Monitoring SESSION BUS ==="
echo "Listening for lock-related signals..."
echo ""
dbus-monitor --session "type='signal'" 2>&1 | \
grep --line-buffered -iE "signal|lock|Lock|screen|Screen|Active|active" | \
while IFS= read -r line; do
if echo "$line" | grep -q "signal"; then
echo "$(date '+%H:%M:%S') [SIGNAL] $line"
else
echo "$(date '+%H:%M:%S') $line"
fi
done
EOF
# System bus monitor
cat > "$TEMP_DIR/monitor_system.sh" << 'EOF'
#!/bin/bash
echo "=== Monitoring SYSTEM BUS ==="
echo "Listening for login1 Session signals..."
echo ""
dbus-monitor --system "type='signal',interface='org.freedesktop.login1.Session'" 2>&1 | \
grep --line-buffered -E "signal|Lock|Unlock|lock|unlock" | \
while IFS= read -r line; do
if echo "$line" | grep -q "signal"; then
echo "$(date '+%H:%M:%S') [SIGNAL] $line"
else
echo "$(date '+%H:%M:%S') $line"
fi
done
EOF
chmod +x "$TEMP_DIR/monitor_session.sh"
chmod +x "$TEMP_DIR/monitor_system.sh"
echo "Monitoring scripts created in: $TEMP_DIR"
echo ""
# ========================================
# 5. 开始监听
# ========================================
echo "========================================"
echo "Step 5: Real-time Signal Monitoring"
echo "========================================"
echo ""
echo -e "${YELLOW}Instructions:${NC}"
echo " 1. This script will now monitor DBus signals"
echo " 2. Open another terminal and lock your screen:"
echo " - Press Super+L (or Ctrl+Alt+L)"
echo " - Or run: gnome-screensaver-command -l"
echo " - Or run: dde-lock (on Deepin)"
echo " 3. Observe which signals appear below"
echo " 4. Unlock your screen"
echo " 5. Press Ctrl+C to stop monitoring"
echo ""
echo -e "${CYAN}Monitoring both SESSION and SYSTEM buses...${NC}"
echo ""
echo "========================================"
echo ""
# 创建日志文件
LOG_FILE="$TEMP_DIR/signals.log"
# 在后台启动两个监听器
"$TEMP_DIR/monitor_session.sh" 2>&1 | tee -a "$LOG_FILE" &
SESSION_PID=$!
"$TEMP_DIR/monitor_system.sh" 2>&1 | tee -a "$LOG_FILE" &
SYSTEM_PID=$!
# 等待用户中断
wait_for_user() {
while true; do
sleep 1
done
}
# 捕获 Ctrl+C
trap "echo ''; echo 'Stopping monitors...'; kill $SESSION_PID $SYSTEM_PID 2>/dev/null; exit 0" INT TERM
wait_for_user
# ========================================
# 清理
# ========================================
echo ""
echo "========================================"
echo "Cleanup"
echo "========================================"
echo ""
echo "Log file saved to: $LOG_FILE"
echo "You can review it with: cat $LOG_FILE"
echo ""
echo "To clean up: rm -rf $TEMP_DIR"
echo ""

163
verify_fix.sh Executable file
View File

@ -0,0 +1,163 @@
#!/bin/bash
# ========================================
# 快速验证锁屏信号修复脚本
# ========================================
echo "========================================"
echo "Lock Signal Fix Verification Script"
echo "========================================"
echo ""
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
# 检查编译是否最新
echo "Step 1: Checking build..."
echo "--------------------------------------"
if [ ! -f "build/bin/ScreenLockDemo" ]; then
echo -e "${RED}${NC} Executable not found. Running build..."
./build.sh
if [ $? -ne 0 ]; then
echo -e "${RED}${NC} Build failed!"
exit 1
fi
else
echo -e "${GREEN}${NC} Executable exists"
fi
echo ""
# 检查环境信息
echo "Step 2: Environment Information"
echo "--------------------------------------"
echo "Desktop Environment:"
echo " XDG_CURRENT_DESKTOP: ${XDG_CURRENT_DESKTOP:-<not set>}"
echo " DESKTOP_SESSION: ${DESKTOP_SESSION:-<not set>}"
echo ""
echo "Session Information:"
echo " XDG_SESSION_ID: ${XDG_SESSION_ID:-<not set>}"
echo " XDG_SESSION_TYPE: ${XDG_SESSION_TYPE:-<not set>}"
echo ""
# 计算会话路径
if [ -n "$XDG_SESSION_ID" ]; then
SESSION_PATH="/org/freedesktop/login1/session/$XDG_SESSION_ID"
echo "Expected session path: $SESSION_PATH"
echo ""
fi
# 检查可用的服务
echo "Step 3: Available DBus Services"
echo "--------------------------------------"
echo "Checking for lock services:"
# GNOME ScreenSaver
echo -n " org.gnome.ScreenSaver (session): "
if dbus-send --session --print-reply --dest=org.gnome.ScreenSaver \
/org/gnome/ScreenSaver \
org.freedesktop.DBus.Introspectable.Introspect &>/dev/null; then
echo -e "${GREEN}✓ Available${NC}"
HAS_SERVICE=1
else
echo -e "${RED}✗ Not available${NC}"
fi
# systemd-logind
echo -n " org.freedesktop.login1 (system): "
if dbus-send --system --print-reply --dest=org.freedesktop.login1 \
/org/freedesktop/login1 \
org.freedesktop.DBus.Introspectable.Introspect &>/dev/null; then
echo -e "${GREEN}✓ Available${NC}"
HAS_SERVICE=1
else
echo -e "${RED}✗ Not available${NC}"
fi
# Deepin services
DEEPIN_SERVICES=(
"com.deepin.dde.lockFront"
"com.deepin.ScreenSaver"
"org.deepin.dde.lockFront"
)
for service in "${DEEPIN_SERVICES[@]}"; do
echo -n " $service (session): "
if dbus-send --session --print-reply --dest="$service" / \
org.freedesktop.DBus.Introspectable.Introspect &>/dev/null; then
echo -e "${GREEN}✓ Available${NC}"
HAS_SERVICE=1
else
echo -e "${RED}✗ Not available${NC}"
fi
done
echo ""
if [ -z "$HAS_SERVICE" ]; then
echo -e "${YELLOW}⚠ Warning: No lock services detected${NC}"
echo "This might be expected if running in a minimal environment"
echo ""
fi
# 运行程序
echo "Step 4: Running Application"
echo "--------------------------------------"
echo ""
echo -e "${CYAN}The application will now start.${NC}"
echo -e "${CYAN}Please check the output for connection status.${NC}"
echo ""
echo "Look for these indicators:"
echo " ${GREEN}${NC} 'ScreenLockDetector initialized successfully'"
echo " ${GREEN}${NC} At least one 'connected: true'"
echo " ${GREEN}${NC} Valid session path (not 'auto')"
echo ""
echo "Then test by locking your screen:"
echo " - Press ${BLUE}Super+L${NC} or ${BLUE}Ctrl+Alt+L${NC}"
echo " - Look for ${GREEN}'LOCK SIGNAL RECEIVED'${NC} in the output"
echo " - Unlock and look for ${GREEN}'UNLOCK SIGNAL RECEIVED'${NC}"
echo ""
echo "Press Ctrl+C to stop the application when done."
echo ""
read -p "Press ENTER to start the application..."
echo ""
echo "========================================"
echo "Application Output:"
echo "========================================"
echo ""
cd build/bin
./ScreenLockDemo
echo ""
echo "========================================"
echo "Application stopped"
echo "========================================"
echo ""
# 提供进一步调试建议
echo "If signals were NOT received:"
echo "--------------------------------------"
echo "1. Run the detailed test script:"
echo " ${CYAN}./test_lock_signals.sh${NC}"
echo ""
echo "2. Check what signals your system actually sends:"
echo " ${CYAN}dbus-monitor --system \"type='signal',interface='org.freedesktop.login1.Session'\"${NC}"
echo " Then lock your screen in another terminal"
echo ""
echo "3. For Deepin systems, run:"
echo " ${CYAN}./debug_deepin_dbus.sh${NC}"
echo ""
echo "4. Check session status:"
echo " ${CYAN}loginctl show-session \$XDG_SESSION_ID${NC}"
echo ""
echo "5. Review the detailed fix guide:"
echo " ${CYAN}cat LOCK_SIGNAL_FIX.md${NC}"
echo ""