ScreenLockDetector/docs/ARCHITECTURE.md

478 lines
15 KiB
Markdown
Raw Permalink Normal View History

2025-11-07 10:56:45 +08:00
# 项目架构说明
## 概述
本项目是一个基于 Qt5 的 Linux 应用程序,通过 DBus 监听系统锁屏事件,并在锁屏时自动停止所有 Paint 事件,以节省系统资源。
## 系统架构图
```
┌─────────────────────────────────────────────────────────────┐
│ Linux System │
2025-11-07 10:56:45 +08:00
│ ┌──────────────────────┐ ┌─────────────────────────┐ │
│ │ GNOME ScreenSaver │ │ systemd-logind │ │
│ │ (DBus Service) │ │ (DBus Service) │ │
│ └──────────┬───────────┘ └───────────┬─────────────┘ │
│ │ ActiveChanged(bool) │ Lock/Unlock │
└─────────────┼──────────────────────────────┼────────────────┘
│ │
│ DBus Signals │
│ │
┌─────────────┴──────────────────────────────┴────────────────┐
│ Qt Application (ScreenLockDemo) │
2025-11-07 10:56:45 +08:00
│ ┌────────────────────────────────────────────────────────┐ │
│ │ MainWindow │ │
│ │ ┌──────────────┐ ┌────────────────────────────────┐ │ │
│ │ │ Control Panel│ │ Status Display │ │ │
│ │ │ - Enable Btn │ │ - Lock Status: 🔒/🔓 │ │ │
│ │ │ - Disable Btn│ │ - Paint Status: ✓/✗ │ │ │
│ │ │ - Reset Btn │ │ - Frame Count │ │ │
│ │ └──────────────┘ └────────────────────────────────┘ │ │
2025-11-07 10:56:45 +08:00
│ └────────────────────────────────────────────────────────┘ │
│ ↕ signals/slots │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ ScreenLockDetector │ │
│ │ - Monitors DBus signals │ │
│ │ - Emits: screenLocked() / screenUnlocked() │ │
│ │ - Manages connection to multiple DBus interfaces │ │
│ └─────────────────────┬──────────────────────────────────┘ │
│ ↓ lockStateChanged(bool) │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ CustomWidget │ │
│ │ - Renders animations (60 FPS) │ │
│ │ - Controls paint events based on lock state │ │
│ │ - Draws: rotating circles, waves, gradients │ │
│ │ - Tracks frame count and statistics │ │
│ └────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
## 核心组件详解
### 1. ScreenLockDetector (锁屏检测器)
**职责**
- 连接到 Linux 系统的 DBus 服务
- 监听屏幕锁定/解锁事件
- 提供锁屏状态查询接口
- 发出标准化的 Qt 信号
**关键方法**
```cpp
bool initialize() // 初始化 DBus 连接
bool isScreenLocked() const // 查询当前锁屏状态
bool connectToGnomeScreenSaver() // 连接 GNOME 接口
bool connectToLoginManager() // 连接 systemd-logind 接口
void queryCurrentLockState() // 查询初始状态
```
**信号**
```cpp
void screenLocked() // 屏幕已锁定
void screenUnlocked() // 屏幕已解锁
void lockStateChanged(bool locked) // 状态改变(通用)
```
**DBus 接口支持**
| 桌面环境 | DBus Service | 路径 | 接口 | 信号 |
|---------|-------------|------|------|-----|
| GNOME | org.gnome.ScreenSaver | /org/gnome/ScreenSaver | org.gnome.ScreenSaver | ActiveChanged(bool) |
| All (systemd) | org.freedesktop.login1 | /org/freedesktop/login1/session/auto | org.freedesktop.login1.Session | Lock(), Unlock() |
### 2. CustomWidget (自定义绘制组件)
**职责**
- 实现动态动画效果
- 根据锁屏状态控制绘制
- 统计绘制性能数据
- 提供可视化反馈
**绘制层次**
```
Layer 1: Background (渐变背景)
Layer 2: Rotating Circles (旋转圆圈)
Layer 3: Wave Effects (波浪效果)
Layer 4: Status Info (状态文字)
```
**动画参数**
- 刷新率60 FPS (16ms/frame)
- 旋转角度:每帧 +2°
- 波浪相位:每帧 +0.05 rad
**关键方法**
```cpp
void setPaintingEnabled(bool enabled) // 控制绘制开关
void paintEvent(QPaintEvent *event) // 重写绘制事件
void drawBackground(QPainter &painter) // 绘制背景
void drawRotatingCircles(...) // 绘制旋转元素
void drawWaveEffect(...) // 绘制波浪
void drawStatusInfo(...) // 绘制状态信息
```
**状态机**
```
[ENABLED] ←→ [DISABLED]
↓ ↓
Timer ON Timer OFF
↓ ↓
Draw frames Draw static
↓ ↓
Count++ Count unchanged
```
### 3. MainWindow (主窗口)
**职责**
- 整合所有组件
- 提供用户界面
- 处理用户交互
- 实时状态展示
**UI 布局**
```
┌─────────────────────────────────────┐
│ MainWindow │
2025-11-07 10:56:45 +08:00
├─────────────────────────────────────┤
│ ┌───────────────────────────────┐ │
│ │ CustomWidget │ │
│ │ (Animation Display Area) │ │
│ │ 600x400px │ │
│ └───────────────────────────────┘ │
├─────────────────────────────────────┤
│ ┌─── Manual Control ────────────┐ │
│ │ [Enable] [Disable] [Reset] │ │
│ └───────────────────────────────┘ │
├─────────────────────────────────────┤
│ ┌─── Status Information ────────┐ │
│ │ Detector: Active │ │
│ │ Lock: 🔓 UNLOCKED │ │
│ │ Paint: ✓ ENABLED │ │
2025-11-07 10:56:45 +08:00
│ │ Frames: 1234 │ │
│ └───────────────────────────────┘ │
└─────────────────────────────────────┘
```
**信号流向**
```
ScreenLockDetector → MainWindow → CustomWidget
screenLocked() onScreenLocked() setPaintingEnabled(false)
screenUnlocked() onScreenUnlocked() setPaintingEnabled(true)
```
## 数据流图
### 锁屏事件流
```
[User locks screen]
[Linux System]
[DBus Signal: Lock/ActiveChanged]
[ScreenLockDetector::onSessionLocked()]
[emit screenLocked()]
[MainWindow::onScreenLocked()]
[CustomWidget::setPaintingEnabled(false)]
[m_animationTimer->stop()]
[paintEvent() returns early]
[Animation stops, resources saved]
```
### 解锁事件流
```
[User unlocks screen]
[Linux System]
[DBus Signal: Unlock/ActiveChanged]
[ScreenLockDetector::onSessionUnlocked()]
[emit screenUnlocked()]
[MainWindow::onScreenUnlocked()]
[CustomWidget::setPaintingEnabled(true)]
[m_animationTimer->start(16)]
[paintEvent() resumes drawing]
[Animation resumes]
```
## 技术细节
### Qt 信号槽机制
```cpp
// 连接示例
connect(m_lockDetector, &ScreenLockDetector::screenLocked,
this, &MainWindow::onScreenLocked);
// 优势:
// - 类型安全
// - 解耦设计
// - 自动生命周期管理
```
### DBus 连接管理
```cpp
// Session Bus (用户会话)
QDBusConnection::sessionBus().connect(
"org.gnome.ScreenSaver", // Service
"/org/gnome/ScreenSaver", // Path
"org.gnome.ScreenSaver", // Interface
"ActiveChanged", // Signal
this, // Receiver
SLOT(onScreenSaverActiveChanged(bool))
);
// System Bus (系统级)
QDBusConnection::systemBus().connect(
"org.freedesktop.login1", // Service
"/org/freedesktop/login1/session/auto",
"org.freedesktop.login1.Session",
"Lock",
this,
SLOT(onSessionLocked())
);
```
### Paint 事件优化
```cpp
void CustomWidget::paintEvent(QPaintEvent *event)
{
// 快速退出:锁屏时不进行复杂绘制
if (!m_paintingEnabled) {
// 仅绘制静态状态信息
drawSimpleStatus();
return; // 节省 CPU 资源
}
2025-11-07 10:56:45 +08:00
// 正常绘制流程
drawBackground();
drawRotatingCircles();
drawWaveEffect();
drawStatusInfo();
2025-11-07 10:56:45 +08:00
m_frameCount++; // 统计
}
```
## 构建系统
### CMake 配置流程
```
CMakeLists.txt
find_package(Qt5)
set(CMAKE_AUTOMOC ON) # 自动 MOC 处理
set(CMAKE_AUTOUIC ON) # 自动 UI 文件
set(CMAKE_AUTORCC ON) # 自动资源文件
add_executable(ScreenLockDemo)
target_link_libraries(Qt5::Core Qt5::Gui Qt5::Widgets Qt5::DBus)
```
### 编译流程
```bash
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
make -j$(nproc)
./bin/ScreenLockDemo
```
## 性能特性
### 资源消耗对比
| 状态 | CPU使用 | GPU使用 | 内存 | 说明 |
|-----|--------|--------|------|-----|
| 绘制启用 | ~2-5% | ~1-3% | ~50MB | 60 FPS 动画 |
| 绘制禁用 | <1% | 0% | ~50MB | 仅监听 DBus |
| 锁屏期间 | <0.5% | 0% | ~50MB | 完全停止绘制 |
### 响应时间
- DBus 信号延迟:< 100ms
- 动画停止延迟:< 20ms (1-2 frames)
- 动画恢复延迟:< 20ms
## 扩展性设计
### 添加新的 DBus 接口
```cpp
// 在 screenlockdetector.cpp 中添加
bool ScreenLockDetector::connectToKDEScreenSaver()
{
// 1. 创建 DBus 接口
m_kdeInterface = new QDBusInterface(
"org.kde.screensaver",
"/ScreenSaver",
"org.freedesktop.ScreenSaver",
QDBusConnection::sessionBus()
);
2025-11-07 10:56:45 +08:00
// 2. 连接信号
bool connected = QDBusConnection::sessionBus().connect(
"org.kde.screensaver",
"/ScreenSaver",
"org.freedesktop.ScreenSaver",
"ActiveChanged",
this,
SLOT(onKDEScreenSaverChanged(bool))
);
2025-11-07 10:56:45 +08:00
return connected;
}
```
### 添加新的动画效果
```cpp
// 在 customwidget.cpp 中添加
void CustomWidget::drawParticleSystem(QPainter &painter)
{
// 1. 更新粒子位置
for (auto &particle : m_particles) {
particle.update(m_deltaTime);
}
2025-11-07 10:56:45 +08:00
// 2. 绘制粒子
for (const auto &particle : m_particles) {
particle.draw(painter);
}
}
// 在 paintEvent 中调用
void CustomWidget::paintEvent(QPaintEvent *event)
{
// ...
drawParticleSystem(painter);
}
```
## 测试策略
### 单元测试建议
```cpp
// 测试锁屏检测器
void TestScreenLockDetector::testLockStateChange()
{
ScreenLockDetector detector;
QSignalSpy spy(&detector, &ScreenLockDetector::lockStateChanged);
2025-11-07 10:56:45 +08:00
// 模拟 DBus 信号
detector.onSessionLocked();
QCOMPARE(spy.count(), 1);
QVERIFY(detector.isScreenLocked());
}
// 测试绘制控制
void TestCustomWidget::testPaintingControl()
{
CustomWidget widget;
widget.setPaintingEnabled(false);
QVERIFY(!widget.isPaintingEnabled());
2025-11-07 10:56:45 +08:00
int initialCount = widget.getPaintFrameCount();
QTest::qWait(100); // 等待
QCOMPARE(widget.getPaintFrameCount(), initialCount);
}
```
### 集成测试场景
1. 启动应用 → 验证动画运行
2. 锁定屏幕 → 验证动画停止
3. 解锁屏幕 → 验证动画恢复
4. 手动禁用 → 验证控制有效
5. 重置计数 → 验证统计准确
## 故障处理
### 错误处理策略
```cpp
bool ScreenLockDetector::initialize()
{
bool gnomeOk = connectToGnomeScreenSaver();
bool loginOk = connectToLoginManager();
2025-11-07 10:56:45 +08:00
// 容错:至少一个接口成功即可
if (!gnomeOk && !loginOk) {
qWarning() << "No lock detection service available";
return false;
}
2025-11-07 10:56:45 +08:00
// 降级:查询当前状态(可能失败)
queryCurrentLockState();
2025-11-07 10:56:45 +08:00
return true;
}
```
### 日志级别
```cpp
qDebug() // 调试信息(开发)
qInfo() // 一般信息
qWarning() // 警告信息(功能降级)
qCritical()// 严重错误
```
## 最佳实践
### 内存管理
- 使用 Qt 父子对象机制自动管理内存
- 显式 delete 前先判空
- 使用智能指针(如需要)
### 信号槽
- 优先使用新式语法(函数指针)
- 避免跨线程信号(本项目单线程)
- 断开不再需要的连接
### 绘制优化
- 使用 update() 而非 repaint()
- 避免在 paintEvent 中进行重计算
- 使用抗锯齿适度(性能影响)
## 总结
本项目展示了:
- ✅ Qt5 应用程序开发
- ✅ DBus 系统集成
- ✅ 信号槽机制运用
- ✅ 自定义绘制实现
- ✅ 事件驱动架构
- ✅ 跨组件通信
- ✅ 资源优化策略
适合作为 Qt + Linux 系统编程的学习参考。