From d2fd4bf445b22d1d5383bf591f9cefc5fe85c58a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jan 2014 16:36:44 -0800 Subject: [PATCH 1/4] expose QTimer to the script engine --- libraries/script-engine/src/ScriptEngine.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 6ea3742592..25467389de 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -105,6 +105,7 @@ bool ScriptEngine::setScriptContents(const QString& scriptContents) { } Q_SCRIPT_DECLARE_QMETAOBJECT(AudioInjectorOptions, QObject*) +Q_SCRIPT_DECLARE_QMETAOBJECT(QTimer, QObject*) void ScriptEngine::init() { if (_isInitialized) { @@ -132,6 +133,9 @@ void ScriptEngine::init() { QScriptValue injectionOptionValue = _engine.scriptValueFromQMetaObject(); _engine.globalObject().setProperty("AudioInjectionOptions", injectionOptionValue); + + QScriptValue timerValue = _engine.scriptValueFromQMetaObject(); + _engine.globalObject().setProperty("Timer", timerValue); registerGlobalObject("Agent", this); registerGlobalObject("Audio", &_audioScriptingInterface); From a7f240650584b3597a8af8f0a2303b5c919c0882 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 31 Jan 2014 16:40:24 -0800 Subject: [PATCH 2/4] add an example timer script --- examples/timer.js | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 examples/timer.js diff --git a/examples/timer.js b/examples/timer.js new file mode 100644 index 0000000000..7ce6418c24 --- /dev/null +++ b/examples/timer.js @@ -0,0 +1,5 @@ +var timer = new Timer(); +timer.interval = 1000; +timer.singleShot = true; // set this is you only want the timer to fire once +timer.timeout.connect(function() { print("TIMER FIRED!"); }); +timer.start(); From 9dd8c11e1e1efdca60d800734fc996b23b123929 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 3 Feb 2014 09:59:16 -0800 Subject: [PATCH 3/4] change script timer setup to match HTML dom standard --- examples/timer.js | 13 ++++--- libraries/script-engine/src/ScriptEngine.cpp | 40 +++++++++++++++++--- libraries/script-engine/src/ScriptEngine.h | 9 ++++- 3 files changed, 50 insertions(+), 12 deletions(-) diff --git a/examples/timer.js b/examples/timer.js index 7ce6418c24..db9a51ef6f 100644 --- a/examples/timer.js +++ b/examples/timer.js @@ -1,5 +1,8 @@ -var timer = new Timer(); -timer.interval = 1000; -timer.singleShot = true; // set this is you only want the timer to fire once -timer.timeout.connect(function() { print("TIMER FIRED!"); }); -timer.start(); +var one_timer = Script.setTimeout(function() { print("One time timer fired!"); }, 1000); +var multiple_timer = Script.setInterval(function() { print("Repeating timer fired!"); }, 1000); + +// this would stop a scheduled single shot timer +Script.clearTimeout(one_timer); + +// this stops the repeating timer +Script.clearInterval(multiple_timer); \ No newline at end of file diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index d040e5b68e..8e45c319c2 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -105,9 +105,6 @@ bool ScriptEngine::setScriptContents(const QString& scriptContents) { return true; } -Q_SCRIPT_DECLARE_QMETAOBJECT(AudioInjectorOptions, QObject*) -Q_SCRIPT_DECLARE_QMETAOBJECT(QTimer, QObject*) - void ScriptEngine::init() { if (_isInitialized) { return; // only initialize once @@ -134,9 +131,6 @@ void ScriptEngine::init() { QScriptValue injectionOptionValue = _engine.scriptValueFromQMetaObject(); _engine.globalObject().setProperty("AudioInjectionOptions", injectionOptionValue); - - QScriptValue timerValue = _engine.scriptValueFromQMetaObject(); - _engine.globalObject().setProperty("Timer", timerValue); registerGlobalObject("Script", this); registerGlobalObject("Audio", &_audioScriptingInterface); @@ -302,4 +296,38 @@ void ScriptEngine::stop() { _isFinished = true; } +void ScriptEngine::timerFired() { + QTimer* callingTimer = reinterpret_cast(sender()); + + // call the associated JS function, if it exists + QScriptValue timerFunction = _timerFunctionMap.value(callingTimer); + if (timerFunction.isValid()) { + timerFunction.call(); + } + + if (!callingTimer->isActive()) { + // this timer is done, we can kill it + qDebug() << "Deleting a single shot timer"; + delete callingTimer; + } +} + +void ScriptEngine::setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot) { + // create the timer, add it to the map, and start it + QTimer* newTimer = new QTimer(this); + connect(newTimer, &QTimer::timeout, this, &ScriptEngine::timerFired); + _timerFunctionMap.insert(newTimer, function); + + newTimer->setSingleShot(isSingleShot); + + newTimer->start(intervalMS); +} + +void ScriptEngine::setInterval(const QScriptValue& function, int intervalMS) { + setupTimerWithInterval(function, intervalMS, false); +} + +void ScriptEngine::setTimeout(const QScriptValue& function, int timeoutMS) { + setupTimerWithInterval(function, timeoutMS, true); +} diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index a07f18f5f7..d706ed7bb0 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -59,12 +59,17 @@ public: bool isAvatar() const { return _isAvatar; } void setAvatarData(AvatarData* avatarData, const QString& objectName); + + void timerFired(); public slots: void init(); void run(); /// runs continuously until Agent.stop() is called void stop(); void evaluate(); /// initializes the engine, and evaluates the script, but then returns control to caller + + void setInterval(const QScriptValue& function, int intervalMS); + void setTimeout(const QScriptValue& function, int timeoutMS); signals: void willSendAudioDataCallback(); @@ -73,15 +78,17 @@ signals: void finished(const QString& fileNameString); protected: - QString _scriptContents; bool _isFinished; bool _isRunning; bool _isInitialized; QScriptEngine _engine; bool _isAvatar; + QHash _timerFunctionMap; private: + void setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot); + static VoxelsScriptingInterface _voxelsScriptingInterface; static ParticlesScriptingInterface _particlesScriptingInterface; AbstractControllerScriptingInterface* _controllerScriptingInterface; From e2842ab7a472733cef92eef101674994028e345f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 3 Feb 2014 10:10:58 -0800 Subject: [PATCH 4/4] stop timers when the script does, add cleanup methods --- examples/timer.js | 2 +- libraries/script-engine/src/ScriptEngine.cpp | 29 ++++++++++++++------ libraries/script-engine/src/ScriptEngine.h | 11 +++++--- 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/examples/timer.js b/examples/timer.js index db9a51ef6f..c7ad0290ab 100644 --- a/examples/timer.js +++ b/examples/timer.js @@ -1,4 +1,4 @@ -var one_timer = Script.setTimeout(function() { print("One time timer fired!"); }, 1000); +var one_timer = Script.setTimeout(function() { print("One time timer fired!"); }, 10000); var multiple_timer = Script.setInterval(function() { print("Repeating timer fired!"); }, 1000); // this would stop a scheduled single shot timer diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 8e45c319c2..3b5cedb3ad 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -312,22 +312,35 @@ void ScriptEngine::timerFired() { } } -void ScriptEngine::setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot) { +QObject* ScriptEngine::setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot) { // create the timer, add it to the map, and start it QTimer* newTimer = new QTimer(this); - connect(newTimer, &QTimer::timeout, this, &ScriptEngine::timerFired); - _timerFunctionMap.insert(newTimer, function); - newTimer->setSingleShot(isSingleShot); + connect(newTimer, &QTimer::timeout, this, &ScriptEngine::timerFired); + + // make sure the timer stops when the script does + connect(this, &ScriptEngine::scriptEnding, newTimer, &QTimer::stop); + + _timerFunctionMap.insert(newTimer, function); + newTimer->start(intervalMS); + return newTimer; } -void ScriptEngine::setInterval(const QScriptValue& function, int intervalMS) { - setupTimerWithInterval(function, intervalMS, false); +QObject* ScriptEngine::setInterval(const QScriptValue& function, int intervalMS) { + return setupTimerWithInterval(function, intervalMS, false); } -void ScriptEngine::setTimeout(const QScriptValue& function, int timeoutMS) { - setupTimerWithInterval(function, timeoutMS, true); +QObject* ScriptEngine::setTimeout(const QScriptValue& function, int timeoutMS) { + return setupTimerWithInterval(function, timeoutMS, true); +} + +void ScriptEngine::stopTimer(QTimer *timer) { + if (_timerFunctionMap.contains(timer)) { + timer->stop(); + _timerFunctionMap.remove(timer); + delete timer; + } } diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index d706ed7bb0..12909a16eb 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -68,9 +68,11 @@ public slots: void stop(); void evaluate(); /// initializes the engine, and evaluates the script, but then returns control to caller - void setInterval(const QScriptValue& function, int intervalMS); - void setTimeout(const QScriptValue& function, int timeoutMS); - + QObject* setInterval(const QScriptValue& function, int intervalMS); + QObject* setTimeout(const QScriptValue& function, int timeoutMS); + void clearInterval(QObject* timer) { stopTimer(reinterpret_cast(timer)); } + void clearTimeout(QObject* timer) { stopTimer(reinterpret_cast(timer)); } + signals: void willSendAudioDataCallback(); void willSendVisualDataCallback(); @@ -87,7 +89,8 @@ protected: QHash _timerFunctionMap; private: - void setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot); + QObject* setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot); + void stopTimer(QTimer* timer); static VoxelsScriptingInterface _voxelsScriptingInterface; static ParticlesScriptingInterface _particlesScriptingInterface;