ScreenLockDetector/docs/ARCHITECTURE.md

478 lines
15 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 项目架构说明
## 概述
本项目是一个基于 Qt5 的 Linux 应用程序,通过 DBus 监听系统锁屏事件,并在锁屏时自动停止所有 Paint 事件,以节省系统资源。
## 系统架构图
```
┌─────────────────────────────────────────────────────────────┐
│ Linux System │
│ ┌──────────────────────┐ ┌─────────────────────────┐ │
│ │ GNOME ScreenSaver │ │ systemd-logind │ │
│ │ (DBus Service) │ │ (DBus Service) │ │
│ └──────────┬───────────┘ └───────────┬─────────────┘ │
│ │ ActiveChanged(bool) │ Lock/Unlock │
└─────────────┼──────────────────────────────┼────────────────┘
│ │
│ DBus Signals │
│ │
┌─────────────┴──────────────────────────────┴────────────────┐
│ Qt Application (ScreenLockDemo) │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ MainWindow │ │
│ │ ┌──────────────┐ ┌────────────────────────────────┐ │ │
│ │ │ Control Panel│ │ Status Display │ │ │
│ │ │ - Enable Btn │ │ - Lock Status: 🔒/🔓 │ │ │
│ │ │ - Disable Btn│ │ - Paint Status: ✓/✗ │ │ │
│ │ │ - Reset Btn │ │ - Frame Count │ │ │
│ │ └──────────────┘ └────────────────────────────────┘ │ │
│ └────────────────────────────────────────────────────────┘ │
│ ↕ 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 │
├─────────────────────────────────────┤
│ ┌───────────────────────────────┐ │
│ │ CustomWidget │ │
│ │ (Animation Display Area) │ │
│ │ 600x400px │ │
│ └───────────────────────────────┘ │
├─────────────────────────────────────┤
│ ┌─── Manual Control ────────────┐ │
│ │ [Enable] [Disable] [Reset] │ │
│ └───────────────────────────────┘ │
├─────────────────────────────────────┤
│ ┌─── Status Information ────────┐ │
│ │ Detector: Active │ │
│ │ Lock: 🔓 UNLOCKED │ │
│ │ Paint: ✓ ENABLED │ │
│ │ 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 资源
}
// 正常绘制流程
drawBackground();
drawRotatingCircles();
drawWaveEffect();
drawStatusInfo();
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()
);
// 2. 连接信号
bool connected = QDBusConnection::sessionBus().connect(
"org.kde.screensaver",
"/ScreenSaver",
"org.freedesktop.ScreenSaver",
"ActiveChanged",
this,
SLOT(onKDEScreenSaverChanged(bool))
);
return connected;
}
```
### 添加新的动画效果
```cpp
// 在 customwidget.cpp 中添加
void CustomWidget::drawParticleSystem(QPainter &painter)
{
// 1. 更新粒子位置
for (auto &particle : m_particles) {
particle.update(m_deltaTime);
}
// 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);
// 模拟 DBus 信号
detector.onSessionLocked();
QCOMPARE(spy.count(), 1);
QVERIFY(detector.isScreenLocked());
}
// 测试绘制控制
void TestCustomWidget::testPaintingControl()
{
CustomWidget widget;
widget.setPaintingEnabled(false);
QVERIFY(!widget.isPaintingEnabled());
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();
// 容错:至少一个接口成功即可
if (!gnomeOk && !loginOk) {
qWarning() << "No lock detection service available";
return false;
}
// 降级:查询当前状态(可能失败)
queryCurrentLockState();
return true;
}
```
### 日志级别
```cpp
qDebug() // 调试信息(开发)
qInfo() // 一般信息
qWarning() // 警告信息(功能降级)
qCritical()// 严重错误
```
## 最佳实践
### 内存管理
- 使用 Qt 父子对象机制自动管理内存
- 显式 delete 前先判空
- 使用智能指针如需要
### 信号槽
- 优先使用新式语法函数指针
- 避免跨线程信号本项目单线程
- 断开不再需要的连接
### 绘制优化
- 使用 update() 而非 repaint()
- 避免在 paintEvent 中进行重计算
- 使用抗锯齿适度性能影响
## 总结
本项目展示了
- Qt5 应用程序开发
- DBus 系统集成
- 信号槽机制运用
- 自定义绘制实现
- 事件驱动架构
- 跨组件通信
- 资源优化策略
适合作为 Qt + Linux 系统编程的学习参考