hyperion.ng/src/hyperiond/SuspendHandler.cpp

313 lines
7.6 KiB
C++

#include "SuspendHandler.h"
#include <QtGlobal>
#include <hyperion/HyperionIManager.h>
#include <iostream>
SuspendHandlerBase::SuspendHandlerBase()
: _isSuspended(false)
, _isIdle(false)
, _isLocked (false)
{
// Trigger suspend/resume/idle scenarios to be executed by Instance mMnager
connect(this, &SuspendHandlerBase::suspendEvent, HyperionIManager::getInstance(), &HyperionIManager::suspend);
connect(this, &SuspendHandlerBase::resumeEvent, HyperionIManager::getInstance(), &HyperionIManager::resume);
connect(this, &SuspendHandlerBase::lockedEvent, HyperionIManager::getInstance(), &HyperionIManager::toggleIdle);
connect(this, &SuspendHandlerBase::idleEvent, HyperionIManager::getInstance(), &HyperionIManager::toggleIdle);
// Listen to suspend/resume/idle events received by the Instance Manager via API
connect(HyperionIManager::getInstance(), &HyperionIManager::triggerSuspend, this, QOverload<bool>::of(&SuspendHandler::suspend));
connect(HyperionIManager::getInstance(), &HyperionIManager::triggerToggleSuspend, this, &SuspendHandler::toggleSuspend);
connect(HyperionIManager::getInstance(), &HyperionIManager::triggerIdle, this, &SuspendHandler::idle);
connect(HyperionIManager::getInstance(), &HyperionIManager::triggerToggleIdle, this, &SuspendHandler::toggleIdle);
}
SuspendHandlerBase::~SuspendHandlerBase()
{
}
void SuspendHandlerBase::suspend()
{
Debug(Logger::getInstance("DAEMON"), "");
suspend(true);
}
void SuspendHandlerBase::suspend(bool sleep)
{
if (sleep)
{
if (!_isSuspended)
{
_isSuspended = true;
Info(Logger::getInstance("DAEMON"), "Suspend event received - Hyperion is going to sleep");
emit suspendEvent();
}
else
{
Debug(Logger::getInstance("DAEMON"), "Suspend event ignored - already suspended");
}
}
else
{
if (_isSuspended || _isIdle)
{
Info(Logger::getInstance("DAEMON"), "Resume event received - Hyperion is going into working mode");
emit resumeEvent();
_isSuspended = false;
_isIdle = false;
}
else
{
Debug(Logger::getInstance("DAEMON"), "Resume event ignored - not in suspend nor idle mode");
}
}
}
void SuspendHandlerBase::resume()
{
Debug(Logger::getInstance("DAEMON"), "");
suspend(false);
}
void SuspendHandlerBase::toggleSuspend()
{
Debug(Logger::getInstance("DAEMON"), "Toggle suspend event received");
if (!_isSuspended)
{
suspend(true);
}
else
{
suspend(false);
}
}
void SuspendHandlerBase::idle(bool isIdle)
{
if (!_isSuspended)
{
if (isIdle)
{
if (!_isIdle)
{
_isIdle = true;
Info(Logger::getInstance("DAEMON"), "Idle event received");
emit idleEvent(isIdle);
}
}
else
{
if (_isIdle)
{
Info(Logger::getInstance("DAEMON"), "Resume from idle event recevied");
emit idleEvent(isIdle);
_isIdle = false;
}
}
}
else
{
Debug(Logger::getInstance("DAEMON"), "Idle event ignored - Hyperion is suspended");
}
}
void SuspendHandlerBase::toggleIdle()
{
Debug(Logger::getInstance("DAEMON"), "Toggle idle event received");
if (!_isIdle)
{
idle(true);
}
else
{
idle(false);
}
}
void SuspendHandlerBase::lock(bool isLocked)
{
if (!_isSuspended)
{
if (isLocked)
{
if (!_isLocked)
{
_isLocked = true;
Info(Logger::getInstance("DAEMON"), "Screen lock event received");
emit lockedEvent(isLocked);
}
}
else
{
if (_isLocked)
{
Info(Logger::getInstance("DAEMON"), "Screen unlock event received");
emit lockedEvent(isLocked);
_isLocked = false;
}
}
}
else
{
Debug(Logger::getInstance("DAEMON"), "Screen lock event ignored - Hyperion is suspended");
}
}
#if defined(_WIN32)
#include <QCoreApplication>
#include <QWidget>
#include <windows.h>
#include <wtsapi32.h>
#pragma comment( lib, "wtsapi32.lib" )
SuspendHandlerWindows::SuspendHandlerWindows()
{
auto handle = reinterpret_cast<HWND> (_widget.winId());
_notifyHandle = RegisterSuspendResumeNotification(handle, DEVICE_NOTIFY_WINDOW_HANDLE);
if (_notifyHandle != NULL)
{
QCoreApplication::instance()->installNativeEventFilter(this);
}
else
{
Error(Logger::getInstance("DAEMON"), "Could not register for suspend/resume events!");
}
if (!WTSRegisterSessionNotification(handle, NOTIFY_FOR_THIS_SESSION))
{
Error(Logger::getInstance("DAEMON"), "Could not register for lock/unlock events!");
}
}
SuspendHandlerWindows::~SuspendHandlerWindows()
{
if (_notifyHandle != NULL)
{
QCoreApplication::instance()->removeNativeEventFilter(this);
UnregisterSuspendResumeNotification(_notifyHandle);
auto handle = reinterpret_cast<HWND> (_widget.winId());
WTSUnRegisterSessionNotification(handle);
}
_notifyHandle = NULL;
}
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
bool SuspendHandlerWindows::nativeEventFilter(const QByteArray& eventType, void* message, qintptr* /*result*/)
#else
bool SuspendHandlerWindows::nativeEventFilter(const QByteArray& eventType, void* message, long int* /*result*/)
#endif
{
MSG* msg = static_cast<MSG*>(message);
switch (msg->message)
{
case WM_WTSSESSION_CHANGE:
switch (msg->wParam)
{
case WTS_SESSION_LOCK:
emit lock(true);
return true;
break;
case WTS_SESSION_UNLOCK:
emit lock(false);
return true;
break;
}
break;
case WM_POWERBROADCAST:
switch (msg->wParam)
{
case PBT_APMRESUMESUSPEND:
emit suspend(false);
return true;
break;
case PBT_APMSUSPEND:
emit suspend(true);
return true;
break;
}
break;
}
return false;
}
#elif defined(__linux__) && defined(HYPERION_HAS_DBUS)
#include <QDBusConnection>
struct dBusSignals
{
QString service;
QString path;
QString interface;
QString name;
};
typedef QMultiMap<QString, dBusSignals> DbusSignalsMap;
// Constants
namespace {
const DbusSignalsMap dbusSignals = {
//system signals
{"Suspend", {"org.freedesktop.login1","/org/freedesktop/login1","org.freedesktop.login1.Manager","PrepareForSleep"}},
//Session signals
{"ScreenSaver", {"org.freedesktop.ScreenSaver","/org/freedesktop/ScreenSaver","org.freedesktop.ScreenSaver","ActiveChanged"}},
{"ScreenSaver", {"org.gnome.ScreenSaver","/org/gnome/ScreenSaver","org.gnome.ScreenSaver","ActiveChanged"}},
};
} //End of constants
SuspendHandlerLinux::SuspendHandlerLinux()
{
QDBusConnection systemBus = QDBusConnection::systemBus();
if (!systemBus.isConnected())
{
Info(Logger::getInstance("DAEMON"), "The suspend/resume feature is not supported by your system configuration");
}
else
{
QString service = dbusSignals.find("Suspend").value().service;
if (!systemBus.connect(service,
dbusSignals.find("Suspend").value().path,
dbusSignals.find("Suspend").value().interface,
dbusSignals.find("Suspend").value().name,
this, SLOT(suspend(bool))))
Error(Logger::getInstance("DAEMON"), "Could not register for suspend/resume events [%s]!", QSTRING_CSTR(service));
else
{
Debug(Logger::getInstance("DAEMON"), "Registered for suspend/resume events [%s].", QSTRING_CSTR(service));
}
}
QDBusConnection sessionBus = QDBusConnection::sessionBus();
if (!sessionBus.isConnected())
{
Info(Logger::getInstance("DAEMON"), "The lock/unlock feature is not supported by your system configuration");
}
else
{
DbusSignalsMap::const_iterator iter = dbusSignals.find("ScreenSaver");
while (iter != dbusSignals.end() && iter.key() == "ScreenSaver") {
QString service = iter.value().service;
if (!sessionBus.connect(service,
iter.value().path,
iter.value().interface,
iter.value().name,
this, SLOT(lock(bool))))
Error(Logger::getInstance("DAEMON"), "Could not register for lock/unlock events [%s]!", QSTRING_CSTR(service));
else
{
Debug(Logger::getInstance("DAEMON"), "Registered for lock/unlock events [%s].", QSTRING_CSTR(service));
}
++iter;
}
}
}
#endif