From dc35dacb47d2eebe5d981d396698f9b106c18939 Mon Sep 17 00:00:00 2001 From: Elias Steurer Date: Sun, 28 Feb 2021 12:46:56 +0100 Subject: [PATCH] Fix quit when qml file contains an error I cannt reproduce this in an empty project but _something_ stopped the quit call in the terminate function. The only workaround I found was using an async loader... Increase ping alive to 3000ms and change it to a static variable Move getAvailableFillModes to globalvariables.h --- ScreenPlay/src/globalvariables.h | 6 ++++ ScreenPlay/src/screenplaymanager.h | 2 +- ScreenPlay/src/screenplaywallpaper.cpp | 23 +++++++------- ScreenPlay/src/screenplaywidget.cpp | 4 +-- ScreenPlay/src/sdkconnection.cpp | 2 +- ScreenPlay/src/util.cpp | 1 + ScreenPlaySDK/src/screenplaysdk.cpp | 2 +- .../inc/public/ScreenPlayUtil/util.h | 1 + ScreenPlayUtil/src/util.cpp | 30 +++++++++++++++++++ ScreenPlayWallpaper/Wallpaper.qml | 10 ++++++- ScreenPlayWallpaper/src/basewindow.h | 8 ++--- ScreenPlayWallpaper/src/winwindow.cpp | 10 ++++--- 12 files changed, 74 insertions(+), 25 deletions(-) diff --git a/ScreenPlay/src/globalvariables.h b/ScreenPlay/src/globalvariables.h index a5141a86..eb665e2c 100644 --- a/ScreenPlay/src/globalvariables.h +++ b/ScreenPlay/src/globalvariables.h @@ -57,6 +57,12 @@ class GlobalVariables : public QObject { public: explicit GlobalVariables(QObject* parent = nullptr); + /*! + \brief We need to check if there was an error in the Wallpaper/Widgets. + For this we ping it every 1s. + */ + static const int contentPingAliveIntervalMS = 3000; + /*! \property GlobalVariables::localStoragePath \brief Returns the localStoragePath. diff --git a/ScreenPlay/src/screenplaymanager.h b/ScreenPlay/src/screenplaymanager.h index 0e5875b3..4521bf05 100644 --- a/ScreenPlay/src/screenplaymanager.h +++ b/ScreenPlay/src/screenplaymanager.h @@ -40,12 +40,12 @@ #include #include +#include "ScreenPlayUtil/projectfile.h" #include "ganalytics.h" #include "globalvariables.h" #include "installedlistmodel.h" #include "monitorlistmodel.h" #include "profilelistmodel.h" -#include "ScreenPlayUtil/projectfile.h" #include "projectsettingslistmodel.h" #include "screenplaywallpaper.h" #include "screenplaywidget.h" diff --git a/ScreenPlay/src/screenplaywallpaper.cpp b/ScreenPlay/src/screenplaywallpaper.cpp index e3fce5ea..3191512b 100644 --- a/ScreenPlay/src/screenplaywallpaper.cpp +++ b/ScreenPlay/src/screenplaywallpaper.cpp @@ -91,6 +91,9 @@ ScreenPlayWallpaper::ScreenPlayWallpaper(const QVector& screenNumber, m_process.setArguments(proArgs); m_process.setProgram(m_globalVariables->wallpaperExecutablePath().toString()); + // We must start detatched otherwise we would instantly close the process + // and would loose the animted fade-out and the background refresh needed + // to display the original wallpaper. const bool success = m_process.startDetached(); qInfo() << "Starting ScreenPlayWallpaper detached: " << (success ? "success" : "failed!"); if (!success) { @@ -181,23 +184,23 @@ void ScreenPlayWallpaper::setWallpaperValue(const QString& key, const QString& v void ScreenPlayWallpaper::setSDKConnection(const std::shared_ptr& connection) { m_connection = connection; - QTimer::singleShot(500, [this]() { + + QTimer::singleShot(1000, [this]() { if (playbackRate() != 1.0) { setWallpaperValue("playbackRate", QString::number(playbackRate()), false); } - }); + QObject::connect(&m_pingAliveTimer, &QTimer::timeout, this, [this]() { + qInfo() << "For " << m_pingAliveTimer.interval() << "ms no alive signal received. This means the Wallpaper is dead and likely crashed!"; + emit requestClose(m_appID); + }); + m_pingAliveTimer.start(GlobalVariables::contentPingAliveIntervalMS); + }); // Check every X seconds if the wallpaper is still alive QObject::connect(m_connection.get(), &SDKConnection::pingAliveReceived, this, [this]() { m_pingAliveTimer.stop(); - m_pingAliveTimer.start(16000); + m_pingAliveTimer.start(GlobalVariables::contentPingAliveIntervalMS); }); - - QObject::connect(&m_pingAliveTimer, &QTimer::timeout, this, [this]() { - qInfo() << "For " << m_pingAliveTimer.interval() << "ms no alive signal received. This means the Wallpaper is dead and likely crashed!"; - emit requestClose(m_appID); - }); - m_pingAliveTimer.start(16000); } /*! @@ -225,7 +228,7 @@ void ScreenPlayWallpaper::replace( obj.insert("command", "replace"); obj.insert("type", QVariant::fromValue(type).toString()); obj.insert("fillMode", QVariant::fromValue(fillMode).toString()); - obj.insert("volume", std::floor(volume * 100.0f) / 100.0f); + obj.insert("volume", std::floor(volume * 100.0F) / 100.0f); obj.insert("absolutePath", absolutePath); obj.insert("file", file); obj.insert("checkWallpaperVisible", checkWallpaperVisible); diff --git a/ScreenPlay/src/screenplaywidget.cpp b/ScreenPlay/src/screenplaywidget.cpp index 52eb285c..c3f1ce8c 100644 --- a/ScreenPlay/src/screenplaywidget.cpp +++ b/ScreenPlay/src/screenplaywidget.cpp @@ -88,14 +88,14 @@ void ScreenPlayWidget::setSDKConnection(const std::shared_ptr& co // Check every X seconds if the widget is still alive QObject::connect(m_connection.get(), &SDKConnection::pingAliveReceived, this, [this]() { m_pingAliveTimer.stop(); - m_pingAliveTimer.start(16000); + m_pingAliveTimer.start(GlobalVariables::contentPingAliveIntervalMS); }); QObject::connect(&m_pingAliveTimer, &QTimer::timeout, this, [this]() { qInfo() << "For " << m_pingAliveTimer.interval() << "ms no alive signal received. This means the Widget is dead and likely crashed!"; emit requestClose(m_appID); }); - m_pingAliveTimer.start(16000); + m_pingAliveTimer.start(GlobalVariables::contentPingAliveIntervalMS); } /*! diff --git a/ScreenPlay/src/sdkconnection.cpp b/ScreenPlay/src/sdkconnection.cpp index c2841c87..366f0670 100644 --- a/ScreenPlay/src/sdkconnection.cpp +++ b/ScreenPlay/src/sdkconnection.cpp @@ -72,7 +72,7 @@ void ScreenPlay::SDKConnection::readyRead() } } else if (msg.startsWith("{") && msg.endsWith("}")) { QJsonObject obj; - QJsonParseError err; + QJsonParseError err {}; QJsonDocument doc = QJsonDocument::fromJson(QByteArray { msg.toUtf8() }, &err); if (err.error != QJsonParseError::NoError) diff --git a/ScreenPlay/src/util.cpp b/ScreenPlay/src/util.cpp index 959676d0..fb0598bb 100644 --- a/ScreenPlay/src/util.cpp +++ b/ScreenPlay/src/util.cpp @@ -58,6 +58,7 @@ bool Util::writeJsonObjectToFile(const QString& absoluteFilePath, const QJsonObj } if (!configTmp.open(openMode)) { + qWarning() << "Could not open out file!" << configTmp.errorString(); return false; } diff --git a/ScreenPlaySDK/src/screenplaysdk.cpp b/ScreenPlaySDK/src/screenplaysdk.cpp index 2c7dc4c3..9fa7ad1b 100644 --- a/ScreenPlaySDK/src/screenplaysdk.cpp +++ b/ScreenPlaySDK/src/screenplaysdk.cpp @@ -43,7 +43,7 @@ void ScreenPlaySDK::init() } QObject::connect(&m_pingAliveTimer, &QTimer::timeout, this, &ScreenPlaySDK::pingAlive); - m_pingAliveTimer.start(5000); + m_pingAliveTimer.start(1000); }); } diff --git a/ScreenPlayUtil/inc/public/ScreenPlayUtil/util.h b/ScreenPlayUtil/inc/public/ScreenPlayUtil/util.h index 29946e9d..dbb0b4a2 100644 --- a/ScreenPlayUtil/inc/public/ScreenPlayUtil/util.h +++ b/ScreenPlayUtil/inc/public/ScreenPlayUtil/util.h @@ -60,6 +60,7 @@ QString executableEnding(); QStringList getAvailableWallpaper(); QStringList getAvailableWidgets(); QStringList getAvailableTypes(); +QStringList getAvailableFillModes(); bool isWallpaper(const ScreenPlay::InstalledType::InstalledType type); bool isWidget(const ScreenPlay::InstalledType::InstalledType type); } diff --git a/ScreenPlayUtil/src/util.cpp b/ScreenPlayUtil/src/util.cpp index 40cbeed7..e5f9265b 100644 --- a/ScreenPlayUtil/src/util.cpp +++ b/ScreenPlayUtil/src/util.cpp @@ -29,6 +29,30 @@ std::optional openJsonFileToObject(const QString& path) return jsonDocument.object(); } +bool writeJsonObjectToFile(const QString& absoluteFilePath, const QJsonObject& object, bool truncate) +{ + QFile configTmp; + configTmp.setFileName(absoluteFilePath); + QIODevice::OpenMode openMode; + if (truncate) { + openMode = QIODevice::ReadWrite | QIODevice::Truncate; + } else { + openMode = QIODevice::ReadWrite | QIODevice::Append; + } + + if (!configTmp.open(openMode)) { + qWarning() << "Could not open out file!" << configTmp.errorString(); + return false; + } + + QTextStream out(&configTmp); + out.setCodec("UTF-8"); + out << QJsonDocument(object).toJson(); + + configTmp.close(); + return true; +} + /*! \brief Opens a json file (absolute path) and tries to convert it to a QString. Returns std::nullopt when not successful. @@ -270,4 +294,10 @@ bool isWidget(const ScreenPlay::InstalledType::InstalledType type) return (type == InstalledType::QMLWidget || type == InstalledType::HTMLWidget); } +QStringList getAvailableFillModes() +{ + // https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit + return { "stretch", "fill", "contain", "cover", "scale-down" }; +} + } diff --git a/ScreenPlayWallpaper/Wallpaper.qml b/ScreenPlayWallpaper/Wallpaper.qml index 51fa3d04..e3e509f8 100644 --- a/ScreenPlayWallpaper/Wallpaper.qml +++ b/ScreenPlayWallpaper/Wallpaper.qml @@ -111,6 +111,15 @@ Rectangle { Loader { id: loader anchors.fill: parent + // QML Engine deadlocks in 5.15.2 when a loader cannot load + // an item. QApplication::quit(); waits for the destruction forever. + asynchronous: true + onStatusChanged: { + if (loader.status === Loader.Error) { + loader.source = "" + Wallpaper.terminate() + } + } Connections { ignoreUnknownSignals: true target: loader.item @@ -129,7 +138,6 @@ Rectangle { right: parent.right } state: "in" - onStatusChanged: print(status,source) sourceSize.width: Wallpaper.width sourceSize.height: Wallpaper.height source: { diff --git a/ScreenPlayWallpaper/src/basewindow.h b/ScreenPlayWallpaper/src/basewindow.h index 57edd8fb..12bef190 100644 --- a/ScreenPlayWallpaper/src/basewindow.h +++ b/ScreenPlayWallpaper/src/basewindow.h @@ -327,12 +327,10 @@ public slots: fillMode = fillMode.toLower(); - QStringList availableFillModes { "stretch", "fill", "contain", "cover", "scale-down" }; - - if (!availableFillModes.contains(fillMode)) { + if (!ScreenPlayUtil::getAvailableFillModes().contains(fillMode)) { qWarning() << "Unable to set fillmode, the provided value did not match the available values" << "Provided: " << fillMode - << "Available: " << availableFillModes; + << "Available: " << ScreenPlayUtil::getAvailableFillModes(); return; } @@ -383,7 +381,7 @@ public slots: if (m_visualsPaused == visualsPaused) return; - qDebug() << "visualsPaused: " << visualsPaused; + qInfo() << "visualsPaused: " << visualsPaused; m_visualsPaused = visualsPaused; emit visualsPausedChanged(m_visualsPaused); diff --git a/ScreenPlayWallpaper/src/winwindow.cpp b/ScreenPlayWallpaper/src/winwindow.cpp index 8a23db84..f02c03d9 100644 --- a/ScreenPlayWallpaper/src/winwindow.cpp +++ b/ScreenPlayWallpaper/src/winwindow.cpp @@ -74,14 +74,17 @@ LRESULT __stdcall MouseHookCallback(int nCode, WPARAM wParam, LPARAM lParam) void WinWindow::setupWindowMouseHook() { + using ScreenPlay::InstalledType::InstalledType; + // MUST be called before setting hook for events! - if (type() != ScreenPlay::InstalledType::InstalledType::VideoWallpaper) { + if (type() != InstalledType::VideoWallpaper && type() != InstalledType::GifWallpaper) { qInfo() << "Enable mousehook"; g_winGlobalHook = &m_window; HINSTANCE hInstance = GetModuleHandle(NULL); if (!(g_mouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookCallback, hInstance, 0))) { - qDebug() << "Faild to install mouse hook!"; + qInfo() << "Faild to install mouse hook!"; + return; } qInfo() << "Setup mousehook"; } @@ -343,7 +346,6 @@ void WinWindow::checkForFullScreenWindow() void WinWindow::terminate() { - ShowWindow(m_windowHandle, SW_HIDE); // Force refresh so that we display the regular @@ -351,7 +353,7 @@ void WinWindow::terminate() ShowWindow(m_windowHandleWorker, SW_HIDE); ShowWindow(m_windowHandleWorker, SW_SHOW); - QCoreApplication::quit(); + QApplication::quit(); } void WinWindow::clearComponentCache()