mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2025-03-01 10:33:28 +00:00
Add Suspend/Resume support (#1535)
* Add Suspend/Resume support * Support Suspend/Resume/Restart via API, UI and Systray * Support screen lock/unlock scenario * Handle idle scenario * Align with fix for #1368 * Update Windows build * Refactor SuspendHandler to maintain state * Do not start BG-Effect, if system goes into suspend mode * Correct Idle and Resume interaction
This commit is contained in:
@@ -251,6 +251,78 @@ QString JsonConnection::getSysInfo()
|
||||
return QString();
|
||||
}
|
||||
|
||||
void JsonConnection::suspend()
|
||||
{
|
||||
Info(_log, "Suspend Hyperion. Stop all instances and components");
|
||||
QJsonObject command;
|
||||
command["command"] = QString("system");
|
||||
command["subcommand"] = QString("suspend");
|
||||
|
||||
QJsonObject reply = sendMessage(command);
|
||||
|
||||
parseReply(reply);
|
||||
}
|
||||
|
||||
void JsonConnection::resume()
|
||||
{
|
||||
Info(_log, "Resume Hyperion. Start all instances and components");
|
||||
QJsonObject command;
|
||||
command["command"] = QString("system");
|
||||
command["subcommand"] = QString("resume");
|
||||
|
||||
QJsonObject reply = sendMessage(command);
|
||||
|
||||
parseReply(reply);
|
||||
}
|
||||
|
||||
void JsonConnection::toggleSuspend()
|
||||
{
|
||||
Info(_log, "Toggle between Suspend and Resume");
|
||||
QJsonObject command;
|
||||
command["command"] = QString("system");
|
||||
command["subcommand"] = QString("toggleSuspend");
|
||||
|
||||
QJsonObject reply = sendMessage(command);
|
||||
|
||||
parseReply(reply);
|
||||
}
|
||||
|
||||
void JsonConnection::idle()
|
||||
{
|
||||
Info(_log, "Put Hyperion in Idle mode.");
|
||||
QJsonObject command;
|
||||
command["command"] = QString("system");
|
||||
command["subcommand"] = QString("idle");
|
||||
|
||||
QJsonObject reply = sendMessage(command);
|
||||
|
||||
parseReply(reply);
|
||||
}
|
||||
|
||||
void JsonConnection::toggleIdle()
|
||||
{
|
||||
Info(_log, "Toggle between Idle and Working mode");
|
||||
QJsonObject command;
|
||||
command["command"] = QString("system");
|
||||
command["subcommand"] = QString("toggleIdle");
|
||||
|
||||
QJsonObject reply = sendMessage(command);
|
||||
|
||||
parseReply(reply);
|
||||
}
|
||||
|
||||
void JsonConnection::restart()
|
||||
{
|
||||
Info(_log, "Restart Hyperion...");
|
||||
QJsonObject command;
|
||||
command["command"] = QString("system");
|
||||
command["subcommand"] = QString("restart");
|
||||
|
||||
QJsonObject reply = sendMessage(command);
|
||||
|
||||
parseReply(reply);
|
||||
}
|
||||
|
||||
void JsonConnection::clear(int priority)
|
||||
{
|
||||
Debug(_log, "Clear priority channel [%d]", priority);
|
||||
|
@@ -99,6 +99,36 @@ public:
|
||||
///
|
||||
QString getSysInfo();
|
||||
|
||||
///
|
||||
/// Suspend Hyperion. Stop all instances and components
|
||||
///
|
||||
void suspend();
|
||||
|
||||
///
|
||||
/// Resume Hyperion. Start all instances and components
|
||||
///
|
||||
void resume();
|
||||
|
||||
///
|
||||
/// Toggle between Suspend and Resume
|
||||
///
|
||||
void toggleSuspend();
|
||||
|
||||
///
|
||||
/// Put Hyperion in Idle mode, i.e. all instances, components will be disabled besides the output processing (LED-devices, smoothing).
|
||||
///
|
||||
void idle();
|
||||
|
||||
///
|
||||
/// Toggle between Idle and Working mode
|
||||
///
|
||||
void toggleIdle();
|
||||
|
||||
///
|
||||
/// Restart Hyperion
|
||||
///
|
||||
void restart();
|
||||
|
||||
///
|
||||
/// Clear the given priority channel
|
||||
///
|
||||
|
@@ -119,8 +119,6 @@ int main(int argc, char * argv[])
|
||||
Option & argCreateEffect = parser.add<Option> (0x0, "createEffect" , "Write a new JSON Effect configuration file.\nFirst parameter = Effect name.\nSecond parameter = Effect file (--effectFile).\nLast parameter = Effect arguments (--effectArgs.)", "");
|
||||
Option & argDeleteEffect = parser.add<Option> (0x0, "deleteEffect" , "Delete a custom created JSON Effect configuration file.");
|
||||
#endif
|
||||
BooleanOption & argServerInfo = parser.add<BooleanOption>('l', "list" , "List server info and active effects with priority and duration");
|
||||
BooleanOption & argSysInfo = parser.add<BooleanOption>('s', "sysinfo" , "show system info");
|
||||
BooleanOption & argClear = parser.add<BooleanOption>('x', "clear" , "Clear data for the priority channel provided by the -p option");
|
||||
BooleanOption & argClearAll = parser.add<BooleanOption>(0x0, "clearall" , "Clear data for all active priority channels");
|
||||
Option & argEnableComponent = parser.add<Option> ('E', "enable" , "Enable the Component with the given name. Available Components are [SMOOTHING, BLACKBORDER, FORWARDER, BOBLIGHTSERVER, GRABBER, V4L, LEDDEVICE]");
|
||||
@@ -148,6 +146,14 @@ int main(int argc, char * argv[])
|
||||
BooleanOption & argConfigGet = parser.add<BooleanOption>(0x0, "configGet" , "Print the current loaded Hyperion configuration file");
|
||||
BooleanOption & argSchemaGet = parser.add<BooleanOption>(0x0, "schemaGet" , "Print the JSON schema for Hyperion configuration");
|
||||
Option & argConfigSet = parser.add<Option> (0x0, "configSet" , "Write to the actual loaded configuration file. Should be a JSON object string.");
|
||||
BooleanOption & argServerInfo = parser.add<BooleanOption>('l', "list" , "List server info and active effects with priority and duration");
|
||||
BooleanOption & argSysInfo = parser.add<BooleanOption>('s', "sysinfo" , "Show system info");
|
||||
BooleanOption & argSystemSuspend = parser.add<BooleanOption>(0x0, "suspend" , "Suspend Hyperion. Stop all instances and components");
|
||||
BooleanOption & argSystemResume = parser.add<BooleanOption>(0x0, "resume" , "Resume Hyperion. Start all instances and components");
|
||||
BooleanOption & argSystemToggleSuspend= parser.add<BooleanOption>(0x0, "toggleSuspend" , "Toggle between Suspend and Resume. First request will trigger suspend");
|
||||
BooleanOption & argSystemIdle = parser.add<BooleanOption>(0x0, "idle" , "Put Hyperion in Idle mode, i.e. all instances, components will be disabled besides the output processing (LED-devices, smoothing).");
|
||||
BooleanOption & argSystemToggleIdle = parser.add<BooleanOption>(0x0, "toggleIdle" , "Toggle between Idle and Working mode. First request will trigger Idle mode");
|
||||
BooleanOption & argSystemRestart = parser.add<BooleanOption>(0x0, "restart" , "Restart Hyperion");
|
||||
|
||||
BooleanOption & argPrint = parser.add<BooleanOption>(0x0, "print", "Print the JSON input and output messages on stdout");
|
||||
BooleanOption & argDebug = parser.add<BooleanOption>(0x0, "debug", "Enable debug logging");
|
||||
@@ -178,9 +184,13 @@ int main(int argc, char * argv[])
|
||||
#if defined(ENABLE_EFFECTENGINE)
|
||||
parser.isSet(argEffect), parser.isSet(argCreateEffect), parser.isSet(argDeleteEffect),
|
||||
#endif
|
||||
parser.isSet(argServerInfo), parser.isSet(argSysInfo),parser.isSet(argClear), parser.isSet(argClearAll), parser.isSet(argEnableComponent), parser.isSet(argDisableComponent), colorAdjust,
|
||||
parser.isSet(argSource), parser.isSet(argSourceAuto), parser.isSet(argOff), parser.isSet(argOn), parser.isSet(argConfigGet), parser.isSet(argSchemaGet), parser.isSet(argConfigSet),
|
||||
parser.isSet(argMapping),parser.isSet(argVideoMode) });
|
||||
parser.isSet(argServerInfo), parser.isSet(argSysInfo),
|
||||
parser.isSet(argSystemSuspend), parser.isSet(argSystemResume), parser.isSet(argSystemToggleSuspend),
|
||||
parser.isSet(argSystemIdle), parser.isSet(argSystemToggleIdle),
|
||||
parser.isSet(argSystemRestart),
|
||||
parser.isSet(argClear), parser.isSet(argClearAll), parser.isSet(argEnableComponent), parser.isSet(argDisableComponent), colorAdjust,
|
||||
parser.isSet(argSource), parser.isSet(argSourceAuto), parser.isSet(argOff), parser.isSet(argOn), parser.isSet(argConfigGet), parser.isSet(argSchemaGet), parser.isSet(argConfigSet),
|
||||
parser.isSet(argMapping),parser.isSet(argVideoMode) });
|
||||
if (commandCount != 1)
|
||||
{
|
||||
qWarning() << (commandCount == 0 ? "No command found." : "Multiple commands found.") << " Provide exactly one of the following options:";
|
||||
@@ -193,6 +203,12 @@ int main(int argc, char * argv[])
|
||||
#endif
|
||||
showHelp(argServerInfo);
|
||||
showHelp(argSysInfo);
|
||||
showHelp(argSystemSuspend);
|
||||
showHelp(argSystemResume);
|
||||
showHelp(argSystemToggleSuspend);
|
||||
showHelp(argSystemIdle);
|
||||
showHelp(argSystemToggleIdle);
|
||||
showHelp(argSystemRestart);
|
||||
showHelp(argClear);
|
||||
showHelp(argClearAll);
|
||||
showHelp(argEnableComponent);
|
||||
@@ -295,6 +311,30 @@ int main(int argc, char * argv[])
|
||||
{
|
||||
std::cout << "System info:\n" << connection.getSysInfo().toStdString() << std::endl;
|
||||
}
|
||||
else if (parser.isSet(argSystemSuspend))
|
||||
{
|
||||
connection.suspend();
|
||||
}
|
||||
else if (parser.isSet(argSystemResume))
|
||||
{
|
||||
connection.resume();
|
||||
}
|
||||
else if (parser.isSet(argSystemToggleSuspend))
|
||||
{
|
||||
connection.toggleSuspend();
|
||||
}
|
||||
else if (parser.isSet(argSystemIdle))
|
||||
{
|
||||
connection.idle();
|
||||
}
|
||||
else if (parser.isSet(argSystemToggleIdle))
|
||||
{
|
||||
connection.toggleIdle();
|
||||
}
|
||||
else if (parser.isSet(argSystemRestart))
|
||||
{
|
||||
connection.restart();
|
||||
}
|
||||
else if (parser.isSet(argClear))
|
||||
{
|
||||
connection.clear(argPriority.getInt(parser));
|
||||
|
@@ -30,17 +30,29 @@ if (APPLE)
|
||||
set_source_files_properties(${BUNDLE_RESOURCE_FILES} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
||||
endif(APPLE)
|
||||
|
||||
if (UNIX)
|
||||
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS DBus REQUIRED )
|
||||
if (Qt${QT_VERSION_MAJOR}DBus_FOUND)
|
||||
set(hyperiond_POWER_MNG_DBUS "Qt${QT_VERSION_MAJOR}::DBus")
|
||||
endif()
|
||||
endif(UNIX)
|
||||
|
||||
add_executable(${PROJECT_NAME}
|
||||
console.h
|
||||
hyperiond.h
|
||||
systray.h
|
||||
hyperiond.cpp
|
||||
systray.cpp
|
||||
SuspendHandler.cpp
|
||||
main.cpp
|
||||
${hyperiond_WIN_RC_PATH}
|
||||
${BUNDLE_RESOURCE_FILES}
|
||||
)
|
||||
|
||||
if (UNIX AND NOT APPLE AND Qt${QT_VERSION_MAJOR}DBus_FOUND)
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC HYPERION_HAS_DBUS)
|
||||
endif()
|
||||
|
||||
# promote hyperiond as GUI app
|
||||
if (WIN32)
|
||||
target_link_options(${PROJECT_NAME} PUBLIC /SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup)
|
||||
@@ -58,6 +70,7 @@ target_link_libraries(${PROJECT_NAME}
|
||||
Qt${QT_VERSION_MAJOR}::Gui
|
||||
Qt${QT_VERSION_MAJOR}::Network
|
||||
Qt${QT_VERSION_MAJOR}::Widgets
|
||||
${hyperiond_POWER_MNG_DBUS}
|
||||
)
|
||||
|
||||
if(ENABLE_EFFECTENGINE)
|
||||
|
312
src/hyperiond/SuspendHandler.cpp
Normal file
312
src/hyperiond/SuspendHandler.cpp
Normal file
@@ -0,0 +1,312 @@
|
||||
#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())
|
||||
{
|
||||
Error(Logger::getInstance("DAEMON"), "Suspend/resume handler - System bus is not connected");
|
||||
}
|
||||
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())
|
||||
{
|
||||
Error(Logger::getInstance("DAEMON"), "Lock/unlock handler- Session bus is not connected");
|
||||
}
|
||||
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
|
79
src/hyperiond/SuspendHandler.h
Normal file
79
src/hyperiond/SuspendHandler.h
Normal file
@@ -0,0 +1,79 @@
|
||||
#ifndef SUSPENDHANDLER_H
|
||||
#define SUSPENDHANDLER_H
|
||||
#include <QObject>
|
||||
|
||||
class SuspendHandlerBase : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SuspendHandlerBase();
|
||||
virtual ~SuspendHandlerBase() override;
|
||||
|
||||
public slots:
|
||||
|
||||
void suspend(bool sleep);
|
||||
|
||||
void suspend();
|
||||
void resume();
|
||||
void toggleSuspend();
|
||||
|
||||
void idle(bool isIdle);
|
||||
void toggleIdle();
|
||||
|
||||
void lock(bool isLocked);
|
||||
|
||||
signals:
|
||||
|
||||
void suspendEvent();
|
||||
void resumeEvent();
|
||||
void lockedEvent(bool);
|
||||
void idleEvent(bool);
|
||||
|
||||
private:
|
||||
|
||||
bool _isSuspended;
|
||||
bool _isIdle;
|
||||
bool _isLocked;
|
||||
};
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <QAbstractNativeEventFilter>
|
||||
#include <QAbstractEventDispatcher>
|
||||
#include <QWidget>
|
||||
#include <windows.h>
|
||||
|
||||
class SuspendHandlerWindows : public SuspendHandlerBase, public QAbstractNativeEventFilter {
|
||||
|
||||
public:
|
||||
SuspendHandlerWindows();
|
||||
~SuspendHandlerWindows() override;
|
||||
|
||||
protected:
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
bool nativeEventFilter(const QByteArray& eventType, void* message, qintptr* result) override;
|
||||
#else
|
||||
bool nativeEventFilter(const QByteArray& eventType, void* message, long int* result) override;
|
||||
#endif
|
||||
|
||||
private:
|
||||
QWidget _widget;
|
||||
HPOWERNOTIFY _notifyHandle;
|
||||
};
|
||||
|
||||
using SuspendHandler = SuspendHandlerWindows;
|
||||
|
||||
#elif defined(__linux__) && defined(HYPERION_HAS_DBUS)
|
||||
|
||||
class SuspendHandlerLinux : public SuspendHandlerBase {
|
||||
|
||||
public:
|
||||
SuspendHandlerLinux();
|
||||
};
|
||||
|
||||
using SuspendHandler = SuspendHandlerLinux;
|
||||
|
||||
#else
|
||||
using SuspendHandler = SuspendHandlerBase;
|
||||
#endif
|
||||
|
||||
#endif // SUSPENDHANDLER_H
|
@@ -96,6 +96,7 @@ HyperionDaemon::HyperionDaemon(const QString& rootPath, QObject* parent, bool lo
|
||||
#ifdef ENABLE_CEC
|
||||
, _cecHandler(nullptr)
|
||||
#endif
|
||||
, _suspendHandler(nullptr)
|
||||
, _currVideoMode(VideoMode::VIDEO_2D)
|
||||
{
|
||||
HyperionDaemon::daemon = this;
|
||||
@@ -171,6 +172,8 @@ HyperionDaemon::HyperionDaemon(const QString& rootPath, QObject* parent, bool lo
|
||||
|
||||
// ---- network services -----
|
||||
startNetworkServices();
|
||||
|
||||
_suspendHandler = new SuspendHandler();
|
||||
}
|
||||
|
||||
HyperionDaemon::~HyperionDaemon()
|
||||
@@ -337,6 +340,8 @@ void HyperionDaemon::freeObjects()
|
||||
}
|
||||
#endif
|
||||
|
||||
delete _suspendHandler;
|
||||
|
||||
// stop Hyperions (non blocking)
|
||||
_instanceManager->stopAll();
|
||||
|
||||
|
@@ -69,6 +69,8 @@
|
||||
#include <utils/settings.h>
|
||||
#include <utils/Components.h>
|
||||
|
||||
#include "SuspendHandler.h"
|
||||
|
||||
class HyperionIManager;
|
||||
class SysTray;
|
||||
class JsonServer;
|
||||
@@ -102,6 +104,11 @@ public:
|
||||
///
|
||||
WebServer *getWebServerInstance() { return _webserver; }
|
||||
|
||||
///
|
||||
/// @brief Get suspense handler pointer
|
||||
///
|
||||
SuspendHandler* getSuspendHandlerInstance() { return _suspendHandler; }
|
||||
|
||||
///
|
||||
/// @brief Get the current videoMode
|
||||
///
|
||||
@@ -198,10 +205,11 @@ private:
|
||||
QtWrapper* _qtGrabber;
|
||||
DirectXWrapper* _dxGrabber;
|
||||
SSDPHandler* _ssdp;
|
||||
|
||||
#ifdef ENABLE_CEC
|
||||
CECHandler* _cecHandler;
|
||||
#endif
|
||||
SuspendHandler* _suspendHandler;
|
||||
|
||||
#if defined(ENABLE_FLATBUF_SERVER)
|
||||
FlatBufferServer* _flatBufferServer;
|
||||
#endif
|
||||
|
@@ -46,6 +46,7 @@
|
||||
|
||||
#include "hyperiond.h"
|
||||
#include "systray.h"
|
||||
#include "SuspendHandler.h"
|
||||
|
||||
using namespace commandline;
|
||||
|
||||
@@ -54,8 +55,8 @@ using namespace commandline;
|
||||
#ifndef _WIN32
|
||||
void signal_handler(int signum)
|
||||
{
|
||||
// Hyperion Managment instance
|
||||
HyperionIManager *_hyperion = HyperionIManager::getInstance();
|
||||
HyperionDaemon* hyperiond = HyperionDaemon::getInstance();
|
||||
SuspendHandler* suspendHandler = hyperiond->getSuspendHandlerInstance();
|
||||
|
||||
if (signum == SIGCHLD)
|
||||
{
|
||||
@@ -64,16 +65,16 @@ void signal_handler(int signum)
|
||||
}
|
||||
else if (signum == SIGUSR1)
|
||||
{
|
||||
if (_hyperion != nullptr)
|
||||
if (suspendHandler != nullptr)
|
||||
{
|
||||
_hyperion->toggleStateAllInstances(false);
|
||||
suspendHandler->suspend();
|
||||
}
|
||||
}
|
||||
else if (signum == SIGUSR2)
|
||||
{
|
||||
if (_hyperion != nullptr)
|
||||
if (suspendHandler != nullptr)
|
||||
{
|
||||
_hyperion->toggleStateAllInstances(true);
|
||||
suspendHandler->resume();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -171,8 +172,8 @@ int main(int argc, char** argv)
|
||||
#ifdef WIN32
|
||||
BooleanOption & consoleOption = parser.add<BooleanOption> ('c', "console", "Open a console window to view log output");
|
||||
#endif
|
||||
parser.add<BooleanOption> (0x0, "desktop", "Show systray on desktop");
|
||||
parser.add<BooleanOption> (0x0, "service", "Force hyperion to start as console service");
|
||||
parser.add<BooleanOption> (0x0, "desktop", "Show systray on desktop");
|
||||
parser.add<BooleanOption> (0x0, "service", "Force hyperion to start as console service");
|
||||
#if defined(ENABLE_EFFECTENGINE)
|
||||
Option & exportEfxOption = parser.add<Option> (0x0, "export-effects", "Export effects to given path");
|
||||
#endif
|
||||
|
@@ -12,6 +12,7 @@
|
||||
#include <QColor>
|
||||
#include <QDesktopServices>
|
||||
#include <QSettings>
|
||||
#include <QtGlobal>
|
||||
|
||||
#include <utils/ColorRgb.h>
|
||||
#include <utils/Process.h>
|
||||
@@ -24,6 +25,7 @@
|
||||
|
||||
#include "hyperiond.h"
|
||||
#include "systray.h"
|
||||
#include "SuspendHandler.h"
|
||||
|
||||
SysTray::SysTray(HyperionDaemon *hyperiond)
|
||||
: QWidget()
|
||||
@@ -31,6 +33,7 @@ SysTray::SysTray(HyperionDaemon *hyperiond)
|
||||
, _hyperiond(hyperiond)
|
||||
, _hyperion(nullptr)
|
||||
, _instanceManager(HyperionIManager::getInstance())
|
||||
, _suspendHandler (hyperiond->getSuspendHandlerInstance())
|
||||
, _webPort(8090)
|
||||
{
|
||||
Q_INIT_RESOURCE(resources);
|
||||
@@ -79,7 +82,15 @@ void SysTray::createTrayIcon()
|
||||
|
||||
restartAction = new QAction(tr("&Restart"), this);
|
||||
restartAction->setIcon(QPixmap(":/restart.svg"));
|
||||
connect(restartAction, &QAction::triggered, this , [=](){ Process::restartHyperion(11); });
|
||||
connect(restartAction, &QAction::triggered, this , [=](){ Process::restartHyperion(12); });
|
||||
|
||||
suspendAction = new QAction(tr("&Suspend"), this);
|
||||
suspendAction->setIcon(QPixmap(":/suspend.svg"));
|
||||
connect(suspendAction, &QAction::triggered, _suspendHandler, QOverload<>::of(&SuspendHandler::suspend));
|
||||
|
||||
resumeAction = new QAction(tr("&Resume"), this);
|
||||
resumeAction->setIcon(QPixmap(":/resume.svg"));
|
||||
connect(resumeAction, &QAction::triggered, _suspendHandler, &SuspendHandler::resume);
|
||||
|
||||
colorAction = new QAction(tr("&Color"), this);
|
||||
colorAction->setIcon(QPixmap(":/color.svg"));
|
||||
@@ -102,7 +113,7 @@ void SysTray::createTrayIcon()
|
||||
_trayIconEfxMenu->setIcon(QPixmap(":/effects.svg"));
|
||||
|
||||
// custom effects
|
||||
for (auto efx : efxs)
|
||||
for (const auto &efx : efxs)
|
||||
{
|
||||
if (efx.file.mid(0, 1) != ":")
|
||||
{
|
||||
@@ -117,7 +128,7 @@ void SysTray::createTrayIcon()
|
||||
_trayIconEfxMenu->addSeparator();
|
||||
|
||||
// build in effects
|
||||
for (auto efx : efxs)
|
||||
for (const auto &efx : efxs)
|
||||
{
|
||||
if (efx.file.mid(0, 1) == ":")
|
||||
{
|
||||
@@ -145,7 +156,16 @@ void SysTray::createTrayIcon()
|
||||
#endif
|
||||
_trayIconMenu->addAction(clearAction);
|
||||
_trayIconMenu->addSeparator();
|
||||
_trayIconMenu->addAction(restartAction);
|
||||
|
||||
_trayIconSystemMenu = new QMenu(_trayIconMenu);
|
||||
_trayIconSystemMenu->setTitle(tr("Instances"));
|
||||
|
||||
_trayIconSystemMenu->addAction(suspendAction);
|
||||
_trayIconSystemMenu->addAction(resumeAction);
|
||||
_trayIconSystemMenu->addAction(restartAction);
|
||||
_trayIconMenu->addMenu(_trayIconSystemMenu);
|
||||
|
||||
_trayIconMenu->addSeparator();
|
||||
_trayIconMenu->addAction(quitAction);
|
||||
|
||||
_trayIcon = new QSystemTrayIcon(this);
|
||||
@@ -180,7 +200,7 @@ void SysTray::setAutorunState()
|
||||
|
||||
void SysTray::setColor(const QColor & color)
|
||||
{
|
||||
std::vector<ColorRgb> rgbColor{ ColorRgb{ (uint8_t)color.red(), (uint8_t)color.green(), (uint8_t)color.blue() } };
|
||||
std::vector<ColorRgb> rgbColor{ ColorRgb{ static_cast<uint8_t>(color.red()), static_cast<uint8_t>(color.green()), static_cast<uint8_t>(color.blue()) } };
|
||||
|
||||
_hyperion->setColor(PriorityMuxer::FG_PRIORITY,rgbColor, PriorityMuxer::ENDLESS);
|
||||
}
|
||||
|
@@ -12,6 +12,7 @@
|
||||
|
||||
#include <hyperion/Hyperion.h>
|
||||
#include <hyperion/HyperionIManager.h>
|
||||
#include "SuspendHandler.h"
|
||||
|
||||
class HyperionDaemon;
|
||||
|
||||
@@ -61,6 +62,8 @@ private:
|
||||
|
||||
QAction *quitAction;
|
||||
QAction *restartAction;
|
||||
QAction *suspendAction;
|
||||
QAction *resumeAction;
|
||||
QAction *startAction;
|
||||
QAction *stopAction;
|
||||
QAction *colorAction;
|
||||
@@ -75,9 +78,12 @@ private:
|
||||
#if defined(ENABLE_EFFECTENGINE)
|
||||
QMenu *_trayIconEfxMenu;
|
||||
#endif
|
||||
QMenu *_trayIconSystemMenu;
|
||||
QColorDialog _colorDlg;
|
||||
HyperionDaemon *_hyperiond;
|
||||
Hyperion *_hyperion;
|
||||
HyperionIManager *_instanceManager;
|
||||
quint16 _webPort;
|
||||
|
||||
SuspendHandler *_suspendHandler;
|
||||
};
|
||||
|
Reference in New Issue
Block a user