Allow to enable/disable suspend & lock event handling

This commit is contained in:
LordGrey 2023-11-02 20:23:04 +01:00
parent f57c4f84ac
commit 7d3f13c7b5
15 changed files with 604 additions and 115 deletions

View File

@ -0,0 +1,11 @@
<div class="container-fluid">
<div class="row">
<div class="col-lg-12">
<h3 class="page-header"><i class="fa fa-server fa-fw"></i><span data-i18n="main_menu_events">Event Services</span></h3>
<div id="conf_cont">
</div>
</div>
</div>
</div>
<script src="/js/content_events.js"></script>

View File

@ -192,6 +192,8 @@
"conf_network_tok_intro": "Here you can create and delete tokens for API authentication. Created tokens will only be displayed once.", "conf_network_tok_intro": "Here you can create and delete tokens for API authentication. Created tokens will only be displayed once.",
"conf_network_tok_lastuse": "Last use", "conf_network_tok_lastuse": "Last use",
"conf_network_tok_title": "Token Management", "conf_network_tok_title": "Token Management",
"conf_system_events_heading_title": "System Events",
"conf_system_events_intro": "Settings related to diffent Operating System events Hyperion can handle",
"conf_webconfig_label_intro": "Webconfiguration settings. Edit wisely.", "conf_webconfig_label_intro": "Webconfiguration settings. Edit wisely.",
"dashboard_active_instance": "Selected instance", "dashboard_active_instance": "Selected instance",
"dashboard_alert_message_confedit": "Your Hyperion configuration has been modified. To apply it, restart Hyperion.", "dashboard_alert_message_confedit": "Your Hyperion configuration has been modified. To apply it, restart Hyperion.",
@ -475,6 +477,12 @@
"edt_conf_smooth_updateDelay_title": "Output delay", "edt_conf_smooth_updateDelay_title": "Output delay",
"edt_conf_smooth_updateFrequency_expl": "The output speed to your LED controller.", "edt_conf_smooth_updateFrequency_expl": "The output speed to your LED controller.",
"edt_conf_smooth_updateFrequency_title": "Update frequency", "edt_conf_smooth_updateFrequency_title": "Update frequency",
"edt_conf_system_events_lockEnable_title": "Listen to lock events",
"edt_conf_system_events_lockEnable_expl": "Listen to screen lock/unlock events",
"edt_conf_system_events_suspendEnable_title": "Listen to suspend events",
"edt_conf_system_events_suspendEnable_expl": "Listen to system suspend/resume events",
"edt_conf_system_events_suspendOnLockEnable_title": "Suspend when locked",
"edt_conf_system_events_suspendOnLockEnable_expl": "Suspend when the screen is locked, otherwise go into idle mode",
"edt_conf_v4l2_blueSignalThreshold_expl": "Darkens low blue values (recognized as black)", "edt_conf_v4l2_blueSignalThreshold_expl": "Darkens low blue values (recognized as black)",
"edt_conf_v4l2_blueSignalThreshold_title": "Blue signal threshold", "edt_conf_v4l2_blueSignalThreshold_title": "Blue signal threshold",
"edt_conf_v4l2_cecDetection_expl": "If enabled, USB capture will be temporarily disabled when CEC standby event received from HDMI bus.", "edt_conf_v4l2_cecDetection_expl": "If enabled, USB capture will be temporarily disabled when CEC standby event received from HDMI bus.",
@ -983,6 +991,8 @@
"main_menu_dashboard_token": "Dashboard", "main_menu_dashboard_token": "Dashboard",
"main_menu_effect_conf_token": "Effects", "main_menu_effect_conf_token": "Effects",
"main_menu_effectsconfigurator_token": "Effects Configurator", "main_menu_effectsconfigurator_token": "Effects Configurator",
"main_menu_events": "Event Services",
"main_menu_event_services_token": "Event Services",
"main_menu_general_conf_token": "General", "main_menu_general_conf_token": "General",
"main_menu_grabber_conf_token": "Capturing Hardware", "main_menu_grabber_conf_token": "Capturing Hardware",
"main_menu_input_selection_token": "Input Selection", "main_menu_input_selection_token": "Input Selection",

View File

