diff --git a/CHANGELOG.md b/CHANGELOG.md index 54437fc5b..ed8549530 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,6 +64,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed: Python 3.12 crashes (#1747) - osX Grabber: Use ScreenCaptureKit under macOS 15 and above - Removed maximum LED number constraint from Matrix layout schema which was not synced with the UI behaviour (#1804) +- UI: Instance listings are sorted, enabled instances are high-lighted in drop-downs - Fixed bespoke WebSocket implementation by using of QWebSockets (#1816, #1448, #1247, #1130) - Fixed mDNS Browser deadlock, plus run in own thread now - Fixed that LED Buffer and Layout might get out of sync. @@ -72,7 +73,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed Last update of an effect event is not removed in sources overview - Fixed Removed stale _logger object - Fixed Smoothing (#1863) -- UI: Instance listings are sorted, enabled instances are high-lighted in drop-downs +- Fixed Crash when XCB,X11 was configured and display manager changed to Wayland +- Fixed Target-directory not correctly build when exporting effects **JSON-API** - Refactored JSON-API to ensure consistent authorization behaviour across sessions and single requests with token authorization. diff --git a/assets/webconfig/js/content_dashboard.js b/assets/webconfig/js/content_dashboard.js index d797e6ba1..dd99168f4 100644 --- a/assets/webconfig/js/content_dashboard.js +++ b/assets/webconfig/js/content_dashboard.js @@ -182,7 +182,6 @@ $(document).ready(function () { $("#general_comp_" + componentName).bootstrapToggle(isInstanceEnabled ? "enable" : "disable"); $("#general_comp_" + componentName).change(function () { - const componentName = componentName; const isChecked = $(this).prop('checked'); requestSetComponentState(componentName, isChecked); }); diff --git a/doc/development/JSON-API _Commands_Overview.md b/doc/development/JSON-API _Commands_Overview.md index fbbb6a5b0..4963ded17 100644 --- a/doc/development/JSON-API _Commands_Overview.md +++ b/doc/development/JSON-API _Commands_Overview.md @@ -66,10 +66,10 @@ _http/s Support_ | instance | switchTo | Yes | No | No | Yes | | instance-data | getImageSnapshot | Yes | Single | Yes | Yes | | instance-data | getLedSnapshot | Yes | Single | Yes | Yes | -| ledcolors | imagestream-start | Yes | Single | Yes | Yes | -| ledcolors | imagestream-stop | Yes | Single | Yes | Yes | -| ledcolors | ledstream-start | Yes | Single | Yes | Yes | -| ledcolors | ledstream-stop | Yes | Single | Yes | Yes | +| ledcolors | imagestream-start | Yes | Single | Yes | No | +| ledcolors | imagestream-stop | Yes | Single | Yes | No | +| ledcolors | ledstream-start | Yes | Single | Yes | No | +| ledcolors | ledstream-stop | Yes | Single | Yes | No | | leddevice | addAuthorization | Yes | Single | Yes | Yes | | leddevice | discover | Yes | No | No | Yes | | leddevice | getProperties | Yes | No | No | Yes | diff --git a/include/api/JsonApiCommand.h b/include/api/JsonApiCommand.h index 866d3529e..b669fba4b 100644 --- a/include/api/JsonApiCommand.h +++ b/include/api/JsonApiCommand.h @@ -330,10 +330,10 @@ class ApiCommandRegister { { {"instance", "switchTo"}, { Command::Instance, SubCommand::SwitchTo, Authorization::Yes, InstanceCmd::No, InstanceCmd::MustRun_No, NoListenerCmd::Yes } }, { {"instance-data", "getImageSnapshot"}, { Command::InstanceData, SubCommand::GetImageSnapshot, Authorization::Yes, InstanceCmd::Single, InstanceCmd::MustRun_Yes, NoListenerCmd::Yes } }, { {"instance-data", "getLedSnapshot"}, { Command::InstanceData, SubCommand::GetLedSnapshot, Authorization::Yes, InstanceCmd::Single, InstanceCmd::MustRun_Yes, NoListenerCmd::Yes } }, - { {"ledcolors", "imagestream-start"}, { Command::LedColors, SubCommand::ImageStreamStart, Authorization::Yes, InstanceCmd::Single, InstanceCmd::MustRun_Yes, NoListenerCmd::Yes } }, - { {"ledcolors", "imagestream-stop"}, { Command::LedColors, SubCommand::ImageStreamStop, Authorization::Yes, InstanceCmd::Single, InstanceCmd::MustRun_Yes, NoListenerCmd::Yes } }, - { {"ledcolors", "ledstream-start"}, { Command::LedColors, SubCommand::LedStreamStart, Authorization::Yes, InstanceCmd::Single, InstanceCmd::MustRun_Yes, NoListenerCmd::Yes } }, - { {"ledcolors", "ledstream-stop"}, { Command::LedColors, SubCommand::LedStreamStop, Authorization::Yes, InstanceCmd::Single, InstanceCmd::MustRun_Yes, NoListenerCmd::Yes } }, + { {"ledcolors", "imagestream-start"}, { Command::LedColors, SubCommand::ImageStreamStart, Authorization::Yes, InstanceCmd::Single, InstanceCmd::MustRun_Yes, NoListenerCmd::No } }, + { {"ledcolors", "imagestream-stop"}, { Command::LedColors, SubCommand::ImageStreamStop, Authorization::Yes, InstanceCmd::Single, InstanceCmd::MustRun_Yes, NoListenerCmd::No } }, + { {"ledcolors", "ledstream-start"}, { Command::LedColors, SubCommand::LedStreamStart, Authorization::Yes, InstanceCmd::Single, InstanceCmd::MustRun_Yes, NoListenerCmd::No } }, + { {"ledcolors", "ledstream-stop"}, { Command::LedColors, SubCommand::LedStreamStop, Authorization::Yes, InstanceCmd::Single, InstanceCmd::MustRun_Yes, NoListenerCmd::No } }, { {"leddevice", "addAuthorization"}, { Command::LedDevice, SubCommand::AddAuthorization, Authorization::Yes, InstanceCmd::Single, InstanceCmd::MustRun_Yes, NoListenerCmd::Yes } }, { {"leddevice", "discover"}, { Command::LedDevice, SubCommand::Discover, Authorization::Yes, InstanceCmd::No, InstanceCmd::MustRun_No, NoListenerCmd::Yes } }, { {"leddevice", "getProperties"}, { Command::LedDevice, SubCommand::GetProperties, Authorization::Yes, InstanceCmd::No, InstanceCmd::MustRun_No, NoListenerCmd::Yes } }, diff --git a/include/api/JsonCallbacks.h b/include/api/JsonCallbacks.h index 808b90967..9b31d7cfe 100644 --- a/include/api/JsonCallbacks.h +++ b/include/api/JsonCallbacks.h @@ -36,7 +36,7 @@ class JsonCallbacks : public QObject /// /// @brief Subscribe to future data updates given by subscription list - /// @param type Array of subscriptionsm + /// @param type Array of subscriptions, an empty array subscribes to all updates /// QStringList subscribe(const QJsonArray& subscriptions); @@ -56,7 +56,7 @@ class JsonCallbacks : public QObject /// /// @brief Unsubscribe to future data updates given by subscription list - /// @param type Array of subscriptions + /// @param type Array of subscriptions, an empty array will unsubcribe all current subscriptions /// QStringList unsubscribe(const QJsonArray& subscriptions); diff --git a/include/grabber/dispmanx/DispmanxFrameGrabber.h b/include/grabber/dispmanx/DispmanxFrameGrabber.h index b61607bc8..bedeea204 100644 --- a/include/grabber/dispmanx/DispmanxFrameGrabber.h +++ b/include/grabber/dispmanx/DispmanxFrameGrabber.h @@ -38,7 +38,7 @@ class DispmanxFrameGrabber : public Grabber /// /// @return true, on success (i.e. library is present), else false /// - bool isAvailable() override; + bool isAvailable(bool logError = true) override; /// /// @brief Opens the input device. diff --git a/include/grabber/qt/QtGrabber.h b/include/grabber/qt/QtGrabber.h index 6ed56707e..abf666bd0 100644 --- a/include/grabber/qt/QtGrabber.h +++ b/include/grabber/qt/QtGrabber.h @@ -72,6 +72,13 @@ class QtGrabber : public Grabber /// bool setupDisplay(); + /// + /// @brief Determine if the grabber is available. + /// + /// @return true, on success (i.e. Window Manager is not Wayland), else false + /// + bool isAvailable(bool logError = true) override; + /// /// @brief Opens the input device. /// diff --git a/include/grabber/qt/QtWrapper.h b/include/grabber/qt/QtWrapper.h index e830e1874..b78e7f980 100644 --- a/include/grabber/qt/QtWrapper.h +++ b/include/grabber/qt/QtWrapper.h @@ -38,6 +38,18 @@ class QtWrapper: public GrabberWrapper /// QtWrapper(const QJsonDocument& grabberConfig = QJsonDocument()); + /// + /// @brief Determine if the grabber is available for usage on the platform + /// + /// @return true, on success, else false + /// + bool isAvailable() override; + + /// + /// Starts the grabber, if available + /// + bool start() override; + /// /// Starts the grabber which produces led values with the specified update rate /// diff --git a/include/grabber/x11/X11Grabber.h b/include/grabber/x11/X11Grabber.h index 3e9ae21ce..adec828db 100644 --- a/include/grabber/x11/X11Grabber.h +++ b/include/grabber/x11/X11Grabber.h @@ -34,8 +34,14 @@ class X11Grabber : public Grabber , public QAbstractNativeEventFilter ~X11Grabber() override; - bool open(); + /// + /// @brief Determine if the grabber is available. + /// + /// @return true, on success (i.e. Window Manager is not Wayland), else false + /// + bool isAvailable(bool logError = true) override; + bool open(); bool setupDisplay(); /// diff --git a/include/grabber/x11/X11Wrapper.h b/include/grabber/x11/X11Wrapper.h index ea1020cf3..a88ca4f5d 100644 --- a/include/grabber/x11/X11Wrapper.h +++ b/include/grabber/x11/X11Wrapper.h @@ -38,6 +38,23 @@ class X11Wrapper: public GrabberWrapper /// ~X11Wrapper() override; + /// + /// @brief Determine if the grabber is available for usage on the platform + /// + /// @return true, on success, else false + /// + bool isAvailable() override; + + /// + /// Starts the grabber, if available + /// + bool start() override; + + /// + /// Starts the grabber which produces led values with the specified update rate + /// + bool open() override; + public slots: /// /// Performs a single frame grab and computes the led-colors diff --git a/include/grabber/xcb/XcbGrabber.h b/include/grabber/xcb/XcbGrabber.h index 4029c59ea..8682d50aa 100644 --- a/include/grabber/xcb/XcbGrabber.h +++ b/include/grabber/xcb/XcbGrabber.h @@ -29,6 +29,13 @@ class XcbGrabber : public Grabber, public QAbstractNativeEventFilter ~XcbGrabber() override; + /// + /// @brief Determine if the grabber is available. + /// + /// @return true, on success (i.e. Window Manager is not Wayland), else false + /// + bool isAvailable(bool logError = true) override; + bool open(); bool setupDisplay(); diff --git a/include/grabber/xcb/XcbWrapper.h b/include/grabber/xcb/XcbWrapper.h index f77e2a3de..9a95ec0a6 100644 --- a/include/grabber/xcb/XcbWrapper.h +++ b/include/grabber/xcb/XcbWrapper.h @@ -37,6 +37,23 @@ class XcbWrapper: public GrabberWrapper ~XcbWrapper() override; + /// + /// @brief Determine if the grabber is available for usage on the platform + /// + /// @return true, on success, else false + /// + bool isAvailable() override; + + /// + /// Starts the grabber, if available + /// + bool start() override; + + /// + /// Starts the grabber which produces led values with the specified update rate + /// + bool open() override; + public slots: void action() override; diff --git a/include/hyperion/Grabber.h b/include/hyperion/Grabber.h index e73c4387e..5ad7c45b2 100644 --- a/include/hyperion/Grabber.h +++ b/include/hyperion/Grabber.h @@ -118,7 +118,7 @@ class Grabber : public QObject /// /// @return true, on success (i.e. library is present), else false /// - virtual bool isAvailable() { return _isAvailable; } + virtual bool isAvailable(bool logError = true) { return _isAvailable; } public slots: diff --git a/include/hyperion/GrabberWrapper.h b/include/hyperion/GrabberWrapper.h index 51e7f792d..5cbbf8da1 100644 --- a/include/hyperion/GrabberWrapper.h +++ b/include/hyperion/GrabberWrapper.h @@ -168,9 +168,6 @@ private slots: /// Will start and stop grabber based on active listeners count void handleSourceRequest(hyperion::Components component, int hyperionInd, bool listen); - /// - - protected: /// diff --git a/libsrc/api/JSONRPC_schema/schema-effect.json b/libsrc/api/JSONRPC_schema/schema-effect.json index 7109e22be..2bf0ddd97 100644 --- a/libsrc/api/JSONRPC_schema/schema-effect.json +++ b/libsrc/api/JSONRPC_schema/schema-effect.json @@ -14,8 +14,7 @@ "minimum": 0, "maximum": 254 }, - "uniqueItems": true, - "minItems": 1 + "uniqueItems": true }, "tan" : { "type" : "integer" diff --git a/libsrc/api/JSONRPC_schema/schema-serverinfo.json b/libsrc/api/JSONRPC_schema/schema-serverinfo.json index ab6cac85d..870da72db 100644 --- a/libsrc/api/JSONRPC_schema/schema-serverinfo.json +++ b/libsrc/api/JSONRPC_schema/schema-serverinfo.json @@ -16,18 +16,11 @@ "minimum": 0, "maximum": 254 }, - "data": { - "type": ["null", "array"], - "properties": { - "subscriptions": { - "type": "array", - "items": {} - } - }, - "additionalProperties": false - }, "subscribe" : { - "type" : "array" + "type" : "array", + "items": { + "type" : "string" + } }, "tan" : { "type" : "integer" diff --git a/libsrc/api/JsonAPI.cpp b/libsrc/api/JsonAPI.cpp index 86b6f9172..daf01f4b6 100644 --- a/libsrc/api/JsonAPI.cpp +++ b/libsrc/api/JsonAPI.cpp @@ -719,13 +719,13 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const JsonApiC case SubCommand::Subscribe: case SubCommand::Unsubscribe: { - const QJsonObject ¶ms = message["data"].toObject(); - const QJsonArray &subscriptions = params["subscriptions"].toArray(); - if (subscriptions.isEmpty()) { + QJsonValue const subscriptionsValue = message["subscribe"]; + if (subscriptionsValue.isUndefined()) + { sendErrorReply("Invalid params", {"No subscriptions provided"}, cmd); - return; } + const QJsonArray &subscriptions = subscriptionsValue.toArray(); QStringList invaliCommands; if (cmd.subCommand == SubCommand::Subscribe) { diff --git a/libsrc/api/JsonCallbacks.cpp b/libsrc/api/JsonCallbacks.cpp index f07f7ba26..cecf5ad62 100644 --- a/libsrc/api/JsonCallbacks.cpp +++ b/libsrc/api/JsonCallbacks.cpp @@ -124,7 +124,7 @@ bool JsonCallbacks::subscribe(const QString& cmd) QStringList JsonCallbacks::subscribe(const QJsonArray& subscriptions) { QJsonArray subsArr; - if (subscriptions.contains("all")) + if (subscriptions.isEmpty()) { for (const auto& entry : getCommands(false)) { @@ -229,7 +229,7 @@ bool JsonCallbacks::unsubscribe(const Subscription::Type cmd) bool JsonCallbacks::unsubscribe(const QString& cmd) { - JsonApiSubscription subscription = ApiSubscriptionRegister::getSubscriptionInfo(cmd); + JsonApiSubscription const subscription = ApiSubscriptionRegister::getSubscriptionInfo(cmd); if (subscription.cmd == Subscription::Unknown) { return false; @@ -240,18 +240,14 @@ bool JsonCallbacks::unsubscribe(const QString& cmd) QStringList JsonCallbacks::unsubscribe(const QJsonArray& subscriptions) { QJsonArray subsArr; - if (subscriptions.contains("all")) - { - for (const auto& entry : getCommands(false)) - { - subsArr.append(entry); - } - } - else + if (subscriptions.isEmpty()) { - subsArr = subscriptions; + resetSubscriptions(); + return {}; } + subsArr = subscriptions; + QStringList invalidSubscriptions; for (auto it = subsArr.begin(); it != subsArr.end(); ++it) { diff --git a/libsrc/grabber/dispmanx/DispmanxFrameGrabber.cpp b/libsrc/grabber/dispmanx/DispmanxFrameGrabber.cpp index 34e0dcac3..331cc86b3 100644 --- a/libsrc/grabber/dispmanx/DispmanxFrameGrabber.cpp +++ b/libsrc/grabber/dispmanx/DispmanxFrameGrabber.cpp @@ -31,7 +31,7 @@ DispmanxFrameGrabber::DispmanxFrameGrabber() _useImageResampler = true; } -bool DispmanxFrameGrabber::isAvailable() +bool DispmanxFrameGrabber::isAvailable(bool logError) { #ifdef BCM_FOUND void* bcm_host = dlopen(std::string("" BCM_LIBRARY).c_str(), RTLD_LAZY | RTLD_GLOBAL); diff --git a/libsrc/grabber/qt/QtGrabber.cpp b/libsrc/grabber/qt/QtGrabber.cpp index ce040a74e..4d2066204 100644 --- a/libsrc/grabber/qt/QtGrabber.cpp +++ b/libsrc/grabber/qt/QtGrabber.cpp @@ -46,34 +46,34 @@ void QtGrabber::freeResources() // Qt seems to hold the ownership of the QScreen pointers } -bool QtGrabber::open() +bool QtGrabber::isAvailable(bool logError) { - bool rc = false; - -#ifndef _WIN32 + #ifndef _WIN32 if (getenv("WAYLAND_DISPLAY") != nullptr) { + ErrorIf(logError, _log, "Grabber does not work under Wayland!"); _isWayland = true; } - else -#endif - { - rc = true; - } - return rc; + #endif + + _isAvailable = !_isWayland; + return _isAvailable; +} + +bool QtGrabber::open() +{ + return _isAvailable; } bool QtGrabber::setupDisplay() { - bool result = false; - if (!open()) + if (!_isAvailable) { - if (_isWayland) - { - Error(_log, "Grabber does not work under Wayland!"); - } + return false; } - else + + bool result = false; + if (open()) { // cleanup last screen freeResources(); @@ -385,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 (isAvailable(false) && open()) { QList screens = QGuiApplication::screens(); if (!screens.isEmpty()) diff --git a/libsrc/grabber/qt/QtWrapper.cpp b/libsrc/grabber/qt/QtWrapper.cpp index 1cb8287d8..aa6df2d8a 100644 --- a/libsrc/grabber/qt/QtWrapper.cpp +++ b/libsrc/grabber/qt/QtWrapper.cpp @@ -17,7 +17,26 @@ QtWrapper::QtWrapper(const QJsonDocument& grabberConfig) GrabberWrapper::DEFAULT_PIXELDECIMATION, 0,0,0,0) { - this->handleSettingsUpdate(settings::SYSTEMCAPTURE, grabberConfig); + _isAvailable = _grabber.isAvailable(); + if (_isAvailable) + { + this->handleSettingsUpdate(settings::SYSTEMCAPTURE, grabberConfig); + } +} + +bool QtWrapper::isAvailable() +{ + return _isAvailable; +} + +bool QtWrapper::start() +{ + if (_isAvailable) + { + return GrabberWrapper::start(); + } + + return false; } bool QtWrapper::open() @@ -27,5 +46,10 @@ bool QtWrapper::open() void QtWrapper::action() { + if (!_isAvailable) + { + return; + } + transferFrame(_grabber); } diff --git a/libsrc/grabber/x11/X11Grabber.cpp b/libsrc/grabber/x11/X11Grabber.cpp index 1feabb9f3..6bd771e61 100644 --- a/libsrc/grabber/x11/X11Grabber.cpp +++ b/libsrc/grabber/x11/X11Grabber.cpp @@ -113,15 +113,25 @@ void X11Grabber::setupResources() } } -bool X11Grabber::open() -{ - bool rc = false; +bool X11Grabber::isAvailable(bool logError) +{ if (getenv("WAYLAND_DISPLAY") != nullptr) { + ErrorIf(logError, _log, "Grabber does not work under Wayland!"); _isWayland = true; } - else + + _isAvailable = !_isWayland; + return _isAvailable; +} + + +bool X11Grabber::open() +{ + bool rc = false; + + if (_isAvailable) { _x11Display = XOpenDisplay(nullptr); if (_x11Display != nullptr) @@ -134,25 +144,24 @@ bool X11Grabber::open() bool X11Grabber::setupDisplay() { + if (!_isAvailable) + { + return false; + } + bool result = false; if ( ! open() ) { - if ( _isWayland ) + if (getenv("DISPLAY") != nullptr) { - Error(_log, "Grabber does not work under Wayland!"); + Error(_log, "Unable to open display [%s]",getenv("DISPLAY")); } else { - if (getenv("DISPLAY") != nullptr) - { - Error(_log, "Unable to open display [%s]",getenv("DISPLAY")); - } - else - { - Error(_log, "DISPLAY environment variable not set"); - } + Error(_log, "DISPLAY environment variable not set"); } + } else { @@ -405,7 +414,7 @@ QJsonObject X11Grabber::discover(const QJsonObject& params) DebugIf(verbose, _log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData()); QJsonObject inputsDiscovered; - if ( open() ) + if ( isAvailable(false) && open() ) { inputsDiscovered["device"] = "x11"; inputsDiscovered["device_name"] = "X11"; diff --git a/libsrc/grabber/x11/X11Wrapper.cpp b/libsrc/grabber/x11/X11Wrapper.cpp index df2c5c512..b8b008324 100644 --- a/libsrc/grabber/x11/X11Wrapper.cpp +++ b/libsrc/grabber/x11/X11Wrapper.cpp @@ -15,7 +15,11 @@ X11Wrapper::X11Wrapper(const QJsonDocument& grabberConfig) GrabberWrapper::DEFAULT_PIXELDECIMATION, 0,0,0,0) { - this->handleSettingsUpdate(settings::SYSTEMCAPTURE, grabberConfig); + _isAvailable = _grabber.isAvailable(); + if (_isAvailable) + { + this->handleSettingsUpdate(settings::SYSTEMCAPTURE, grabberConfig); + } } X11Wrapper::~X11Wrapper() @@ -26,22 +30,51 @@ X11Wrapper::~X11Wrapper() } } + +bool X11Wrapper::isAvailable() +{ + return _isAvailable; +} + +bool X11Wrapper::start() +{ + if (_isAvailable) + { + return GrabberWrapper::start(); + } + + return false; +} + + +bool X11Wrapper::open() +{ + bool isOpen {false}; + if ( _isAvailable && _grabber.setupDisplay()) + { + if (_grabber.updateScreenDimensions() >= 0) + { + isOpen = true; + } + } + + return isOpen; +} + void X11Wrapper::action() { + if (!_isAvailable) + { + return; + } + if (! _init ) { _init = true; - if ( ! _grabber.setupDisplay() ) + if ( ! open() ) { stop(); } - else - { - if (_grabber.updateScreenDimensions() < 0 ) - { - stop(); - } - } } if (isActive()) diff --git a/libsrc/grabber/xcb/XcbGrabber.cpp b/libsrc/grabber/xcb/XcbGrabber.cpp index 44319bb52..cafa73a71 100644 --- a/libsrc/grabber/xcb/XcbGrabber.cpp +++ b/libsrc/grabber/xcb/XcbGrabber.cpp @@ -179,15 +179,23 @@ void XcbGrabber::setupShm() } } -bool XcbGrabber::open() +bool XcbGrabber::isAvailable(bool logError) { - bool rc = false; - if (getenv("WAYLAND_DISPLAY") != nullptr) { + ErrorIf(logError, _log, "Grabber does not work under Wayland!"); _isWayland = true; } - else + + _isAvailable = !_isWayland; + return _isAvailable; +} + +bool XcbGrabber::open() +{ + bool rc = false; + + if (_isAvailable) { _connection = xcb_connect(nullptr, &_screen_num); @@ -212,26 +220,24 @@ bool XcbGrabber::open() bool XcbGrabber::setupDisplay() { - bool result = false; + if (!_isAvailable) + { + return false; + } + + bool result {false}; if ( ! open() ) { - if ( _isWayland ) + if (getenv("DISPLAY") != nullptr) { - Error(_log, "Grabber does not work under Wayland!"); + Error(_log, "Unable to open display [%s], screen %d does not exist", getenv("DISPLAY"), _screen_num); } else { - if (getenv("DISPLAY") != nullptr) - { - Error(_log, "Unable to open display [%s], screen %d does not exist", getenv("DISPLAY"), _screen_num); - } - else - { - Error(_log, "DISPLAY environment variable not set"); - } - freeResources(); + Error(_log, "DISPLAY environment variable not set"); } + freeResources(); } else { @@ -506,7 +512,7 @@ QJsonObject XcbGrabber::discover(const QJsonObject& params) DebugIf(verbose, _log, "params: [%s]", QString(QJsonDocument(params).toJson(QJsonDocument::Compact)).toUtf8().constData()); QJsonObject inputsDiscovered; - if ( open() ) + if ( isAvailable(false) && open() ) { inputsDiscovered["device"] = "xcb"; inputsDiscovered["device_name"] = "XCB"; diff --git a/libsrc/grabber/xcb/XcbWrapper.cpp b/libsrc/grabber/xcb/XcbWrapper.cpp index c9d4abd49..03c3643e9 100644 --- a/libsrc/grabber/xcb/XcbWrapper.cpp +++ b/libsrc/grabber/xcb/XcbWrapper.cpp @@ -15,7 +15,11 @@ XcbWrapper::XcbWrapper(const QJsonDocument& grabberConfig) GrabberWrapper::DEFAULT_PIXELDECIMATION, 0,0,0,0) { - this->handleSettingsUpdate(settings::SYSTEMCAPTURE, grabberConfig); + _isAvailable = _grabber.isAvailable(); + if (_isAvailable) + { + this->handleSettingsUpdate(settings::SYSTEMCAPTURE, grabberConfig); + } } XcbWrapper::~XcbWrapper() @@ -26,22 +30,50 @@ XcbWrapper::~XcbWrapper() } } +bool XcbWrapper::isAvailable() +{ + return _isAvailable; +} + +bool XcbWrapper::start() +{ + if (_isAvailable) + { + return GrabberWrapper::start(); + } + + return false; +} + + +bool XcbWrapper::open() +{ + bool isOpen {false}; + if ( _isAvailable && _grabber.setupDisplay()) + { + if (_grabber.updateScreenDimensions() >= 0) + { + isOpen = true; + } + } + + return isOpen; +} + void XcbWrapper::action() { + if (!_isAvailable) + { + return; + } + if (! _init ) { _init = true; - if ( ! _grabber.setupDisplay() ) + if ( ! open() ) { stop(); } - else - { - if (_grabber.updateScreenDimensions() < 0 ) - { - stop(); - } - } } if (isActive()) diff --git a/src/hyperion-qt/QtWrapper.cpp b/src/hyperion-qt/QtWrapper.cpp index aba98d426..d9f6b80f4 100644 --- a/src/hyperion-qt/QtWrapper.cpp +++ b/src/hyperion-qt/QtWrapper.cpp @@ -39,7 +39,12 @@ void QtWrapper::stop() bool QtWrapper::screenInit() { - return _grabber.setupDisplay(); + if (_grabber.isAvailable()) + { + return _grabber.setupDisplay(); + } + + return false; } void QtWrapper::capture() diff --git a/src/hyperion-x11/X11Wrapper.cpp b/src/hyperion-x11/X11Wrapper.cpp index ac6e0b0c1..9062a2395 100644 --- a/src/hyperion-x11/X11Wrapper.cpp +++ b/src/hyperion-x11/X11Wrapper.cpp @@ -38,7 +38,12 @@ void X11Wrapper::stop() bool X11Wrapper::screenInit() { - return _grabber.setupDisplay(); + if (_grabber.isAvailable()) + { + return _grabber.setupDisplay(); + } + + return false; } void X11Wrapper::capture() diff --git a/src/hyperion-xcb/XcbWrapper.cpp b/src/hyperion-xcb/XcbWrapper.cpp index 59c21db7b..308c57d4b 100644 --- a/src/hyperion-xcb/XcbWrapper.cpp +++ b/src/hyperion-xcb/XcbWrapper.cpp @@ -39,7 +39,12 @@ void XcbWrapper::stop() bool XcbWrapper::screenInit() { - return _grabber.setupDisplay(); + if (_grabber.isAvailable()) + { + return _grabber.setupDisplay(); + } + + return false; } void XcbWrapper::capture() diff --git a/src/hyperiond/main.cpp b/src/hyperiond/main.cpp index 921d00228..52711dc83 100644 --- a/src/hyperiond/main.cpp +++ b/src/hyperiond/main.cpp @@ -235,30 +235,49 @@ int main(int argc, char** argv) if (parser.isSet(exportEfxOption)) { Q_INIT_RESOURCE(EffectEngine); - QDir directory(":/effects/"); - QDir destDir(exportEfxOption.value(parser)); - if (directory.exists() && destDir.exists()) + QDir const sourceDir(":/effects/"); + QDir const destinationDir(exportEfxOption.value(parser)); + + // Create destination if it does not exist + if (!destinationDir.exists()) + { + std::cout << "Creating target directory: " << destinationDir.absolutePath().toStdString() << '\n'; + if (!QDir().mkpath(destinationDir.absolutePath())) + { + std::cerr << "Failed to create directory: \"" << destinationDir.absolutePath().toStdString() << "\", aborting" << '\n'; + return 1; + } + } + + if (sourceDir.exists()) { - std::cout << "Extract to folder: " << destDir.absolutePath().toStdString() << std::endl; - const QStringList filenames = directory.entryList(QStringList() << "*", QDir::Files, QDir::Name | QDir::IgnoreCase); - QString destFileName; + std::cout << "Extract to folder: " << destinationDir.absolutePath().toStdString() << '\n'; + const QStringList filenames = sourceDir.entryList(QStringList() << "*", QDir::Files, QDir::Name | QDir::IgnoreCase); for (const QString & filename : filenames) { - destFileName = destDir.dirName()+"/"+filename; - if (QFile::exists(destFileName)) + QString const sourceFilePath = sourceDir.absoluteFilePath(filename); + QString const destinationFilePath = destinationDir.absoluteFilePath(filename); + + if (QFile::exists(destinationFilePath)) + { + QFile::remove(destinationFilePath); + } + + if (Logger::getLogLevel() == Logger::DEBUG ) { - QFile::remove(destFileName); + std::cout << "Copy \"" << sourceFilePath.toStdString() << "\" -> \"" << destinationFilePath.toStdString() << "\"" << '\n'; } std::cout << "Extract: " << filename.toStdString() << " ... "; - if (QFile::copy(QString(":/effects/")+filename, destFileName)) + if (QFile::copy(sourceFilePath, destinationFilePath)) { - QFile::setPermissions(destFileName, PERM0664 ); - std::cout << "OK" << std::endl; + QFile::setPermissions(destinationFilePath, PERM0664 ); + std::cout << "OK" << '\n'; } else { - std::cout << "Error, aborting" << std::endl; + std::cerr << "Error copying [" << sourceFilePath.toStdString() << " -> [" << destinationFilePath.toStdString() << "]" << '\n'; + std::cerr << "Error, aborting" << '\n'; return 1; } }