mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2025-03-01 10:33:28 +00:00
UI and Web updates (#1421)
* Stop Web-Capture when priority changes * Remote control UI: Treat duration=0 as endless * Stop Web-Capture on non-Image events changes * LED Matrix Layout - Support vertical cabling direction * Additional Yeelight models * Treat http headers case insensitive * Update change log * Treat http headers case insensitive (consider Qt version) * API - Consider provided format when setImage * UI - Support Boblight configuration per LED instance * Support multiple Boblight clients with different priorities * Update changelog * Simplify isGUI rules allowing for QT only builds * Sysinfo: Fix indents * LED-Devices: Show warning, if get properties failed * Qt-Grabber: Fixed position handling of multiple monitors * LED layout: Remove indention limitations * Yeelight: Test YLTD003 * hyperion-remote: Provide image filename to muxer/UI * Refactor PriorityMuxer and related * Temp: Build under Windows 2019 * Yeelight: Remove YLTD003 as it is not working without additional changes * Test Windows-latest with out removing redistributables/new MSVC * correct workflows * correct CI script * Build Windows with Qt 5.15.2 * Priority Muxer: Updates after testing * Fix Typo * Update BGHandler * QTGrabber - Reactivate windows code to avoid cursor issues * Emit prioritiesChanged when autoselect was changed by user Co-authored-by: Paulchen Panther <Paulchen-Panter@protonmail.com>
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
#include <QDateTime>
|
||||
#include <QCryptographicHash>
|
||||
#include <QImage>
|
||||
#include <QImageReader>
|
||||
#include <QBuffer>
|
||||
#include <QByteArray>
|
||||
#include <QTimer>
|
||||
@@ -83,15 +84,19 @@ void API::init()
|
||||
}
|
||||
// if this is localConnection and network allows unauth locals, set authorized flag
|
||||
if (apiAuthRequired && _localConnection)
|
||||
{
|
||||
_authorized = !_authManager->isLocalAuthRequired();
|
||||
}
|
||||
|
||||
// admin access is allowed, when the connection is local and the option for local admin isn't set. Con: All local connections get full access
|
||||
if (_localConnection)
|
||||
{
|
||||
_adminAuthorized = !_authManager->isLocalAdminAuthRequired();
|
||||
// just in positive direction
|
||||
if (_adminAuthorized)
|
||||
_authorized = true;
|
||||
if (_adminAuthorized)
|
||||
{
|
||||
_authorized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,12 +118,25 @@ bool API::setImage(ImageCmdData &data, hyperion::Components comp, QString &reply
|
||||
// truncate name length
|
||||
data.imgName.truncate(16);
|
||||
|
||||
if (data.format == "auto")
|
||||
{
|
||||
QImage img = QImage::fromData(data.data);
|
||||
if (!data.format.isEmpty())
|
||||
{
|
||||
if (data.format == "auto")
|
||||
{
|
||||
data.format = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!QImageReader::supportedImageFormats().contains(data.format.toLower().toUtf8()))
|
||||
{
|
||||
replyMsg = "The given format [" + data.format + "] is not supported";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
QImage img = QImage::fromData(data.data, QSTRING_CSTR(data.format));
|
||||
if (img.isNull())
|
||||
{
|
||||
replyMsg = "Failed to parse picture, the file might be corrupted";
|
||||
replyMsg = "Failed to parse picture, the file might be corrupted or content does not match the given format [" + data.format + "]";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@@ -365,20 +365,26 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const QString
|
||||
QJsonArray priorities;
|
||||
uint64_t now = QDateTime::currentMSecsSinceEpoch();
|
||||
QList<int> activePriorities = _hyperion->getActivePriorities();
|
||||
activePriorities.removeAll(255);
|
||||
activePriorities.removeAll(PriorityMuxer::LOWEST_PRIORITY);
|
||||
int currentPriority = _hyperion->getCurrentPriority();
|
||||
|
||||
for(int priority : activePriorities)
|
||||
for(int priority : qAsConst(activePriorities))
|
||||
{
|
||||
const Hyperion::InputInfo &priorityInfo = _hyperion->getPriorityInfo(priority);
|
||||
|
||||
QJsonObject item;
|
||||
item["priority"] = priority;
|
||||
if (priorityInfo.timeoutTime_ms > 0)
|
||||
|
||||
if (priorityInfo.timeoutTime_ms > 0 )
|
||||
{
|
||||
item["duration_ms"] = int(priorityInfo.timeoutTime_ms - now);
|
||||
}
|
||||
|
||||
// owner has optional informations to the component
|
||||
if (!priorityInfo.owner.isEmpty())
|
||||
{
|
||||
item["owner"] = priorityInfo.owner;
|
||||
}
|
||||
|
||||
item["componentId"] = QString(hyperion::componentToIdString(priorityInfo.componentId));
|
||||
item["origin"] = priorityInfo.origin;
|
||||
@@ -397,7 +403,8 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const QString
|
||||
LEDcolor.insert("RGB", RGBValue);
|
||||
|
||||
uint16_t Hue;
|
||||
float Saturation, Luminace;
|
||||
float Saturation;
|
||||
float Luminace;
|
||||
|
||||
// add HSL Value to Array
|
||||
QJsonArray HSLValue;
|
||||
|
@@ -44,6 +44,8 @@ JsonCB::JsonCB(QObject* parent)
|
||||
#if defined(ENABLE_EFFECTENGINE)
|
||||
_availableCommands << "effects-update";
|
||||
#endif
|
||||
|
||||
qRegisterMetaType<PriorityMuxer::InputsMap>("InputsMap");
|
||||
}
|
||||
|
||||
bool JsonCB::subscribeFor(const QString& type, bool unsubscribe)
|
||||
@@ -226,25 +228,33 @@ void JsonCB::handleBonjourChange(const QMap<QString,BonjourRecord>& bRegisters)
|
||||
doCallback("sessions-update", QVariant(data));
|
||||
}
|
||||
#endif
|
||||
void JsonCB::handlePriorityUpdate()
|
||||
|
||||
void JsonCB::handlePriorityUpdate(int currentPriority, const PriorityMuxer::InputsMap& activeInputs)
|
||||
{
|
||||
QJsonObject data;
|
||||
QJsonArray priorities;
|
||||
uint64_t now = QDateTime::currentMSecsSinceEpoch();
|
||||
QList<int> activePriorities = _prioMuxer->getPriorities();
|
||||
activePriorities.removeAll(255);
|
||||
int currentPriority = _prioMuxer->getCurrentPriority();
|
||||
QList<int> activePriorities = activeInputs.keys();
|
||||
|
||||
activePriorities.removeAll(PriorityMuxer::LOWEST_PRIORITY);
|
||||
|
||||
for (int priority : qAsConst(activePriorities)) {
|
||||
|
||||
const Hyperion::InputInfo& priorityInfo = activeInputs[priority];
|
||||
|
||||
for (int priority : activePriorities) {
|
||||
const Hyperion::InputInfo priorityInfo = _prioMuxer->getInputInfo(priority);
|
||||
QJsonObject item;
|
||||
item["priority"] = priority;
|
||||
|
||||
if (priorityInfo.timeoutTime_ms > 0 )
|
||||
{
|
||||
item["duration_ms"] = int(priorityInfo.timeoutTime_ms - now);
|
||||
}
|
||||
|
||||
// owner has optional informations to the component
|
||||
if(!priorityInfo.owner.isEmpty())
|
||||
{
|
||||
item["owner"] = priorityInfo.owner;
|
||||
}
|
||||
|
||||
item["componentId"] = QString(hyperion::componentToIdString(priorityInfo.componentId));
|
||||
item["origin"] = priorityInfo.origin;
|
||||
@@ -263,7 +273,8 @@ void JsonCB::handlePriorityUpdate()
|
||||
LEDcolor.insert("RGB", RGBValue);
|
||||
|
||||
uint16_t Hue;
|
||||
float Saturation, Luminace;
|
||||
float Saturation;
|
||||
float Luminace;
|
||||
|
||||
// add HSL Value to Array
|
||||
QJsonArray HSLValue;
|
||||
|
@@ -55,11 +55,7 @@ BoblightClientConnection::BoblightClientConnection(Hyperion* hyperion, QTcpSocke
|
||||
|
||||
BoblightClientConnection::~BoblightClientConnection()
|
||||
{
|
||||
// clear the current channel
|
||||
if (_priority != 0 && _priority >= BOBLIGHT_MIN_PRIORITY && _priority <= BOBLIGHT_MAX_PRIORITY)
|
||||
_hyperion->clear(_priority);
|
||||
|
||||
delete _socket;
|
||||
_socket->deleteLater();
|
||||
}
|
||||
|
||||
void BoblightClientConnection::readData()
|
||||
@@ -117,9 +113,10 @@ QString BoblightClientConnection::readMessage(const char* data, const size_t siz
|
||||
|
||||
void BoblightClientConnection::socketClosed()
|
||||
{
|
||||
// clear the current channel
|
||||
if (_priority >= BOBLIGHT_MIN_PRIORITY && _priority <= BOBLIGHT_MAX_PRIORITY)
|
||||
{
|
||||
_hyperion->clear(_priority);
|
||||
}
|
||||
|
||||
emit connectionClosed(this);
|
||||
}
|
||||
@@ -205,40 +202,58 @@ void BoblightClientConnection::handleMessage(const QString& message)
|
||||
{
|
||||
bool rc;
|
||||
const int prio = static_cast<int>(parseUInt(messageParts[2], &rc));
|
||||
if (rc && prio != _priority)
|
||||
if (rc)
|
||||
{
|
||||
if (_priority != 0 && _hyperion->getPriorityInfo(_priority).componentId == hyperion::COMP_BOBLIGHTSERVER)
|
||||
_hyperion->clear(_priority);
|
||||
int currentPriority = _hyperion->getCurrentPriority();
|
||||
|
||||
if (prio < BOBLIGHT_MIN_PRIORITY || prio > BOBLIGHT_MAX_PRIORITY)
|
||||
if (prio == currentPriority)
|
||||
{
|
||||
_priority = BOBLIGHT_DEFAULT_PRIORITY;
|
||||
while (_hyperion->getActivePriorities().contains(_priority))
|
||||
{
|
||||
_priority += 1;
|
||||
}
|
||||
|
||||
// warn against invalid priority
|
||||
Warning(_log, "The priority %i is not in the priority range of [%d-%d]. Priority %i is used instead.",
|
||||
prio, BOBLIGHT_MIN_PRIORITY, BOBLIGHT_MAX_PRIORITY, _priority);
|
||||
// register new priority (previously modified)
|
||||
_hyperion->registerInput(_priority, hyperion::COMP_BOBLIGHTSERVER, QString("Boblight@%1").arg(_socket->peerAddress().toString()));
|
||||
Error(_log, "The priority %i is already in use onther component of type [%s]", prio, componentToString(_hyperion->getPriorityInfo(currentPriority).componentId));
|
||||
_socket->close();
|
||||
}
|
||||
else
|
||||
{
|
||||
// register new priority
|
||||
_hyperion->registerInput(prio, hyperion::COMP_BOBLIGHTSERVER, QString("Boblight@%1").arg(_socket->peerAddress().toString()));
|
||||
_priority = prio;
|
||||
}
|
||||
if (prio < BOBLIGHT_MIN_PRIORITY || prio > BOBLIGHT_MAX_PRIORITY)
|
||||
{
|
||||
_priority = BOBLIGHT_DEFAULT_PRIORITY;
|
||||
while (_hyperion->getActivePriorities().contains(_priority))
|
||||
{
|
||||
_priority += 1;
|
||||
}
|
||||
|
||||
return;
|
||||
// warn against invalid priority
|
||||
Warning(_log, "The priority %i is not in the priority range of [%d-%d]. Priority %i is used instead.",
|
||||
prio, BOBLIGHT_MIN_PRIORITY, BOBLIGHT_MAX_PRIORITY, _priority);
|
||||
// register new priority (previously modified)
|
||||
_hyperion->registerInput(_priority, hyperion::COMP_BOBLIGHTSERVER, QString("Boblight@%1").arg(_clientAddress));
|
||||
}
|
||||
else
|
||||
{
|
||||
// register new priority
|
||||
_hyperion->registerInput(prio, hyperion::COMP_BOBLIGHTSERVER, QString("Boblight@%1").arg(_clientAddress));
|
||||
_priority = prio;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (messageParts[0] == "sync")
|
||||
{
|
||||
if (_priority >= BOBLIGHT_MIN_PRIORITY && _priority <= BOBLIGHT_MAX_PRIORITY)
|
||||
_hyperion->setInput(_priority, _ledColors); // send current color values to hyperion
|
||||
{
|
||||
int currentPriority = _hyperion->getCurrentPriority();
|
||||
if ( _priority != currentPriority)
|
||||
{
|
||||
// register this connection's priority
|
||||
_hyperion->registerInput(_priority, hyperion::COMP_BOBLIGHTSERVER, QString("Boblight@%1").arg(_clientAddress));
|
||||
}
|
||||
|
||||
if (_priority >= BOBLIGHT_MIN_PRIORITY && _priority <= BOBLIGHT_MAX_PRIORITY)
|
||||
{
|
||||
_hyperion->setInput(_priority, _ledColors); // send current color values to hyperion
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -387,6 +402,14 @@ uint8_t BoblightClientConnection::parseByte(const QString& s, bool *ok) const
|
||||
return static_cast<uint8_t>(qBound(LO, int(HI * d), HI)); // qBound args are in order min, value, max; see: https://doc.qt.io/qt-5/qtglobal.html#qBound
|
||||
}
|
||||
|
||||
void BoblightClientConnection::sendMessage(const QByteArray &message)
|
||||
{
|
||||
if (_socket->isOpen())
|
||||
{
|
||||
_socket->write(message);
|
||||
}
|
||||
}
|
||||
|
||||
void BoblightClientConnection::sendLightMessage()
|
||||
{
|
||||
char buffer[256];
|
||||
|
@@ -36,6 +36,13 @@ public:
|
||||
///
|
||||
~BoblightClientConnection() override;
|
||||
|
||||
///
|
||||
/// Get the Boblight client's IP-address
|
||||
///
|
||||
/// @returns IP-address as QString
|
||||
///
|
||||
QString getClientAddress() { return _clientAddress; }
|
||||
|
||||
signals:
|
||||
///
|
||||
/// Signal which is emitted when the connection is being closed
|
||||
@@ -67,7 +74,7 @@ private:
|
||||
///
|
||||
/// @param message The boblight message to send
|
||||
///
|
||||
void sendMessage(const QByteArray &message) { _socket->write(message); };
|
||||
void sendMessage(const QByteArray &message);
|
||||
|
||||
///
|
||||
/// Send a lights message the to connected client
|
||||
|
@@ -22,9 +22,12 @@ BoblightServer::BoblightServer(Hyperion* hyperion,const QJsonDocument& config)
|
||||
, _server(new QTcpServer(this))
|
||||
, _openConnections()
|
||||
, _priority(0)
|
||||
, _log(Logger::getInstance("BOBLIGHT"))
|
||||
, _log(nullptr)
|
||||
, _port(0)
|
||||
{
|
||||
QString subComponent = _hyperion->property("instance").toString();
|
||||
_log= Logger::getInstance("BOBLIGHT", subComponent);
|
||||
|
||||
Debug(_log, "Instance created");
|
||||
|
||||
// listen for component change
|
||||
@@ -49,7 +52,7 @@ void BoblightServer::start()
|
||||
if (NetUtils::portAvailable(_port, _log))
|
||||
_server->listen(QHostAddress::Any, _port);
|
||||
|
||||
Info(_log, "Started on port %d", _port);
|
||||
Info(_log, "Started on port: %d", _port);
|
||||
|
||||
_hyperion->setNewComponentState(COMP_BOBLIGHTSERVER, _server->isListening());
|
||||
}
|
||||
@@ -92,11 +95,9 @@ uint16_t BoblightServer::getPort() const
|
||||
void BoblightServer::newConnection()
|
||||
{
|
||||
QTcpSocket * socket = _server->nextPendingConnection();
|
||||
|
||||
if (socket != nullptr)
|
||||
{
|
||||
Info(_log, "new connection");
|
||||
_hyperion->registerInput(_priority, hyperion::COMP_BOBLIGHTSERVER, QString("Boblight@%1").arg(socket->peerAddress().toString()));
|
||||
Info(_log, "New connection from %s ", QSTRING_CSTR(QString("Boblight@%1").arg(socket->peerAddress().toString())));
|
||||
BoblightClientConnection * connection = new BoblightClientConnection(_hyperion, socket, _priority);
|
||||
_openConnections.insert(connection);
|
||||
|
||||
@@ -107,7 +108,7 @@ void BoblightServer::newConnection()
|
||||
|
||||
void BoblightServer::closedConnection(BoblightClientConnection *connection)
|
||||
{
|
||||
Debug(_log, "connection closed");
|
||||
Debug(_log, "Connection closed for %s", QSTRING_CSTR(QString("Boblight@%1").arg(connection->getClientAddress())));
|
||||
_openConnections.remove(connection);
|
||||
|
||||
// schedule to delete the connection object
|
||||
|
@@ -219,7 +219,7 @@ void EffectEngine::effectFinished()
|
||||
_hyperion->clear(effect->getPriority());
|
||||
}
|
||||
|
||||
Info( _log, "effect finished");
|
||||
Info( _log, "Effect [%s] finished", QSTRING_CSTR(effect->getName()));
|
||||
for (auto effectIt = _activeEffects.begin(); effectIt != _activeEffects.end(); ++effectIt)
|
||||
{
|
||||
if (*effectIt == effect)
|
||||
|
@@ -127,7 +127,7 @@ void MessageForwarder::handleCompStateChangeRequest(hyperion::Components compone
|
||||
}
|
||||
}
|
||||
|
||||
void MessageForwarder::handlePriorityChanges(quint8 priority)
|
||||
void MessageForwarder::handlePriorityChanges(int priority)
|
||||
{
|
||||
const QJsonObject obj = _hyperion->getSetting(settings::NETFORWARD).object();
|
||||
if (priority != 0 && _forwarder_enabled && obj["enable"].toBool())
|
||||
|
@@ -66,9 +66,9 @@ bool QtGrabber::open()
|
||||
bool QtGrabber::setupDisplay()
|
||||
{
|
||||
bool result = false;
|
||||
if ( ! open() )
|
||||
if (!open())
|
||||
{
|
||||
if ( _isWayland )
|
||||
if (_isWayland)
|
||||
{
|
||||
Error(_log, "Grabber does not work under Wayland!");
|
||||
}
|
||||
@@ -80,45 +80,46 @@ bool QtGrabber::setupDisplay()
|
||||
_numberOfSDisplays = 0;
|
||||
|
||||
QScreen* primary = QGuiApplication::primaryScreen();
|
||||
QList<QScreen *> screens = QGuiApplication::screens();
|
||||
QList<QScreen*> screens = QGuiApplication::screens();
|
||||
// inject main screen at 0, if not nullptr
|
||||
if(primary != nullptr)
|
||||
if (primary != nullptr)
|
||||
{
|
||||
screens.prepend(primary);
|
||||
// remove last main screen if twice in list
|
||||
if(screens.lastIndexOf(primary) > 0)
|
||||
if (screens.lastIndexOf(primary) > 0)
|
||||
{
|
||||
screens.removeAt(screens.lastIndexOf(primary));
|
||||
}
|
||||
}
|
||||
|
||||
if(screens.isEmpty())
|
||||
if (screens.isEmpty())
|
||||
{
|
||||
Error(_log, "No displays found to capture from!");
|
||||
result = false;
|
||||
result = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_numberOfSDisplays = screens.size();
|
||||
|
||||
Info(_log,"Available Displays:");
|
||||
Info(_log, "Available Displays:");
|
||||
int index = 0;
|
||||
for(auto * screen : qAsConst(screens))
|
||||
for (auto* screen : qAsConst(screens))
|
||||
{
|
||||
const QRect geo = screen->geometry();
|
||||
Info(_log,"Display %d: Name: %s Geometry: (L,T,R,B) %d,%d,%d,%d Depth:%dbit", index, QSTRING_CSTR(screen->name()), geo.left(), geo.top() ,geo.right(), geo.bottom(), screen->depth());
|
||||
Info(_log, "Display %d: Name: %s Resolution: [%dx%d], Geometry: (L,T,R,B) %d,%d,%d,%d Depth:%dbit", index, QSTRING_CSTR(screen->name()), geo.width(), geo.height(), geo.x(), geo.y(), geo.x() + geo.width(), geo.y() + geo.height(), screen->depth());
|
||||
|
||||
++index;
|
||||
}
|
||||
|
||||
if (screens.at(0)->size() != screens.at(0)->virtualSize())
|
||||
{
|
||||
const QRect vgeo = screens.at(0)->virtualGeometry();
|
||||
Info(_log,"Display %d: Name: %s Geometry: (L,T,R,B) %d,%d,%d,%d Depth:%dbit", _numberOfSDisplays, "All Displays", vgeo.left(), vgeo.top() ,vgeo.right(), vgeo.bottom(), screens.at(0)->depth());
|
||||
Info(_log, "Display %d: Name: %s Resolution: [%dx%d], Geometry: (L,T,R,B) %d,%d,%d,%d Depth:%dbit", _numberOfSDisplays, "All Displays", vgeo.width(), vgeo.height(), vgeo.x(), vgeo.y(), vgeo.x() + vgeo.width(), vgeo.y() + vgeo.height(), screens.at(0)->depth());
|
||||
}
|
||||
|
||||
_isVirtual = false;
|
||||
// be sure the index is available
|
||||
if (_display > _numberOfSDisplays - 1 )
|
||||
if (_display > _numberOfSDisplays - 1)
|
||||
{
|
||||
|
||||
if ((screens.at(0)->size() != screens.at(0)->virtualSize()) && (_display == _numberOfSDisplays))
|
||||
@@ -145,17 +146,17 @@ bool QtGrabber::setupDisplay()
|
||||
}
|
||||
else
|
||||
{
|
||||
Info(_log,"Initialized display %d", _display);
|
||||
Info(_log, "Initialized display %d", _display);
|
||||
}
|
||||
result = true;
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void QtGrabber::geometryChanged(const QRect &geo)
|
||||
void QtGrabber::geometryChanged(const QRect& geo)
|
||||
{
|
||||
Info(_log, "The current display changed geometry to (L,T,R,B) %d,%d,%d,%d", geo.left(), geo.top() ,geo.right(), geo.bottom());
|
||||
Info(_log, "The current display changed geometry to (L,T,R,B) %d,%d,%d,%d", geo.left(), geo.top(), geo.x() + geo.width(), geo.y() + geo.height());
|
||||
updateScreenDimensions(true);
|
||||
}
|
||||
|
||||
@@ -165,8 +166,6 @@ extern QPixmap qt_pixmapFromWinHBITMAP(HBITMAP bitmap, int format = 0);
|
||||
QPixmap QtGrabber::grabWindow(quintptr window, int xIn, int yIn, int width, int height) const
|
||||
{
|
||||
QSize windowSize;
|
||||
int x = xIn;
|
||||
int y = yIn;
|
||||
HWND hwnd = reinterpret_cast<HWND>(window);
|
||||
if (hwnd)
|
||||
{
|
||||
@@ -179,15 +178,13 @@ QPixmap QtGrabber::grabWindow(quintptr window, int xIn, int yIn, int width, int
|
||||
hwnd = GetDesktopWindow();
|
||||
const QRect screenGeometry = _screen->geometry();
|
||||
windowSize = screenGeometry.size();
|
||||
x += screenGeometry.x();
|
||||
y += screenGeometry.y();
|
||||
}
|
||||
|
||||
if (width < 0)
|
||||
width = windowSize.width() - x;
|
||||
width = windowSize.width() - xIn;
|
||||
|
||||
if (height < 0)
|
||||
height = windowSize.height() - y;
|
||||
height = windowSize.height() - yIn;
|
||||
|
||||
// Create and setup bitmap
|
||||
HDC display_dc = GetDC(nullptr);
|
||||
@@ -197,7 +194,7 @@ QPixmap QtGrabber::grabWindow(quintptr window, int xIn, int yIn, int width, int
|
||||
|
||||
// copy data
|
||||
HDC window_dc = GetDC(hwnd);
|
||||
BitBlt(bitmap_dc, 0, 0, width, height, window_dc, x, y, SRCCOPY);
|
||||
BitBlt(bitmap_dc, 0, 0, width, height, window_dc, xIn, yIn, SRCCOPY);
|
||||
|
||||
// clean up all but bitmap
|
||||
ReleaseDC(hwnd, window_dc);
|
||||
@@ -211,12 +208,12 @@ QPixmap QtGrabber::grabWindow(quintptr window, int xIn, int yIn, int width, int
|
||||
}
|
||||
#endif
|
||||
|
||||
int QtGrabber::grabFrame(Image<ColorRgb> & image)
|
||||
int QtGrabber::grabFrame(Image<ColorRgb>& image)
|
||||
{
|
||||
int rc = 0;
|
||||
if (_isEnabled && !_isDeviceInError)
|
||||
{
|
||||
if(_screen == nullptr)
|
||||
if (_screen == nullptr)
|
||||
{
|
||||
// reinit, this will disable capture on failure
|
||||
bool result = setupDisplay();
|
||||
@@ -229,14 +226,14 @@ int QtGrabber::grabFrame(Image<ColorRgb> & image)
|
||||
QPixmap originalPixmap = grabWindow(0, _src_x, _src_y, _src_x_max, _src_y_max);
|
||||
#else
|
||||
QPixmap originalPixmap = _screen->grabWindow(0, _src_x, _src_y, _src_x_max, _src_y_max);
|
||||
#endif
|
||||
#endif
|
||||
if (originalPixmap.isNull())
|
||||
{
|
||||
rc = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
QImage imageFrame = originalPixmap.toImage().scaled(_calculatedWidth, _calculatedHeight).convertToFormat( QImage::Format_RGB888);
|
||||
QImage imageFrame = originalPixmap.toImage().scaled(_calculatedWidth, _calculatedHeight).convertToFormat(QImage::Format_RGB888);
|
||||
image.resize(static_cast<uint>(_calculatedWidth), static_cast<uint>(_calculatedHeight));
|
||||
|
||||
for (int y = 0; y < imageFrame.height(); y++)
|
||||
@@ -251,7 +248,7 @@ int QtGrabber::grabFrame(Image<ColorRgb> & image)
|
||||
|
||||
int QtGrabber::updateScreenDimensions(bool force)
|
||||
{
|
||||
if(_screen == nullptr)
|
||||
if (_screen == nullptr)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
@@ -273,53 +270,65 @@ int QtGrabber::updateScreenDimensions(bool force)
|
||||
}
|
||||
|
||||
Info(_log, "Update of screen resolution: [%dx%d] to [%dx%d]", _width, _height, geo.width(), geo.height());
|
||||
_width = geo.width();
|
||||
_width = geo.width();
|
||||
_height = geo.height();
|
||||
|
||||
int width=0;
|
||||
int height=0;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
|
||||
// Image scaling is performed by Qt
|
||||
width = (_width > (_cropLeft + _cropRight))
|
||||
width = (_width > (_cropLeft + _cropRight))
|
||||
? ((_width - _cropLeft - _cropRight) / _pixelDecimation)
|
||||
: (_width / _pixelDecimation);
|
||||
|
||||
height = (_height > (_cropTop + _cropBottom))
|
||||
height = (_height > (_cropTop + _cropBottom))
|
||||
? ((_height - _cropTop - _cropBottom) / _pixelDecimation)
|
||||
: (_height / _pixelDecimation);
|
||||
|
||||
|
||||
// calculate final image dimensions and adjust top/left cropping in 3D modes
|
||||
if (_isVirtual)
|
||||
{
|
||||
_src_x = geo.x();
|
||||
_src_y = geo.y();
|
||||
}
|
||||
else
|
||||
{
|
||||
_src_x = 0;
|
||||
_src_y = 0;
|
||||
}
|
||||
|
||||
switch (_videoMode)
|
||||
{
|
||||
case VideoMode::VIDEO_3DSBS:
|
||||
_calculatedWidth = width /2;
|
||||
_calculatedWidth = width / 2;
|
||||
_calculatedHeight = height;
|
||||
_src_x = _cropLeft / 2;
|
||||
_src_y = _cropTop;
|
||||
_src_x = _src_x + (_cropLeft / 2);
|
||||
_src_y = _src_y + _cropTop;
|
||||
_src_x_max = (_width / 2) - _cropRight - _cropLeft;
|
||||
_src_y_max = _height - _cropBottom - _cropTop;
|
||||
break;
|
||||
case VideoMode::VIDEO_3DTAB:
|
||||
_calculatedWidth = width;
|
||||
_calculatedWidth = width;
|
||||
_calculatedHeight = height / 2;
|
||||
_src_x = _cropLeft;
|
||||
_src_y = _cropTop / 2;
|
||||
_src_x = _src_x + _cropLeft;
|
||||
_src_y = _src_y + (_cropTop / 2);
|
||||
_src_x_max = _width - _cropRight - _cropLeft;
|
||||
_src_y_max = (_height / 2) - _cropBottom - _cropTop;
|
||||
break;
|
||||
case VideoMode::VIDEO_2D:
|
||||
default:
|
||||
_calculatedWidth = width;
|
||||
_calculatedWidth = width;
|
||||
_calculatedHeight = height;
|
||||
_src_x = _cropLeft;
|
||||
_src_y = _cropTop;
|
||||
_src_x = _src_x + _cropLeft;
|
||||
_src_y = _src_y + _cropTop;
|
||||
_src_x_max = _width - _cropRight - _cropLeft;
|
||||
_src_y_max = _height - _cropBottom - _cropTop;
|
||||
break;
|
||||
}
|
||||
|
||||
Info(_log, "Update output image resolution to [%dx%d]", _calculatedWidth, _calculatedHeight);
|
||||
Debug(_log, "Grab screen area: %d,%d,%d,%d", _src_x, _src_y, _src_x_max, _src_y_max);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -331,10 +340,10 @@ void QtGrabber::setVideoMode(VideoMode mode)
|
||||
|
||||
bool QtGrabber::setPixelDecimation(int pixelDecimation)
|
||||
{
|
||||
bool rc (true);
|
||||
if(Grabber::setPixelDecimation(pixelDecimation))
|
||||
bool rc(true);
|
||||
if (Grabber::setPixelDecimation(pixelDecimation))
|
||||
{
|
||||
if ( updateScreenDimensions(true) < 0)
|
||||
if (updateScreenDimensions(true) < 0)
|
||||
{
|
||||
rc = false;
|
||||
}
|
||||
@@ -350,14 +359,20 @@ void QtGrabber::setCropping(int cropLeft, int cropRight, int cropTop, int cropBo
|
||||
|
||||
bool QtGrabber::setDisplayIndex(int index)
|
||||
{
|
||||
bool rc (true);
|
||||
if (_display != index)
|
||||
bool rc(true);
|
||||
if (_display != index || _isVirtual)
|
||||
{
|
||||
_isVirtual = false;
|
||||
if (index <= _numberOfSDisplays)
|
||||
{
|
||||
_display = index;
|
||||
if (index == _numberOfSDisplays)
|
||||
{
|
||||
_isVirtual = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
_display = 0;
|
||||
}
|
||||
rc = setupDisplay();
|
||||
@@ -370,7 +385,7 @@ QJsonObject QtGrabber::discover(const QJsonObject& params)
|
||||
DebugIf(verbose, _log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||
|
||||
QJsonObject inputsDiscovered;
|
||||
if ( open() )
|
||||
if (open())
|
||||
{
|
||||
QList<QScreen*> screens = QGuiApplication::screens();
|
||||
if (!screens.isEmpty())
|
||||
@@ -390,7 +405,7 @@ QJsonObject QtGrabber::discover(const QJsonObject& params)
|
||||
int pos = name.lastIndexOf('\\');
|
||||
if (pos != -1)
|
||||
{
|
||||
name = name.right(name.length()-pos-1);
|
||||
name = name.right(name.length() - pos - 1);
|
||||
}
|
||||
|
||||
in["name"] = name;
|
||||
@@ -460,5 +475,4 @@ QJsonObject QtGrabber::discover(const QJsonObject& params)
|
||||
DebugIf(verbose, _log, "device: [%s]", QString(QJsonDocument(inputsDiscovered).toJson(QJsonDocument::Compact)).toUtf8().constData());
|
||||
|
||||
return inputsDiscovered;
|
||||
|
||||
}
|
||||
|
@@ -193,7 +193,10 @@ void Hyperion::stop()
|
||||
|
||||
void Hyperion::freeObjects()
|
||||
{
|
||||
// switch off all leds
|
||||
//delete Background effect first that it does not kick in when other priorities are stopped
|
||||
delete _BGEffectHandler;
|
||||
|
||||
//Remove all priorities to switch off all leds
|
||||
clear(-1,true);
|
||||
|
||||
// delete components on exit of hyperion core
|
||||
@@ -462,11 +465,6 @@ void Hyperion::setColor(int priority, const std::vector<ColorRgb> &ledColors, in
|
||||
}
|
||||
end:
|
||||
|
||||
if (getPriorityInfo(priority).componentId != hyperion::COMP_COLOR)
|
||||
{
|
||||
clear(priority);
|
||||
}
|
||||
|
||||
// register color
|
||||
registerInput(priority, hyperion::COMP_COLOR, origin);
|
||||
|
||||
@@ -618,10 +616,9 @@ void Hyperion::handleVisibleComponentChanged(hyperion::Components comp)
|
||||
_raw2ledAdjustment->setBacklightEnabled((comp != hyperion::COMP_COLOR && comp != hyperion::COMP_EFFECT));
|
||||
}
|
||||
|
||||
void Hyperion::handleSourceAvailability(const quint8& priority)
|
||||
void Hyperion::handleSourceAvailability(int priority)
|
||||
{ int previousPriority = _muxer->getPreviousPriority();
|
||||
|
||||
Debug(_log,"priority[%d], previousPriority[%d]", priority, previousPriority);
|
||||
if ( priority == PriorityMuxer::LOWEST_PRIORITY)
|
||||
{
|
||||
Debug(_log,"No source left -> Pause output processing and switch LED-Device off");
|
||||
|
@@ -17,6 +17,7 @@ const int PriorityMuxer::BG_PRIORITY = 254;
|
||||
const int PriorityMuxer::MANUAL_SELECTED_PRIORITY = 256;
|
||||
const int PriorityMuxer::LOWEST_PRIORITY = std::numeric_limits<uint8_t>::max();
|
||||
const int PriorityMuxer::TIMEOUT_NOT_ACTIVE_PRIO = -100;
|
||||
const int PriorityMuxer::REMOVE_CLEARED_PRIO = -101;
|
||||
const int PriorityMuxer::ENDLESS = -1;
|
||||
|
||||
PriorityMuxer::PriorityMuxer(int ledCount, QObject * parent)
|
||||
@@ -26,8 +27,6 @@ PriorityMuxer::PriorityMuxer(int ledCount, QObject * parent)
|
||||
, _previousPriority(_currentPriority)
|
||||
, _manualSelectedPriority(MANUAL_SELECTED_PRIORITY)
|
||||
, _prevVisComp (hyperion::Components::COMP_COLOR)
|
||||
, _activeInputs()
|
||||
, _lowestPriorityInfo()
|
||||
, _sourceAutoSelectEnabled(true)
|
||||
, _updateTimer(new QTimer(this))
|
||||
, _timer(new QTimer(this))
|
||||
@@ -38,8 +37,10 @@ PriorityMuxer::PriorityMuxer(int ledCount, QObject * parent)
|
||||
|
||||
// init lowest priority info
|
||||
_lowestPriorityInfo.priority = PriorityMuxer::LOWEST_PRIORITY;
|
||||
_lowestPriorityInfo.timeoutTime_ms = PriorityMuxer::ENDLESS;
|
||||
_lowestPriorityInfo.ledColors = std::vector<ColorRgb>(ledCount, {0, 0, 0});
|
||||
|
||||
_lowestPriorityInfo.timeoutTime_ms = -1;
|
||||
_lowestPriorityInfo.ledColors = std::vector<ColorRgb>(ledCount, ColorRgb::BLACK);
|
||||
|
||||
_lowestPriorityInfo.componentId = hyperion::COMP_COLOR;
|
||||
_lowestPriorityInfo.origin = "System";
|
||||
_lowestPriorityInfo.owner = "";
|
||||
@@ -50,12 +51,10 @@ PriorityMuxer::PriorityMuxer(int ledCount, QObject * parent)
|
||||
connect(_timer, &QTimer::timeout, this, &PriorityMuxer::timeTrigger);
|
||||
_timer->setSingleShot(true);
|
||||
_blockTimer->setSingleShot(true);
|
||||
// forward timeRunner signal to prioritiesChanged signal & threading workaround
|
||||
connect(this, &PriorityMuxer::timeRunner, this, &PriorityMuxer::prioritiesChanged);
|
||||
connect(this, &PriorityMuxer::signalTimeTrigger, this, &PriorityMuxer::timeTrigger);
|
||||
|
||||
// start muxer timer
|
||||
connect(_updateTimer, &QTimer::timeout, this, &PriorityMuxer::setCurrentTime);
|
||||
connect(_updateTimer, &QTimer::timeout, this, &PriorityMuxer::updatePriorities);
|
||||
_updateTimer->setInterval(250);
|
||||
_updateTimer->start();
|
||||
}
|
||||
@@ -85,7 +84,9 @@ bool PriorityMuxer::setSourceAutoSelectEnabled(bool enable, bool update)
|
||||
|
||||
// update _currentPriority if called from external
|
||||
if(update)
|
||||
setCurrentTime();
|
||||
{
|
||||
emit prioritiesChanged(_currentPriority,_activeInputs);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -128,10 +129,10 @@ bool PriorityMuxer::hasPriority(int priority) const
|
||||
|
||||
PriorityMuxer::InputInfo PriorityMuxer::getInputInfo(int priority) const
|
||||
{
|
||||
auto elemIt = _activeInputs.find(priority);
|
||||
auto elemIt = _activeInputs.constFind(priority);
|
||||
if (elemIt == _activeInputs.end())
|
||||
{
|
||||
elemIt = _activeInputs.find(PriorityMuxer::LOWEST_PRIORITY);
|
||||
elemIt = _activeInputs.constFind(PriorityMuxer::LOWEST_PRIORITY);
|
||||
if (elemIt == _activeInputs.end())
|
||||
{
|
||||
// fallback
|
||||
@@ -150,11 +151,18 @@ void PriorityMuxer::registerInput(int priority, hyperion::Components component,
|
||||
{
|
||||
// detect new registers
|
||||
bool newInput = false;
|
||||
bool reusedInput = false;
|
||||
|
||||
if (!_activeInputs.contains(priority))
|
||||
{
|
||||
newInput = true;
|
||||
}
|
||||
else if(_prevVisComp == component || _activeInputs[priority].componentId == component)
|
||||
reusedInput = true;
|
||||
{
|
||||
if (_activeInputs[priority].owner != owner)
|
||||
{
|
||||
newInput = true;
|
||||
}
|
||||
}
|
||||
|
||||
InputInfo& input = _activeInputs[priority];
|
||||
input.priority = priority;
|
||||
@@ -166,18 +174,11 @@ void PriorityMuxer::registerInput(int priority, hyperion::Components component,
|
||||
|
||||
if (newInput)
|
||||
{
|
||||
Debug(_log,"Register new input '%s/%s' with priority %d as inactive", QSTRING_CSTR(origin), hyperion::componentToIdString(component), priority);
|
||||
// emit 'prioritiesChanged' only if _sourceAutoSelectEnabled is false
|
||||
if (!_sourceAutoSelectEnabled)
|
||||
{
|
||||
emit prioritiesChanged();
|
||||
}
|
||||
return;
|
||||
Debug(_log,"Register new input '%s/%s' (%s) with priority %d as inactive", QSTRING_CSTR(origin), hyperion::componentToIdString(component), QSTRING_CSTR(owner), priority);
|
||||
}
|
||||
|
||||
if (reusedInput)
|
||||
else
|
||||
{
|
||||
emit timeRunner();
|
||||
Debug(_log,"Reuse input '%s/%s' (%s) with priority %d", QSTRING_CSTR(origin), hyperion::componentToIdString(component), QSTRING_CSTR(owner), priority);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,12 +222,12 @@ bool PriorityMuxer::setInput(int priority, const std::vector<ColorRgb>& ledColor
|
||||
// emit active change
|
||||
if(activeChange)
|
||||
{
|
||||
Debug(_log, "Priority %d is now %s", priority, active ? "active" : "inactive");
|
||||
if (_currentPriority < priority)
|
||||
if (_currentPriority <= priority || !_sourceAutoSelectEnabled)
|
||||
{
|
||||
emit prioritiesChanged();
|
||||
Debug(_log, "Priority %d is now %s", priority, active ? "active" : "inactive");
|
||||
emit prioritiesChanged(_currentPriority,_activeInputs);
|
||||
}
|
||||
setCurrentTime();
|
||||
updatePriorities();
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -272,12 +273,12 @@ bool PriorityMuxer::setInputImage(int priority, const Image<ColorRgb>& image, in
|
||||
// emit active change
|
||||
if(activeChange)
|
||||
{
|
||||
Debug(_log, "Priority %d is now %s", priority, active ? "active" : "inactive");
|
||||
if (_currentPriority < priority)
|
||||
if (_currentPriority <= priority || !_sourceAutoSelectEnabled)
|
||||
{
|
||||
emit prioritiesChanged();
|
||||
Debug(_log, "Priority %d is now %s", priority, active ? "active" : "inactive");
|
||||
emit prioritiesChanged(_currentPriority,_activeInputs);
|
||||
}
|
||||
setCurrentTime();
|
||||
updatePriorities();
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -291,14 +292,9 @@ bool PriorityMuxer::setInputInactive(int priority)
|
||||
|
||||
bool PriorityMuxer::clearInput(int priority)
|
||||
{
|
||||
if (priority < PriorityMuxer::LOWEST_PRIORITY && (_activeInputs.remove(priority) > 0))
|
||||
if (priority < PriorityMuxer::LOWEST_PRIORITY)
|
||||
{
|
||||
Debug(_log,"Removed source priority %d",priority);
|
||||
// on clear success update _currentPriority
|
||||
setCurrentTime();
|
||||
// emit 'prioritiesChanged' only if _sourceAutoSelectEnabled is false
|
||||
if ((!_sourceAutoSelectEnabled && (_currentPriority < priority)) || _currentPriority == BG_PRIORITY)
|
||||
emit prioritiesChanged();
|
||||
_activeInputs[priority].timeoutTime_ms = REMOVE_CLEARED_PRIO;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -312,6 +308,7 @@ void PriorityMuxer::clearAll(bool forceClearAll)
|
||||
_activeInputs.clear();
|
||||
_currentPriority = PriorityMuxer::LOWEST_PRIORITY;
|
||||
_activeInputs[_currentPriority] = _lowestPriorityInfo;
|
||||
updatePriorities();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -326,35 +323,61 @@ void PriorityMuxer::clearAll(bool forceClearAll)
|
||||
}
|
||||
}
|
||||
|
||||
void PriorityMuxer::setCurrentTime()
|
||||
void PriorityMuxer::updatePriorities()
|
||||
{
|
||||
const int64_t now = QDateTime::currentMSecsSinceEpoch();
|
||||
int newPriority;
|
||||
bool priorityChanged {false};
|
||||
|
||||
_activeInputs.contains(0) ? newPriority = 0 : newPriority = PriorityMuxer::LOWEST_PRIORITY;
|
||||
|
||||
for (auto infoIt = _activeInputs.begin(); infoIt != _activeInputs.end();)
|
||||
{
|
||||
if (infoIt->timeoutTime_ms > 0 && infoIt->timeoutTime_ms <= now)
|
||||
QMutableMapIterator<int, PriorityMuxer::InputInfo> i(_activeInputs);
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
|
||||
if ( i.value().timeoutTime_ms == REMOVE_CLEARED_PRIO )
|
||||
{
|
||||
int tPrio = infoIt->priority;
|
||||
infoIt = _activeInputs.erase(infoIt);
|
||||
Debug(_log,"Timeout clear for priority %d",tPrio);
|
||||
emit prioritiesChanged();
|
||||
int tPrio = i.value().priority;
|
||||
i.remove();
|
||||
|
||||
Debug(_log,"Removed source priority %d", tPrio);
|
||||
priorityChanged = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// timeoutTime of TIMEOUT_NOT_ACTIVE_PRIO is awaiting data (inactive); skip
|
||||
if(infoIt->timeoutTime_ms > TIMEOUT_NOT_ACTIVE_PRIO)
|
||||
newPriority = qMin(newPriority, infoIt->priority);
|
||||
|
||||
// call timeTrigger when effect or color is running with timeout > 0, blacklist prio 255
|
||||
if (infoIt->priority < BG_PRIORITY && infoIt->timeoutTime_ms > 0 && (infoIt->componentId == hyperion::COMP_EFFECT || infoIt->componentId == hyperion::COMP_COLOR || infoIt->componentId == hyperion::COMP_IMAGE))
|
||||
if (i.value().timeoutTime_ms > 0 && i.value().timeoutTime_ms <= now)
|
||||
{
|
||||
emit signalTimeTrigger(); // as signal to prevent Threading issues
|
||||
//Stop timer for deleted items to avoid additional priority update
|
||||
_timer->stop();
|
||||
int tPrio = i.value().priority;
|
||||
i.remove();
|
||||
|
||||
Debug(_log,"Timeout clear for priority %d",tPrio);
|
||||
priorityChanged = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// timeoutTime of TIMEOUT_NOT_ACTIVE_PRIO is awaiting data (inactive); skip
|
||||
if(i.value().timeoutTime_ms > TIMEOUT_NOT_ACTIVE_PRIO)
|
||||
{
|
||||
newPriority = qMin(newPriority, i.value().priority);
|
||||
}
|
||||
|
||||
// call timeTrigger when effect or color is running with timeout > 0, blacklist prio 255
|
||||
if (i.value().priority < BG_PRIORITY &&
|
||||
i.value().timeoutTime_ms > 0 &&
|
||||
( i.value().componentId == hyperion::COMP_EFFECT ||
|
||||
i.value().componentId == hyperion::COMP_COLOR ||
|
||||
(i.value().componentId == hyperion::COMP_IMAGE && i.value().owner != "Streaming")
|
||||
)
|
||||
)
|
||||
{
|
||||
emit signalTimeTrigger(); // as signal to prevent Threading issues
|
||||
}
|
||||
}
|
||||
++infoIt;
|
||||
}
|
||||
}
|
||||
|
||||
// evaluate, if manual selected priority is still available
|
||||
if(!_sourceAutoSelectEnabled)
|
||||
{
|
||||
@@ -371,7 +394,7 @@ void PriorityMuxer::setCurrentTime()
|
||||
}
|
||||
// apply & emit on change (after apply!)
|
||||
hyperion::Components comp = getComponentOfPriority(newPriority);
|
||||
if (_currentPriority != newPriority || comp != _prevVisComp)
|
||||
if (_currentPriority != newPriority || comp != _prevVisComp )
|
||||
{
|
||||
_previousPriority = _currentPriority;
|
||||
_currentPriority = newPriority;
|
||||
@@ -383,7 +406,12 @@ void PriorityMuxer::setCurrentTime()
|
||||
_prevVisComp = comp;
|
||||
emit visibleComponentChanged(comp);
|
||||
}
|
||||
emit prioritiesChanged();
|
||||
priorityChanged = true;
|
||||
}
|
||||
|
||||
if (priorityChanged)
|
||||
{
|
||||
emit prioritiesChanged(_currentPriority,_activeInputs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,7 +423,7 @@ void PriorityMuxer::timeTrigger()
|
||||
}
|
||||
else
|
||||
{
|
||||
emit timeRunner();
|
||||
_blockTimer->start(1000);
|
||||
emit prioritiesChanged(_currentPriority,_activeInputs);
|
||||
}
|
||||
}
|
||||
|
@@ -15,6 +15,7 @@
|
||||
"type" : "integer",
|
||||
"required" : true,
|
||||
"title" : "edt_conf_general_port_title",
|
||||
"default" : 19333,
|
||||
"minimum" : 1024,
|
||||
"maximum" : 65535,
|
||||
"propertyOrder" : 2
|
||||
|
@@ -137,6 +137,10 @@
|
||||
"type": "string",
|
||||
"enum": [ "snake", "parallel" ]
|
||||
},
|
||||
"direction": {
|
||||
"type": "string",
|
||||
"enum": [ "horizontal", "vertical" ]
|
||||
},
|
||||
"start": {
|
||||
"type": "string",
|
||||
"enum": [ "top-left", "top-right", "bottom-left", "bottom-right" ]
|
||||
|
@@ -357,8 +357,10 @@ QJsonObject LedDeviceWled::getProperties(const QJsonObject& params)
|
||||
}
|
||||
|
||||
QJsonObject propertiesDetails = response.getBody().object();
|
||||
propertiesDetails.insert("maxLedCount", UDP_MAX_LED_NUM);
|
||||
|
||||
if (!propertiesDetails.isEmpty())
|
||||
{
|
||||
propertiesDetails.insert("maxLedCount", UDP_MAX_LED_NUM);
|
||||
}
|
||||
properties.insert("properties", propertiesDetails);
|
||||
|
||||
DebugIf(verbose, _log, "properties: [%s]", QString(QJsonDocument(properties).toJson(QJsonDocument::Compact)).toUtf8().constData() );
|
||||
|
@@ -98,10 +98,14 @@ void QtHttpClientWrapper::onClientDataReceived (void)
|
||||
|
||||
if (pos > 0)
|
||||
{
|
||||
QByteArray header = raw.left (pos).trimmed ();
|
||||
QByteArray value = raw.mid (pos +1).trimmed ();
|
||||
QByteArray header = raw.left (pos).trimmed();
|
||||
QByteArray value = raw.mid (pos +1).trimmed();
|
||||
m_currentRequest->addHeader (header, value);
|
||||
if (header == QtHttpHeader::ContentLength)
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
|
||||
if (header.compare(QtHttpHeader::ContentLength, Qt::CaseInsensitive) == 0)
|
||||
#else
|
||||
if (header.toLower() == QtHttpHeader::ContentLength.toLower())
|
||||
#endif
|
||||
{
|
||||
bool ok = false;
|
||||
const int len = value.toInt (&ok, 10);
|
||||
@@ -153,7 +157,7 @@ void QtHttpClientWrapper::onClientDataReceived (void)
|
||||
case RequestParsed: // a valid request has ben fully parsed
|
||||
{
|
||||
// Catch websocket header "Upgrade"
|
||||
if(m_currentRequest->getHeader(QtHttpHeader::Upgrade).toLower() == "websocket")
|
||||
if(m_currentRequest->getHeader(QtHttpHeader::Upgrade) == "websocket")
|
||||
{
|
||||
if(m_websocketClient == Q_NULLPTR)
|
||||
{
|
||||
@@ -327,7 +331,7 @@ QtHttpClientWrapper::ParsingStatus QtHttpClientWrapper::sendReplyToClient (QtHtt
|
||||
{
|
||||
static const QByteArray & CLOSE = QByteArrayLiteral ("close");
|
||||
|
||||
if (m_currentRequest->getHeader (QtHttpHeader::Connection).toLower () == CLOSE)
|
||||
if (m_currentRequest->getHeader(QtHttpHeader::Connection) == CLOSE)
|
||||
{
|
||||
// must close connection after this request
|
||||
m_sockClient->close ();
|
||||
|
@@ -25,7 +25,7 @@ void QtHttpRequest::setClientInfo (const QHostAddress & server, const QHostAddre
|
||||
|
||||
void QtHttpRequest::addHeader (const QByteArray & header, const QByteArray & value)
|
||||
{
|
||||
QByteArray key = header.trimmed ();
|
||||
QByteArray key = header.trimmed().toLower();
|
||||
|
||||
if (!key.isEmpty ())
|
||||
{
|
||||
|
@@ -38,7 +38,7 @@ public:
|
||||
|
||||
QByteArray getHeader (const QByteArray & header) const
|
||||
{
|
||||
return m_headersHash.value (header, QByteArray ());
|
||||
return m_headersHash.value (header.toLower(), QByteArray ());
|
||||
};
|
||||
|
||||
public slots:
|
||||
|
Reference in New Issue
Block a user