@ -280,6 +280,7 @@
<li> <li>
<a class="inactive"><i class="fa fa-industry fa-fw"></i><span data-i18n="main_menu_system_token">System</span><span class="fa arrow"></span></a> <a class="inactive"><i class="fa fa-industry fa-fw"></i><span data-i18n="main_menu_system_token">System</span><span class="fa arrow"></span></a>
<ul class="nav nav-second-level"> <ul class="nav nav-second-level">
<li> <a class="inactive mnava" id="MenuItemEventServices" href="#conf_events"><i class="fa fa-server fa-fw"></i><span data-i18n="main_menu_event_services_token">Event Services</span></a> </li>
<li> <a class="inactive mnava" id="MenuItemWeb" href="#conf_webconfig" id="load_webconfig"><i class="fa fa-wrench fa-fw"></i><span data-i18n="main_menu_webconfig_token">Webconfiguration</span></a> </li> <li> <a class="inactive mnava" id="MenuItemWeb" href="#conf_webconfig" id="load_webconfig"><i class="fa fa-wrench fa-fw"></i><span data-i18n="main_menu_webconfig_token">Webconfiguration</span></a> </li>
<li> <a class="inactive mnava" id="MenuItemLogging" href="#conf_logging"><i class="fa fa-reorder fa-fw"></i><span data-i18n="main_menu_logging_token">Log</span></a> </li> <li> <a class="inactive mnava" id="MenuItemLogging" href="#conf_logging"><i class="fa fa-reorder fa-fw"></i><span data-i18n="main_menu_logging_token">Log</span></a> </li>
<li> <a class="inactive mnava" href="#update"><i class="fa fa-download fa-fw"></i><span data-i18n="main_menu_update_token">Update</span></a> </li> <li> <a class="inactive mnava" href="#update"><i class="fa fa-download fa-fw"></i><span data-i18n="main_menu_update_token">Update</span></a> </li>

View File

@ -0,0 +1,37 @@
$(document).ready(function () {
performTranslation();
var conf_editor_systemEvents = null;
if (window.showOptHelp) {
//System Events
$('#conf_cont').append(createRow('conf_cont_system_events'));
$('#conf_cont_system_events').append(createOptPanel('fa-laptop', $.i18n("conf_system_events_heading_title"), 'editor_container_system_events', 'btn_submit_system_events', 'panel-system'));
$('#conf_cont_system_events').append(createHelpTable(window.schema.systemEvents.properties, $.i18n("conf_system_events_heading_title")));
}
else {
$('#conf_cont').addClass('row');
$('#conf_cont').append(createOptPanel('fa-laptop', $.i18n("conf_system_events_heading_title"), 'editor_container_system_events', 'btn_submit_system_events'));
}
//System Events
conf_editor_systemEvents = createJsonEditor('editor_container_system_events', {
systemEvents: window.schema.systemEvents
}, true, true);
conf_editor_systemEvents.on('change', function () {
conf_editor_systemEvents.validate().length || window.readOnlyMode ? $('#btn_submit_system_events').prop('disabled', true) : $('#btn_submit_system_events').prop('disabled', false);
});
$('#btn_submit_system_events').off().on('click', function () {
requestWriteConfig(conf_editor_systemEvents.getValue());
});
//create introduction
if (window.showOptHelp) {
createHint("intro", $.i18n('conf_system_events_intro'), "editor_container_system_events");
}
removeOverlay();
});

View File

@ -248,5 +248,10 @@
"vmax": 0.08, "vmax": 0.08,
"vmin": 0 "vmin": 0
} }
] ],
"systemEvents": {
"suspendEnable": true,
"lockEnable": true
}
} }

View File

@ -112,6 +112,8 @@ public:
list << "jsonServer" << "protoServer" << "flatbufServer" << "forwarder" << "webConfig" << "network" list << "jsonServer" << "protoServer" << "flatbufServer" << "forwarder" << "webConfig" << "network"
// capture // capture
<< "framegrabber" << "grabberV4L2" << "grabberAudio" << "framegrabber" << "grabberV4L2" << "grabberAudio"
//Events
<< "systemEvents"
// other // other
<< "logger" << "general"; << "logger" << "general";

View File

@ -84,7 +84,13 @@ public slots:
void resume(); void resume();
/// ///
/// @brief Toggle the state of all Hyperion instances for an idle sceanrio (user is not interacting with the system /// @brief Toggle the state of all Hyperion instances for a suspend sceanrio (user is not interacting with the system)
/// @param isSuspend, If true all instances toggle to suspend, else to resume
///
void toggleSuspend(bool isSuspend);
///
/// @brief Toggle the state of all Hyperion instances for an idle sceanrio
/// @param isIdle, If true all instances toggle to idle, else to resume /// @param isIdle, If true all instances toggle to idle, else to resume
/// ///
void toggleIdle(bool isIdle); void toggleIdle(bool isIdle);

View File

