ScreenLockDetector/src/screenlockdetector.cpp

454 lines
15 KiB
C++
Raw 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.

#include "screenlockdetector.h"
#include <QDBusMessage>
#include <QDBusConnection>
#include <QDBusConnectionInterface>
#include <QDBusReply>
ScreenLockDetector::ScreenLockDetector(QObject *parent)
: QObject(parent)
, m_isLocked(false)
, m_gnomeInterface(nullptr)
, m_loginInterface(nullptr)
, m_deepinInterface(nullptr)
, m_gnomeConnected(false)
, m_loginConnected(false)
, m_deepinConnected(false)
{
}
ScreenLockDetector::~ScreenLockDetector()
{
if (m_gnomeInterface) {
delete m_gnomeInterface;
m_gnomeInterface = nullptr;
}
if (m_loginInterface) {
delete m_loginInterface;
m_loginInterface = nullptr;
}
if (m_deepinInterface) {
delete m_deepinInterface;
m_deepinInterface = nullptr;
}
}
bool ScreenLockDetector::isScreenLocked() const
{
return m_isLocked;
}
bool ScreenLockDetector::initialize()
{
qDebug() << "=================================================";
qDebug() << "Initializing ScreenLockDetector...";
qDebug() << "=================================================";
// 尝试连接到不同的DBus接口
bool deepinOk = connectToDeepinDDE();
bool gnomeOk = connectToGnomeScreenSaver();
bool loginOk = connectToLoginManager();
if (!deepinOk && !gnomeOk && !loginOk) {
qWarning() << "Failed to connect to any screen lock detection service";
qWarning() << "Make sure you are running on a supported Linux desktop environment";
return false;
}
// 查询当前锁屏状态
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;
}
void ScreenLockDetector::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();
}
}
}
bool ScreenLockDetector::connectToGnomeScreenSaver()
{
qDebug() << "\n--- Connecting to GNOME ScreenSaver ---";
// 连接到GNOME屏幕保护程序的DBus接口
m_gnomeInterface = new QDBusInterface(
"org.gnome.ScreenSaver",
"/org/gnome/ScreenSaver",
"org.gnome.ScreenSaver",
QDBusConnection::sessionBus(),
this
);
if (!m_gnomeInterface->isValid()) {
qDebug() << "GNOME ScreenSaver interface not available:"
<< m_gnomeInterface->lastError().message();
delete m_gnomeInterface;
m_gnomeInterface = nullptr;
return false;
}
qDebug() << "GNOME ScreenSaver interface is valid";
// 连接ActiveChanged信号
bool connected = QDBusConnection::sessionBus().connect(
"org.gnome.ScreenSaver",
"/org/gnome/ScreenSaver",
"org.gnome.ScreenSaver",
"ActiveChanged",
this,
SLOT(onScreenSaverActiveChanged(bool))
);
qDebug() << "GNOME ActiveChanged signal connected:" << connected;
if (!connected) {
qWarning() << "Failed to connect to GNOME ScreenSaver ActiveChanged signal";
delete m_gnomeInterface;
m_gnomeInterface = nullptr;
return false;
}
m_gnomeConnected = true;
qDebug() << "Successfully connected to GNOME ScreenSaver";
return true;
}
bool ScreenLockDetector::connectToLoginManager()
{
qDebug() << "\n--- Connecting to Login Manager (systemd-logind) ---";
// 首先获取当前会话的路径
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;
}
// 方法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",
"Lock",
this,
SLOT(onSessionLocked())
);
bool unlockConnected = QDBusConnection::systemBus().connect(
"org.freedesktop.login1",
"", // 空路径表示监听所有对象
"org.freedesktop.login1.Session",
"Unlock",
this,
SLOT(onSessionUnlocked())
);
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;
}
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()
{
qDebug() << "\n--- Connecting to Deepin DDE ---";
// 可能的服务配置列表
struct DeepinService {
QString service;
QString path;
QString interface;
QString lockSignal;
QString unlockSignal;
};
QList<DeepinService> services = {
// Deepin 20/23 主要接口
{"com.deepin.dde.lockFront", "/com/deepin/dde/lockFront", "com.deepin.dde.lockFront", "Visible", "Visible"},
// 备用接口
{"com.deepin.daemon.ScreenSaver", "/com/deepin/daemon/ScreenSaver", "com.deepin.daemon.ScreenSaver", "ActiveChanged", "ActiveChanged"},
};
for (const auto& svc : services) {
qDebug() << "Trying Deepin service:" << svc.service;
m_deepinInterface = new QDBusInterface(
svc.service,
svc.path,
svc.interface,
QDBusConnection::sessionBus(),
this
);
if (!m_deepinInterface->isValid()) {
qDebug() << " Interface not available:" << m_deepinInterface->lastError().message();
delete m_deepinInterface;
m_deepinInterface = nullptr;
continue;
}
qDebug() << " Interface is valid, connecting signals...";
// 尝试连接锁屏信号
bool visibleConnected = QDBusConnection::sessionBus().connect(
svc.service,
svc.path,
svc.interface,
svc.lockSignal,
this,
SLOT(onLockFrontVisible(bool))
);
qDebug() << " Visible signal (" << svc.lockSignal << ") connected:" << visibleConnected;
if (visibleConnected) {
m_deepinConnected = true;
qDebug() << "Successfully connected to Deepin DDE via" << svc.service;
qDebug() << "Listening for signals:" << svc.lockSignal;
return true;
}
qWarning() << " Failed to connect signals for" << svc.service;
delete m_deepinInterface;
m_deepinInterface = nullptr;
}
qWarning() << "Failed to connect to any Deepin DDE lock service";
return false;
}
void ScreenLockDetector::queryCurrentLockState()
{
qDebug() << "\n--- Querying current lock state ---";
// 尝试从Deepin DDE查询当前状态
if (m_deepinInterface && m_deepinInterface->isValid()) {
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() << " Method" << method << "returned:" << (locked ? "LOCKED" : "UNLOCKED");
setLockState(locked);
return;
}
}
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/LOCKED" : "INACTIVE/UNLOCKED");
setLockState(active);
return;
}
}
// 尝试从登录管理器查询锁定状态
if (m_loginInterface && m_loginInterface->isValid()) {
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()) {
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() << "##################################################";
qDebug() << "## GNOME ScreenSaver ActiveChanged signal received";
qDebug() << "## New state:" << (active ? "ACTIVE (LOCKED)" : "INACTIVE (UNLOCKED)");
qDebug() << "##################################################";
setLockState(active);
}
void ScreenLockDetector::onLockFrontVisible(bool visible)
{
qDebug() << "##################################################";
qDebug() << "## DEEPIN LockFront Visible signal received";
qDebug() << "## New state:" << (visible ? "ACTIVE (LOCKED)" : "INACTIVE (UNLOCKED)");
qDebug() << "##################################################";
setLockState(visible);
}
void ScreenLockDetector::onSessionLocked()
{
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";
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);
}