Add macOS support and cross-platform CMake
This commit is contained in:
parent
9248f3945d
commit
471b4c7b3b
107
CMakeLists.txt
107
CMakeLists.txt
|
|
@ -12,32 +12,94 @@ set(CMAKE_AUTOMOC ON)
|
||||||
set(CMAKE_AUTOUIC ON)
|
set(CMAKE_AUTOUIC ON)
|
||||||
set(CMAKE_AUTORCC ON)
|
set(CMAKE_AUTORCC ON)
|
||||||
|
|
||||||
# Set Qt5 path
|
# Platform detection
|
||||||
set(Qt5_DIR "$ENV{HOME}/sdk/qt-5.15.2/lib/cmake/Qt5")
|
if(APPLE)
|
||||||
|
message(STATUS "Building for macOS")
|
||||||
|
set(PLATFORM_NAME "macOS")
|
||||||
|
elseif(UNIX)
|
||||||
|
message(STATUS "Building for Linux")
|
||||||
|
set(PLATFORM_NAME "Linux")
|
||||||
|
else()
|
||||||
|
message(WARNING "Unsupported platform")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Set Qt5 path (customize this based on your installation)
|
||||||
|
if(APPLE)
|
||||||
|
# macOS: Try common Qt installation paths
|
||||||
|
if(NOT DEFINED Qt5_DIR)
|
||||||
|
# Check MacPorts installation
|
||||||
|
if(EXISTS "/opt/local/lib/cmake/Qt5")
|
||||||
|
set(Qt5_DIR "/opt/local/lib/cmake/Qt5")
|
||||||
|
# Check Homebrew installation (Intel)
|
||||||
|
elseif(EXISTS "/usr/local/opt/qt@5/lib/cmake/Qt5")
|
||||||
|
set(Qt5_DIR "/usr/local/opt/qt@5/lib/cmake/Qt5")
|
||||||
|
# Check Homebrew installation (Apple Silicon)
|
||||||
|
elseif(EXISTS "/opt/homebrew/opt/qt@5/lib/cmake/Qt5")
|
||||||
|
set(Qt5_DIR "/opt/homebrew/opt/qt@5/lib/cmake/Qt5")
|
||||||
|
# Check official Qt installer
|
||||||
|
elseif(EXISTS "$ENV{HOME}/Qt/5.15.2/clang_64/lib/cmake/Qt5")
|
||||||
|
set(Qt5_DIR "$ENV{HOME}/Qt/5.15.2/clang_64/lib/cmake/Qt5")
|
||||||
|
# Check custom installation
|
||||||
|
elseif(EXISTS "$ENV{HOME}/sdk/qt-5.15.2/lib/cmake/Qt5")
|
||||||
|
set(Qt5_DIR "$ENV{HOME}/sdk/qt-5.15.2/lib/cmake/Qt5")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
# Linux: Use custom path
|
||||||
|
if(NOT DEFINED Qt5_DIR)
|
||||||
|
set(Qt5_DIR "$ENV{HOME}/sdk/qt-5.15.2/lib/cmake/Qt5")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
# Find Qt5 packages
|
# Find Qt5 packages
|
||||||
find_package(Qt5 REQUIRED COMPONENTS
|
set(QT_COMPONENTS Core Gui Widgets)
|
||||||
Core
|
|
||||||
Gui
|
|
||||||
Widgets
|
|
||||||
DBus
|
|
||||||
)
|
|
||||||
|
|
||||||
# Source files
|
if(UNIX AND NOT APPLE)
|
||||||
|
list(APPEND QT_COMPONENTS DBus)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_package(Qt5 REQUIRED COMPONENTS ${QT_COMPONENTS})
|
||||||
|
|
||||||
|
# Common source files
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
src/mainwindow.cpp
|
src/mainwindow.cpp
|
||||||
src/screenlockdetector.cpp
|
|
||||||
src/customwidget.cpp
|
src/customwidget.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
# Header files
|
|
||||||
set(HEADERS
|
set(HEADERS
|
||||||
src/mainwindow.h
|
src/mainwindow.h
|
||||||
src/screenlockdetector.h
|
|
||||||
src/customwidget.h
|
src/customwidget.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Platform-specific source files
|
||||||
|
if(APPLE)
|
||||||
|
# macOS specific files
|
||||||
|
list(APPEND SOURCES
|
||||||
|
src/screenlockdetector.cpp
|
||||||
|
src/screenlockdetector_mac.mm
|
||||||
|
)
|
||||||
|
list(APPEND HEADERS
|
||||||
|
src/screenlockdetector.h
|
||||||
|
src/screenlockdetector_mac.h
|
||||||
|
)
|
||||||
|
|
||||||
|
# Enable Objective-C++ for .mm files
|
||||||
|
set_source_files_properties(
|
||||||
|
src/screenlockdetector_mac.mm
|
||||||
|
PROPERTIES
|
||||||
|
COMPILE_FLAGS "-x objective-c++"
|
||||||
|
)
|
||||||
|
elseif(UNIX)
|
||||||
|
# Linux specific files
|
||||||
|
list(APPEND SOURCES
|
||||||
|
src/screenlockdetector.cpp
|
||||||
|
)
|
||||||
|
list(APPEND HEADERS
|
||||||
|
src/screenlockdetector.h
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
# Add executable
|
# Add executable
|
||||||
add_executable(${PROJECT_NAME}
|
add_executable(${PROJECT_NAME}
|
||||||
${SOURCES}
|
${SOURCES}
|
||||||
|
|
@ -49,14 +111,31 @@ target_link_libraries(${PROJECT_NAME}
|
||||||
Qt5::Core
|
Qt5::Core
|
||||||
Qt5::Gui
|
Qt5::Gui
|
||||||
Qt5::Widgets
|
Qt5::Widgets
|
||||||
Qt5::DBus
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Platform-specific linking
|
||||||
|
if(UNIX AND NOT APPLE)
|
||||||
|
target_link_libraries(${PROJECT_NAME} Qt5::DBus)
|
||||||
|
elseif(APPLE)
|
||||||
|
# Link macOS frameworks
|
||||||
|
target_link_libraries(${PROJECT_NAME}
|
||||||
|
"-framework Foundation"
|
||||||
|
"-framework Cocoa"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
# Set output directory
|
# Set output directory
|
||||||
set_target_properties(${PROJECT_NAME} PROPERTIES
|
set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
|
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# macOS specific settings
|
||||||
|
if(APPLE)
|
||||||
|
set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||||
|
MACOSX_BUNDLE FALSE
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
# Install target
|
# Install target
|
||||||
install(TARGETS ${PROJECT_NAME}
|
install(TARGETS ${PROJECT_NAME}
|
||||||
RUNTIME DESTINATION bin
|
RUNTIME DESTINATION bin
|
||||||
|
|
@ -66,6 +145,8 @@ install(TARGETS ${PROJECT_NAME}
|
||||||
message(STATUS "========================================")
|
message(STATUS "========================================")
|
||||||
message(STATUS "Build Configuration:")
|
message(STATUS "Build Configuration:")
|
||||||
message(STATUS "========================================")
|
message(STATUS "========================================")
|
||||||
|
message(STATUS "Platform: ${PLATFORM_NAME}")
|
||||||
message(STATUS "Qt5_DIR: ${Qt5_DIR}")
|
message(STATUS "Qt5_DIR: ${Qt5_DIR}")
|
||||||
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
|
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
|
||||||
|
message(STATUS "Qt Components: ${QT_COMPONENTS}")
|
||||||
message(STATUS "========================================")
|
message(STATUS "========================================")
|
||||||
|
|
|
||||||
244
README.md
244
README.md
|
|
@ -1,23 +1,33 @@
|
||||||
# Qt Screen Lock Detection Demo
|
# Qt Screen Lock Detection Demo
|
||||||
|
|
||||||
一个基于 Qt5 + CMake 的 Linux 应用程序,用于检测 Ubuntu 系统的锁屏状态,并在锁屏时自动停止所有 Paint 事件。
|
一个基于 Qt5 + CMake 的跨平台应用程序,用于检测系统的锁屏状态,并在锁屏时自动停止所有 Paint 事件。
|
||||||
|
|
||||||
|
**支持平台:**
|
||||||
|
- ✅ **Linux** (Ubuntu, Deepin, Fedora 等)
|
||||||
|
- ✅ **macOS** (10.12 及以上版本)
|
||||||
|
|
||||||
## 功能特性
|
## 功能特性
|
||||||
|
|
||||||
- ✅ **自动检测锁屏状态**:通过 DBus 监听 Linux 系统的锁屏/解锁事件
|
- ✅ **自动检测锁屏状态**:
|
||||||
|
- Linux: 通过 DBus 监听系统的锁屏/解锁事件
|
||||||
|
- macOS: 通过 NSDistributedNotificationCenter 监听系统通知
|
||||||
- ✅ **自动停止绘制**:屏幕锁定时自动停止所有 Paint 事件,节省系统资源
|
- ✅ **自动停止绘制**:屏幕锁定时自动停止所有 Paint 事件,节省系统资源
|
||||||
- ✅ **实时动画演示**:持续的动画效果,直观展示绘制的启用/禁用状态
|
- ✅ **实时动画演示**:持续的动画效果,直观展示绘制的启用/禁用状态
|
||||||
- ✅ **手动控制**:提供手动启用/禁用绘制的按钮
|
- ✅ **手动控制**:提供手动启用/禁用绘制的按钮
|
||||||
- ✅ **状态监控**:实时显示锁屏状态、绘制状态和帧数统计
|
- ✅ **状态监控**:实时显示锁屏状态、绘制状态和帧数统计
|
||||||
- ✅ **多桌面环境支持**:支持 GNOME、KDE、XFCE、Deepin DDE 等主流桌面环境
|
- ✅ **多平台支持**:
|
||||||
|
- Linux: 支持 GNOME、KDE、XFCE、Deepin DDE 等主流桌面环境
|
||||||
|
- macOS: 原生系统通知支持
|
||||||
|
|
||||||
## 技术架构
|
## 技术架构
|
||||||
|
|
||||||
### 核心组件
|
### 核心组件
|
||||||
|
|
||||||
1. **ScreenLockDetector** - 锁屏检测器
|
1. **ScreenLockDetector** - 跨平台锁屏检测器
|
||||||
- 通过 Qt DBus 监听系统锁屏信号
|
- **Linux**: 通过 Qt DBus 监听系统锁屏信号
|
||||||
- 支持 GNOME ScreenSaver、systemd-logind 和 Deepin DDE 接口
|
- 支持 GNOME ScreenSaver、systemd-logind 和 Deepin DDE 接口
|
||||||
|
- **macOS**: 通过 NSDistributedNotificationCenter 监听系统通知
|
||||||
|
- 监听 com.apple.screenIsLocked/Unlocked 通知
|
||||||
- 发出锁屏/解锁信号供其他组件订阅
|
- 发出锁屏/解锁信号供其他组件订阅
|
||||||
|
|
||||||
2. **CustomWidget** - 自定义绘制组件
|
2. **CustomWidget** - 自定义绘制组件
|
||||||
|
|
@ -33,69 +43,142 @@
|
||||||
|
|
||||||
### 技术栈
|
### 技术栈
|
||||||
|
|
||||||
- **语言**:C++11
|
- **语言**:C++11 / Objective-C++ (macOS)
|
||||||
- **GUI 框架**:Qt 5.15.2
|
- **GUI 框架**:Qt 5.15.2 (或更高版本)
|
||||||
- **构建系统**:CMake 3.10+
|
- **构建系统**:CMake 3.10+
|
||||||
- **系统接口**:Qt DBus
|
- **系统接口**:
|
||||||
- **平台**:Linux Ubuntu
|
- Linux: Qt DBus
|
||||||
|
- macOS: Foundation Framework (NSDistributedNotificationCenter)
|
||||||
|
- **平台**:Linux Ubuntu / macOS 10.12+
|
||||||
|
|
||||||
## 系统要求
|
## 系统要求
|
||||||
|
|
||||||
- Linux Ubuntu 18.04 或更高版本(也支持 Deepin OS)
|
### Linux
|
||||||
- Qt 5.15.2(安装在 `$HOME/sdk/qt-5.15.2`)
|
- Linux Ubuntu 18.04 或更高版本(也支持 Deepin OS、Fedora 等)
|
||||||
|
- Qt 5.15.2 或更高版本
|
||||||
- CMake 3.10 或更高版本
|
- CMake 3.10 或更高版本
|
||||||
- GCC/G++ 编译器(支持 C++11)
|
- GCC/G++ 编译器(支持 C++11)
|
||||||
- DBus 系统服务
|
- DBus 系统服务
|
||||||
|
|
||||||
|
### macOS
|
||||||
|
- macOS 10.12 (Sierra) 或更高版本
|
||||||
|
- Qt 5.15.2 或更高版本(可通过 Homebrew 安装)
|
||||||
|
- CMake 3.10 或更高版本
|
||||||
|
- Xcode Command Line Tools
|
||||||
|
- Foundation 和 Cocoa 框架(系统自带)
|
||||||
|
|
||||||
## 安装与编译
|
## 安装与编译
|
||||||
|
|
||||||
### 1. 确保 Qt5 已安装
|
### macOS 平台
|
||||||
|
|
||||||
|
#### 1. 安装依赖
|
||||||
|
|
||||||
|
使用 Homebrew 安装 Qt5:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 检查 Qt5 目录是否存在
|
# 安装 Homebrew(如果尚未安装)
|
||||||
|
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||||
|
|
||||||
|
# 安装 Qt5
|
||||||
|
brew install qt@5
|
||||||
|
|
||||||
|
# 安装 CMake(如果尚未安装)
|
||||||
|
brew install cmake
|
||||||
|
```
|
||||||
|
|
||||||
|
或者从 Qt 官网下载安装器:https://www.qt.io/download
|
||||||
|
|
||||||
|
#### 2. 编译项目
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 赋予脚本执行权限
|
||||||
|
chmod +x build_mac.sh run_mac.sh
|
||||||
|
|
||||||
|
# 编译
|
||||||
|
./build_mac.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
脚本会自动搜索 Qt 安装路径。如果需要手动指定,可以设置环境变量:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export Qt5_DIR=/path/to/qt/lib/cmake/Qt5
|
||||||
|
./build_mac.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Linux 平台
|
||||||
|
|
||||||
|
#### 1. 确保 Qt5 已安装
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Ubuntu/Debian
|
||||||
|
sudo apt-get install qt5-default qtbase5-dev libqt5dbus5
|
||||||
|
|
||||||
|
# Fedora
|
||||||
|
sudo dnf install qt5-qtbase-devel qt5-qtbase-gui
|
||||||
|
|
||||||
|
# 或使用自定义安装的 Qt
|
||||||
ls $HOME/sdk/qt-5.15.2
|
ls $HOME/sdk/qt-5.15.2
|
||||||
```
|
```
|
||||||
|
|
||||||
如果 Qt5 安装在其他位置,请修改 `CMakeLists.txt` 中的 Qt5_DIR 路径:
|
如果 Qt5 安装在其他位置,请修改 `CMakeLists.txt` 中的 Qt5_DIR 路径或设置环境变量。
|
||||||
|
|
||||||
```cmake
|
#### 2. 赋予脚本执行权限
|
||||||
set(Qt5_DIR "$ENV{HOME}/sdk/qt-5.15.2/lib/cmake/Qt5")
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 赋予脚本执行权限
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
chmod +x build.sh run.sh
|
chmod +x build.sh run.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. 编译项目
|
#### 3. 编译项目
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./build.sh
|
./build.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
编译成功后,可执行文件将生成在 `build/bin/ScreenLockDemo`
|
编译成功后,可执行文件将生成在 `build/bin/ScreenLockDetector`
|
||||||
|
|
||||||
## 运行应用
|
## 运行应用
|
||||||
|
|
||||||
### 方法 1:使用运行脚本(推荐)
|
### macOS 平台
|
||||||
|
|
||||||
|
#### 方法 1:使用运行脚本(推荐)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./run_mac.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 方法 2:直接运行可执行文件
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./build/bin/ScreenLockDetector
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 方法 3:手动设置环境变量并运行
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export DYLD_LIBRARY_PATH=/path/to/qt/lib:$DYLD_LIBRARY_PATH
|
||||||
|
./build/bin/ScreenLockDetector
|
||||||
|
```
|
||||||
|
|
||||||
|
### Linux 平台
|
||||||
|
|
||||||
|
#### 方法 1:使用运行脚本(推荐)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./run.sh
|
./run.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
### 方法 2:直接运行可执行文件
|
#### 方法 2:直接运行可执行文件
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd build/bin
|
cd build/bin
|
||||||
./ScreenLockDemo
|
./ScreenLockDetector
|
||||||
```
|
```
|
||||||
|
|
||||||
### 方法 3:手动设置环境变量并运行
|
#### 方法 3:手动设置环境变量并运行
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
export LD_LIBRARY_PATH=$HOME/sdk/qt-5.15.2/lib:$LD_LIBRARY_PATH
|
export LD_LIBRARY_PATH=$HOME/sdk/qt-5.15.2/lib:$LD_LIBRARY_PATH
|
||||||
./build/bin/ScreenLockDemo
|
./build/bin/ScreenLockDetector
|
||||||
```
|
```
|
||||||
|
|
||||||
## 使用说明
|
## 使用说明
|
||||||
|
|
@ -103,7 +186,8 @@ export LD_LIBRARY_PATH=$HOME/sdk/qt-5.15.2/lib:$LD_LIBRARY_PATH
|
||||||
1. **启动应用**:运行应用后,会看到一个带有动态动画的窗口
|
1. **启动应用**:运行应用后,会看到一个带有动态动画的窗口
|
||||||
|
|
||||||
2. **测试锁屏检测**:
|
2. **测试锁屏检测**:
|
||||||
- 使用快捷键锁定屏幕:`Ctrl + Alt + L` 或 `Super + L`
|
- **macOS**: 使用快捷键 `Ctrl + Cmd + Q` 或从菜单栏选择"锁定屏幕"
|
||||||
|
- **Linux**: 使用快捷键 `Ctrl + Alt + L` 或 `Super + L`
|
||||||
- 观察动画是否停止
|
- 观察动画是否停止
|
||||||
- 解锁后动画应自动恢复
|
- 解锁后动画应自动恢复
|
||||||
|
|
||||||
|
|
@ -120,7 +204,7 @@ export LD_LIBRARY_PATH=$HOME/sdk/qt-5.15.2/lib:$LD_LIBRARY_PATH
|
||||||
|
|
||||||
## 工作原理
|
## 工作原理
|
||||||
|
|
||||||
### DBus 监听机制
|
### Linux: DBus 监听机制
|
||||||
|
|
||||||
应用程序通过 Qt DBus 连接到 Linux 系统的锁屏服务:
|
应用程序通过 Qt DBus 连接到 Linux 系统的锁屏服务:
|
||||||
|
|
||||||
|
|
@ -148,6 +232,29 @@ export LD_LIBRARY_PATH=$HOME/sdk/qt-5.15.2/lib:$LD_LIBRARY_PATH
|
||||||
Signals: Lock(), Unlock()
|
Signals: Lock(), Unlock()
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### macOS: 分布式通知中心
|
||||||
|
|
||||||
|
应用程序通过 NSDistributedNotificationCenter 监听 macOS 系统通知:
|
||||||
|
|
||||||
|
1. **屏幕锁定通知**
|
||||||
|
```
|
||||||
|
Notification: com.apple.screenIsLocked
|
||||||
|
当用户锁定屏幕时发送
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **屏幕解锁通知**
|
||||||
|
```
|
||||||
|
Notification: com.apple.screenIsUnlocked
|
||||||
|
当用户解锁屏幕时发送
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **屏幕保护程序通知**(辅助检测)
|
||||||
|
```
|
||||||
|
Notifications:
|
||||||
|
- com.apple.screensaver.didstart
|
||||||
|
- com.apple.screensaver.didstop
|
||||||
|
```
|
||||||
|
|
||||||
### Paint 事件控制
|
### Paint 事件控制
|
||||||
|
|
||||||
当检测到锁屏时:
|
当检测到锁屏时:
|
||||||
|
|
@ -165,24 +272,72 @@ export LD_LIBRARY_PATH=$HOME/sdk/qt-5.15.2/lib:$LD_LIBRARY_PATH
|
||||||
## 项目结构
|
## 项目结构
|
||||||
|
|
||||||
```
|
```
|
||||||
qt_screan_lock/
|
ScreenLockDetector/
|
||||||
├── CMakeLists.txt # CMake 构建配置
|
├── CMakeLists.txt # CMake 构建配置(跨平台)
|
||||||
├── README.md # 项目文档
|
├── README.md # 项目文档
|
||||||
├── build.sh # 编译脚本
|
├── build.sh # Linux 编译脚本
|
||||||
├── run.sh # 运行脚本
|
├── run.sh # Linux 运行脚本
|
||||||
|
├── build_mac.sh # macOS 编译脚本
|
||||||
|
├── run_mac.sh # macOS 运行脚本
|
||||||
└── src/
|
└── src/
|
||||||
├── main.cpp # 程序入口
|
├── main.cpp # 程序入口
|
||||||
├── mainwindow.h # 主窗口头文件
|
├── mainwindow.h # 主窗口头文件
|
||||||
├── mainwindow.cpp # 主窗口实现
|
├── mainwindow.cpp # 主窗口实现
|
||||||
├── screenlockdetector.h # 锁屏检测器头文件
|
├── screenlockdetector.h # 跨平台锁屏检测器头文件
|
||||||
├── screenlockdetector.cpp # 锁屏检测器实现
|
├── screenlockdetector.cpp # 跨平台锁屏检测器实现
|
||||||
├── customwidget.h # 自定义组件头文件
|
├── screenlockdetector_mac.h # macOS 特定实现头文件
|
||||||
└── customwidget.cpp # 自定义组件实现
|
├── screenlockdetector_mac.mm # macOS 特定实现(Objective-C++)
|
||||||
|
├── customwidget.h # 自定义组件头文件
|
||||||
|
└── customwidget.cpp # 自定义组件实现
|
||||||
```
|
```
|
||||||
|
|
||||||
## 故障排除
|
## 故障排除
|
||||||
|
|
||||||
### 问题 1:锁屏检测不工作
|
### macOS 平台
|
||||||
|
|
||||||
|
#### 问题 1:应用无法检测到锁屏
|
||||||
|
|
||||||
|
**可能原因**:
|
||||||
|
- 权限问题
|
||||||
|
- 系统通知未正常工作
|
||||||
|
|
||||||
|
**解决方案**:
|
||||||
|
```bash
|
||||||
|
# 查看应用日志
|
||||||
|
./run_mac.sh 2>&1 | grep "ScreenLock"
|
||||||
|
|
||||||
|
# 检查系统完整性保护(SIP)状态
|
||||||
|
csrutil status
|
||||||
|
|
||||||
|
# 确保应用有必要的权限
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 问题 2:编译错误 - Qt5 not found
|
||||||
|
|
||||||
|
**解决方案**:
|
||||||
|
```bash
|
||||||
|
# 使用 Homebrew 安装 Qt5
|
||||||
|
brew install qt@5
|
||||||
|
|
||||||
|
# 设置 Qt5_DIR 环境变量
|
||||||
|
export Qt5_DIR=$(brew --prefix qt@5)/lib/cmake/Qt5
|
||||||
|
./build_mac.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 问题 3:运行时找不到 Qt 库
|
||||||
|
|
||||||
|
**解决方案**:
|
||||||
|
```bash
|
||||||
|
# 设置 DYLD_LIBRARY_PATH
|
||||||
|
export DYLD_LIBRARY_PATH=$(brew --prefix qt@5)/lib:$DYLD_LIBRARY_PATH
|
||||||
|
|
||||||
|
# 或使用 run_mac.sh 脚本(已包含此配置)
|
||||||
|
./run_mac.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Linux 平台
|
||||||
|
|
||||||
|
#### 问题 1:锁屏检测不工作
|
||||||
|
|
||||||
**可能原因**:
|
**可能原因**:
|
||||||
- DBus 服务未运行
|
- DBus 服务未运行
|
||||||
|
|
@ -272,6 +427,13 @@ Qt Screen Lock Detection Demo
|
||||||
|
|
||||||
## 更新日志
|
## 更新日志
|
||||||
|
|
||||||
|
### v2.0.0 (2024)
|
||||||
|
- ✅ **重大更新**: 新增 macOS 平台支持
|
||||||
|
- ✅ 实现跨平台架构(Linux + macOS)
|
||||||
|
- ✅ macOS: 使用 NSDistributedNotificationCenter 监听系统通知
|
||||||
|
- ✅ 创建平台特定的构建和运行脚本
|
||||||
|
- ✅ 更新文档,包含 macOS 使用说明
|
||||||
|
|
||||||
### v1.1.0 (2024)
|
### v1.1.0 (2024)
|
||||||
- ✅ 新增 Deepin OS (DDE) 锁屏检测支持
|
- ✅ 新增 Deepin OS (DDE) 锁屏检测支持
|
||||||
- ✅ 优化多桌面环境兼容性
|
- ✅ 优化多桌面环境兼容性
|
||||||
|
|
|
||||||
16
build.sh
16
build.sh
|
|
@ -17,15 +17,15 @@ echo "========================================"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# Check if Qt5 directory exists
|
# Check if Qt5 directory exists
|
||||||
QT5_DIR="$HOME/sdk/qt-5.15.2"
|
# QT5_DIR="$HOME/sdk/qt-5.15.2"
|
||||||
if [ ! -d "$QT5_DIR" ]; then
|
# if [ ! -d "$QT5_DIR" ]; then
|
||||||
echo -e "${RED}Error: Qt5 directory not found at $QT5_DIR${NC}"
|
# echo -e "${RED}Error: Qt5 directory not found at $QT5_DIR${NC}"
|
||||||
echo "Please install Qt5 or update the path in CMakeLists.txt"
|
# echo "Please install Qt5 or update the path in CMakeLists.txt"
|
||||||
exit 1
|
# exit 1
|
||||||
fi
|
# fi
|
||||||
|
|
||||||
echo -e "${GREEN}✓ Qt5 directory found: $QT5_DIR${NC}"
|
# echo -e "${GREEN}✓ Qt5 directory found: $QT5_DIR${NC}"
|
||||||
echo ""
|
# echo ""
|
||||||
|
|
||||||
# Create build directory
|
# Create build directory
|
||||||
BUILD_DIR="build"
|
BUILD_DIR="build"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,117 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# macOS Build Script for ScreenLockDetector
|
||||||
|
# This script builds the project on macOS
|
||||||
|
|
||||||
|
set -e # Exit on error
|
||||||
|
|
||||||
|
echo "=========================================="
|
||||||
|
echo "Building ScreenLockDetector for macOS"
|
||||||
|
echo "=========================================="
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# Check if we're on macOS
|
||||||
|
if [[ "$OSTYPE" != "darwin"* ]]; then
|
||||||
|
echo -e "${RED}Error: This script is for macOS only${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Function to find Qt installation
|
||||||
|
find_qt() {
|
||||||
|
# Try to find Qt in common locations
|
||||||
|
QT_PATHS=(
|
||||||
|
"/opt/local" # MacPorts
|
||||||
|
"/usr/local/opt/qt@5" # Homebrew (Intel)
|
||||||
|
"/opt/homebrew/opt/qt@5" # Homebrew (Apple Silicon)
|
||||||
|
"$HOME/Qt/5.15.2/clang_64" # Official Qt installer
|
||||||
|
"$HOME/sdk/qt-5.15.2" # Custom installation
|
||||||
|
)
|
||||||
|
|
||||||
|
for path in "${QT_PATHS[@]}"; do
|
||||||
|
if [ -d "$path" ]; then
|
||||||
|
# Check if Qt cmake files exist
|
||||||
|
if [ -f "$path/lib/cmake/Qt5/Qt5Config.cmake" ]; then
|
||||||
|
echo "$path"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Find Qt installation
|
||||||
|
echo "Searching for Qt installation..."
|
||||||
|
QT_PATH=$(find_qt)
|
||||||
|
|
||||||
|
if [ -z "$QT_PATH" ]; then
|
||||||
|
echo -e "${YELLOW}Warning: Qt not found in common locations${NC}"
|
||||||
|
echo "Please install Qt 5 using one of these methods:"
|
||||||
|
echo " 1. MacPorts: sudo port install qt5"
|
||||||
|
echo " 2. Homebrew: brew install qt@5"
|
||||||
|
echo " 3. Official installer: https://www.qt.io/download"
|
||||||
|
echo ""
|
||||||
|
echo "Or set Qt5_DIR environment variable manually:"
|
||||||
|
echo " export Qt5_DIR=/path/to/qt/lib/cmake/Qt5"
|
||||||
|
|
||||||
|
# Ask user if they want to continue anyway
|
||||||
|
read -p "Do you want to continue and let CMake search for Qt? (y/n) " -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo -e "${GREEN}Found Qt at: $QT_PATH${NC}"
|
||||||
|
export Qt5_DIR="$QT_PATH/lib/cmake/Qt5"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create build directory
|
||||||
|
BUILD_DIR="build"
|
||||||
|
if [ -d "$BUILD_DIR" ]; then
|
||||||
|
echo "Cleaning existing build directory..."
|
||||||
|
rm -rf "$BUILD_DIR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Creating build directory..."
|
||||||
|
mkdir -p "$BUILD_DIR"
|
||||||
|
|
||||||
|
# Run CMake
|
||||||
|
echo ""
|
||||||
|
echo "Running CMake configuration..."
|
||||||
|
cd "$BUILD_DIR"
|
||||||
|
|
||||||
|
if [ -n "$Qt5_DIR" ]; then
|
||||||
|
cmake .. -DCMAKE_BUILD_TYPE=Release -DQt5_DIR="$Qt5_DIR"
|
||||||
|
else
|
||||||
|
cmake .. -DCMAKE_BUILD_TYPE=Release
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build the project
|
||||||
|
echo ""
|
||||||
|
echo "Building project..."
|
||||||
|
make -j$(sysctl -n hw.ncpu)
|
||||||
|
|
||||||
|
# Check if build succeeded
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo ""
|
||||||
|
echo -e "${GREEN}=========================================="
|
||||||
|
echo "Build completed successfully!"
|
||||||
|
echo "==========================================${NC}"
|
||||||
|
echo ""
|
||||||
|
echo "Executable location: $BUILD_DIR/bin/ScreenLockDetector"
|
||||||
|
echo ""
|
||||||
|
echo "To run the application:"
|
||||||
|
echo " ./run_mac.sh"
|
||||||
|
echo " or"
|
||||||
|
echo " ./build/bin/ScreenLockDetector"
|
||||||
|
else
|
||||||
|
echo -e "${RED}=========================================="
|
||||||
|
echo "Build failed!"
|
||||||
|
echo "==========================================${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# macOS Run Script for ScreenLockDetector
|
||||||
|
# This script runs the application on macOS
|
||||||
|
|
||||||
|
set -e # Exit on error
|
||||||
|
|
||||||
|
echo "=========================================="
|
||||||
|
echo "Running ScreenLockDetector on macOS"
|
||||||
|
echo "=========================================="
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# Check if we're on macOS
|
||||||
|
if [[ "$OSTYPE" != "darwin"* ]]; then
|
||||||
|
echo -e "${RED}Error: This script is for macOS only${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if executable exists
|
||||||
|
EXECUTABLE="build/bin/ScreenLockDetector"
|
||||||
|
|
||||||
|
if [ ! -f "$EXECUTABLE" ]; then
|
||||||
|
echo -e "${RED}Error: Executable not found at $EXECUTABLE${NC}"
|
||||||
|
echo ""
|
||||||
|
echo "Please build the project first:"
|
||||||
|
echo " ./build_mac.sh"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Function to find Qt installation
|
||||||
|
find_qt() {
|
||||||
|
# Try to find Qt in common locations
|
||||||
|
QT_PATHS=(
|
||||||
|
"/opt/local" # MacPorts
|
||||||
|
"/usr/local/opt/qt@5" # Homebrew (Intel)
|
||||||
|
"/opt/homebrew/opt/qt@5" # Homebrew (Apple Silicon)
|
||||||
|
"$HOME/Qt/5.15.2/clang_64" # Official Qt installer
|
||||||
|
"$HOME/sdk/qt-5.15.2" # Custom installation
|
||||||
|
)
|
||||||
|
|
||||||
|
for path in "${QT_PATHS[@]}"; do
|
||||||
|
if [ -d "$path" ]; then
|
||||||
|
# Check if Qt cmake files exist
|
||||||
|
if [ -f "$path/lib/cmake/Qt5/Qt5Config.cmake" ]; then
|
||||||
|
echo "$path"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Find Qt installation and set up library path
|
||||||
|
QT_PATH=$(find_qt)
|
||||||
|
|
||||||
|
if [ -n "$QT_PATH" ]; then
|
||||||
|
echo -e "${GREEN}Found Qt at: $QT_PATH${NC}"
|
||||||
|
export DYLD_LIBRARY_PATH="$QT_PATH/lib:$DYLD_LIBRARY_PATH"
|
||||||
|
export DYLD_FRAMEWORK_PATH="$QT_PATH/lib:$DYLD_FRAMEWORK_PATH"
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}Warning: Qt not found in common locations${NC}"
|
||||||
|
echo "If the application fails to run, please set DYLD_LIBRARY_PATH manually:"
|
||||||
|
echo " export DYLD_LIBRARY_PATH=/path/to/qt/lib:\$DYLD_LIBRARY_PATH"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Run the application
|
||||||
|
echo ""
|
||||||
|
echo "Starting ScreenLockDetector..."
|
||||||
|
echo "=========================================="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
./"$EXECUTABLE"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Application exited."
|
||||||
|
|
@ -1,23 +1,36 @@
|
||||||
#include "screenlockdetector.h"
|
#include "screenlockdetector.h"
|
||||||
|
|
||||||
|
#ifdef Q_OS_MAC
|
||||||
|
#include "screenlockdetector_mac.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
#include <QDBusMessage>
|
#include <QDBusMessage>
|
||||||
#include <QDBusConnection>
|
#include <QDBusConnection>
|
||||||
#include <QDBusConnectionInterface>
|
#include <QDBusConnectionInterface>
|
||||||
#include <QDBusReply>
|
#include <QDBusReply>
|
||||||
|
#endif
|
||||||
|
|
||||||
ScreenLockDetector::ScreenLockDetector(QObject *parent)
|
ScreenLockDetector::ScreenLockDetector(QObject *parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, m_isLocked(false)
|
, m_isLocked(false)
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
, m_gnomeInterface(nullptr)
|
, m_gnomeInterface(nullptr)
|
||||||
, m_loginInterface(nullptr)
|
, m_loginInterface(nullptr)
|
||||||
, m_deepinInterface(nullptr)
|
, m_deepinInterface(nullptr)
|
||||||
, m_gnomeConnected(false)
|
, m_gnomeConnected(false)
|
||||||
, m_loginConnected(false)
|
, m_loginConnected(false)
|
||||||
, m_deepinConnected(false)
|
, m_deepinConnected(false)
|
||||||
|
#endif
|
||||||
|
#ifdef Q_OS_MAC
|
||||||
|
, m_macDetector(nullptr)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ScreenLockDetector::~ScreenLockDetector()
|
ScreenLockDetector::~ScreenLockDetector()
|
||||||
{
|
{
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
if (m_gnomeInterface) {
|
if (m_gnomeInterface) {
|
||||||
delete m_gnomeInterface;
|
delete m_gnomeInterface;
|
||||||
m_gnomeInterface = nullptr;
|
m_gnomeInterface = nullptr;
|
||||||
|
|
@ -32,6 +45,14 @@ ScreenLockDetector::~ScreenLockDetector()
|
||||||
delete m_deepinInterface;
|
delete m_deepinInterface;
|
||||||
m_deepinInterface = nullptr;
|
m_deepinInterface = nullptr;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef Q_OS_MAC
|
||||||
|
if (m_macDetector) {
|
||||||
|
delete m_macDetector;
|
||||||
|
m_macDetector = nullptr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ScreenLockDetector::isScreenLocked() const
|
bool ScreenLockDetector::isScreenLocked() const
|
||||||
|
|
@ -41,8 +62,40 @@ bool ScreenLockDetector::isScreenLocked() const
|
||||||
|
|
||||||
bool ScreenLockDetector::initialize()
|
bool ScreenLockDetector::initialize()
|
||||||
{
|
{
|
||||||
|
#ifdef Q_OS_MAC
|
||||||
qDebug() << "=================================================";
|
qDebug() << "=================================================";
|
||||||
qDebug() << "Initializing ScreenLockDetector...";
|
qDebug() << "Initializing ScreenLockDetector for macOS...";
|
||||||
|
qDebug() << "=================================================";
|
||||||
|
|
||||||
|
// 创建 macOS 特定的检测器
|
||||||
|
m_macDetector = new ScreenLockDetectorMac(this);
|
||||||
|
|
||||||
|
// 连接信号
|
||||||
|
connect(m_macDetector, &ScreenLockDetectorMac::screenLocked,
|
||||||
|
this, &ScreenLockDetector::screenLocked);
|
||||||
|
connect(m_macDetector, &ScreenLockDetectorMac::screenUnlocked,
|
||||||
|
this, &ScreenLockDetector::screenUnlocked);
|
||||||
|
connect(m_macDetector, &ScreenLockDetectorMac::lockStateChanged,
|
||||||
|
this, [this](bool locked) {
|
||||||
|
m_isLocked = locked;
|
||||||
|
emit lockStateChanged(locked);
|
||||||
|
});
|
||||||
|
|
||||||
|
bool success = m_macDetector->initialize();
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
qDebug() << "=================================================";
|
||||||
|
qDebug() << "ScreenLockDetector initialized successfully on macOS";
|
||||||
|
qDebug() << "=================================================";
|
||||||
|
} else {
|
||||||
|
qWarning() << "Failed to initialize ScreenLockDetector on macOS";
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
|
||||||
|
#elif defined(Q_OS_LINUX)
|
||||||
|
qDebug() << "=================================================";
|
||||||
|
qDebug() << "Initializing ScreenLockDetector for Linux...";
|
||||||
qDebug() << "=================================================";
|
qDebug() << "=================================================";
|
||||||
|
|
||||||
// 尝试连接到不同的DBus接口
|
// 尝试连接到不同的DBus接口
|
||||||
|
|
@ -60,13 +113,18 @@ bool ScreenLockDetector::initialize()
|
||||||
queryCurrentLockState();
|
queryCurrentLockState();
|
||||||
|
|
||||||
qDebug() << "=================================================";
|
qDebug() << "=================================================";
|
||||||
qDebug() << "ScreenLockDetector initialized successfully";
|
qDebug() << "ScreenLockDetector initialized successfully on Linux";
|
||||||
qDebug() << "Deepin DDE connected:" << m_deepinConnected;
|
qDebug() << "Deepin DDE connected:" << m_deepinConnected;
|
||||||
qDebug() << "GNOME ScreenSaver connected:" << m_gnomeConnected;
|
qDebug() << "GNOME ScreenSaver connected:" << m_gnomeConnected;
|
||||||
qDebug() << "Login Manager connected:" << m_loginConnected;
|
qDebug() << "Login Manager connected:" << m_loginConnected;
|
||||||
qDebug() << "=================================================";
|
qDebug() << "=================================================";
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
#else
|
||||||
|
qWarning() << "ScreenLockDetector: Unsupported platform";
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreenLockDetector::setLockState(bool locked)
|
void ScreenLockDetector::setLockState(bool locked)
|
||||||
|
|
@ -88,6 +146,8 @@ void ScreenLockDetector::setLockState(bool locked)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
|
||||||
bool ScreenLockDetector::connectToGnomeScreenSaver()
|
bool ScreenLockDetector::connectToGnomeScreenSaver()
|
||||||
{
|
{
|
||||||
qDebug() << "\n--- Connecting to GNOME ScreenSaver ---";
|
qDebug() << "\n--- Connecting to GNOME ScreenSaver ---";
|
||||||
|
|
@ -451,3 +511,5 @@ void ScreenLockDetector::onSessionUnlocked()
|
||||||
qDebug() << "##################################################";
|
qDebug() << "##################################################";
|
||||||
setLockState(false);
|
setLockState(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // Q_OS_LINUX
|
||||||
|
|
@ -2,20 +2,34 @@
|
||||||
#define SCREENLOCKDETECTOR_H
|
#define SCREENLOCKDETECTOR_H
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
#include <QDBusConnection>
|
#include <QDBusConnection>
|
||||||
#include <QDBusInterface>
|
#include <QDBusInterface>
|
||||||
#include <QDBusReply>
|
#include <QDBusReply>
|
||||||
#include <QDBusContext>
|
#include <QDBusContext>
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
|
// 前向声明
|
||||||
|
#ifdef Q_OS_MAC
|
||||||
|
class ScreenLockDetectorMac;
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 屏幕锁定检测器类
|
* @brief 跨平台屏幕锁定检测器类
|
||||||
*
|
*
|
||||||
* 通过监听Linux系统的DBus信号来检测屏幕锁定/解锁状态
|
* Linux: 通过监听DBus信号来检测屏幕锁定/解锁状态
|
||||||
* 支持多种桌面环境:Deepin DDE, GNOME, KDE, XFCE等
|
* 支持多种桌面环境:Deepin DDE, GNOME, KDE, XFCE等
|
||||||
|
*
|
||||||
|
* macOS: 通过监听NSDistributedNotificationCenter的系统通知
|
||||||
*/
|
*/
|
||||||
class ScreenLockDetector : public QObject, protected QDBusContext
|
class ScreenLockDetector : public QObject
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
, protected QDBusContext
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
|
@ -30,7 +44,7 @@ public:
|
||||||
bool isScreenLocked() const;
|
bool isScreenLocked() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 初始化DBus连接
|
* @brief 初始化平台特定的锁屏检测
|
||||||
* @return true 如果初始化成功,否则返回 false
|
* @return true 如果初始化成功,否则返回 false
|
||||||
*/
|
*/
|
||||||
bool initialize();
|
bool initialize();
|
||||||
|
|
@ -54,6 +68,7 @@ signals:
|
||||||
*/
|
*/
|
||||||
void lockStateChanged(bool locked);
|
void lockStateChanged(bool locked);
|
||||||
|
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
private slots:
|
private slots:
|
||||||
/**
|
/**
|
||||||
* @brief 处理GNOME屏幕保护程序的DBus信号
|
* @brief 处理GNOME屏幕保护程序的DBus信号
|
||||||
|
|
@ -63,7 +78,7 @@ private slots:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 处理DEEPIN屏幕保护程序的DBus信号
|
* @brief 处理DEEPIN屏幕保护程序的DBus信号
|
||||||
* @param active 屏幕保护程序是否激活
|
* @param visible 屏幕保护程序是否可见
|
||||||
*/
|
*/
|
||||||
void onLockFrontVisible(bool visible);
|
void onLockFrontVisible(bool visible);
|
||||||
|
|
||||||
|
|
@ -76,6 +91,7 @@ private slots:
|
||||||
* @brief 处理登录管理器的会话解锁信号
|
* @brief 处理登录管理器的会话解锁信号
|
||||||
*/
|
*/
|
||||||
void onSessionUnlocked();
|
void onSessionUnlocked();
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
|
|
@ -84,6 +100,7 @@ private:
|
||||||
*/
|
*/
|
||||||
void setLockState(bool locked);
|
void setLockState(bool locked);
|
||||||
|
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
/**
|
/**
|
||||||
* @brief 连接到GNOME屏幕保护程序的DBus接口
|
* @brief 连接到GNOME屏幕保护程序的DBus接口
|
||||||
* @return true 如果连接成功
|
* @return true 如果连接成功
|
||||||
|
|
@ -112,15 +129,23 @@ private:
|
||||||
* @return 当前会话的路径,如果无法确定则返回空字符串
|
* @return 当前会话的路径,如果无法确定则返回空字符串
|
||||||
*/
|
*/
|
||||||
QString getCurrentSessionPath();
|
QString getCurrentSessionPath();
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_isLocked; // 当前锁屏状态
|
bool m_isLocked; // 当前锁屏状态
|
||||||
|
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
QDBusInterface *m_gnomeInterface; // GNOME屏幕保护程序接口
|
QDBusInterface *m_gnomeInterface; // GNOME屏幕保护程序接口
|
||||||
QDBusInterface *m_loginInterface; // 登录管理器接口
|
QDBusInterface *m_loginInterface; // 登录管理器接口
|
||||||
QDBusInterface *m_deepinInterface; // Deepin DDE接口
|
QDBusInterface *m_deepinInterface; // Deepin DDE接口
|
||||||
bool m_gnomeConnected; // GNOME接口是否连接成功
|
bool m_gnomeConnected; // GNOME接口是否连接成功
|
||||||
bool m_loginConnected; // 登录管理器接口是否连接成功
|
bool m_loginConnected; // 登录管理器接口是否连接成功
|
||||||
bool m_deepinConnected; // Deepin DDE接口是否连接成功
|
bool m_deepinConnected; // Deepin DDE接口是否连接成功
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef Q_OS_MAC
|
||||||
|
ScreenLockDetectorMac *m_macDetector; // macOS 特定的检测器
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SCREENLOCKDETECTOR_H
|
#endif // SCREENLOCKDETECTOR_H
|
||||||
|
|
@ -0,0 +1,100 @@
|
||||||
|
#ifndef SCREENLOCKDETECTOR_MAC_H
|
||||||
|
#define SCREENLOCKDETECTOR_MAC_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#ifdef Q_OS_MAC
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief macOS 屏幕锁定检测器类
|
||||||
|
*
|
||||||
|
* 通过监听 macOS 的分布式通知中心来检测屏幕锁定/解锁状态
|
||||||
|
* 使用 NSDistributedNotificationCenter 监听系统通知
|
||||||
|
*/
|
||||||
|
class ScreenLockDetectorMac : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ScreenLockDetectorMac(QObject *parent = nullptr);
|
||||||
|
~ScreenLockDetectorMac();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取当前锁屏状态
|
||||||
|
* @return true 如果屏幕已锁定,否则返回 false
|
||||||
|
*/
|
||||||
|
bool isScreenLocked() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 初始化通知监听
|
||||||
|
* @return true 如果初始化成功,否则返回 false
|
||||||
|
*/
|
||||||
|
bool initialize();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
/**
|
||||||
|
* @brief 屏幕锁定信号
|
||||||
|
* 当检测到屏幕被锁定时发出
|
||||||
|
*/
|
||||||
|
void screenLocked();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 屏幕解锁信号
|
||||||
|
* 当检测到屏幕被解锁时发出
|
||||||
|
*/
|
||||||
|
void screenUnlocked();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 锁屏状态改变信号
|
||||||
|
* @param locked true表示已锁定,false表示已解锁
|
||||||
|
*/
|
||||||
|
void lockStateChanged(bool locked);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief 处理屏幕锁定通知的回调
|
||||||
|
*/
|
||||||
|
void handleScreenLocked();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 处理屏幕解锁通知的回调
|
||||||
|
*/
|
||||||
|
void handleScreenUnlocked();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 处理屏幕保护程序启动通知的回调
|
||||||
|
*/
|
||||||
|
void handleScreenSaverStarted();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 处理屏幕保护程序停止通知的回调
|
||||||
|
*/
|
||||||
|
void handleScreenSaverStopped();
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* @brief 设置锁屏状态
|
||||||
|
* @param locked 新的锁屏状态
|
||||||
|
*/
|
||||||
|
void setLockState(bool locked);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 注册通知观察者
|
||||||
|
* @return true 如果注册成功
|
||||||
|
*/
|
||||||
|
bool registerNotificationObservers();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 注销通知观察者
|
||||||
|
*/
|
||||||
|
void unregisterNotificationObservers();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_isLocked; // 当前锁屏状态
|
||||||
|
void *m_observerToken; // Objective-C 观察者令牌(不透明指针)
|
||||||
|
bool m_initialized; // 是否已初始化
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // Q_OS_MAC
|
||||||
|
|
||||||
|
#endif // SCREENLOCKDETECTOR_MAC_H
|
||||||
|
|
@ -0,0 +1,243 @@
|
||||||
|
#include "screenlockdetector_mac.h"
|
||||||
|
|
||||||
|
#ifdef Q_OS_MAC
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
// Objective-C 观察者类,用于接收通知
|
||||||
|
@interface ScreenLockObserver : NSObject
|
||||||
|
@property (nonatomic, assign) ScreenLockDetectorMac *detector;
|
||||||
|
- (instancetype)initWithDetector:(ScreenLockDetectorMac *)detector;
|
||||||
|
- (void)screenLocked:(NSNotification *)notification;
|
||||||
|
- (void)screenUnlocked:(NSNotification *)notification;
|
||||||
|
- (void)screenSaverStarted:(NSNotification *)notification;
|
||||||
|
- (void)screenSaverStopped:(NSNotification *)notification;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation ScreenLockObserver
|
||||||
|
|
||||||
|
- (instancetype)initWithDetector:(ScreenLockDetectorMac *)detector
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
_detector = detector;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)screenLocked:(NSNotification *)notification
|
||||||
|
{
|
||||||
|
NSLog(@"[ScreenLockObserver] Screen locked notification received");
|
||||||
|
if (_detector) {
|
||||||
|
_detector->handleScreenLocked();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)screenUnlocked:(NSNotification *)notification
|
||||||
|
{
|
||||||
|
NSLog(@"[ScreenLockObserver] Screen unlocked notification received");
|
||||||
|
if (_detector) {
|
||||||
|
_detector->handleScreenUnlocked();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)screenSaverStarted:(NSNotification *)notification
|
||||||
|
{
|
||||||
|
NSLog(@"[ScreenLockObserver] Screen saver started notification received");
|
||||||
|
if (_detector) {
|
||||||
|
_detector->handleScreenSaverStarted();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)screenSaverStopped:(NSNotification *)notification
|
||||||
|
{
|
||||||
|
NSLog(@"[ScreenLockObserver] Screen saver stopped notification received");
|
||||||
|
if (_detector) {
|
||||||
|
_detector->handleScreenSaverStopped();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
ScreenLockDetectorMac::ScreenLockDetectorMac(QObject *parent)
|
||||||
|
: QObject(parent)
|
||||||
|
, m_isLocked(false)
|
||||||
|
, m_observerToken(nullptr)
|
||||||
|
, m_initialized(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ScreenLockDetectorMac::~ScreenLockDetectorMac()
|
||||||
|
{
|
||||||
|
unregisterNotificationObservers();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScreenLockDetectorMac::isScreenLocked() const
|
||||||
|
{
|
||||||
|
return m_isLocked;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScreenLockDetectorMac::initialize()
|
||||||
|
{
|
||||||
|
qDebug() << "=================================================";
|
||||||
|
qDebug() << "Initializing ScreenLockDetectorMac...";
|
||||||
|
qDebug() << "=================================================";
|
||||||
|
|
||||||
|
if (m_initialized) {
|
||||||
|
qWarning() << "ScreenLockDetectorMac already initialized";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool success = registerNotificationObservers();
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
m_initialized = true;
|
||||||
|
qDebug() << "=================================================";
|
||||||
|
qDebug() << "ScreenLockDetectorMac initialized successfully";
|
||||||
|
qDebug() << "Listening for macOS screen lock notifications";
|
||||||
|
qDebug() << "=================================================";
|
||||||
|
} else {
|
||||||
|
qWarning() << "Failed to initialize ScreenLockDetectorMac";
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScreenLockDetectorMac::registerNotificationObservers()
|
||||||
|
{
|
||||||
|
@autoreleasepool {
|
||||||
|
qDebug() << "\n--- Registering macOS notification observers ---";
|
||||||
|
|
||||||
|
// 创建观察者对象
|
||||||
|
ScreenLockObserver *observer = [[ScreenLockObserver alloc] initWithDetector:this];
|
||||||
|
// 使用 CFBridgingRetain 保持对象,并保存指针
|
||||||
|
m_observerToken = (void *)CFBridgingRetain(observer);
|
||||||
|
|
||||||
|
// 获取分布式通知中心
|
||||||
|
NSDistributedNotificationCenter *center = [NSDistributedNotificationCenter defaultCenter];
|
||||||
|
|
||||||
|
// 注册屏幕锁定通知
|
||||||
|
// macOS 使用 "com.apple.screenIsLocked" 通知
|
||||||
|
[center addObserver:observer
|
||||||
|
selector:@selector(screenLocked:)
|
||||||
|
name:@"com.apple.screenIsLocked"
|
||||||
|
object:nil
|
||||||
|
suspensionBehavior:NSNotificationSuspensionBehaviorDeliverImmediately];
|
||||||
|
|
||||||
|
qDebug() << "Registered observer for: com.apple.screenIsLocked";
|
||||||
|
|
||||||
|
// 注册屏幕解锁通知
|
||||||
|
// macOS 使用 "com.apple.screenIsUnlocked" 通知
|
||||||
|
[center addObserver:observer
|
||||||
|
selector:@selector(screenUnlocked:)
|
||||||
|
name:@"com.apple.screenIsUnlocked"
|
||||||
|
object:nil
|
||||||
|
suspensionBehavior:NSNotificationSuspensionBehaviorDeliverImmediately];
|
||||||
|
|
||||||
|
qDebug() << "Registered observer for: com.apple.screenIsUnlocked";
|
||||||
|
|
||||||
|
// 注册屏幕保护程序启动通知(可选,作为备用检测方式)
|
||||||
|
[center addObserver:observer
|
||||||
|
selector:@selector(screenSaverStarted:)
|
||||||
|
name:@"com.apple.screensaver.didstart"
|
||||||
|
object:nil
|
||||||
|
suspensionBehavior:NSNotificationSuspensionBehaviorDeliverImmediately];
|
||||||
|
|
||||||
|
qDebug() << "Registered observer for: com.apple.screensaver.didstart";
|
||||||
|
|
||||||
|
// 注册屏幕保护程序停止通知(可选,作为备用检测方式)
|
||||||
|
[center addObserver:observer
|
||||||
|
selector:@selector(screenSaverStopped:)
|
||||||
|
name:@"com.apple.screensaver.didstop"
|
||||||
|
object:nil
|
||||||
|
suspensionBehavior:NSNotificationSuspensionBehaviorDeliverImmediately];
|
||||||
|
|
||||||
|
qDebug() << "Registered observer for: com.apple.screensaver.didstop";
|
||||||
|
|
||||||
|
qDebug() << "Successfully registered all notification observers";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenLockDetectorMac::unregisterNotificationObservers()
|
||||||
|
{
|
||||||
|
@autoreleasepool {
|
||||||
|
if (m_observerToken) {
|
||||||
|
qDebug() << "Unregistering macOS notification observers";
|
||||||
|
|
||||||
|
// 使用 CFBridgingRelease 释放对象
|
||||||
|
ScreenLockObserver *observer = (ScreenLockObserver *)CFBridgingRelease(m_observerToken);
|
||||||
|
NSDistributedNotificationCenter *center = [NSDistributedNotificationCenter defaultCenter];
|
||||||
|
|
||||||
|
// 移除所有通知观察者
|
||||||
|
[center removeObserver:observer];
|
||||||
|
|
||||||
|
m_observerToken = nullptr;
|
||||||
|
m_initialized = false;
|
||||||
|
|
||||||
|
qDebug() << "Notification observers unregistered";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenLockDetectorMac::setLockState(bool locked)
|
||||||
|
{
|
||||||
|
if (m_isLocked != locked) {
|
||||||
|
m_isLocked = locked;
|
||||||
|
|
||||||
|
qDebug() << "##################################################";
|
||||||
|
qDebug() << "## Screen lock state changed:" << (locked ? "LOCKED" : "UNLOCKED");
|
||||||
|
qDebug() << "##################################################";
|
||||||
|
|
||||||
|
emit lockStateChanged(locked);
|
||||||
|
|
||||||
|
if (locked) {
|
||||||
|
emit screenLocked();
|
||||||
|
} else {
|
||||||
|
emit screenUnlocked();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenLockDetectorMac::handleScreenLocked()
|
||||||
|
{
|
||||||
|
qDebug() << "##################################################";
|
||||||
|
qDebug() << "## macOS LOCK NOTIFICATION RECEIVED";
|
||||||
|
qDebug() << "## Screen is now LOCKED";
|
||||||
|
qDebug() << "##################################################";
|
||||||
|
setLockState(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenLockDetectorMac::handleScreenUnlocked()
|
||||||
|
{
|
||||||
|
qDebug() << "##################################################";
|
||||||
|
qDebug() << "## macOS UNLOCK NOTIFICATION RECEIVED";
|
||||||
|
qDebug() << "## Screen is now UNLOCKED";
|
||||||
|
qDebug() << "##################################################";
|
||||||
|
setLockState(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenLockDetectorMac::handleScreenSaverStarted()
|
||||||
|
{
|
||||||
|
qDebug() << "##################################################";
|
||||||
|
qDebug() << "## macOS SCREEN SAVER STARTED";
|
||||||
|
qDebug() << "## Note: Screen saver started (may not be locked yet)";
|
||||||
|
qDebug() << "##################################################";
|
||||||
|
// 屏幕保护程序启动不一定意味着锁定
|
||||||
|
// 只有在设置中启用了"从睡眠或屏幕保护程序恢复时需要密码"时才会锁定
|
||||||
|
// 我们可以选择在这里设置锁定状态,或者等待真正的锁定通知
|
||||||
|
// 为了保守起见,这里不设置锁定状态
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenLockDetectorMac::handleScreenSaverStopped()
|
||||||
|
{
|
||||||
|
qDebug() << "##################################################";
|
||||||
|
qDebug() << "## macOS SCREEN SAVER STOPPED";
|
||||||
|
qDebug() << "## Note: Screen saver stopped";
|
||||||
|
qDebug() << "##################################################";
|
||||||
|
// 屏幕保护程序停止,但解锁通知会单独发送
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // Q_OS_MAC
|
||||||
Loading…
Reference in New Issue