From 012ae741a513bfd5fdc6597f50a7c79dd9b7a7f3 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 16 May 2018 09:52:19 -0700 Subject: [PATCH 1/4] Fix MS15103: Interface crashes on snap if snap dir is deleted --- interface/src/Application.cpp | 14 +++++-- .../src/scripting/WindowScriptingInterface.h | 4 +- interface/src/ui/Snapshot.cpp | 39 ++++++++++++++----- interface/src/ui/Snapshot.h | 3 +- interface/src/ui/SnapshotAnimated.cpp | 38 +++++++++++------- interface/src/ui/SnapshotAnimated.h | 1 + scripts/system/snapshot.js | 5 ++- 7 files changed, 74 insertions(+), 30 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 61ed5acdd2..bb58f2bf5d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -7590,8 +7590,9 @@ void Application::loadAvatarBrowser() const { void Application::takeSnapshot(bool notify, bool includeAnimated, float aspectRatio, const QString& filename) { postLambdaEvent([notify, includeAnimated, aspectRatio, filename, this] { + bool initialWriteFailed = false; // Get a screenshot and save it - QString path = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getScreenshot(aspectRatio), filename, + QString path = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getScreenshot(aspectRatio), filename, initialWriteFailed, TestScriptingInterface::getInstance()->getTestResultsLocation()); // If we're not doing an animated snapshot as well... @@ -7599,15 +7600,20 @@ void Application::takeSnapshot(bool notify, bool includeAnimated, float aspectRa // Tell the dependency manager that the capture of the still snapshot has taken place. emit DependencyManager::get()->stillSnapshotTaken(path, notify); } else if (!SnapshotAnimated::isAlreadyTakingSnapshotAnimated()) { - // Get an animated GIF snapshot and save it - SnapshotAnimated::saveSnapshotAnimated(path, aspectRatio, qApp, DependencyManager::get()); + if (initialWriteFailed) { + emit DependencyManager::get()->processingGifStarted(path, true); + } else { + // Get an animated GIF snapshot and save it + SnapshotAnimated::saveSnapshotAnimated(path, aspectRatio, qApp, DependencyManager::get()); + } } }); } void Application::takeSecondaryCameraSnapshot(const QString& filename) { postLambdaEvent([filename, this] { - QString snapshotPath = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getSecondaryCameraScreenshot(), filename, + bool initialWriteFailed = false; + QString snapshotPath = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getSecondaryCameraScreenshot(), filename, initialWriteFailed, TestScriptingInterface::getInstance()->getTestResultsLocation()); emit DependencyManager::get()->stillSnapshotTaken(snapshotPath, true); diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index 348882e0f8..d01a7ed0a5 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -594,9 +594,11 @@ signals: * starting to be processed. * @function Window.processingGifStarted * @param {string} pathStillSnapshot - The path and name of the still snapshot image file. + * @param {bool} stillWriteFailed - True if the still snapshot (taken before the GIF) failed to write to disk + * (this means the GIF won't capture). * @returns {Signal} */ - void processingGifStarted(const QString& pathStillSnapshot); + void processingGifStarted(const QString& pathStillSnapshot, const bool& stillWriteFailed); /**jsdoc * Triggered when a GIF has been prepared of the snapshot images captured by {@link Window.takeSnapshot|takeSnapshot}. diff --git a/interface/src/ui/Snapshot.cpp b/interface/src/ui/Snapshot.cpp index 39fef1d742..5c58737e78 100644 --- a/interface/src/ui/Snapshot.cpp +++ b/interface/src/ui/Snapshot.cpp @@ -74,26 +74,31 @@ SnapshotMetaData* Snapshot::parseSnapshotData(QString snapshotPath) { return data; } -QString Snapshot::saveSnapshot(QImage image, const QString& filename, const QString& pathname) { +QString Snapshot::saveSnapshot(QImage image, const QString& filename, bool& initialWriteFailed, const QString& pathname) { - QFile* snapshotFile = savedFileForSnapshot(image, false, filename, pathname); + QFile* snapshotFile = savedFileForSnapshot(image, false, initialWriteFailed, filename, pathname); - // we don't need the snapshot file, so close it, grab its filename and delete it - snapshotFile->close(); + if (snapshotFile) { + // we don't need the snapshot file, so close it, grab its filename and delete it + snapshotFile->close(); - QString snapshotPath = QFileInfo(*snapshotFile).absoluteFilePath(); + QString snapshotPath = QFileInfo(*snapshotFile).absoluteFilePath(); - delete snapshotFile; + delete snapshotFile; - return snapshotPath; + return snapshotPath; + } + + return ""; } QTemporaryFile* Snapshot::saveTempSnapshot(QImage image) { // return whatever we get back from saved file for snapshot - return static_cast(savedFileForSnapshot(image, true)); + bool initialWriteFailed = false; + return static_cast(savedFileForSnapshot(image, true, initialWriteFailed)); } -QFile* Snapshot::savedFileForSnapshot(QImage & shot, bool isTemporary, const QString& userSelectedFilename, const QString& userSelectedPathname) { +QFile* Snapshot::savedFileForSnapshot(QImage & shot, bool isTemporary, bool& initialWriteFailed, const QString& userSelectedFilename, const QString& userSelectedPathname) { // adding URL to snapshot QUrl currentURL = DependencyManager::get()->currentPublicAddress(); @@ -140,7 +145,21 @@ QFile* Snapshot::savedFileForSnapshot(QImage & shot, bool isTemporary, const QSt snapshotFullPath.append(filename); QFile* imageFile = new QFile(snapshotFullPath); - imageFile->open(QIODevice::WriteOnly); + while (!imageFile->open(QIODevice::WriteOnly)) { + initialWriteFailed = true; + snapshotFullPath = OffscreenUi::getExistingDirectory(nullptr, "Write Error - Choose New Snapshots Directory", QStandardPaths::writableLocation(QStandardPaths::DesktopLocation)); + if (snapshotFullPath.isEmpty()) { + return NULL; + } + snapshotsLocation.set(snapshotFullPath); + + if (!snapshotFullPath.endsWith(QDir::separator())) { + snapshotFullPath.append(QDir::separator()); + } + snapshotFullPath.append(filename); + + imageFile = new QFile(snapshotFullPath); + } shot.save(imageFile, 0, IMAGE_QUALITY); imageFile->close(); diff --git a/interface/src/ui/Snapshot.h b/interface/src/ui/Snapshot.h index 606313f3c3..265d666cc8 100644 --- a/interface/src/ui/Snapshot.h +++ b/interface/src/ui/Snapshot.h @@ -38,7 +38,7 @@ class Snapshot : public QObject, public Dependency { Q_OBJECT SINGLETON_DEPENDENCY public: - static QString saveSnapshot(QImage image, const QString& filename, const QString& pathname = QString()); + static QString saveSnapshot(QImage image, const QString& filename, bool& initialWriteFailed, const QString& pathname = QString()); static QTemporaryFile* saveTempSnapshot(QImage image); static SnapshotMetaData* parseSnapshotData(QString snapshotPath); @@ -54,6 +54,7 @@ public slots: private: static QFile* savedFileForSnapshot(QImage& image, bool isTemporary, + bool& initialWriteFailed, const QString& userSelectedFilename = QString(), const QString& userSelectedPathname = QString()); }; diff --git a/interface/src/ui/SnapshotAnimated.cpp b/interface/src/ui/SnapshotAnimated.cpp index 7866e742d9..d9eedddcb7 100644 --- a/interface/src/ui/SnapshotAnimated.cpp +++ b/interface/src/ui/SnapshotAnimated.cpp @@ -89,7 +89,7 @@ void SnapshotAnimated::captureFrames() { // Notify the user that we're processing the snapshot // This also pops up the "Share" dialog. The unprocessed GIF will be visualized as a loading icon until processingGifCompleted() is called. - emit SnapshotAnimated::snapshotAnimatedDM->processingGifStarted(SnapshotAnimated::snapshotStillPath); + emit SnapshotAnimated::snapshotAnimatedDM->processingGifStarted(SnapshotAnimated::snapshotStillPath, false); // Kick off the thread that'll pack the frames into the GIF QtConcurrent::run(processFrames); @@ -103,18 +103,40 @@ void SnapshotAnimated::captureFrames() { } } +void SnapshotAnimated::clearTempVariables() { + // Clear out the frame and frame delay vectors. + // Also release the memory not required to store the items. + SnapshotAnimated::snapshotAnimatedFrameVector.clear(); + SnapshotAnimated::snapshotAnimatedFrameVector.squeeze(); + SnapshotAnimated::snapshotAnimatedFrameDelayVector.clear(); + SnapshotAnimated::snapshotAnimatedFrameDelayVector.squeeze(); + // Reset the current frame timestamp + SnapshotAnimated::snapshotAnimatedTimestamp = 0; + SnapshotAnimated::snapshotAnimatedFirstFrameTimestamp = 0; +} + void SnapshotAnimated::processFrames() { uint32_t width = SnapshotAnimated::snapshotAnimatedFrameVector[0].width(); uint32_t height = SnapshotAnimated::snapshotAnimatedFrameVector[0].height(); // Create the GIF from the temporary files // Write out the header and beginning of the GIF file - GifBegin( + if (!GifBegin( &(SnapshotAnimated::snapshotAnimatedGifWriter), qPrintable(SnapshotAnimated::snapshotAnimatedPath), width, height, - 1); // "1" means "yes there is a delay" with this GifCreator library. + 1)) { // "1" means "yes there is a delay" with this GifCreator library. + + // We should never, ever get here. If we do, that means that writing a still JPG to the filesystem + // has succeeded, but that writing the tiny header to a GIF file in the same directory failed. + // If that happens, we _could_ throw up the "Folder Chooser" dialog like we do for still JPG images, + // but I have no way of testing whether or not that'll work or get properly exercised, + // so I'm not going to bother for now. + SnapshotAnimated::clearTempVariables(); + qDebug() << "Animated snapshot header failed to write - aborting GIF processing."; + return; + } for (int itr = 0; itr < SnapshotAnimated::snapshotAnimatedFrameVector.size(); itr++) { // Write each frame to the GIF GifWriteFrame(&(SnapshotAnimated::snapshotAnimatedGifWriter), @@ -125,16 +147,6 @@ void SnapshotAnimated::processFrames() { } // Write out the end of the GIF GifEnd(&(SnapshotAnimated::snapshotAnimatedGifWriter)); - - // Clear out the frame and frame delay vectors. - // Also release the memory not required to store the items. - SnapshotAnimated::snapshotAnimatedFrameVector.clear(); - SnapshotAnimated::snapshotAnimatedFrameVector.squeeze(); - SnapshotAnimated::snapshotAnimatedFrameDelayVector.clear(); - SnapshotAnimated::snapshotAnimatedFrameDelayVector.squeeze(); - // Reset the current frame timestamp - SnapshotAnimated::snapshotAnimatedTimestamp = 0; - SnapshotAnimated::snapshotAnimatedFirstFrameTimestamp = 0; // Update the "Share" dialog with the processed GIF. emit SnapshotAnimated::snapshotAnimatedDM->processingGifCompleted(SnapshotAnimated::snapshotAnimatedPath); diff --git a/interface/src/ui/SnapshotAnimated.h b/interface/src/ui/SnapshotAnimated.h index dd32e4893d..87ce533fc3 100644 --- a/interface/src/ui/SnapshotAnimated.h +++ b/interface/src/ui/SnapshotAnimated.h @@ -49,6 +49,7 @@ private: static void captureFrames(); static void processFrames(); + static void clearTempVariables(); public: static void saveSnapshotAnimated(QString pathStill, float aspectRatio, Application* app, QSharedPointer dm); static bool isAlreadyTakingSnapshotAnimated() { return snapshotAnimatedFirstFrameTimestamp != 0; }; diff --git a/scripts/system/snapshot.js b/scripts/system/snapshot.js index 5690c91c76..a4f4b17579 100644 --- a/scripts/system/snapshot.js +++ b/scripts/system/snapshot.js @@ -574,7 +574,7 @@ function snapshotDirChanged(snapshotPath) { } } -function processingGifStarted(pathStillSnapshot) { +function processingGifStarted(pathStillSnapshot, stillWriteFailed) { Window.processingGifStarted.disconnect(processingGifStarted); Window.processingGifCompleted.connect(processingGifCompleted); isLoggedIn = Account.isLoggedIn(); @@ -608,6 +608,9 @@ function processingGifStarted(pathStillSnapshot) { image_data: imageData })); }); + if (stillWriteFailed) { + processingGifCompleted(""); + } } function processingGifCompleted(pathAnimatedSnapshot) { From c34605f686a5daccf757e200c4b989073b1ecad6 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 16 May 2018 10:13:54 -0700 Subject: [PATCH 2/4] GIF snapshots using the Snap app are still weird, but the bug is fixed --- interface/src/Application.cpp | 14 ++++---------- interface/src/scripting/WindowScriptingInterface.h | 4 +--- interface/src/ui/Snapshot.cpp | 10 ++++------ interface/src/ui/Snapshot.h | 3 +-- interface/src/ui/SnapshotAnimated.cpp | 4 +++- scripts/system/snapshot.js | 5 +---- 6 files changed, 14 insertions(+), 26 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index bb58f2bf5d..61ed5acdd2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -7590,9 +7590,8 @@ void Application::loadAvatarBrowser() const { void Application::takeSnapshot(bool notify, bool includeAnimated, float aspectRatio, const QString& filename) { postLambdaEvent([notify, includeAnimated, aspectRatio, filename, this] { - bool initialWriteFailed = false; // Get a screenshot and save it - QString path = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getScreenshot(aspectRatio), filename, initialWriteFailed, + QString path = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getScreenshot(aspectRatio), filename, TestScriptingInterface::getInstance()->getTestResultsLocation()); // If we're not doing an animated snapshot as well... @@ -7600,20 +7599,15 @@ void Application::takeSnapshot(bool notify, bool includeAnimated, float aspectRa // Tell the dependency manager that the capture of the still snapshot has taken place. emit DependencyManager::get()->stillSnapshotTaken(path, notify); } else if (!SnapshotAnimated::isAlreadyTakingSnapshotAnimated()) { - if (initialWriteFailed) { - emit DependencyManager::get()->processingGifStarted(path, true); - } else { - // Get an animated GIF snapshot and save it - SnapshotAnimated::saveSnapshotAnimated(path, aspectRatio, qApp, DependencyManager::get()); - } + // Get an animated GIF snapshot and save it + SnapshotAnimated::saveSnapshotAnimated(path, aspectRatio, qApp, DependencyManager::get()); } }); } void Application::takeSecondaryCameraSnapshot(const QString& filename) { postLambdaEvent([filename, this] { - bool initialWriteFailed = false; - QString snapshotPath = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getSecondaryCameraScreenshot(), filename, initialWriteFailed, + QString snapshotPath = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getSecondaryCameraScreenshot(), filename, TestScriptingInterface::getInstance()->getTestResultsLocation()); emit DependencyManager::get()->stillSnapshotTaken(snapshotPath, true); diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index d01a7ed0a5..348882e0f8 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -594,11 +594,9 @@ signals: * starting to be processed. * @function Window.processingGifStarted * @param {string} pathStillSnapshot - The path and name of the still snapshot image file. - * @param {bool} stillWriteFailed - True if the still snapshot (taken before the GIF) failed to write to disk - * (this means the GIF won't capture). * @returns {Signal} */ - void processingGifStarted(const QString& pathStillSnapshot, const bool& stillWriteFailed); + void processingGifStarted(const QString& pathStillSnapshot); /**jsdoc * Triggered when a GIF has been prepared of the snapshot images captured by {@link Window.takeSnapshot|takeSnapshot}. diff --git a/interface/src/ui/Snapshot.cpp b/interface/src/ui/Snapshot.cpp index 5c58737e78..a005fd8be8 100644 --- a/interface/src/ui/Snapshot.cpp +++ b/interface/src/ui/Snapshot.cpp @@ -74,9 +74,9 @@ SnapshotMetaData* Snapshot::parseSnapshotData(QString snapshotPath) { return data; } -QString Snapshot::saveSnapshot(QImage image, const QString& filename, bool& initialWriteFailed, const QString& pathname) { +QString Snapshot::saveSnapshot(QImage image, const QString& filename, const QString& pathname) { - QFile* snapshotFile = savedFileForSnapshot(image, false, initialWriteFailed, filename, pathname); + QFile* snapshotFile = savedFileForSnapshot(image, false, filename, pathname); if (snapshotFile) { // we don't need the snapshot file, so close it, grab its filename and delete it @@ -94,11 +94,10 @@ QString Snapshot::saveSnapshot(QImage image, const QString& filename, bool& init QTemporaryFile* Snapshot::saveTempSnapshot(QImage image) { // return whatever we get back from saved file for snapshot - bool initialWriteFailed = false; - return static_cast(savedFileForSnapshot(image, true, initialWriteFailed)); + return static_cast(savedFileForSnapshot(image, true)); } -QFile* Snapshot::savedFileForSnapshot(QImage & shot, bool isTemporary, bool& initialWriteFailed, const QString& userSelectedFilename, const QString& userSelectedPathname) { +QFile* Snapshot::savedFileForSnapshot(QImage & shot, bool isTemporary, const QString& userSelectedFilename, const QString& userSelectedPathname) { // adding URL to snapshot QUrl currentURL = DependencyManager::get()->currentPublicAddress(); @@ -146,7 +145,6 @@ QFile* Snapshot::savedFileForSnapshot(QImage & shot, bool isTemporary, bool& ini QFile* imageFile = new QFile(snapshotFullPath); while (!imageFile->open(QIODevice::WriteOnly)) { - initialWriteFailed = true; snapshotFullPath = OffscreenUi::getExistingDirectory(nullptr, "Write Error - Choose New Snapshots Directory", QStandardPaths::writableLocation(QStandardPaths::DesktopLocation)); if (snapshotFullPath.isEmpty()) { return NULL; diff --git a/interface/src/ui/Snapshot.h b/interface/src/ui/Snapshot.h index 265d666cc8..606313f3c3 100644 --- a/interface/src/ui/Snapshot.h +++ b/interface/src/ui/Snapshot.h @@ -38,7 +38,7 @@ class Snapshot : public QObject, public Dependency { Q_OBJECT SINGLETON_DEPENDENCY public: - static QString saveSnapshot(QImage image, const QString& filename, bool& initialWriteFailed, const QString& pathname = QString()); + static QString saveSnapshot(QImage image, const QString& filename, const QString& pathname = QString()); static QTemporaryFile* saveTempSnapshot(QImage image); static SnapshotMetaData* parseSnapshotData(QString snapshotPath); @@ -54,7 +54,6 @@ public slots: private: static QFile* savedFileForSnapshot(QImage& image, bool isTemporary, - bool& initialWriteFailed, const QString& userSelectedFilename = QString(), const QString& userSelectedPathname = QString()); }; diff --git a/interface/src/ui/SnapshotAnimated.cpp b/interface/src/ui/SnapshotAnimated.cpp index d9eedddcb7..9d58d89385 100644 --- a/interface/src/ui/SnapshotAnimated.cpp +++ b/interface/src/ui/SnapshotAnimated.cpp @@ -89,7 +89,7 @@ void SnapshotAnimated::captureFrames() { // Notify the user that we're processing the snapshot // This also pops up the "Share" dialog. The unprocessed GIF will be visualized as a loading icon until processingGifCompleted() is called. - emit SnapshotAnimated::snapshotAnimatedDM->processingGifStarted(SnapshotAnimated::snapshotStillPath, false); + emit SnapshotAnimated::snapshotAnimatedDM->processingGifStarted(SnapshotAnimated::snapshotStillPath); // Kick off the thread that'll pack the frames into the GIF QtConcurrent::run(processFrames); @@ -147,6 +147,8 @@ void SnapshotAnimated::processFrames() { } // Write out the end of the GIF GifEnd(&(SnapshotAnimated::snapshotAnimatedGifWriter)); + + SnapshotAnimated::clearTempVariables(); // Update the "Share" dialog with the processed GIF. emit SnapshotAnimated::snapshotAnimatedDM->processingGifCompleted(SnapshotAnimated::snapshotAnimatedPath); diff --git a/scripts/system/snapshot.js b/scripts/system/snapshot.js index a4f4b17579..5690c91c76 100644 --- a/scripts/system/snapshot.js +++ b/scripts/system/snapshot.js @@ -574,7 +574,7 @@ function snapshotDirChanged(snapshotPath) { } } -function processingGifStarted(pathStillSnapshot, stillWriteFailed) { +function processingGifStarted(pathStillSnapshot) { Window.processingGifStarted.disconnect(processingGifStarted); Window.processingGifCompleted.connect(processingGifCompleted); isLoggedIn = Account.isLoggedIn(); @@ -608,9 +608,6 @@ function processingGifStarted(pathStillSnapshot, stillWriteFailed) { image_data: imageData })); }); - if (stillWriteFailed) { - processingGifCompleted(""); - } } function processingGifCompleted(pathAnimatedSnapshot) { From c3ea176b5811f4f6ba1c15b95e6e97fdaf0ead29 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 16 May 2018 10:54:58 -0700 Subject: [PATCH 3/4] Give me my reticle back! --- interface/src/ui/Snapshot.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/interface/src/ui/Snapshot.cpp b/interface/src/ui/Snapshot.cpp index a005fd8be8..6027c6765d 100644 --- a/interface/src/ui/Snapshot.cpp +++ b/interface/src/ui/Snapshot.cpp @@ -33,6 +33,7 @@ #include #include "Application.h" +#include "display-plugins/CompositorHelper.h" #include "SnapshotUploader.h" // filename format: hifi-snap-by-%username%-on-%date%_%time%_@-%location%.jpg @@ -145,6 +146,13 @@ QFile* Snapshot::savedFileForSnapshot(QImage & shot, bool isTemporary, const QSt QFile* imageFile = new QFile(snapshotFullPath); while (!imageFile->open(QIODevice::WriteOnly)) { + // It'd be better for the directory chooser to restore the cursor to its previous state + // after choosing a directory, but if the user has entered this codepath, + // something terrible has happened. Let's just show the user their cursor so they can get + // out of this awful state. + qApp->getApplicationCompositor().getReticleInterface()->setVisible(true); + qApp->getApplicationCompositor().getReticleInterface()->setAllowMouseCapture(true); + snapshotFullPath = OffscreenUi::getExistingDirectory(nullptr, "Write Error - Choose New Snapshots Directory", QStandardPaths::writableLocation(QStandardPaths::DesktopLocation)); if (snapshotFullPath.isEmpty()) { return NULL; From f8215b59993629f77069921c5335981ed35c9039 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 16 May 2018 11:05:21 -0700 Subject: [PATCH 4/4] Fix final? crash --- interface/src/Application.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 61ed5acdd2..29ba699246 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -7596,8 +7596,10 @@ void Application::takeSnapshot(bool notify, bool includeAnimated, float aspectRa // If we're not doing an animated snapshot as well... if (!includeAnimated) { - // Tell the dependency manager that the capture of the still snapshot has taken place. - emit DependencyManager::get()->stillSnapshotTaken(path, notify); + if (!path.isEmpty()) { + // Tell the dependency manager that the capture of the still snapshot has taken place. + emit DependencyManager::get()->stillSnapshotTaken(path, notify); + } } else if (!SnapshotAnimated::isAlreadyTakingSnapshotAnimated()) { // Get an animated GIF snapshot and save it SnapshotAnimated::saveSnapshotAnimated(path, aspectRatio, qApp, DependencyManager::get());