@ -30,6 +30,7 @@ namespace settings {
NETWORK, NETWORK,
FLATBUFSERVER, FLATBUFSERVER,
PROTOSERVER, PROTOSERVER,
SYSTEMEVENTS,
INVALID INVALID
}; };
@ -42,29 +43,30 @@ namespace settings {
{ {
switch (type) switch (type)
{ {
case BGEFFECT: return "backgroundEffect"; case BGEFFECT: return "backgroundEffect";
case FGEFFECT: return "foregroundEffect"; case FGEFFECT: return "foregroundEffect";
case BLACKBORDER: return "blackborderdetector"; case BLACKBORDER: return "blackborderdetector";
case BOBLSERVER: return "boblightServer"; case BOBLSERVER: return "boblightServer";
case COLOR: return "color"; case COLOR: return "color";
case DEVICE: return "device"; case DEVICE: return "device";
case EFFECTS: return "effects"; case EFFECTS: return "effects";
case NETFORWARD: return "forwarder"; case NETFORWARD: return "forwarder";
case SYSTEMCAPTURE: return "framegrabber"; case SYSTEMCAPTURE: return "framegrabber";
case GENERAL: return "general"; case GENERAL: return "general";
case V4L2: return "grabberV4L2"; case V4L2: return "grabberV4L2";
case AUDIO: return "grabberAudio"; case AUDIO: return "grabberAudio";
case JSONSERVER: return "jsonServer"; case JSONSERVER: return "jsonServer";
case LEDCONFIG: return "ledConfig"; case LEDCONFIG: return "ledConfig";
case LEDS: return "leds"; case LEDS: return "leds";
case LOGGER: return "logger"; case LOGGER: return "logger";
case SMOOTHING: return "smoothing"; case SMOOTHING: return "smoothing";
case WEBSERVER: return "webConfig"; case WEBSERVER: return "webConfig";
case INSTCAPTURE: return "instCapture"; case INSTCAPTURE: return "instCapture";
case NETWORK: return "network"; case NETWORK: return "network";
case FLATBUFSERVER: return "flatbufServer"; case FLATBUFSERVER: return "flatbufServer";
case PROTOSERVER: return "protoServer"; case PROTOSERVER: return "protoServer";
default: return "invalid"; case SYSTEMEVENTS: return "systemEvents";
default: return "invalid";
} }
} }
@ -97,6 +99,7 @@ namespace settings {
else if (type == "network") return NETWORK; else if (type == "network") return NETWORK;
else if (type == "flatbufServer") return FLATBUFSERVER; else if (type == "flatbufServer") return FLATBUFSERVER;
else if (type == "protoServer") return PROTOSERVER; else if (type == "protoServer") return PROTOSERVER;
else if (type == "systemEvents") return SYSTEMEVENTS;
else return INVALID; else return INVALID;
} }
} }

View File

@ -83,6 +83,16 @@ void HyperionIManager::resume()
} }
} }
void HyperionIManager::toggleSuspend(bool isSuspend)
{
Info(_log,"Put all instances in %s state", isSuspend ? "suspend" : "working");
QMap<quint8, Hyperion*> instCopy = _runningInstances;
for(const auto instance : instCopy)
{
emit instance->suspendRequest(isSuspend);
}
}
void HyperionIManager::toggleIdle(bool isIdle) void HyperionIManager::toggleIdle(bool isIdle)
{ {
Info(_log,"Put all instances in %s state", isIdle ? "idle" : "working"); Info(_log,"Put all instances in %s state", isIdle ? "idle" : "working");

View File

@ -90,6 +90,10 @@
"leds": "leds":
{ {
"$ref": "schema-leds.json" "$ref": "schema-leds.json"
},
"systemEvents":
{
"$ref": "schema-systemEvents.json"
} }
}, },
"additionalProperties" : false "additionalProperties" : false

View File

@ -23,5 +23,6 @@
<file alias="schema-leds.json">schema/schema-leds.json</file> <file alias="schema-leds.json">schema/schema-leds.json</file>
<file alias="schema-instCapture.json">schema/schema-instCapture.json</file> <file alias="schema-instCapture.json">schema/schema-instCapture.json</file>
<file alias="schema-network.json">schema/schema-network.json</file> <file alias="schema-network.json">schema/schema-network.json</file>
<file alias="schema-systemEvents.json">schema/schema-systemEvents.json</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@ -0,0 +1,34 @@
{
"type" : "object",
"required" : true,
"title" : "edt_conf_system_events_heading_title",
"properties": {
"suspendEnable": {
"type": "boolean",
"required": true,
"title": "edt_conf_system_events_suspendEnable_title",
"default": true,
"propertyOrder": 1
},
"lockEnable": {
"type": "boolean",
"required": true,
"title": "edt_conf_system_events_lockEnable_title",
"default": true,
"propertyOrder": 2
},
"suspendOnLockEnable": {
"type": "boolean",
"required": false,
"title": "edt_conf_system_events_suspendOnLockEnable_title",
"default": false,
"options": {
"dependencies": {
"lockEnable": true
}
},
"propertyOrder": 3
}
},
"additionalProperties" : false
}

