mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2023-10-10 13:36:59 +02: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:
parent
2217135336
commit
1189f86c1a
9
.github/workflows/pull-request.yml
vendored
9
.github/workflows/pull-request.yml
vendored
@ -151,10 +151,15 @@ jobs:
|
|||||||
path: C:\Users\runneradmin\AppData\Local\Temp\chocolatey
|
path: C:\Users\runneradmin\AppData\Local\Temp\chocolatey
|
||||||
key: ${{ runner.os }}-chocolatey
|
key: ${{ runner.os }}-chocolatey
|
||||||
|
|
||||||
- name: Install Python, OpenSSL, DirectX SDK
|
# - name: Install Python
|
||||||
|
# shell: powershell
|
||||||
|
# run: |
|
||||||
|
# choco install --no-progress python -y
|
||||||
|
|
||||||
|
- name: Install OpenSSL, DirectX SDK
|
||||||
shell: powershell
|
shell: powershell
|
||||||
run: |
|
run: |
|
||||||
choco install --no-progress python openssl directx-sdk -y
|
choco install --no-progress openssl directx-sdk -y
|
||||||
|
|
||||||
- name: Install libjpeg-turbo
|
- name: Install libjpeg-turbo
|
||||||
run: |
|
run: |
|
||||||
|
9
.github/workflows/push-master.yml
vendored
9
.github/workflows/push-master.yml
vendored
@ -116,10 +116,15 @@ jobs:
|
|||||||
path: C:\Users\runneradmin\AppData\Local\Temp\chocolatey
|
path: C:\Users\runneradmin\AppData\Local\Temp\chocolatey
|
||||||
key: ${{ runner.os }}-chocolatey
|
key: ${{ runner.os }}-chocolatey
|
||||||
|
|
||||||
- name: Install Python, OpenSSL, DirectX SDK
|
# - name: Install Python
|
||||||
|
# shell: powershell
|
||||||
|
# run: |
|
||||||
|
# choco install --no-progress python -y
|
||||||
|
|
||||||
|
- name: Install OpenSSL, DirectX SDK
|
||||||
shell: powershell
|
shell: powershell
|
||||||
run: |
|
run: |
|
||||||
choco install --no-progress python openssl directx-sdk -y
|
choco install --no-progress openssl directx-sdk -y
|
||||||
|
|
||||||
- name: Install libjpeg-turbo
|
- name: Install libjpeg-turbo
|
||||||
run: |
|
run: |
|
||||||
|
11
CHANGELOG.md
11
CHANGELOG.md
@ -10,10 +10,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- Allow to Disable / Enable all instances (#970) by
|
||||||
|
- Suspend/Resume support for Linux and Windows (#1493,#1282, #978).
|
||||||
|
Suspend/Resume/Restart is supported via API, UI, Systray and hyperion-remote
|
||||||
|
- Idle scenario via Screen Locking (Linux/Windows), Screensaver invokation (Linux), hyperion-remote or API
|
||||||
|
In Idle, all instances, components will be disabled besides the output processing (LED-Devices, smoothing).
|
||||||
|
The current priorities will be cleared and the background effect per instance will be executed, if enabled.
|
||||||
|
- Commands toogleSuspend and toggleIdle allow to flip between modes, e.g. might be used to trigger modes by a remote
|
||||||
|
- Add instance# in API response (#1504)
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
- Restart correctly, if running as service (#1368)
|
||||||
|
|
||||||
## Removed
|
## Removed
|
||||||
|
|
||||||
## [2.0.14](https://github.com/hyperion-project/hyperion.ng/releases/tag/2.0.14) - 2022-11
|
## [2.0.14](https://github.com/hyperion-project/hyperion.ng/releases/tag/2.0.14) - 2022-11
|
||||||
|
@ -13,6 +13,9 @@
|
|||||||
"infoDialog_password_current_text": "Current password",
|
"infoDialog_password_current_text": "Current password",
|
||||||
"infoDialog_password_minimum_length": "Passwords must be minimum 8 characters.",
|
"infoDialog_password_minimum_length": "Passwords must be minimum 8 characters.",
|
||||||
"infoDialog_password_new_text": "New password",
|
"infoDialog_password_new_text": "New password",
|
||||||
|
"InfoDialog_systemSuspend_title": "Suspend",
|
||||||
|
"InfoDialog_systemResume_title": "Resume",
|
||||||
|
"InfoDialog_systemRestart_title": "Restart",
|
||||||
"infoDialog_username_text": "Username",
|
"infoDialog_username_text": "Username",
|
||||||
"about_3rd_party_licenses": "3rd party licenses",
|
"about_3rd_party_licenses": "3rd party licenses",
|
||||||
"about_3rd_party_licenses_error": "We had trouble collecting 3rd party licenses information from web. <br />Please follow this link to the GitHub Resource.",
|
"about_3rd_party_licenses_error": "We had trouble collecting 3rd party licenses information from web. <br />Please follow this link to the GitHub Resource.",
|
||||||
|
@ -213,6 +213,39 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
<!-- /.dropdown -->
|
||||||
|
<li class="dropdown">
|
||||||
|
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
|
||||||
|
<i class="fa fa-power-off fa-fw"></i> <i class="fa fa-caret-down"></i>
|
||||||
|
</a>
|
||||||
|
<ul class="dropdown-menu dropdown-alerts">
|
||||||
|
<li id="btn_systemSuspend">
|
||||||
|
<a>
|
||||||
|
<div>
|
||||||
|
<i class="fa fa-stop fa-fw"></i>
|
||||||
|
<span data-i18n="InfoDialog_systemSuspend_title"></span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li id="btn_systemResume">
|
||||||
|
<a>
|
||||||
|
<div>
|
||||||
|
<i class="fa fa-play fa-fw"></i>
|
||||||
|
<span data-i18n="InfoDialog_systemResume_title"></span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="divider"></li>
|
||||||
|
<li id="btn_systemRestart">
|
||||||
|
<a>
|
||||||
|
<div>
|
||||||
|
<i class="fa fa-refresh fa-fw"></i>
|
||||||
|
<span data-i18n="InfoDialog_systemRestart_title"></span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
|
||||||
<!-- /.lock-ui -->
|
<!-- /.lock-ui -->
|
||||||
<li class="dropdown" id="btn_lock_ui" style="display:none">
|
<li class="dropdown" id="btn_lock_ui" style="display:none">
|
||||||
|
@ -318,6 +318,21 @@ function requestSysInfo()
|
|||||||
sendToHyperion("sysinfo");
|
sendToHyperion("sysinfo");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function requestSystemSuspend()
|
||||||
|
{
|
||||||
|
sendToHyperion("system","suspend");
|
||||||
|
}
|
||||||
|
|
||||||
|
function requestSystemResume()
|
||||||
|
{
|
||||||
|
sendToHyperion("system","resume");
|
||||||
|
}
|
||||||
|
|
||||||
|
function requestSystemRestart()
|
||||||
|
{
|
||||||
|
sendToHyperion("system","restart");
|
||||||
|
}
|
||||||
|
|
||||||
function requestServerConfigSchema()
|
function requestServerConfigSchema()
|
||||||
{
|
{
|
||||||
sendToHyperion("config","getschema");
|
sendToHyperion("config","getschema");
|
||||||
|
@ -75,6 +75,21 @@ $(document).ready(function () {
|
|||||||
changePassword();
|
changePassword();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//Suspend Hyperion
|
||||||
|
$('#btn_systemSuspend').off().on('click', function () {
|
||||||
|
requestSystemSuspend();
|
||||||
|
});
|
||||||
|
|
||||||
|
//Resume Hyperion
|
||||||
|
$('#btn_systemResume').off().on('click', function () {
|
||||||
|
requestSystemResume();
|
||||||
|
});
|
||||||
|
|
||||||
|
//Restart Hyperion
|
||||||
|
$('#btn_systemRestart').off().on('click', function () {
|
||||||
|
requestSystemRestart();
|
||||||
|
});
|
||||||
|
|
||||||
//Lock Ui
|
//Lock Ui
|
||||||
$('#btn_lock_ui').off().on('click', function () {
|
$('#btn_lock_ui').off().on('click', function () {
|
||||||
removeStorage('loginToken');
|
removeStorage('loginToken');
|
||||||
|
@ -99,6 +99,26 @@ signals:
|
|||||||
///
|
///
|
||||||
void forwardJsonMessage(QJsonObject);
|
void forwardJsonMessage(QJsonObject);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Signal emits whenever a suspend/resume request for all instances should be forwarded
|
||||||
|
///
|
||||||
|
void suspendAll(bool isSuspend);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Signal emits whenever a toggle suspend/resume request for all instances should be forwarded
|
||||||
|
///
|
||||||
|
void toggleSuspendAll();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Signal emits whenever a idle mode request for all instances should be forwarded
|
||||||
|
///
|
||||||
|
void idleAll(bool isIdle);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Signal emits whenever a toggle idle/working mode request for all instances should be forwarded
|
||||||
|
///
|
||||||
|
void toggleIdleAll();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// true if further callbacks are forbidden (http)
|
// true if further callbacks are forbidden (http)
|
||||||
bool _noListener;
|
bool _noListener;
|
||||||
@ -298,6 +318,12 @@ private:
|
|||||||
///
|
///
|
||||||
void handleServiceCommand(const QJsonObject &message, const QString &command, int tan);
|
void handleServiceCommand(const QJsonObject &message, const QString &command, int tan);
|
||||||
|
|
||||||
|
/// Handle an incoming JSON message for actions related to the overall Hyperion system
|
||||||
|
///
|
||||||
|
/// @param message the incoming message
|
||||||
|
///
|
||||||
|
void handleSystemCommand(const QJsonObject &message, const QString &command, int tan);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Handle an incoming JSON message of unknown type
|
/// Handle an incoming JSON message of unknown type
|
||||||
///
|
///
|
||||||
|
@ -20,6 +20,7 @@ public:
|
|||||||
, _hyperion(hyperion)
|
, _hyperion(hyperion)
|
||||||
, _prioMuxer(_hyperion->getMuxerInstance())
|
, _prioMuxer(_hyperion->getMuxerInstance())
|
||||||
, _isBgEffectEnabled(false)
|
, _isBgEffectEnabled(false)
|
||||||
|
, _isSuspended(false)
|
||||||
{
|
{
|
||||||
QString subComponent = parent()->property("instance").toString();
|
QString subComponent = parent()->property("instance").toString();
|
||||||
_log = Logger::getInstance("HYPERION", subComponent);
|
_log = Logger::getInstance("HYPERION", subComponent);
|
||||||
@ -33,6 +34,11 @@ public:
|
|||||||
this->handlePriorityUpdate();
|
this->handlePriorityUpdate();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// listen for suspend/resume requests, to not start a background effect when system goes into suspend mode
|
||||||
|
connect(_hyperion, &Hyperion::suspendRequest, this, [=] (bool isSuspended) {
|
||||||
|
_isSuspended = isSuspended;
|
||||||
|
});
|
||||||
|
|
||||||
// initialization
|
// initialization
|
||||||
handleSettingsUpdate(settings::BGEFFECT, _hyperion->getSetting(settings::BGEFFECT));
|
handleSettingsUpdate(settings::BGEFFECT, _hyperion->getSetting(settings::BGEFFECT));
|
||||||
}
|
}
|
||||||
@ -109,7 +115,7 @@ private slots:
|
|||||||
Debug(_log,"Stop background (color-) effect as it moved out of scope");
|
Debug(_log,"Stop background (color-) effect as it moved out of scope");
|
||||||
_hyperion->clear(PriorityMuxer::BG_PRIORITY);
|
_hyperion->clear(PriorityMuxer::BG_PRIORITY);
|
||||||
}
|
}
|
||||||
else if (_prioMuxer->getCurrentPriority() == PriorityMuxer::LOWEST_PRIORITY && _isBgEffectEnabled)
|
else if (!_isSuspended && _prioMuxer->getCurrentPriority() == PriorityMuxer::LOWEST_PRIORITY && _isBgEffectEnabled)
|
||||||
{
|
{
|
||||||
Debug(_log,"Start background (color-) effect as it moved in scope");
|
Debug(_log,"Start background (color-) effect as it moved in scope");
|
||||||
emit handleSettingsUpdate (settings::BGEFFECT, _bgEffectConfig);
|
emit handleSettingsUpdate (settings::BGEFFECT, _bgEffectConfig);
|
||||||
@ -126,6 +132,8 @@ private:
|
|||||||
|
|
||||||
QJsonDocument _bgEffectConfig;
|
QJsonDocument _bgEffectConfig;
|
||||||
bool _isBgEffectEnabled;
|
bool _isBgEffectEnabled;
|
||||||
|
|
||||||
|
bool _isSuspended;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // BGEFFECTHANDLER_H
|
#endif // BGEFFECTHANDLER_H
|
||||||
|
@ -7,12 +7,15 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
class Hyperion;
|
class Hyperion;
|
||||||
|
|
||||||
|
typedef QVector<hyperion::Components> ComponentList;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief The component register reflects and manages the current state of all components and Hyperion as a whole
|
/// @brief The component register reflects and manages the current state of all components and Hyperion as a whole
|
||||||
/// It emits also real component state changes (triggert from the specific component), which can be used for listening APIs (Network Clients/Plugins)
|
/// It emits also real component state changes (triggered from the specific component), which can be used for listening APIs (Network Clients/Plugins)
|
||||||
///
|
///
|
||||||
class ComponentRegister : public QObject
|
class ComponentRegister : public QObject
|
||||||
{
|
{
|
||||||
@ -36,23 +39,32 @@ signals:
|
|||||||
///
|
///
|
||||||
/// @brief Emits whenever a component changed (really) the state
|
/// @brief Emits whenever a component changed (really) the state
|
||||||
/// @param comp The component
|
/// @param comp The component
|
||||||
/// @param state The new state of the component
|
/// @param isActive The new state of the component
|
||||||
///
|
///
|
||||||
void updatedComponentState(hyperion::Components comp, bool state);
|
void updatedComponentState(hyperion::Components comp, bool isActive);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
///
|
///
|
||||||
/// @brief is called whenever a component change a state, DO NOT CALL FROM API, use signal hyperion->compStateChangeRequest
|
/// @brief is called whenever a component change a state, DO NOT CALL FROM API, use signal hyperion->compStateChangeRequest
|
||||||
/// @param comp The component
|
/// @param comp The component
|
||||||
/// @param state The new state of the component
|
/// @param isActive The new state of the component
|
||||||
///
|
///
|
||||||
void setNewComponentState(hyperion::Components comp, bool activated);
|
void setNewComponentState(hyperion::Components comp, bool isActive);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
///
|
///
|
||||||
/// @brief Handle COMP_ALL changes from Hyperion->compStateChangeRequest
|
/// @brief Handle COMP_ALL changes from Hyperion->compStateChangeRequest
|
||||||
|
/// @param comp COMP_ALL
|
||||||
|
/// @param isActive The new state for all components
|
||||||
///
|
///
|
||||||
void handleCompStateChangeRequest(hyperion::Components comps, bool activated);
|
void handleCompStateChangeRequest(hyperion::Components comps, bool isActive);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Activate/Deactivate all components, except those provided by the list of excluded components
|
||||||
|
/// @param isActive The new state for all components
|
||||||
|
/// @param execludeList of excluded components
|
||||||
|
///
|
||||||
|
void handleCompStateChangeRequestAll(bool isActive, const ComponentList& excludeList = ComponentList{});
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Hyperion instance
|
/// Hyperion instance
|
||||||
|
@ -389,6 +389,20 @@ public slots:
|
|||||||
|
|
||||||
int getLatchTime() const;
|
int getLatchTime() const;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Set hyperion in suspend mode or resume from suspend/idle.
|
||||||
|
/// All instances and components will be disabled/enabled.
|
||||||
|
/// @param isSupend True, components will be deactivated, else put into their previous state before suspend
|
||||||
|
///
|
||||||
|
void setSuspend(bool isSupend);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Set hyperion in idle /working mode.
|
||||||
|
/// In idle, all instances and components will be disabled besides the output processing (LED-Devices, smoothing).
|
||||||
|
/// @param isIdle True, selected components will be deactivated, else put into their previous state before idle
|
||||||
|
///
|
||||||
|
void setIdle(bool isIdle);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
/// Signal which is emitted when a priority channel is actively cleared
|
/// Signal which is emitted when a priority channel is actively cleared
|
||||||
/// This signal will not be emitted when a priority channel time out
|
/// This signal will not be emitted when a priority channel time out
|
||||||
@ -406,6 +420,18 @@ signals:
|
|||||||
///
|
///
|
||||||
void compStateChangeRequest(hyperion::Components component, bool enabled);
|
void compStateChangeRequest(hyperion::Components component, bool enabled);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Emits when all (besides excluded) components are subject to state changes
|
||||||
|
/// @param isActive The new state for all components
|
||||||
|
/// @param execlude List of excluded components
|
||||||
|
void compStateChangeRequestAll(bool isActive, const ComponentList& excludeList = {});
|
||||||
|
|
||||||
|
/// Signal which is emitted, when system is to be suspended/resumed
|
||||||
|
void suspendRequest(bool isSuspend);
|
||||||
|
|
||||||
|
/// Signal which is emitted, when system should go into idle/working mode
|
||||||
|
void idleRequest(bool isIdle);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Emits whenever the imageToLedsMapping has changed
|
/// @brief Emits whenever the imageToLedsMapping has changed
|
||||||
/// @param mappingType The new mapping type
|
/// @param mappingType The new mapping type
|
||||||
|
@ -74,10 +74,26 @@ public slots:
|
|||||||
bool stopInstance(quint8 inst);
|
bool stopInstance(quint8 inst);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Toggle the state of all Hyperion instances
|
/// @brief Suspend (disable) all Hyperion instances
|
||||||
/// @param pause If true all instances toggle to pause, else to resume
|
|
||||||
///
|
///
|
||||||
void toggleStateAllInstances(bool pause = false);
|
void suspend();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Resume (resume) all Hyperion instances
|
||||||
|
///
|
||||||
|
void resume();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Toggle the state of all Hyperion instances for an idle sceanrio (user is not interacting with the system
|
||||||
|
/// @param isIdle, If true all instances toggle to idle, else to resume
|
||||||
|
///
|
||||||
|
void toggleIdle(bool isIdle);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Toggle the state of all Hyperion instances
|
||||||
|
/// @param enable, If false all instances toggle to pause, else to resume
|
||||||
|
///
|
||||||
|
void toggleStateAllInstances(bool enable = false);
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Create a new Hyperion instance entry in db
|
/// @brief Create a new Hyperion instance entry in db
|
||||||
@ -125,6 +141,11 @@ signals:
|
|||||||
///
|
///
|
||||||
void startInstanceResponse(QObject *caller, const int &tan);
|
void startInstanceResponse(QObject *caller, const int &tan);
|
||||||
|
|
||||||
|
void triggerSuspend(bool isSuspend);
|
||||||
|
void triggerToggleSuspend();
|
||||||
|
void triggerIdle(bool isIdle);
|
||||||
|
void triggerToggleIdle();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
/// FROM HYPERIONDAEMON TO HYPERION ///
|
/// FROM HYPERIONDAEMON TO HYPERION ///
|
||||||
|
20
libsrc/api/JSONRPC_schema/schema-system.json
Normal file
20
libsrc/api/JSONRPC_schema/schema-system.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"type":"object",
|
||||||
|
"required":true,
|
||||||
|
"properties":{
|
||||||
|
"command": {
|
||||||
|
"type" : "string",
|
||||||
|
"required" : true,
|
||||||
|
"enum" : ["system"]
|
||||||
|
},
|
||||||
|
"tan" : {
|
||||||
|
"type" : "integer"
|
||||||
|
},
|
||||||
|
"subcommand": {
|
||||||
|
"type" : "string",
|
||||||
|
"required" : true,
|
||||||
|
"enum": [ "restart", "resume", "suspend", "toggleSuspend", "idle", "toggleIdle" ]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
@ -5,7 +5,7 @@
|
|||||||
"command": {
|
"command": {
|
||||||
"type" : "string",
|
"type" : "string",
|
||||||
"required" : true,
|
"required" : true,
|
||||||
"enum": [ "color", "image", "effect", "create-effect", "delete-effect", "serverinfo", "clear", "clearall", "adjustment", "sourceselect", "config", "componentstate", "ledcolors", "logging", "processing", "sysinfo", "videomode", "authorize", "instance", "leddevice", "inputsource", "service", "transform", "correction", "temperature" ]
|
"enum": [ "color", "image", "effect", "create-effect", "delete-effect", "serverinfo", "clear", "clearall", "adjustment", "sourceselect", "config", "componentstate", "ledcolors", "logging", "processing", "sysinfo", "videomode", "authorize", "instance", "leddevice", "inputsource", "service", "system", "transform", "correction", "temperature" ]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
<file alias="schema-leddevice">JSONRPC_schema/schema-leddevice.json</file>
|
<file alias="schema-leddevice">JSONRPC_schema/schema-leddevice.json</file>
|
||||||
<file alias="schema-inputsource">JSONRPC_schema/schema-inputsource.json</file>
|
<file alias="schema-inputsource">JSONRPC_schema/schema-inputsource.json</file>
|
||||||
<file alias="schema-service">JSONRPC_schema/schema-service.json</file>
|
<file alias="schema-service">JSONRPC_schema/schema-service.json</file>
|
||||||
|
<file alias="schema-system">JSONRPC_schema/schema-system.json</file>
|
||||||
<!-- The following schemas are derecated but used to ensure backward compatibility with hyperion Classic remote control-->
|
<!-- The following schemas are derecated but used to ensure backward compatibility with hyperion Classic remote control-->
|
||||||
<file alias="schema-transform">JSONRPC_schema/schema-hyperion-classic.json</file>
|
<file alias="schema-transform">JSONRPC_schema/schema-hyperion-classic.json</file>
|
||||||
<file alias="schema-correction">JSONRPC_schema/schema-hyperion-classic.json</file>
|
<file alias="schema-correction">JSONRPC_schema/schema-hyperion-classic.json</file>
|
||||||
|
@ -120,6 +120,12 @@ void JsonAPI::initialize()
|
|||||||
_jsonCB->setSubscriptionsTo(_hyperion);
|
_jsonCB->setSubscriptionsTo(_hyperion);
|
||||||
connect(this, &JsonAPI::forwardJsonMessage, _hyperion, &Hyperion::forwardJsonMessage);
|
connect(this, &JsonAPI::forwardJsonMessage, _hyperion, &Hyperion::forwardJsonMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//notify instance manager on suspend/resume/idle requests
|
||||||
|
connect(this, &JsonAPI::suspendAll, _instanceManager, &HyperionIManager::triggerSuspend);
|
||||||
|
connect(this, &JsonAPI::toggleSuspendAll, _instanceManager, &HyperionIManager::triggerToggleSuspend);
|
||||||
|
connect(this, &JsonAPI::idleAll, _instanceManager, &HyperionIManager::triggerIdle);
|
||||||
|
connect(this, &JsonAPI::toggleIdleAll, _instanceManager, &HyperionIManager::triggerToggleIdle);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JsonAPI::handleInstanceSwitch(quint8 inst, bool forced)
|
bool JsonAPI::handleInstanceSwitch(quint8 inst, bool forced)
|
||||||
@ -236,6 +242,8 @@ proceed:
|
|||||||
handleInputSourceCommand(message, command, tan);
|
handleInputSourceCommand(message, command, tan);
|
||||||
else if (command == "service")
|
else if (command == "service")
|
||||||
handleServiceCommand(message, command, tan);
|
handleServiceCommand(message, command, tan);
|
||||||
|
else if (command == "system")
|
||||||
|
handleSystemCommand(message, command, tan);
|
||||||
|
|
||||||
// BEGIN | The following commands are deprecated but used to ensure backward compatibility with hyperion Classic remote control
|
// BEGIN | The following commands are deprecated but used to ensure backward compatibility with hyperion Classic remote control
|
||||||
else if (command == "clearall")
|
else if (command == "clearall")
|
||||||
@ -920,15 +928,15 @@ void JsonAPI::handleAdjustmentCommand(const QJsonObject &message, const QString
|
|||||||
colorAdjustment->_rgbTransform.setBrightnessCompensation(adjustment["brightnessCompensation"].toInt());
|
colorAdjustment->_rgbTransform.setBrightnessCompensation(adjustment["brightnessCompensation"].toInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (adjustment.contains("saturationGain"))
|
if (adjustment.contains("saturationGain"))
|
||||||
{
|
{
|
||||||
colorAdjustment->_okhsvTransform.setSaturationGain(adjustment["saturationGain"].toDouble());
|
colorAdjustment->_okhsvTransform.setSaturationGain(adjustment["saturationGain"].toDouble());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (adjustment.contains("brightnessGain"))
|
if (adjustment.contains("brightnessGain"))
|
||||||
{
|
{
|
||||||
colorAdjustment->_okhsvTransform.setBrightnessGain(adjustment["brightnessGain"].toDouble());
|
colorAdjustment->_okhsvTransform.setBrightnessGain(adjustment["brightnessGain"].toDouble());
|
||||||
}
|
}
|
||||||
|
|
||||||
// commit the changes
|
// commit the changes
|
||||||
_hyperion->adjustmentsUpdated();
|
_hyperion->adjustmentsUpdated();
|
||||||
@ -1799,6 +1807,49 @@ void JsonAPI::handleServiceCommand(const QJsonObject &message, const QString &co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void JsonAPI::handleSystemCommand(const QJsonObject &message, const QString &command, int tan)
|
||||||
|
{
|
||||||
|
DebugIf(verbose, _log, "message: [%s]", QString(QJsonDocument(message).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||||
|
|
||||||
|
const QString &subc = message["subcommand"].toString().trimmed();
|
||||||
|
|
||||||
|
if (subc == "suspend")
|
||||||
|
{
|
||||||
|
emit suspendAll(true);
|
||||||
|
sendSuccessReply(command + "-" + subc, tan);
|
||||||
|
}
|
||||||
|
else if (subc == "resume")
|
||||||
|
{
|
||||||
|
emit suspendAll(false);
|
||||||
|
sendSuccessReply(command + "-" + subc, tan);
|
||||||
|
}
|
||||||
|
else if (subc == "restart")
|
||||||
|
{
|
||||||
|
Process::restartHyperion(11);
|
||||||
|
sendSuccessReply(command + "-" + subc, tan);
|
||||||
|
}
|
||||||
|
else if (subc == "toggleSuspend")
|
||||||
|
{
|
||||||
|
emit toggleSuspendAll();
|
||||||
|
sendSuccessReply(command + "-" + subc, tan);
|
||||||
|
}
|
||||||
|
else if (subc == "idle")
|
||||||
|
{
|
||||||
|
emit idleAll(true);
|
||||||
|
sendSuccessReply(command + "-" + subc, tan);
|
||||||
|
}
|
||||||
|
else if (subc == "toggleIdle")
|
||||||
|
{
|
||||||
|
emit toggleIdleAll();
|
||||||
|
sendSuccessReply(command + "-" + subc, tan);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QString full_command = command + "-" + subc;
|
||||||
|
sendErrorReply("Unknown or missing subcommand", full_command, tan);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void JsonAPI::handleNotImplemented(const QString &command, int tan)
|
void JsonAPI::handleNotImplemented(const QString &command, int tan)
|
||||||
{
|
{
|
||||||
sendErrorReply("Command not implemented", command, tan);
|
sendErrorReply("Command not implemented", command, tan);
|
||||||
|
@ -55,12 +55,13 @@ ComponentRegister::ComponentRegister(Hyperion* hyperion)
|
|||||||
vect << COMP_FORWARDER;
|
vect << COMP_FORWARDER;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for(auto e : vect)
|
for(auto e : qAsConst(vect))
|
||||||
{
|
{
|
||||||
_componentStates.emplace(e, (e == COMP_ALL));
|
_componentStates.emplace(e, (e == COMP_ALL));
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(_hyperion, &Hyperion::compStateChangeRequest, this, &ComponentRegister::handleCompStateChangeRequest);
|
connect(_hyperion, &Hyperion::compStateChangeRequest, this, &ComponentRegister::handleCompStateChangeRequest);
|
||||||
|
connect(_hyperion, &Hyperion::compStateChangeRequestAll, this, &ComponentRegister::handleCompStateChangeRequestAll);
|
||||||
}
|
}
|
||||||
|
|
||||||
ComponentRegister::~ComponentRegister()
|
ComponentRegister::~ComponentRegister()
|
||||||
@ -72,56 +73,93 @@ int ComponentRegister::isComponentEnabled(hyperion::Components comp) const
|
|||||||
return (_componentStates.count(comp)) ? _componentStates.at(comp) : -1;
|
return (_componentStates.count(comp)) ? _componentStates.at(comp) : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ComponentRegister::setNewComponentState(hyperion::Components comp, bool activated)
|
void ComponentRegister::setNewComponentState(hyperion::Components comp, bool isActive)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (_componentStates.count(comp) > 0)
|
if (_componentStates.count(comp) > 0)
|
||||||
{
|
{
|
||||||
if (_componentStates[comp] != activated)
|
if (_componentStates[comp] != isActive)
|
||||||
{
|
{
|
||||||
Debug(_log, "%s: %s", componentToString(comp), (activated ? "enabled" : "disabled"));
|
Debug(_log, "%s: %s", componentToString(comp), (isActive ? "enabled" : "disabled"));
|
||||||
_componentStates[comp] = activated;
|
_componentStates[comp] = isActive;
|
||||||
// emit component has changed state
|
// emit component has changed state
|
||||||
emit updatedComponentState(comp, activated);
|
emit updatedComponentState(comp, isActive);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ComponentRegister::handleCompStateChangeRequest(hyperion::Components comps, bool activated)
|
void ComponentRegister::handleCompStateChangeRequest(hyperion::Components comps, bool isActive)
|
||||||
{
|
{
|
||||||
if(comps == COMP_ALL && !_inProgress)
|
if(comps == COMP_ALL )
|
||||||
|
{
|
||||||
|
handleCompStateChangeRequestAll(isActive,{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ComponentRegister::handleCompStateChangeRequestAll(bool isActive, const ComponentList& excludeList)
|
||||||
|
{
|
||||||
|
if (!_inProgress)
|
||||||
{
|
{
|
||||||
_inProgress = true;
|
_inProgress = true;
|
||||||
if(!activated && _prevComponentStates.empty())
|
if(!isActive)
|
||||||
{
|
{
|
||||||
Debug(_log,"Disable Hyperion, store current component states");
|
if (excludeList.isEmpty())
|
||||||
|
{
|
||||||
|
Debug(_log,"Disable Hyperion instance, store current components' state");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug(_log,"Disable selected Hyperion components, store their current state");
|
||||||
|
}
|
||||||
|
|
||||||
for(const auto &comp : _componentStates)
|
for(const auto &comp : _componentStates)
|
||||||
{
|
{
|
||||||
// save state
|
if (!excludeList.contains(comp.first) && comp.first != COMP_ALL)
|
||||||
_prevComponentStates.emplace(comp.first, comp.second);
|
|
||||||
// disable if enabled
|
|
||||||
if(comp.second)
|
|
||||||
{
|
{
|
||||||
emit _hyperion->compStateChangeRequest(comp.first, false);
|
// save state
|
||||||
|
_prevComponentStates.emplace(comp.first, comp.second);
|
||||||
|
// disable if enabled
|
||||||
|
if(comp.second)
|
||||||
|
{
|
||||||
|
emit _hyperion->compStateChangeRequest(comp.first, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setNewComponentState(COMP_ALL, false);
|
|
||||||
|
if (excludeList.isEmpty())
|
||||||
|
{
|
||||||
|
setNewComponentState(COMP_ALL, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(activated && !_prevComponentStates.empty())
|
if(isActive && !_prevComponentStates.empty())
|
||||||
{
|
{
|
||||||
Debug(_log,"Enable Hyperion, recover previous component states");
|
if (excludeList.isEmpty())
|
||||||
|
{
|
||||||
|
Debug(_log,"Enable Hyperion instance, restore components' previous state");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug(_log,"Enable selected Hyperion components, restore their previous state");
|
||||||
|
}
|
||||||
|
|
||||||
for(const auto &comp : _prevComponentStates)
|
for(const auto &comp : _prevComponentStates)
|
||||||
{
|
{
|
||||||
// if comp was enabled, enable again
|
if (!excludeList.contains(comp.first) && comp.first != COMP_ALL)
|
||||||
if(comp.second)
|
|
||||||
{
|
{
|
||||||
emit _hyperion->compStateChangeRequest(comp.first, true);
|
// if comp was enabled, enable again
|
||||||
|
if(comp.second)
|
||||||
|
{
|
||||||
|
emit _hyperion->compStateChangeRequest(comp.first, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_prevComponentStates.clear();
|
_prevComponentStates.clear();
|
||||||
setNewComponentState(COMP_ALL, true);
|
if (excludeList.isEmpty())
|
||||||
|
{
|
||||||
|
setNewComponentState(COMP_ALL, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_inProgress = false;
|
_inProgress = false;
|
||||||
|
@ -75,6 +75,8 @@ Hyperion::Hyperion(quint8 instance, bool readonlyMode)
|
|||||||
#endif
|
#endif
|
||||||
, _readOnlyMode(readonlyMode)
|
, _readOnlyMode(readonlyMode)
|
||||||
{
|
{
|
||||||
|
qRegisterMetaType<ComponentList>("ComponentList");
|
||||||
|
|
||||||
QString subComponent = "I"+QString::number(instance);
|
QString subComponent = "I"+QString::number(instance);
|
||||||
this->setProperty("instance", (QString) subComponent);
|
this->setProperty("instance", (QString) subComponent);
|
||||||
|
|
||||||
@ -117,8 +119,9 @@ void Hyperion::start()
|
|||||||
connect(_muxer, &PriorityMuxer::visiblePriorityChanged, this, &Hyperion::handleSourceAvailability);
|
connect(_muxer, &PriorityMuxer::visiblePriorityChanged, this, &Hyperion::handleSourceAvailability);
|
||||||
connect(_muxer, &PriorityMuxer::visibleComponentChanged, this, &Hyperion::handleVisibleComponentChanged);
|
connect(_muxer, &PriorityMuxer::visibleComponentChanged, this, &Hyperion::handleVisibleComponentChanged);
|
||||||
|
|
||||||
// listens for ComponentRegister changes of COMP_ALL to perform core enable/disable actions
|
// listen for suspend/resume, idle requests to perform core activation/deactivation actions
|
||||||
// connect(&_componentRegister, &ComponentRegister::updatedComponentState, this, &Hyperion::updatedComponentState);
|
connect(this, &Hyperion::suspendRequest, this, &Hyperion::setSuspend);
|
||||||
|
connect(this, &Hyperion::idleRequest, this, &Hyperion::setIdle);
|
||||||
|
|
||||||
// listen for settings updates of this instance (LEDS & COLOR)
|
// listen for settings updates of this instance (LEDS & COLOR)
|
||||||
connect(_settingsManager, &SettingsManager::settingsChanged, this, &Hyperion::handleSettingsUpdate);
|
connect(_settingsManager, &SettingsManager::settingsChanged, this, &Hyperion::handleSettingsUpdate);
|
||||||
@ -377,6 +380,20 @@ int Hyperion::isComponentEnabled(hyperion::Components comp) const
|
|||||||
return _componentRegister->isComponentEnabled(comp);
|
return _componentRegister->isComponentEnabled(comp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Hyperion::setSuspend(bool isSuspend)
|
||||||
|
{
|
||||||
|
bool enable = !isSuspend;
|
||||||
|
emit compStateChangeRequestAll(enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hyperion::setIdle(bool isIdle)
|
||||||
|
{
|
||||||
|
clear(-1);
|
||||||
|
|
||||||
|
bool enable = !isIdle;
|
||||||
|
emit compStateChangeRequestAll(enable, {hyperion::COMP_LEDDEVICE, hyperion::COMP_SMOOTHING} );
|
||||||
|
}
|
||||||
|
|
||||||
void Hyperion::registerInput(int priority, hyperion::Components component, const QString& origin, const QString& owner, unsigned smooth_cfg)
|
void Hyperion::registerInput(int priority, hyperion::Components component, const QString& origin, const QString& owner, unsigned smooth_cfg)
|
||||||
{
|
{
|
||||||
_muxer->registerInput(priority, component, origin, owner, smooth_cfg);
|
_muxer->registerInput(priority, component, origin, owner, smooth_cfg);
|
||||||
|
@ -63,13 +63,43 @@ void HyperionIManager::stopAll()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HyperionIManager::toggleStateAllInstances(bool pause)
|
void HyperionIManager::suspend()
|
||||||
|
{
|
||||||
|
Info(_log,"Suspend all instances and enabled components");
|
||||||
|
QMap<quint8, Hyperion*> instCopy = _runningInstances;
|
||||||
|
for(const auto instance : instCopy)
|
||||||
|
{
|
||||||
|
emit instance->suspendRequest(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HyperionIManager::resume()
|
||||||
|
{
|
||||||
|
Info(_log,"Resume all instances and enabled components");
|
||||||
|
QMap<quint8, Hyperion*> instCopy = _runningInstances;
|
||||||
|
for(const auto instance : instCopy)
|
||||||
|
{
|
||||||
|
emit instance->suspendRequest(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HyperionIManager::toggleIdle(bool isIdle)
|
||||||
|
{
|
||||||
|
Info(_log,"Put all instances in %s state", isIdle ? "idle" : "working");
|
||||||
|
QMap<quint8, Hyperion*> instCopy = _runningInstances;
|
||||||
|
for(const auto instance : instCopy)
|
||||||
|
{
|
||||||
|
emit instance->idleRequest(isIdle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HyperionIManager::toggleStateAllInstances(bool enable)
|
||||||
{
|
{
|
||||||
// copy the instances due to loop corruption, even with .erase() return next iter
|
// copy the instances due to loop corruption, even with .erase() return next iter
|
||||||
QMap<quint8, Hyperion*> instCopy = _runningInstances;
|
QMap<quint8, Hyperion*> instCopy = _runningInstances;
|
||||||
for(const auto instance : instCopy)
|
for(const auto instance : instCopy)
|
||||||
{
|
{
|
||||||
emit instance->compStateChangeRequest(hyperion::COMP_ALL, pause);
|
emit instance->compStateChangeRequest(hyperion::COMP_ALL, enable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1
resources/icons/resume.svg
Normal file
1
resources/icons/resume.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg width="512px" height="512px" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><title>ionicons-v5-c</title><polygon points="96 448 416 256 96 64 96 448"/></svg>
|
After Width: | Height: | Size: 172 B |
3
resources/icons/suspend.svg
Normal file
3
resources/icons/suspend.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||||
|
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512"><title>ionicons-v5-c</title><rect x="80" y="80" width="352" height="352"/></svg>
|
After Width: | Height: | Size: 324 B |
@ -251,6 +251,78 @@ QString JsonConnection::getSysInfo()
|
|||||||
return QString();
|
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)
|
void JsonConnection::clear(int priority)
|
||||||
{
|
{
|
||||||
Debug(_log, "Clear priority channel [%d]", priority);
|
Debug(_log, "Clear priority channel [%d]", priority);
|
||||||
|
@ -99,6 +99,36 @@ public:
|
|||||||
///
|
///
|
||||||
QString getSysInfo();
|
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
|
/// 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 & 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.");
|
Option & argDeleteEffect = parser.add<Option> (0x0, "deleteEffect" , "Delete a custom created JSON Effect configuration file.");
|
||||||
#endif
|
#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 & 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");
|
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]");
|
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 & 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");
|
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.");
|
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 & 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");
|
BooleanOption & argDebug = parser.add<BooleanOption>(0x0, "debug", "Enable debug logging");
|
||||||
@ -178,9 +184,13 @@ int main(int argc, char * argv[])
|
|||||||
#if defined(ENABLE_EFFECTENGINE)
|
#if defined(ENABLE_EFFECTENGINE)
|
||||||
parser.isSet(argEffect), parser.isSet(argCreateEffect), parser.isSet(argDeleteEffect),
|
parser.isSet(argEffect), parser.isSet(argCreateEffect), parser.isSet(argDeleteEffect),
|
||||||
#endif
|
#endif
|
||||||
parser.isSet(argServerInfo), parser.isSet(argSysInfo),parser.isSet(argClear), parser.isSet(argClearAll), parser.isSet(argEnableComponent), parser.isSet(argDisableComponent), colorAdjust,
|
parser.isSet(argServerInfo), parser.isSet(argSysInfo),
|
||||||
parser.isSet(argSource), parser.isSet(argSourceAuto), parser.isSet(argOff), parser.isSet(argOn), parser.isSet(argConfigGet), parser.isSet(argSchemaGet), parser.isSet(argConfigSet),
|
parser.isSet(argSystemSuspend), parser.isSet(argSystemResume), parser.isSet(argSystemToggleSuspend),
|
||||||
parser.isSet(argMapping),parser.isSet(argVideoMode) });
|
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)
|
if (commandCount != 1)
|
||||||
{
|
{
|
||||||
qWarning() << (commandCount == 0 ? "No command found." : "Multiple commands found.") << " Provide exactly one of the following options:";
|
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
|
#endif
|
||||||
showHelp(argServerInfo);
|
showHelp(argServerInfo);
|
||||||
showHelp(argSysInfo);
|
showHelp(argSysInfo);
|
||||||
|
showHelp(argSystemSuspend);
|
||||||
|
showHelp(argSystemResume);
|
||||||
|
showHelp(argSystemToggleSuspend);
|
||||||
|
showHelp(argSystemIdle);
|
||||||
|
showHelp(argSystemToggleIdle);
|
||||||
|
showHelp(argSystemRestart);
|
||||||
showHelp(argClear);
|
showHelp(argClear);
|
||||||
showHelp(argClearAll);
|
showHelp(argClearAll);
|
||||||
showHelp(argEnableComponent);
|
showHelp(argEnableComponent);
|
||||||
@ -295,6 +311,30 @@ int main(int argc, char * argv[])
|
|||||||
{
|
{
|
||||||
std::cout << "System info:\n" << connection.getSysInfo().toStdString() << std::endl;
|
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))
|
else if (parser.isSet(argClear))
|
||||||
{
|
{
|
||||||
connection.clear(argPriority.getInt(parser));
|
connection.clear(argPriority.getInt(parser));
|
||||||
|
@ -30,17 +30,29 @@ if (APPLE)
|
|||||||
set_source_files_properties(${BUNDLE_RESOURCE_FILES} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
set_source_files_properties(${BUNDLE_RESOURCE_FILES} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
||||||
endif(APPLE)
|
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}
|
add_executable(${PROJECT_NAME}
|
||||||
console.h
|
console.h
|
||||||
hyperiond.h
|
hyperiond.h
|
||||||
systray.h
|
systray.h
|
||||||
hyperiond.cpp
|
hyperiond.cpp
|
||||||
systray.cpp
|
systray.cpp
|
||||||
|
SuspendHandler.cpp
|
||||||
main.cpp
|
main.cpp
|
||||||
${hyperiond_WIN_RC_PATH}
|
${hyperiond_WIN_RC_PATH}
|
||||||
${BUNDLE_RESOURCE_FILES}
|
${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
|
# promote hyperiond as GUI app
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
target_link_options(${PROJECT_NAME} PUBLIC /SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup)
|
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}::Gui
|
||||||
Qt${QT_VERSION_MAJOR}::Network
|
Qt${QT_VERSION_MAJOR}::Network
|
||||||
Qt${QT_VERSION_MAJOR}::Widgets
|
Qt${QT_VERSION_MAJOR}::Widgets
|
||||||
|
${hyperiond_POWER_MNG_DBUS}
|
||||||
)
|
)
|
||||||
|
|
||||||
if(ENABLE_EFFECTENGINE)
|
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
|
#ifdef ENABLE_CEC
|
||||||
, _cecHandler(nullptr)
|
, _cecHandler(nullptr)
|
||||||
#endif
|
#endif
|
||||||
|
, _suspendHandler(nullptr)
|
||||||
, _currVideoMode(VideoMode::VIDEO_2D)
|
, _currVideoMode(VideoMode::VIDEO_2D)
|
||||||
{
|
{
|
||||||
HyperionDaemon::daemon = this;
|
HyperionDaemon::daemon = this;
|
||||||
@ -171,6 +172,8 @@ HyperionDaemon::HyperionDaemon(const QString& rootPath, QObject* parent, bool lo
|
|||||||
|
|
||||||
// ---- network services -----
|
// ---- network services -----
|
||||||
startNetworkServices();
|
startNetworkServices();
|
||||||
|
|
||||||
|
_suspendHandler = new SuspendHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
HyperionDaemon::~HyperionDaemon()
|
HyperionDaemon::~HyperionDaemon()
|
||||||
@ -337,6 +340,8 @@ void HyperionDaemon::freeObjects()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
delete _suspendHandler;
|
||||||
|
|
||||||
// stop Hyperions (non blocking)
|
// stop Hyperions (non blocking)
|
||||||
_instanceManager->stopAll();
|
_instanceManager->stopAll();
|
||||||
|
|
||||||
|
@ -69,6 +69,8 @@
|
|||||||
#include <utils/settings.h>
|
#include <utils/settings.h>
|
||||||
#include <utils/Components.h>
|
#include <utils/Components.h>
|
||||||
|
|
||||||
|
#include "SuspendHandler.h"
|
||||||
|
|
||||||
class HyperionIManager;
|
class HyperionIManager;
|
||||||
class SysTray;
|
class SysTray;
|
||||||
class JsonServer;
|
class JsonServer;
|
||||||
@ -102,6 +104,11 @@ public:
|
|||||||
///
|
///
|
||||||
WebServer *getWebServerInstance() { return _webserver; }
|
WebServer *getWebServerInstance() { return _webserver; }
|
||||||
|
|
||||||
|
///
|
||||||
|
/// @brief Get suspense handler pointer
|
||||||
|
///
|
||||||
|
SuspendHandler* getSuspendHandlerInstance() { return _suspendHandler; }
|
||||||
|
|
||||||
///
|
///
|
||||||
/// @brief Get the current videoMode
|
/// @brief Get the current videoMode
|
||||||
///
|
///
|
||||||
@ -198,10 +205,11 @@ private:
|
|||||||
QtWrapper* _qtGrabber;
|
QtWrapper* _qtGrabber;
|
||||||
DirectXWrapper* _dxGrabber;
|
DirectXWrapper* _dxGrabber;
|
||||||
SSDPHandler* _ssdp;
|
SSDPHandler* _ssdp;
|
||||||
|
|
||||||
#ifdef ENABLE_CEC
|
#ifdef ENABLE_CEC
|
||||||
CECHandler* _cecHandler;
|
CECHandler* _cecHandler;
|
||||||
#endif
|
#endif
|
||||||
|
SuspendHandler* _suspendHandler;
|
||||||
|
|
||||||
#if defined(ENABLE_FLATBUF_SERVER)
|
#if defined(ENABLE_FLATBUF_SERVER)
|
||||||
FlatBufferServer* _flatBufferServer;
|
FlatBufferServer* _flatBufferServer;
|
||||||
#endif
|
#endif
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
|
|
||||||
#include "hyperiond.h"
|
#include "hyperiond.h"
|
||||||
#include "systray.h"
|
#include "systray.h"
|
||||||
|
#include "SuspendHandler.h"
|
||||||
|
|
||||||
using namespace commandline;
|
using namespace commandline;
|
||||||
|
|
||||||
@ -54,8 +55,8 @@ using namespace commandline;
|
|||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
void signal_handler(int signum)
|
void signal_handler(int signum)
|
||||||
{
|
{
|
||||||
// Hyperion Managment instance
|
HyperionDaemon* hyperiond = HyperionDaemon::getInstance();
|
||||||
HyperionIManager *_hyperion = HyperionIManager::getInstance();
|
SuspendHandler* suspendHandler = hyperiond->getSuspendHandlerInstance();
|
||||||
|
|
||||||
if (signum == SIGCHLD)
|
if (signum == SIGCHLD)
|
||||||
{
|
{
|
||||||
@ -64,16 +65,16 @@ void signal_handler(int signum)
|
|||||||
}
|
}
|
||||||
else if (signum == SIGUSR1)
|
else if (signum == SIGUSR1)
|
||||||
{
|
{
|
||||||
if (_hyperion != nullptr)
|
if (suspendHandler != nullptr)
|
||||||
{
|
{
|
||||||
_hyperion->toggleStateAllInstances(false);
|
suspendHandler->suspend();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (signum == SIGUSR2)
|
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
|
#ifdef WIN32
|
||||||
BooleanOption & consoleOption = parser.add<BooleanOption> ('c', "console", "Open a console window to view log output");
|
BooleanOption & consoleOption = parser.add<BooleanOption> ('c', "console", "Open a console window to view log output");
|
||||||
#endif
|
#endif
|
||||||
parser.add<BooleanOption> (0x0, "desktop", "Show systray on desktop");
|
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, "service", "Force hyperion to start as console service");
|
||||||
#if defined(ENABLE_EFFECTENGINE)
|
#if defined(ENABLE_EFFECTENGINE)
|
||||||
Option & exportEfxOption = parser.add<Option> (0x0, "export-effects", "Export effects to given path");
|
Option & exportEfxOption = parser.add<Option> (0x0, "export-effects", "Export effects to given path");
|
||||||
#endif
|
#endif
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include <QColor>
|
#include <QColor>
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
#include <utils/ColorRgb.h>
|
#include <utils/ColorRgb.h>
|
||||||
#include <utils/Process.h>
|
#include <utils/Process.h>
|
||||||
@ -24,6 +25,7 @@
|
|||||||
|
|
||||||
#include "hyperiond.h"
|
#include "hyperiond.h"
|
||||||
#include "systray.h"
|
#include "systray.h"
|
||||||
|
#include "SuspendHandler.h"
|
||||||
|
|
||||||
SysTray::SysTray(HyperionDaemon *hyperiond)
|
SysTray::SysTray(HyperionDaemon *hyperiond)
|
||||||
: QWidget()
|
: QWidget()
|
||||||
@ -31,6 +33,7 @@ SysTray::SysTray(HyperionDaemon *hyperiond)
|
|||||||
, _hyperiond(hyperiond)
|
, _hyperiond(hyperiond)
|
||||||
, _hyperion(nullptr)
|
, _hyperion(nullptr)
|
||||||
, _instanceManager(HyperionIManager::getInstance())
|
, _instanceManager(HyperionIManager::getInstance())
|
||||||
|
, _suspendHandler (hyperiond->getSuspendHandlerInstance())
|
||||||
, _webPort(8090)
|
, _webPort(8090)
|
||||||
{
|
{
|
||||||
Q_INIT_RESOURCE(resources);
|
Q_INIT_RESOURCE(resources);
|
||||||
@ -79,7 +82,15 @@ void SysTray::createTrayIcon()
|
|||||||
|
|
||||||
restartAction = new QAction(tr("&Restart"), this);
|
restartAction = new QAction(tr("&Restart"), this);
|
||||||
restartAction->setIcon(QPixmap(":/restart.svg"));
|
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 = new QAction(tr("&Color"), this);
|
||||||
colorAction->setIcon(QPixmap(":/color.svg"));
|
colorAction->setIcon(QPixmap(":/color.svg"));
|
||||||
@ -102,7 +113,7 @@ void SysTray::createTrayIcon()
|
|||||||
_trayIconEfxMenu->setIcon(QPixmap(":/effects.svg"));
|
_trayIconEfxMenu->setIcon(QPixmap(":/effects.svg"));
|
||||||
|
|
||||||
// custom effects
|
// custom effects
|
||||||
for (auto efx : efxs)
|
for (const auto &efx : efxs)
|
||||||
{
|
{
|
||||||
if (efx.file.mid(0, 1) != ":")
|
if (efx.file.mid(0, 1) != ":")
|
||||||
{
|
{
|
||||||
@ -117,7 +128,7 @@ void SysTray::createTrayIcon()
|
|||||||
_trayIconEfxMenu->addSeparator();
|
_trayIconEfxMenu->addSeparator();
|
||||||
|
|
||||||
// build in effects
|
// build in effects
|
||||||
for (auto efx : efxs)
|
for (const auto &efx : efxs)
|
||||||
{
|
{
|
||||||
if (efx.file.mid(0, 1) == ":")
|
if (efx.file.mid(0, 1) == ":")
|
||||||
{
|
{
|
||||||
@ -145,7 +156,16 @@ void SysTray::createTrayIcon()
|
|||||||
#endif
|
#endif
|
||||||
_trayIconMenu->addAction(clearAction);
|
_trayIconMenu->addAction(clearAction);
|
||||||
_trayIconMenu->addSeparator();
|
_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);
|
_trayIconMenu->addAction(quitAction);
|
||||||
|
|
||||||
_trayIcon = new QSystemTrayIcon(this);
|
_trayIcon = new QSystemTrayIcon(this);
|
||||||
@ -180,7 +200,7 @@ void SysTray::setAutorunState()
|
|||||||
|
|
||||||
void SysTray::setColor(const QColor & color)
|
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);
|
_hyperion->setColor(PriorityMuxer::FG_PRIORITY,rgbColor, PriorityMuxer::ENDLESS);
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include <hyperion/Hyperion.h>
|
#include <hyperion/Hyperion.h>
|
||||||
#include <hyperion/HyperionIManager.h>
|
#include <hyperion/HyperionIManager.h>
|
||||||
|
#include "SuspendHandler.h"
|
||||||
|
|
||||||
class HyperionDaemon;
|
class HyperionDaemon;
|
||||||
|
|
||||||
@ -61,6 +62,8 @@ private:
|
|||||||
|
|
||||||
QAction *quitAction;
|
QAction *quitAction;
|
||||||
QAction *restartAction;
|
QAction *restartAction;
|
||||||
|
QAction *suspendAction;
|
||||||
|
QAction *resumeAction;
|
||||||
QAction *startAction;
|
QAction *startAction;
|
||||||
QAction *stopAction;
|
QAction *stopAction;
|
||||||
QAction *colorAction;
|
QAction *colorAction;
|
||||||
@ -75,9 +78,12 @@ private:
|
|||||||
#if defined(ENABLE_EFFECTENGINE)
|
#if defined(ENABLE_EFFECTENGINE)
|
||||||
QMenu *_trayIconEfxMenu;
|
QMenu *_trayIconEfxMenu;
|
||||||
#endif
|
#endif
|
||||||
|
QMenu *_trayIconSystemMenu;
|
||||||
QColorDialog _colorDlg;
|
QColorDialog _colorDlg;
|
||||||
HyperionDaemon *_hyperiond;
|
HyperionDaemon *_hyperiond;
|
||||||
Hyperion *_hyperion;
|
Hyperion *_hyperion;
|
||||||
HyperionIManager *_instanceManager;
|
HyperionIManager *_instanceManager;
|
||||||
quint16 _webPort;
|
quint16 _webPort;
|
||||||
|
|
||||||
|
SuspendHandler *_suspendHandler;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user