From 00a3fc77a113dfa05296a6f248b86b7815c1e7ef Mon Sep 17 00:00:00 2001
From: seefo <robbie.uvanni@gmail.com>
Date: Tue, 20 Jun 2017 11:18:22 -0700
Subject: [PATCH] Fixed an issue where toolbar buttons duplicated themselves
 when reloading scripts

---
 libraries/script-engine/src/ScriptEngines.cpp | 10 +++++++++-
 libraries/script-engine/src/ScriptEngines.h   |  1 +
 scripts/system/snapshot.js                    | 14 +++++++++++---
 3 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/libraries/script-engine/src/ScriptEngines.cpp b/libraries/script-engine/src/ScriptEngines.cpp
index b310e137b7..1942afb38b 100644
--- a/libraries/script-engine/src/ScriptEngines.cpp
+++ b/libraries/script-engine/src/ScriptEngines.cpp
@@ -352,6 +352,13 @@ QStringList ScriptEngines::getRunningScripts() {
 void ScriptEngines::stopAllScripts(bool restart) {
     QVector<QString> toReload;
     QReadLocker lock(&_scriptEnginesHashLock);
+
+    if (_isReloading) {
+        return;
+    } else {
+        _isReloading = true;
+    }
+
     for (QHash<QUrl, ScriptEngine*>::const_iterator it = _scriptEnginesHash.constBegin();
         it != _scriptEnginesHash.constEnd(); it++) {
         ScriptEngine *scriptEngine = it.value();
@@ -371,7 +378,7 @@ void ScriptEngines::stopAllScripts(bool restart) {
     }
     // wait for engines to stop (ie: providing time for .scriptEnding cleanup handlers to run) before
     // triggering reload of any Client scripts / Entity scripts
-    QTimer::singleShot(500, this, [=]() {
+    QTimer::singleShot(1000, this, [=]() {
         for(const auto &scriptName : toReload) {
             auto scriptEngine = getScriptEngine(scriptName);
             if (scriptEngine && !scriptEngine->isFinished()) {
@@ -386,6 +393,7 @@ void ScriptEngines::stopAllScripts(bool restart) {
             qCDebug(scriptengine) << "stopAllScripts -- emitting scriptsReloading";
             emit scriptsReloading();
         }
+        _isReloading = false;
     });
 }
 
diff --git a/libraries/script-engine/src/ScriptEngines.h b/libraries/script-engine/src/ScriptEngines.h
index 5152c3952a..5aabd70dff 100644
--- a/libraries/script-engine/src/ScriptEngines.h
+++ b/libraries/script-engine/src/ScriptEngines.h
@@ -110,6 +110,7 @@ protected:
     ScriptsModel _scriptsModel;
     ScriptsModelFilter _scriptsModelFilter;
     std::atomic<bool> _isStopped { false };
+    std::atomic<bool> _isReloading { false };
 };
 
 QUrl normalizeScriptURL(const QUrl& rawScriptURL);
diff --git a/scripts/system/snapshot.js b/scripts/system/snapshot.js
index b045e64c6a..6321c17ded 100644
--- a/scripts/system/snapshot.js
+++ b/scripts/system/snapshot.js
@@ -41,7 +41,16 @@ var numStillSnapshotUploadsPending = 0;
 
 // It's totally unnecessary to return to C++ to perform many of these requests, such as DELETEing an old story,
 // POSTING a new one, PUTTING a new audience, or GETTING story data. It's far more efficient to do all of that within JS
-var request = Script.require('request').request;
+var request;
+
+try {
+    // Due to an issue where if the user spams 'script reload', this call could cause an exception
+    // preventing our scriptEnding to not properly be initialized resulting in the tablet button
+    // duplicating itself where you end up with a bunch of SNAP buttons on your toolbar
+    request = Script.require('request').request;
+} catch(err) {
+    print('Failed to resolve request api, error: ' + err);
+}
 
 function openLoginWindow() {
     if ((HMD.active && Settings.getValue("hmdTabletBecomesToolbar", false))
@@ -750,11 +759,10 @@ Script.scriptEnding.connect(function () {
     }
     if (tablet) {
         tablet.removeButton(button);
+        tablet.screenChanged.disconnect(onTabletScreenChanged);
     }
     Window.snapshotShared.disconnect(snapshotUploaded);
-    tablet.screenChanged.disconnect(onTabletScreenChanged);
     Snapshot.snapshotLocationSet.disconnect(snapshotLocationSet);
-    
     Entities.canRezChanged.disconnect(processRezPermissionChange);
     Entities.canRezTmpChanged.disconnect(processRezPermissionChange);
 });