View File

@ -1,36 +1,195 @@
#include "SuspendHandler.h" #include "SuspendHandler.h"
#include <QtGlobal> #include <QtGlobal>
#include <QJsonDocument>
#include <QJsonObject>
#include <hyperion/HyperionIManager.h> #include <hyperion/HyperionIManager.h>
#include <iostream> #include <iostream>
SuspendHandlerBase::SuspendHandlerBase() SuspendHandlerBase::SuspendHandlerBase()
: _isSuspended(false) : _isSuspendEnabled(false)
, _isLockEnabled(false)
, _isSuspendOnLock(false)
, _isSuspendRegistered(false)
, _isLockRegistered(false)
, _isSuspended(false)
, _isIdle(false) , _isIdle(false)
, _isLocked (false) , _isLocked (false)
{ {
// Trigger suspend/resume/idle scenarios to be executed by Instance mMnager _log = Logger::getInstance("EVENTS");
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() SuspendHandlerBase::~SuspendHandlerBase()
{ {
unregisterLockHandler();
unregisterSuspendHandler();
unregisterIdleApiHandler();
unregisterSuspendApiHandler();
}
void SuspendHandlerBase::handleSettingsUpdate(settings::type type, const QJsonDocument& config)
{
if(type == settings::SYSTEMEVENTS)
{
const QJsonObject& obj = config.object();
//Suspend on lock or go into idle mode
bool prevIsSuspendOnLock = _isSuspendOnLock;
_isSuspendOnLock = obj["suspendOnLockEnable"].toBool(false);
//Handle OS event related configurations
_isSuspendEnabled = obj["suspendEnable"].toBool(true);
if (_isSuspendEnabled)
{
// Listen to suspend/resume/idle events received by the OS
registerSuspendHandler();
}
else
{
unregisterSuspendHandler();
}
_isLockEnabled = obj["lockEnable"].toBool(true);
if (_isLockEnabled || _isSuspendOnLock != prevIsSuspendOnLock)
{
// Listen to lock/screensaver events received by the OS
registerLockHandler();
}
else
{
unregisterLockHandler();
}
//Handle API event related configurations
_isSuspendApiEnabled = obj["suspendApiEnable"].toBool(true);
if (_isSuspendApiEnabled)
{
// Listen to suspend/resume/idle events received by the OS
registerSuspendApiHandler();
}
else
{
unregisterSuspendApiHandler();
}
_isIdleApiEnabled = obj["idleApiEnable"].toBool(true);
if (_isIdleApiEnabled)
{
// Listen to lock/screensaver events received by the OS
registerIdleApiHandler();
}
else
{
unregisterIdleApiHandler();
}
}
}
bool SuspendHandlerBase::registerSuspendHandler()
{
Debug(_log, "_isSuspendRegistered: %d", _isSuspendRegistered);
if (!_isSuspendRegistered)
{
connect(this, &SuspendHandlerBase::suspendEvent, HyperionIManager::getInstance(), &HyperionIManager::suspend);
connect(this, &SuspendHandlerBase::resumeEvent, HyperionIManager::getInstance(), &HyperionIManager::resume);
Info(_log, "Registered for suspend/resume events.");
_isSuspendRegistered = true;
}
return true;
}
void SuspendHandlerBase::unregisterSuspendHandler()
{
if (_isSuspendRegistered)
{
disconnect(this, &SuspendHandlerBase::suspendEvent, HyperionIManager::getInstance(), &HyperionIManager::suspend);
disconnect(this, &SuspendHandlerBase::resumeEvent, HyperionIManager::getInstance(), &HyperionIManager::resume);
Info(_log, "Unregistered for suspend/resume events.");
_isSuspendRegistered = false;
}
}
bool SuspendHandlerBase::registerLockHandler()
{
disconnect(this, &SuspendHandlerBase::lockedEvent,nullptr, nullptr);
if (_isSuspendOnLock)
{
connect(this, &SuspendHandlerBase::lockedEvent, HyperionIManager::getInstance(), &HyperionIManager::toggleSuspend);
}
else
{
connect(this, &SuspendHandlerBase::lockedEvent, HyperionIManager::getInstance(), &HyperionIManager::toggleIdle);
}
connect(this, &SuspendHandlerBase::idleEvent, HyperionIManager::getInstance(), &HyperionIManager::toggleIdle);
Info(_log, "Registered for lock/unlock events. %s on lock event.", _isSuspendOnLock ? "Suspend" : "Idle");
_isLockRegistered = true;
return true;
}
void SuspendHandlerBase::unregisterLockHandler()
{
if (_isLockRegistered)
{
disconnect(this, &SuspendHandlerBase::lockedEvent, HyperionIManager::getInstance(), &HyperionIManager::toggleSuspend);
disconnect(this, &SuspendHandlerBase::lockedEvent, HyperionIManager::getInstance(), &HyperionIManager::toggleIdle);
disconnect(this, &SuspendHandlerBase::idleEvent, HyperionIManager::getInstance(), &HyperionIManager::toggleIdle);
Info(_log, "Unregistered for lock/unlock events.");
_isLockRegistered = false;
}
}
bool SuspendHandlerBase::registerSuspendApiHandler()
{
if (!_isSuspendApiRegistered)
{
connect(HyperionIManager::getInstance(), &HyperionIManager::triggerSuspend, this, QOverload<bool>::of(&SuspendHandler::suspend));
connect(HyperionIManager::getInstance(), &HyperionIManager::triggerToggleSuspend, this, &SuspendHandler::toggleSuspend);
Info(_log, "Registered for suspend/resume API events.");
_isSuspendApiRegistered = true;
}
return true;
}
void SuspendHandlerBase::unregisterSuspendApiHandler()
{
if (_isSuspendApiRegistered)
{
disconnect(HyperionIManager::getInstance(), &HyperionIManager::triggerSuspend, this, QOverload<bool>::of(&SuspendHandler::suspend));
disconnect(HyperionIManager::getInstance(), &HyperionIManager::triggerToggleSuspend, this, &SuspendHandler::toggleSuspend);
Info(_log, "Unregistered for suspend/resume API events.");
_isSuspendApiRegistered = false;
}
}
bool SuspendHandlerBase::registerIdleApiHandler()
{
if (!_isIdleApiRegistered)
{
connect(HyperionIManager::getInstance(), &HyperionIManager::triggerIdle, this, &SuspendHandler::idle);
connect(HyperionIManager::getInstance(), &HyperionIManager::triggerToggleIdle, this, &SuspendHandler::toggleIdle);
Info(_log, "Registered for idle API events.");
_isIdleApiRegistered = true;
}
return true;
}
void SuspendHandlerBase::unregisterIdleApiHandler()
{
if (_isIdleApiRegistered)
{
disconnect(HyperionIManager::getInstance(), &HyperionIManager::triggerIdle, this, &SuspendHandler::idle);
disconnect(HyperionIManager::getInstance(), &HyperionIManager::triggerToggleIdle, this, &SuspendHandler::toggleIdle);
Info(_log, "Unregistered for idle API events.");
_isIdleApiRegistered = false;
}
} }
void SuspendHandlerBase::suspend() void SuspendHandlerBase::suspend()
{ {
Debug(Logger::getInstance("DAEMON"), "");
suspend(true); suspend(true);
} }
@ -41,39 +200,38 @@ void SuspendHandlerBase::suspend(bool sleep)
if (!_isSuspended) if (!_isSuspended)
{ {
_isSuspended = true; _isSuspended = true;
Info(Logger::getInstance("DAEMON"), "Suspend event received - Hyperion is going to sleep"); Info(_log, "Suspend event received - Hyperion is going to sleep");
emit suspendEvent(); emit suspendEvent();
} }
else else
{ {
Debug(Logger::getInstance("DAEMON"), "Suspend event ignored - already suspended"); Debug(_log, "Suspend event ignored - already suspended");
} }
} }
else else
{ {
if (_isSuspended || _isIdle) if (_isSuspended || _isIdle)
{ {
Info(Logger::getInstance("DAEMON"), "Resume event received - Hyperion is going into working mode"); Info(_log, "Resume event received - Hyperion is going into working mode");
emit resumeEvent(); emit resumeEvent();
_isSuspended = false; _isSuspended = false;
_isIdle = false; _isIdle = false;
} }
else else
{ {
Debug(Logger::getInstance("DAEMON"), "Resume event ignored - not in suspend nor idle mode"); Debug(_log, "Resume event ignored - not in suspend nor idle mode");
} }
} }
} }
void SuspendHandlerBase::resume() void SuspendHandlerBase::resume()
{ {
Debug(Logger::getInstance("DAEMON"), "");
suspend(false); suspend(false);
} }
void SuspendHandlerBase::toggleSuspend() void SuspendHandlerBase::toggleSuspend()
{ {
Debug(Logger::getInstance("DAEMON"), "Toggle suspend event received"); Debug(_log, "Toggle suspend event received");
if (!_isSuspended) if (!_isSuspended)
{ {
suspend(true); suspend(true);
@ -93,7 +251,7 @@ void SuspendHandlerBase::idle(bool isIdle)
if (!_isIdle) if (!_isIdle)
{ {
_isIdle = true; _isIdle = true;
Info(Logger::getInstance("DAEMON"), "Idle event received"); Info(_log, "Idle event received");
emit idleEvent(isIdle); emit idleEvent(isIdle);
} }
} }
@ -101,7 +259,7 @@ void SuspendHandlerBase::idle(bool isIdle)
{ {
if (_isIdle) if (_isIdle)
{ {
Info(Logger::getInstance("DAEMON"), "Resume from idle event recevied"); Info(_log, "Resume from idle event recevied");
emit idleEvent(isIdle); emit idleEvent(isIdle);
_isIdle = false; _isIdle = false;
} }
@ -109,13 +267,13 @@ void SuspendHandlerBase::idle(bool isIdle)
} }
else else
{ {
Debug(Logger::getInstance("DAEMON"), "Idle event ignored - Hyperion is suspended"); Debug(_log, "Idle event ignored - Hyperion is suspended");
} }
} }
void SuspendHandlerBase::toggleIdle() void SuspendHandlerBase::toggleIdle()
{ {
Debug(Logger::getInstance("DAEMON"), "Toggle idle event received"); Debug(_log, "Toggle idle event received");
if (!_isIdle) if (!_isIdle)
{ {
idle(true); idle(true);
@ -135,7 +293,7 @@ void SuspendHandlerBase::lock(bool isLocked)
if (!_isLocked) if (!_isLocked)
{ {
_isLocked = true; _isLocked = true;
Info(Logger::getInstance("DAEMON"), "Screen lock event received"); Info(_log, "Screen lock event received");
emit lockedEvent(isLocked); emit lockedEvent(isLocked);
} }
} }
@ -143,7 +301,7 @@ void SuspendHandlerBase::lock(bool isLocked)
{ {
if (_isLocked) if (_isLocked)
{ {
Info(Logger::getInstance("DAEMON"), "Screen unlock event received"); Info(_log, "Screen unlock event received");
emit lockedEvent(isLocked); emit lockedEvent(isLocked);
_isLocked = false; _isLocked = false;
} }
@ -151,7 +309,7 @@ void SuspendHandlerBase::lock(bool isLocked)
} }
else else
{ {
Debug(Logger::getInstance("DAEMON"), "Screen lock event ignored - Hyperion is suspended"); Debug(_log, "Screen lock event ignored - Hyperion is suspended");
} }
} }
@ -165,36 +323,12 @@ void SuspendHandlerBase::lock(bool isLocked)
SuspendHandlerWindows::SuspendHandlerWindows() 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() SuspendHandlerWindows::~SuspendHandlerWindows()
{ {
if (_notifyHandle != NULL) unregisterLockHandler();
{ unregisterSuspendHandler();
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)) #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
@ -238,6 +372,68 @@ bool SuspendHandlerWindows::nativeEventFilter(const QByteArray& eventType, void*
return false; return false;
} }
bool SuspendHandlerWindows::registerSuspendHandler()
{
bool isRegistered {false};
if (!_isSuspendRegistered)
{
auto handle = reinterpret_cast<HWND> (_widget.winId());
_notifyHandle = RegisterSuspendResumeNotification(handle, DEVICE_NOTIFY_WINDOW_HANDLE);
if (_notifyHandle != NULL)
{
QCoreApplication::instance()->installNativeEventFilter(this);
isRegistered = SuspendHandlerBase::registerSuspendHandler();
}
else
{
Error(_log, "Could not register for suspend/resume events!");
}
}
return isRegistered;
}
void SuspendHandlerWindows::unregisterSuspendHandler()
{
if (_isSuspendRegistered)
{
if (_notifyHandle != NULL)
{
QCoreApplication::instance()->removeNativeEventFilter(this);
UnregisterSuspendResumeNotification(_notifyHandle);
}
_notifyHandle = NULL;
SuspendHandlerBase::unregisterSuspendHandler();
}
}
bool SuspendHandlerWindows::registerLockHandler()
{
bool isRegistered {false};
if (!_isLockRegistered)
{
auto handle = reinterpret_cast<HWND> (_widget.winId());
if (WTSRegisterSessionNotification(handle, NOTIFY_FOR_THIS_SESSION))
{
isRegistered = SuspendHandlerBase::registerLockHandler();
}
else
{
Error(_log, "Could not register for lock/unlock events!");
}
}
return isRegistered;
}
void SuspendHandlerWindows::unregisterLockHandler()
{
if (_isLockRegistered)
{
auto handle = reinterpret_cast<HWND> (_widget.winId());
WTSUnRegisterSessionNotification(handle);
SuspendHandlerBase::unregisterLockHandler();
}
}
#elif defined(__linux__) && defined(HYPERION_HAS_DBUS) #elif defined(__linux__) && defined(HYPERION_HAS_DBUS)
#include <QDBusConnection> #include <QDBusConnection>
@ -265,48 +461,158 @@ const DbusSignalsMap dbusSignals = {
SuspendHandlerLinux::SuspendHandlerLinux() SuspendHandlerLinux::SuspendHandlerLinux()
{ {
QDBusConnection systemBus = QDBusConnection::systemBus(); }
if (!systemBus.isConnected())
bool SuspendHandlerLinux::registerSuspendHandler()
{
bool isRegistered {_isSuspendRegistered};
if (!_isSuspendRegistered)
{ {
Info(Logger::getInstance("DAEMON"), "The suspend/resume feature is not supported by your system configuration"); QDBusConnection systemBus = QDBusConnection::systemBus();
} if (!systemBus.isConnected())
else {
{ Info(_log, "The suspend/resume feature is not supported by your system configuration");
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 else
{ {
Debug(Logger::getInstance("DAEMON"), "Registered for suspend/resume events [%s].", QSTRING_CSTR(service)); QString service = dbusSignals.find("Suspend").value().service;
} if (systemBus.connect(service,
} dbusSignals.find("Suspend").value().path,
dbusSignals.find("Suspend").value().interface,
QDBusConnection sessionBus = QDBusConnection::sessionBus(); dbusSignals.find("Suspend").value().name,
if (!sessionBus.isConnected()) this, SLOT(suspend(bool))))
{ {
Info(Logger::getInstance("DAEMON"), "The lock/unlock feature is not supported by your system configuration"); Debug(_log, "Registered for suspend/resume events via service: %s", QSTRING_CSTR(service));
} isRegistered = true;
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 else
{ {
Debug(Logger::getInstance("DAEMON"), "Registered for lock/unlock events [%s].", QSTRING_CSTR(service)); Error(_log, "Could not register for suspend/resume events via service: %s", QSTRING_CSTR(service));
}
}
if (isRegistered)
{
isRegistered = SuspendHandlerBase::registerSuspendHandler();
}
}
return isRegistered;
}
void SuspendHandlerLinux::unregisterSuspendHandler()
{
if (_isSuspendRegistered)
{
QDBusConnection systemBus = QDBusConnection::systemBus();
if (!systemBus.isConnected())
{
Info(_log, "The suspend/resume feature is not supported by your system configuration");
}
else
{
QString service = dbusSignals.find("Suspend").value().service;
if (systemBus.disconnect(service,
dbusSignals.find("Suspend").value().path,
dbusSignals.find("Suspend").value().interface,
dbusSignals.find("Suspend").value().name,
this, SLOT(suspend(bool))))
{
Debug(_log, "Unregistered for suspend/resume events via service: %s", QSTRING_CSTR(service));
SuspendHandlerBase::unregisterSuspendHandler();
}
else
{
Error(_log, "Could not unregister for suspend/resume events via service: %s", QSTRING_CSTR(service));
} }
++iter;
} }
} }
} }
bool SuspendHandlerLinux::registerLockHandler()
{
bool isRegistered {_isLockRegistered};
if (!_isLockRegistered)
{
QDBusConnection sessionBus = QDBusConnection::sessionBus();
if (!sessionBus.isConnected())
{
Info(_log, "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))))
{
Debug(_log, "Registered for lock/unlock events via service: %s", QSTRING_CSTR(service));
isRegistered = true;
}
else
{
Error(_log, "Could not register for lock/unlock events via service: %s", QSTRING_CSTR(service));
}
++iter;
}
}
}
if (isRegistered)
{
isRegistered = SuspendHandlerBase::registerLockHandler();
}
return isRegistered;
}
void SuspendHandlerLinux::unregisterLockHandler()
{
bool isUnregistered {false};
if (_isLockRegistered)
{
QDBusConnection sessionBus = QDBusConnection::sessionBus();
if (!sessionBus.isConnected())
{
Info(_log, "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.disconnect(service,
iter.value().path,
iter.value().interface,
iter.value().name,
this, SLOT(lock(bool))))
{
Debug(_log, "Unregistered for lock/unlock events via service: %s", QSTRING_CSTR(service));
isUnregistered = true;
}
else
{
Error(_log, "Could not unregister for lock/unlock events via service: %s", QSTRING_CSTR(service));
}
++iter;
}
if (isUnregistered)
{
SuspendHandlerBase::unregisterLockHandler();
}
}
}
}
#endif #endif

