Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/ClusterM/fceux.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorharry <hrosen2016@gmail.com>2024-01-15 22:17:13 +0300
committerharry <hrosen2016@gmail.com>2024-01-15 22:17:13 +0300
commit198cdafbf80da0dbdad6424e4afc4c49e21c05b4 (patch)
tree782b0f9f2cd6cbd2dbfbea8f5b16342290278fdf
parent8e7e5e8c05d283b0caadc26e03303f209dd3d22a (diff)
Qt JS script engine interface in work.
-rw-r--r--src/drivers/Qt/ConsoleWindow.cpp10
-rw-r--r--src/drivers/Qt/QtScriptManager.cpp152
-rw-r--r--src/drivers/Qt/QtScriptManager.h18
-rw-r--r--src/drivers/Qt/fceuWrapper.cpp18
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();