diff options
author | harry <hrosen2016@gmail.com> | 2024-01-15 22:17:13 +0300 |
---|---|---|
committer | harry <hrosen2016@gmail.com> | 2024-01-15 22:17:13 +0300 |
commit | 198cdafbf80da0dbdad6424e4afc4c49e21c05b4 (patch) | |
tree | 782b0f9f2cd6cbd2dbfbea8f5b16342290278fdf | |
parent | 8e7e5e8c05d283b0caadc26e03303f209dd3d22a (diff) |
Qt JS script engine interface in work.
-rw-r--r-- | src/drivers/Qt/ConsoleWindow.cpp | 10 | ||||
-rw-r--r-- | src/drivers/Qt/QtScriptManager.cpp | 152 | ||||
-rw-r--r-- | src/drivers/Qt/QtScriptManager.h | 18 | ||||
-rw-r--r-- | src/drivers/Qt/fceuWrapper.cpp | 18 |
4 files changed, 137 insertions, 61 deletions
diff --git a/src/drivers/Qt/ConsoleWindow.cpp b/src/drivers/Qt/ConsoleWindow.cpp index e656939b..6af6d43b 100644 --- a/src/drivers/Qt/ConsoleWindow.cpp +++ b/src/drivers/Qt/ConsoleWindow.cpp @@ -186,6 +186,10 @@ consoleWin_t::consoleWin_t(QWidget *parent) gameTimer->setTimerType( Qt::PreciseTimer ); gameTimer->start( 8 ); // 120hz +#ifdef __FCEU_QSCRIPT_ENABLE__ + QtScriptManager::create(nullptr); +#endif + emulatorThread->start(); g_config->getOption( "SDL.SetSchedParam", &opt ); @@ -272,9 +276,6 @@ consoleWin_t::consoleWin_t(QWidget *parent) // Create AVI Recording Disk Thread aviDiskThread = new AviRecordDiskThread_t(this); -#ifdef __FCEU_QSCRIPT_ENABLE__ - QtScriptManager::create(this); -#endif scrHandlerConnected = false; } @@ -316,6 +317,9 @@ consoleWin_t::~consoleWin_t(void) closeGamePadConfWindow(); +#ifdef __FCEU_QSCRIPT_ENABLE__ + QtScriptManager::destroy(); +#endif // The closeApp function call stops all threads. // Calling quit on threads should not happen here. //printf("Thread Finished: %i \n", emulatorThread->isFinished() ); diff --git a/src/drivers/Qt/QtScriptManager.cpp b/src/drivers/Qt/QtScriptManager.cpp index fd084f6f..a8b11343 100644 --- a/src/drivers/Qt/QtScriptManager.cpp +++ b/src/drivers/Qt/QtScriptManager.cpp @@ -167,10 +167,29 @@ void EmuScriptObject::speedMode(const QString& mode) FCEUD_SetEmulationSpeed(speed); } //---------------------------------------------------- +void EmuScriptObject::registerBefore(const QJSValue& func) +{ + script->registerBefore(func); +} +//---------------------------------------------------- +void EmuScriptObject::registerAfter(const QJSValue& func) +{ + script->registerAfter(func); +} +//---------------------------------------------------- +void EmuScriptObject::registerStop(const QJSValue& func) +{ + script->registerStop(func); +} +//---------------------------------------------------- bool EmuScriptObject::loadRom(const QString& romPath) { - int ret = LoadGame(romPath.toLocal8Bit().constData()); + int ret = 0; + if (!romPath.isEmpty()) + { + ret = LoadGame(romPath.toLocal8Bit().constData()); + } return ret != 0; } //---------------------------------------------------- @@ -193,7 +212,7 @@ QtScriptInstance::QtScriptInstance(QObject* parent) dialog = win; emu->setDialog(dialog); } - engine = new QJSEngine(this); + engine = new QJSEngine(nullptr); emu->setEngine(engine); @@ -223,7 +242,14 @@ void QtScriptInstance::resetEngine() engine->deleteLater(); engine = nullptr; } - engine = new QJSEngine(this); + engine = new QJSEngine(nullptr); + + if (ui_rootWidget != nullptr) + { + ui_rootWidget->hide(); + ui_rootWidget->deleteLater(); + ui_rootWidget = nullptr; + } configEngine(); } @@ -240,8 +266,7 @@ int QtScriptInstance::configEngine() engine->globalObject().setProperty("gui", guiObject); - QtScriptManager::getInstance()->removeFrameFinishedConnection(this); - + onFrameBeginCallback = QJSValue(); onFrameFinishCallback = QJSValue(); onScriptStopCallback = QJSValue(); @@ -276,13 +301,10 @@ int QtScriptInstance::loadScriptFile( QString filepath ) running = true; //printf("Script Evaluation Success!\n"); } - onFrameFinishCallback = engine->globalObject().property("onFrameFinish"); - onScriptStopCallback = engine->globalObject().property("onScriptStop"); + //onFrameBeginCallback = engine->globalObject().property("onFrameBegin"); + //onFrameFinishCallback = engine->globalObject().property("onFrameFinish"); + //onScriptStopCallback = engine->globalObject().property("onScriptStop"); - if (onFrameFinishCallback.isCallable()) - { - QtScriptManager::getInstance()->addFrameFinishedConnection(this); - } return 0; } //---------------------------------------------------- @@ -313,24 +335,40 @@ void QtScriptInstance::loadUI(const QString& uiFilePath) QFile uiFile(uiFilePath); QUiLoader uiLoader; - QWidget* rootWidget = uiLoader.load(&uiFile, dialog); + ui_rootWidget = uiLoader.load(&uiFile, dialog); - if (rootWidget == nullptr) + if (ui_rootWidget == nullptr) { return; } - QJSValue uiObject = engine->newQObject(rootWidget); + + QJSValue uiObject = engine->newQObject(ui_rootWidget); engine->globalObject().setProperty("ui", uiObject); - loadObjectChildren( uiObject, rootWidget); + loadObjectChildren( uiObject, ui_rootWidget); - rootWidget->show(); + ui_rootWidget->show(); #else throwError(QJSValue::GenericError, "Error: Application was not linked against Qt UI Tools"); #endif } //---------------------------------------------------- +void QtScriptInstance::registerBefore(const QJSValue& func) +{ + onFrameBeginCallback = func; +} +//---------------------------------------------------- +void QtScriptInstance::registerAfter(const QJSValue& func) +{ + onFrameFinishCallback = func; +} +//---------------------------------------------------- +void QtScriptInstance::registerStop(const QJSValue& func) +{ + onScriptStopCallback = func; +} +//---------------------------------------------------- void QtScriptInstance::print(const QString& msg) { if (dialog) @@ -416,6 +454,14 @@ void QtScriptInstance::stopRunning() } } //---------------------------------------------------- +void QtScriptInstance::onFrameBegin() +{ + if (running && onFrameBeginCallback.isCallable()) + { + onFrameBeginCallback.call(); + } +} +//---------------------------------------------------- void QtScriptInstance::onFrameFinish() { if (running && onFrameFinishCallback.isCallable()) @@ -499,6 +545,14 @@ QtScriptManager* QtScriptManager::create(QObject* parent) return mgr; } //---------------------------------------------------- +void QtScriptManager::destroy(void) +{ + if (_instance != nullptr) + { + delete _instance; + } +} +//---------------------------------------------------- void QtScriptManager::addScriptInstance(QtScriptInstance* script) { scriptList.push_back(script); @@ -519,45 +573,22 @@ void QtScriptManager::removeScriptInstance(QtScriptInstance* script) it++; } } - - removeFrameFinishedConnection(script); } //---------------------------------------------------- -void QtScriptManager::addFrameFinishedConnection(QtScriptInstance* script) +void QtScriptManager::frameBeginUpdate() { - if (frameFinishConnectList.size() == 0) - { - connect(consoleWindow->emulatorThread, SIGNAL(frameFinished(void)), this, SLOT(frameFinishedUpdate(void)), Qt::BlockingQueuedConnection); - } - frameFinishConnectList.push_back(script); -} -//---------------------------------------------------- -void QtScriptManager::removeFrameFinishedConnection(QtScriptInstance* script) -{ - auto it = frameFinishConnectList.begin(); - - while (it != frameFinishConnectList.end()) - { - if (*it == script) - { - it = frameFinishConnectList.erase(it); - } - else - { - it++; - } - } - - if (frameFinishConnectList.size() == 0) + FCEU_WRAPPER_LOCK(); + for (auto script : scriptList) { - consoleWindow->emulatorThread->disconnect( SIGNAL(frameFinished(void)), this, SLOT(frameFinishedUpdate(void))); + script->onFrameBegin(); } + FCEU_WRAPPER_UNLOCK(); } //---------------------------------------------------- void QtScriptManager::frameFinishedUpdate() { FCEU_WRAPPER_LOCK(); - for (auto script : frameFinishConnectList) + for (auto script : scriptList) { script->onFrameFinish(); } @@ -649,6 +680,8 @@ QScriptDialog_t::QScriptDialog_t(QWidget *parent) setLayout(mainLayout); + emuThreadText.reserve(4096); + //winList.push_back(this); periodicTimer = new QTimer(this); @@ -694,13 +727,15 @@ void QScriptDialog_t::closeWindow(void) //---------------------------------------------------- void QScriptDialog_t::updatePeriodic(void) { - // TODO //printf("Update JS\n"); - //if (updateJSDisplay) - //{ - // updateJSWindows(); - // updateJSDisplay = false; - //} + FCEU_WRAPPER_LOCK(); + if (!emuThreadText.isEmpty()) + { + jsOutput->insertPlainText(emuThreadText); + emuThreadText.clear(); + } + refreshState(); + FCEU_WRAPPER_UNLOCK(); } //---------------------------------------------------- void QScriptDialog_t::openJSKillMessageBox(void) @@ -863,10 +898,12 @@ void QScriptDialog_t::openScriptFile(void) //---------------------------------------------------- void QScriptDialog_t::startScript(void) { + FCEU_WRAPPER_LOCK(); scriptInstance->resetEngine(); if (scriptInstance->loadScriptFile(scriptPath->text())) { // Script parsing error + FCEU_WRAPPER_UNLOCK(); return; } // TODO add option to pass options to script main. @@ -880,12 +917,16 @@ void QScriptDialog_t::startScript(void) scriptInstance->call("main", argList); refreshState(); + + FCEU_WRAPPER_UNLOCK(); } //---------------------------------------------------- void QScriptDialog_t::stopScript(void) { + FCEU_WRAPPER_LOCK(); scriptInstance->stopRunning(); refreshState(); + FCEU_WRAPPER_UNLOCK(); } //---------------------------------------------------- void QScriptDialog_t::refreshState(void) @@ -904,7 +945,14 @@ void QScriptDialog_t::refreshState(void) //---------------------------------------------------- void QScriptDialog_t::logOutput(const QString& text) { - jsOutput->insertPlainText(text); + if (QThread::currentThread() == consoleWindow->emulatorThread) + { + emuThreadText.append(text); + } + else + { + jsOutput->insertPlainText(text); + } } //---------------------------------------------------- #endif // __FCEU_QSCRIPT_ENABLE__ diff --git a/src/drivers/Qt/QtScriptManager.h b/src/drivers/Qt/QtScriptManager.h index 6e8690e3..05e609ea 100644 --- a/src/drivers/Qt/QtScriptManager.h +++ b/src/drivers/Qt/QtScriptManager.h @@ -55,6 +55,9 @@ public slots: Q_INVOKABLE bool lagged(); Q_INVOKABLE void setlagflag(bool flag); Q_INVOKABLE bool emulating(); + Q_INVOKABLE void registerBefore(const QJSValue& func); + Q_INVOKABLE void registerAfter(const QJSValue& func); + Q_INVOKABLE void registerStop(const QJSValue& func); Q_INVOKABLE void message(const QString& msg); Q_INVOKABLE void speedMode(const QString& mode); Q_INVOKABLE bool loadRom(const QString& romPath); @@ -76,6 +79,7 @@ public: void stopRunning(); int call(const QString& funcName, const QJSValueList& args = QJSValueList()); + void onFrameBegin(); void onFrameFinish(); int throwError(QJSValue::ErrorType errorType, const QString &message = QString()); @@ -90,6 +94,8 @@ private: QJSEngine* engine = nullptr; QScriptDialog_t* dialog = nullptr; EmuScriptObject* emu = nullptr; + QWidget* ui_rootWidget = nullptr; + QJSValue onFrameBeginCallback; QJSValue onFrameFinishCallback; QJSValue onScriptStopCallback; bool running = false; @@ -98,6 +104,9 @@ public slots: Q_INVOKABLE void print(const QString& msg); Q_INVOKABLE void loadUI(const QString& uiFilePath); Q_INVOKABLE QString openFileBrowser(const QString& initialPath = QString()); + Q_INVOKABLE void registerBefore(const QJSValue& func); + Q_INVOKABLE void registerAfter(const QJSValue& func); + Q_INVOKABLE void registerStop(const QJSValue& func); }; class QtScriptManager : public QObject @@ -110,21 +119,19 @@ public: static QtScriptManager* getInstance(){ return _instance; } static QtScriptManager* create(QObject* parent = nullptr); + static void destroy(); + int numScriptsLoaded(void){ return scriptList.size(); } void addScriptInstance(QtScriptInstance* script); void removeScriptInstance(QtScriptInstance* script); - void addFrameFinishedConnection(QtScriptInstance* script); - void removeFrameFinishedConnection(QtScriptInstance* script); private: static QtScriptManager* _instance; QList<QtScriptInstance*> scriptList; - QList<QtScriptInstance*> frameFinishConnectList; FCEU::timeStampRecord lastFrameUpdate; - int frameFinishedConnectCount = 0; - public slots: + void frameBeginUpdate(); void frameFinishedUpdate(); }; @@ -151,6 +158,7 @@ protected: QPushButton *startButton; QTextEdit *jsOutput; QtScriptInstance *scriptInstance; + QString emuThreadText; private: public slots: diff --git a/src/drivers/Qt/fceuWrapper.cpp b/src/drivers/Qt/fceuWrapper.cpp index 331c1ece..0aaa73ce 100644 --- a/src/drivers/Qt/fceuWrapper.cpp +++ b/src/drivers/Qt/fceuWrapper.cpp @@ -42,6 +42,7 @@ #include "Qt/CheatsConf.h" #include "Qt/SymbolicDebug.h" #include "Qt/CodeDataLogger.h" +#include "Qt/QtScriptManager.h" #include "Qt/ConsoleDebugger.h" #include "Qt/ConsoleWindow.h" #include "Qt/ConsoleUtilities.h" @@ -1477,17 +1478,32 @@ int fceuWrapperUpdate( void ) if ( GameInfo ) { + auto* qscriptMgr = QtScriptManager::getInstance(); + + bool scriptsLoaded = (qscriptMgr != nullptr) && (qscriptMgr->numScriptsLoaded() > 0); + + if (scriptsLoaded) + { + qscriptMgr->frameBeginUpdate(); + } + DoFun(frameskip, periodic_saves); + if (scriptsLoaded) + { + qscriptMgr->frameFinishedUpdate(); + } + hexEditorUpdateMemoryValues(); fceuWrapperUnLock(); + emulatorHasMutex = 0; + if ( consoleWindow ) { consoleWindow->emulatorThread->signalFrameFinished(); } - emulatorHasMutex = 0; #ifdef __FCEU_PROFILER_ENABLE__ FCEU_profiler_log_thread_activity(); |