View File

@ -1,6 +1,11 @@
#ifndef SUSPENDHANDLER_H #ifndef SUSPENDHANDLER_H
#define SUSPENDHANDLER_H #define SUSPENDHANDLER_H
#include <QObject> #include <QObject>
#include <QJsonDocument>
#include <utils/settings.h>
class Logger;
class SuspendHandlerBase : public QObject { class SuspendHandlerBase : public QObject {
Q_OBJECT Q_OBJECT
@ -22,6 +27,8 @@ public slots:
void lock(bool isLocked); void lock(bool isLocked);
virtual void handleSettingsUpdate(settings::type type, const QJsonDocument& config);
signals: signals:
void suspendEvent(); void suspendEvent();
@ -29,6 +36,31 @@ signals:
void lockedEvent(bool); void lockedEvent(bool);
void idleEvent(bool); void idleEvent(bool);
protected:
virtual bool registerSuspendHandler();
virtual void unregisterSuspendHandler();
virtual bool registerLockHandler();
virtual void unregisterLockHandler();
virtual bool registerSuspendApiHandler();
virtual void unregisterSuspendApiHandler();
virtual bool registerIdleApiHandler();
virtual void unregisterIdleApiHandler();
bool _isSuspendEnabled;
bool _isLockEnabled;
bool _isSuspendApiEnabled;
bool _isIdleApiEnabled;
bool _isSuspendOnLock;
bool _isSuspendRegistered;
bool _isLockRegistered;
bool _isSuspendApiRegistered;
bool _isIdleApiRegistered;
Logger * _log {};
private: private:
bool _isSuspended; bool _isSuspended;
@ -56,6 +88,12 @@ protected:
#endif #endif
private: private:
bool registerSuspendHandler() override;
bool unregisterSuspendHandler() override;
void registerLockHandler() override;
void unregisterLockHandler() override;
QWidget _widget; QWidget _widget;
HPOWERNOTIFY _notifyHandle; HPOWERNOTIFY _notifyHandle;
}; };
@ -65,9 +103,16 @@ using SuspendHandler = SuspendHandlerWindows;
#elif defined(__linux__) && defined(HYPERION_HAS_DBUS) #elif defined(__linux__) && defined(HYPERION_HAS_DBUS)
class SuspendHandlerLinux : public SuspendHandlerBase { class SuspendHandlerLinux : public SuspendHandlerBase {
Q_OBJECT
public: public:
SuspendHandlerLinux(); SuspendHandlerLinux();
private:
bool registerSuspendHandler() override;
void unregisterSuspendHandler() override;
bool registerLockHandler() override;
void unregisterLockHandler() override;
}; };
using SuspendHandler = SuspendHandlerLinux; using SuspendHandler = SuspendHandlerLinux;

