# 项目架构说明 ## 概述 本项目是一个基于 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 系统编程的学习参考。