Introduce Event Services (#1653)

* Allow to enable/disable suspend & lock event handling

* Fix Windows

* Refactor event handling incl.CEC

* Revert "Auxiliary commit to revert individual files from 0d9a8b8a3a4a09609a339f54c7d8a9384c561282"

This reverts commit 80737d926ad151a07b2493dd1685ed502975cb2e.

* Support Events for Grabbers generically

* Have CECEvent to actions configurable, further clean-ups

* Remove handleEvent from V4L2grabber, as grabber will be stopped on suspend

* Validate that one CEC Event can only trigger one action

* MacOS lock/unlock added

* fast windows fix

* Corrections

* Fix CodeQL findings

* add macos lock/unlock handler

* Migration of CEC-config and have default actions

* Correct target_link_libraries

* Include Foundation

* macOS include AppKit

* Support Scheduled Events, cleanups.

* Fix destructing

* Fix coredump during free

* Consider additional error sceanrio

* Fix missing code

* install desktop icons

* correct bash logic

---------

Co-authored-by: Paulchen-Panther <16664240+Paulchen-Panther@users.noreply.github.com>
This commit is contained in:
LordGrey
2023-11-27 09:06:43 +01:00
committed by GitHub
parent 2e0cc9cfa8
commit a1f0821f33
53 changed files with 2306 additions and 829 deletions

View File

@@ -34,7 +34,6 @@ add_executable(${PROJECT_NAME}
systray.h
hyperiond.cpp
systray.cpp
SuspendHandler.cpp
main.cpp
${WIN_RC_FILE}
${MACOS_BUNDLE_RESOURCE_FILES}
@@ -48,6 +47,7 @@ target_link_libraries(${PROJECT_NAME}
ssdp
database
resources
events
Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::Gui
Qt${QT_VERSION_MAJOR}::Network

View File

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

View File

@@ -1,79 +0,0 @@
#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

View File

@@ -92,12 +92,14 @@ HyperionDaemon::HyperionDaemon(const QString& rootPath, QObject* parent, bool lo
, _osxGrabber(nullptr)
, _qtGrabber(nullptr)
, _dxGrabber(nullptr)
, _ssdp(nullptr)
, _audioGrabber(nullptr)
#ifdef ENABLE_CEC
, _cecHandler(nullptr)
#endif
, _suspendHandler(nullptr)
, _ssdp(nullptr)
, _eventHandler(nullptr)
, _osEventHandler(nullptr)
, _eventScheduler(nullptr)
#ifdef ENABLE_CEC
, _cecHandler(nullptr)
#endif
, _currVideoMode(VideoMode::VIDEO_2D)
{
HyperionDaemon::daemon = this;
@@ -119,8 +121,6 @@ HyperionDaemon::HyperionDaemon(const QString& rootPath, QObject* parent, bool lo
handleSettingsUpdate(settings::LOGGER, getSetting(settings::LOGGER));
}
createCecHandler();
//Create MdnsBrowser singleton in main tread to ensure thread affinity during destruction
#ifdef ENABLE_MDNS
MdnsBrowser::getInstance();
@@ -177,7 +177,8 @@ HyperionDaemon::HyperionDaemon(const QString& rootPath, QObject* parent, bool lo
// ---- network services -----
startNetworkServices();
_suspendHandler = new SuspendHandler();
// init events services
startEventServices();
}
HyperionDaemon::~HyperionDaemon()
@@ -234,6 +235,7 @@ void HyperionDaemon::handleInstanceStateChange(InstanceState state, quint8 insta
#endif
sslWsThread->start();
}
break;
case InstanceState::H_STOPPED:
@@ -262,6 +264,10 @@ void HyperionDaemon::freeObjects()
{
Debug(_log, "Cleaning up Hyperion before quit.");
stopCecHandler();
delete _eventScheduler;
delete _osEventHandler;
#ifdef ENABLE_MDNS
if (_mDNSProvider != nullptr)
{
@@ -332,20 +338,6 @@ void HyperionDaemon::freeObjects()
_sslWebserver = nullptr;
}
#ifdef ENABLE_CEC
if (_cecHandler != nullptr)
{
auto cecHandlerThread = _cecHandler->thread();
cecHandlerThread->quit();
cecHandlerThread->wait();
delete cecHandlerThread;
delete _cecHandler;
_cecHandler = nullptr;
}
#endif
delete _suspendHandler;
// stop Hyperions (non blocking)
_instanceManager->stopAll();
@@ -432,6 +424,33 @@ void HyperionDaemon::startNetworkServices()
ssdpThread->start();
}
void HyperionDaemon::startEventServices()
{
if (_eventHandler == nullptr)
{
_eventHandler = EventHandler::getInstance();
Debug(_log, "Hyperion event handler created");
}
if (_eventScheduler == nullptr)
{
_eventScheduler = new EventScheduler();
_eventScheduler->handleSettingsUpdate(settings::SCHEDEVENTS, getSetting(settings::SCHEDEVENTS));
connect(this, &HyperionDaemon::settingsChanged, _eventScheduler, &EventScheduler::handleSettingsUpdate);
Debug(_log, "Hyperion event scheduler created");
}
if (_osEventHandler == nullptr)
{
_osEventHandler = new OsEventHandler();
_osEventHandler->handleSettingsUpdate(settings::OSEVENTS, getSetting(settings::OSEVENTS));
connect(this, &HyperionDaemon::settingsChanged, _osEventHandler, &OsEventHandler::handleSettingsUpdate);
Debug(_log, "Operating System event handler created");
}
startCecHandler();
}
void HyperionDaemon::handleSettingsUpdate(settings::type settingsType, const QJsonDocument& config)
{
if (settingsType == settings::LOGGER)
@@ -692,19 +711,6 @@ void HyperionDaemon::handleSettingsUpdate(settings::type settingsType, const QJs
}
else if (settingsType == settings::V4L2)
{
#ifdef ENABLE_CEC
const QJsonObject& grabberConfig = config.object();
if (_cecHandler != nullptr && grabberConfig["cecDetection"].toBool(false))
{
QMetaObject::invokeMethod(_cecHandler, "start", Qt::QueuedConnection);
}
else
{
QMetaObject::invokeMethod(_cecHandler, "stop", Qt::QueuedConnection);
}
#endif
#if defined(ENABLE_V4L2) || defined(ENABLE_MF)
if (_videoGrabber == nullptr)
{
@@ -915,26 +921,41 @@ void HyperionDaemon::createGrabberOsx(const QJsonObject& grabberConfig)
#endif
}
void HyperionDaemon::createCecHandler()
void HyperionDaemon::startCecHandler()
{
#if defined(ENABLE_V4L2) && defined(ENABLE_CEC)
_cecHandler = new CECHandler;
#if defined(ENABLE_CEC)
if (_cecHandler == nullptr)
{
_cecHandler = new CECHandler(getSetting(settings::CECEVENTS));
QThread* thread = new QThread(this);
thread->setObjectName("CECThread");
_cecHandler->moveToThread(thread);
thread->start();
QThread* cecHandlerThread = new QThread(this);
cecHandlerThread->setObjectName("CECThread");
_cecHandler->moveToThread(cecHandlerThread);
connect(_cecHandler, &CECHandler::cecEvent, [&](CECEvent event) {
if (_videoGrabber != nullptr)
{
_videoGrabber->handleCecEvent(event);
}
});
connect(cecHandlerThread, &QThread::started, _cecHandler, &CECHandler::start);
connect(cecHandlerThread, &QThread::finished, _cecHandler, &CECHandler::stop);
connect(this, &HyperionDaemon::settingsChanged, _cecHandler, &CECHandler::handleSettingsUpdate);
Info(_log, "CEC event handler created");
Info(_log, "CEC handler created");
cecHandlerThread->start();
}
#else
Debug(_log, "The CEC handler is not supported on this platform");
#endif
}
void HyperionDaemon::stopCecHandler()
{
#if defined(ENABLE_CEC)
if (_cecHandler != nullptr)
{
auto cecHandlerThread = _cecHandler->thread();
cecHandlerThread->quit();
cecHandlerThread->wait();
delete cecHandlerThread;
_cecHandler = nullptr;
}
Info(_log, "CEC handler stopped");
#endif
}

View File

@@ -75,7 +75,9 @@
#include <utils/settings.h>
#include <utils/Components.h>
#include "SuspendHandler.h"
#include <events/EventHandler.h>
#include <events/OsEventHandler.h>
#include <events/EventScheduler.h>
class HyperionIManager;
class SysTray;
@@ -103,18 +105,13 @@ class HyperionDaemon : public QObject
public:
HyperionDaemon(const QString& rootPath, QObject *parent, bool logLvlOverwrite, bool readonlyMode = false);
~HyperionDaemon();
~HyperionDaemon() override;
///
/// @brief Get webserver pointer (systray)
///
WebServer *getWebServerInstance() { return _webserver; }
///
/// @brief Get suspense handler pointer
///
SuspendHandler* getSuspendHandlerInstance() { return _suspendHandler; }
///
/// @brief Get the current videoMode
///
@@ -126,6 +123,7 @@ public:
QJsonDocument getSetting(settings::type type) const;
void startNetworkServices();
void startEventServices();
static HyperionDaemon* getInstance() { return daemon; }
static HyperionDaemon* daemon;
@@ -185,10 +183,12 @@ private:
void createGrabberX11(const QJsonObject & grabberConfig);
void createGrabberXcb(const QJsonObject & grabberConfig);
void createGrabberQt(const QJsonObject & grabberConfig);
void createCecHandler();
void createGrabberDx(const QJsonObject & grabberConfig);
void createGrabberAudio(const QJsonObject & grabberConfig);
void startCecHandler();
void stopCecHandler();
Logger* _log;
HyperionIManager* _instanceManager;
AuthManager* _authManager;
@@ -213,10 +213,12 @@ private:
DirectXWrapper* _dxGrabber;
SSDPHandler* _ssdp;
AudioWrapper* _audioGrabber;
#ifdef ENABLE_CEC
CECHandler* _cecHandler;
#endif
SuspendHandler* _suspendHandler;
EventHandler* _eventHandler;
OsEventHandler* _osEventHandler;
EventScheduler* _eventScheduler;
#ifdef ENABLE_CEC
CECHandler* _cecHandler;
#endif
#if defined(ENABLE_FLATBUF_SERVER)
FlatBufferServer* _flatBufferServer;

View File

@@ -1,5 +1,4 @@
#include <cassert>
#include <csignal>
#include <stdlib.h>
#include <stdio.h>
@@ -46,40 +45,12 @@
#include "hyperiond.h"
#include "systray.h"
#include "SuspendHandler.h"
#include <events/EventHandler.h>
using namespace commandline;
#define PERM0664 (QFileDevice::ReadOwner | QFileDevice::ReadGroup | QFileDevice::ReadOther | QFileDevice::WriteOwner | QFileDevice::WriteGroup)
#ifndef _WIN32
void signal_handler(int signum)
{
HyperionDaemon* hyperiond = HyperionDaemon::getInstance();
SuspendHandler* suspendHandler = hyperiond->getSuspendHandlerInstance();
if (signum == SIGCHLD)
{
// only quit when a registered child process is gone
// currently this feature is not active ...
}
else if (signum == SIGUSR1)
{
if (suspendHandler != nullptr)
{
suspendHandler->suspend();
}
}
else if (signum == SIGUSR2)
{
if (suspendHandler != nullptr)
{
suspendHandler->resume();
}
}
}
#endif
QCoreApplication* createApplication(int &argc, char *argv[])
{
bool isGuiApp = false;
@@ -150,11 +121,6 @@ int main(int argc, char** argv)
DefaultSignalHandler::install();
#ifndef _WIN32
signal(SIGCHLD, signal_handler);
signal(SIGUSR1, signal_handler);
signal(SIGUSR2, signal_handler);
#endif
// force the locale
setlocale(LC_ALL, "C");
QLocale::setDefault(QLocale::c());

View File

@@ -22,10 +22,11 @@
#endif
#include <webserver/WebServer.h>
#include <hyperion/PriorityMuxer.h>
#include <events/EventHandler.h>
#include "hyperiond.h"
#include "systray.h"
#include "SuspendHandler.h"
SysTray::SysTray(HyperionDaemon *hyperiond)
: QWidget()
@@ -34,7 +35,6 @@ SysTray::SysTray(HyperionDaemon *hyperiond)
, _hyperion(nullptr)
, _instanceManager(HyperionIManager::getInstance())
, _webPort(8090)
, _suspendHandler (hyperiond->getSuspendHandlerInstance())
{
Q_INIT_RESOURCE(resources);
@@ -44,6 +44,8 @@ SysTray::SysTray(HyperionDaemon *hyperiond)
// instance changes
connect(_instanceManager, &HyperionIManager::instanceStateChanged, this, &SysTray::handleInstanceStateChange);
connect(this, &SysTray::signalEvent, EventHandler::getInstance(), &EventHandler::handleEvent);
}
SysTray::~SysTray()
@@ -84,13 +86,15 @@ void SysTray::createTrayIcon()
restartAction->setIcon(QPixmap(":/restart.svg"));
connect(restartAction, &QAction::triggered, this , [=](){ Process::restartHyperion(12); });
// TODO: Check if can be done with SystemEvents
suspendAction = new QAction(tr("&Suspend"), this);
suspendAction->setIcon(QPixmap(":/suspend.svg"));
connect(suspendAction, &QAction::triggered, _suspendHandler, QOverload<>::of(&SuspendHandler::suspend));
connect(suspendAction, &QAction::triggered, this, [this]() { emit signalEvent(Event::Suspend); });
resumeAction = new QAction(tr("&Resume"), this);
resumeAction->setIcon(QPixmap(":/resume.svg"));
connect(resumeAction, &QAction::triggered, _suspendHandler, &SuspendHandler::resume);
connect(resumeAction, &QAction::triggered, this, [this]() { emit signalEvent(Event::Resume); });
colorAction = new QAction(tr("&Color"), this);
colorAction->setIcon(QPixmap(":/color.svg"));

View File

@@ -12,7 +12,7 @@
#include <hyperion/Hyperion.h>
#include <hyperion/HyperionIManager.h>
#include "SuspendHandler.h"
#include <events/EventHandler.h>
class HyperionDaemon;
@@ -22,13 +22,13 @@ class SysTray : public QWidget
public:
SysTray(HyperionDaemon *hyperiond);
~SysTray();
~SysTray() override;
public slots:
void showColorDialog();
void setColor(const QColor & color);
void closeEvent(QCloseEvent *event);
void closeEvent(QCloseEvent *event) override;
void settings() const;
#if defined(ENABLE_EFFECTENGINE)
void setEffect();
@@ -42,13 +42,16 @@ private slots:
///
/// @brief is called whenever the webserver changes the port
///
void webserverPortChanged(quint16 port) { _webPort = port; };
void webserverPortChanged(quint16 port) { _webPort = port; }
///
/// @brief is called whenever a hyperion instance state changes
///
void handleInstanceStateChange(InstanceState state, quint8 instance, const QString& name);
signals:
void signalEvent(Event event);
private:
void createTrayIcon();
@@ -84,6 +87,4 @@ private:
Hyperion *_hyperion;
HyperionIManager *_instanceManager;
quint16 _webPort;
SuspendHandler *_suspendHandler;
};