View File

@ -92,8 +92,8 @@ HyperionDaemon::HyperionDaemon(const QString& rootPath, QObject* parent, bool lo
, _osxGrabber(nullptr) , _osxGrabber(nullptr)
, _qtGrabber(nullptr) , _qtGrabber(nullptr)
, _dxGrabber(nullptr) , _dxGrabber(nullptr)
, _ssdp(nullptr)
, _audioGrabber(nullptr) , _audioGrabber(nullptr)
, _ssdp(nullptr)
#ifdef ENABLE_CEC #ifdef ENABLE_CEC
, _cecHandler(nullptr) , _cecHandler(nullptr)
#endif #endif
@ -177,7 +177,8 @@ HyperionDaemon::HyperionDaemon(const QString& rootPath, QObject* parent, bool lo
// ---- network services ----- // ---- network services -----
startNetworkServices(); startNetworkServices();
_suspendHandler = new SuspendHandler(); // init events services
handleSettingsUpdate(settings::SYSTEMEVENTS, getSetting(settings::SYSTEMEVENTS));
} }
HyperionDaemon::~HyperionDaemon() HyperionDaemon::~HyperionDaemon()
@ -742,6 +743,19 @@ void HyperionDaemon::handleSettingsUpdate(settings::type settingsType, const QJs
Debug(_log, "Audio capture not supported on this platform"); Debug(_log, "Audio capture not supported on this platform");
#endif #endif
} }
else if (settingsType == settings::SYSTEMEVENTS)
{
// Create suspend handler
if (_suspendHandler == nullptr)
{
_suspendHandler = new SuspendHandler();
_suspendHandler->handleSettingsUpdate(settings::SYSTEMEVENTS, getSetting(settings::SYSTEMEVENTS));
connect(this, &HyperionDaemon::settingsChanged, _suspendHandler, &SuspendHandler::handleSettingsUpdate);
Debug(_log, "SuspendHandler created");
}
}
} }
void HyperionDaemon::createGrabberDispmanx(const QJsonObject& /*grabberConfig*/) void HyperionDaemon::createGrabberDispmanx(const QJsonObject& /*grabberConfig*/)