mirror of
https://github.com/rizinorg/cutter.git
synced 2024-12-18 19:06:10 +00:00
Add PluginManager
This commit is contained in:
parent
280e10d154
commit
986041380c
@ -2617,16 +2617,6 @@ QList<QString> CutterCore::getColorThemes()
|
||||
return r;
|
||||
}
|
||||
|
||||
void CutterCore::setCutterPlugins(QList<CutterPlugin *> plugins)
|
||||
{
|
||||
this->plugins = plugins;
|
||||
}
|
||||
|
||||
QList<CutterPlugin *> CutterCore::getCutterPlugins()
|
||||
{
|
||||
return plugins;
|
||||
}
|
||||
|
||||
QString CutterCore::ansiEscapeToHtml(const QString &text)
|
||||
{
|
||||
int len;
|
||||
|
@ -723,9 +723,6 @@ public:
|
||||
|
||||
void message(const QString &msg, bool debug = false);
|
||||
|
||||
void setCutterPlugins(QList<CutterPlugin*> plugins);
|
||||
QList<CutterPlugin*> getCutterPlugins();
|
||||
|
||||
QStringList getSectionList();
|
||||
|
||||
RCoreLocked core() const;
|
||||
@ -787,7 +784,6 @@ private:
|
||||
|
||||
bool emptyGraph = false;
|
||||
|
||||
QList<CutterPlugin*> plugins;
|
||||
};
|
||||
|
||||
class ccClass : public CutterCore
|
||||
|
@ -230,7 +230,8 @@ SOURCES += \
|
||||
dialogs/LoadNewTypesDialog.cpp \
|
||||
widgets/SdbWidget.cpp \
|
||||
plugins/CutterPythonPlugin.cpp \
|
||||
common/PythonManager.cpp
|
||||
common/PythonManager.cpp \
|
||||
plugins/PluginManager.cpp
|
||||
|
||||
HEADERS += \
|
||||
Cutter.h \
|
||||
@ -343,7 +344,8 @@ HEADERS += \
|
||||
dialogs/LoadNewTypesDialog.h \
|
||||
widgets/SdbWidget.h \
|
||||
plugins/CutterPythonPlugin.h \
|
||||
common/PythonManager.h
|
||||
common/PythonManager.h \
|
||||
plugins/PluginManager.h
|
||||
|
||||
FORMS += \
|
||||
dialogs/AboutDialog.ui \
|
||||
|
@ -3,7 +3,7 @@
|
||||
#ifdef CUTTER_ENABLE_JUPYTER
|
||||
#include "common/JupyterConnection.h"
|
||||
#endif
|
||||
#include "plugins/CutterPythonPlugin.h"
|
||||
#include "plugins/PluginManager.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QFileOpenEvent>
|
||||
@ -119,7 +119,7 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc
|
||||
}
|
||||
}
|
||||
|
||||
loadPlugins();
|
||||
Plugins()->loadPlugins();
|
||||
|
||||
mainWindow = new MainWindow();
|
||||
installEventFilter(mainWindow);
|
||||
@ -170,11 +170,7 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc
|
||||
|
||||
CutterApplication::~CutterApplication()
|
||||
{
|
||||
QList<CutterPlugin *> plugins = Core()->getCutterPlugins();
|
||||
for (CutterPlugin *plugin : plugins) {
|
||||
delete plugin;
|
||||
}
|
||||
|
||||
Plugins()->destroyPlugins();
|
||||
delete mainWindow;
|
||||
Python()->shutdown();
|
||||
}
|
||||
@ -205,51 +201,6 @@ bool CutterApplication::event(QEvent *e)
|
||||
return QApplication::event(e);
|
||||
}
|
||||
|
||||
void CutterApplication::loadPlugins()
|
||||
{
|
||||
QList<CutterPlugin *> plugins;
|
||||
QDir pluginsDir(qApp->applicationDirPath());
|
||||
#if defined(Q_OS_WIN)
|
||||
if (pluginsDir.dirName().toLower() == "debug" || pluginsDir.dirName().toLower() == "release")
|
||||
pluginsDir.cdUp();
|
||||
#elif defined(Q_OS_MAC)
|
||||
if (pluginsDir.dirName() == "MacOS") {
|
||||
pluginsDir.cdUp();
|
||||
pluginsDir.cdUp();
|
||||
pluginsDir.cdUp();
|
||||
}
|
||||
#endif
|
||||
if (!pluginsDir.cd("plugins")) {
|
||||
return;
|
||||
}
|
||||
|
||||
Python()->addPythonPath(pluginsDir.absolutePath().toLatin1().data());
|
||||
|
||||
foreach (QString fileName, pluginsDir.entryList(QDir::Files)) {
|
||||
CutterPlugin *cutterPlugin = nullptr;
|
||||
if (fileName.endsWith(".py")) {
|
||||
// Load python plugins
|
||||
QStringList l = fileName.split(".py");
|
||||
cutterPlugin = (CutterPlugin*) Python()->loadPlugin(l.at(0).toLatin1().constData());
|
||||
} else {
|
||||
// Load C++ plugins
|
||||
QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(fileName));
|
||||
QObject *plugin = pluginLoader.instance();
|
||||
if (plugin) {
|
||||
cutterPlugin = qobject_cast<CutterPlugin *>(plugin);
|
||||
}
|
||||
}
|
||||
|
||||
if (cutterPlugin) {
|
||||
cutterPlugin->setupPlugin(Core());
|
||||
plugins.append(cutterPlugin);
|
||||
}
|
||||
}
|
||||
|
||||
qInfo() << "Loaded" << plugins.length() << "plugin(s).";
|
||||
Core()->setCutterPlugins(plugins);
|
||||
}
|
||||
|
||||
bool CutterApplication::loadTranslations()
|
||||
{
|
||||
const QString &language = Config()->getCurrLocale().bcp47Name();
|
||||
|
@ -22,8 +22,6 @@ public:
|
||||
return mainWindow;
|
||||
}
|
||||
|
||||
void loadPlugins();
|
||||
|
||||
protected:
|
||||
bool event(QEvent *e);
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "ui_MainWindow.h"
|
||||
#include "common/Helpers.h"
|
||||
#include "CutterConfig.h"
|
||||
#include "plugins/PluginManager.h"
|
||||
|
||||
// Qt Headers
|
||||
#include <QApplication>
|
||||
@ -276,8 +277,7 @@ void MainWindow::initUI()
|
||||
&MainWindow::updateTasksIndicator);
|
||||
|
||||
/* Setup plugins interfaces */
|
||||
QList<CutterPlugin *> plugins = core->getCutterPlugins();
|
||||
for (auto plugin : plugins) {
|
||||
for (auto plugin : Plugins()->getPlugins()) {
|
||||
plugin->setupInterface(this);
|
||||
}
|
||||
}
|
||||
|
@ -67,6 +67,7 @@ void PythonManager::initialize()
|
||||
PyImport_AppendInittab("CutterBindings", &PyInit_CutterBindings);
|
||||
Py_Initialize();
|
||||
PyEval_InitThreads();
|
||||
pyThreadStateCounter = 1; // we have the thread now => 1
|
||||
|
||||
RegQtResImporter();
|
||||
|
||||
@ -109,34 +110,19 @@ void PythonManager::addPythonPath(char *path) {
|
||||
saveThread();
|
||||
}
|
||||
|
||||
|
||||
CutterPythonPlugin* PythonManager::loadPlugin(const char *pluginName) {
|
||||
CutterPythonPlugin *plugin = nullptr;
|
||||
if (!cutterPluginModule) {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
restoreThread();
|
||||
PyObject *pluginModule = PyImport_ImportModule(pluginName);
|
||||
if (!pluginModule) {
|
||||
qWarning() << "Couldn't load the plugin" << QString(pluginName);
|
||||
PyErr_PrintEx(10);
|
||||
} else {
|
||||
plugin = new CutterPythonPlugin(pluginModule);
|
||||
}
|
||||
saveThread();
|
||||
|
||||
return plugin;
|
||||
}
|
||||
|
||||
void PythonManager::restoreThread()
|
||||
{
|
||||
if (pyThreadState) {
|
||||
pyThreadStateCounter++;
|
||||
if (pyThreadStateCounter == 1 && pyThreadState) {
|
||||
PyEval_RestoreThread(pyThreadState);
|
||||
}
|
||||
}
|
||||
|
||||
void PythonManager::saveThread()
|
||||
{
|
||||
pyThreadState = PyEval_SaveThread();
|
||||
pyThreadStateCounter--;
|
||||
assert(pyThreadStateCounter >= 0);
|
||||
if (pyThreadStateCounter == 0) {
|
||||
pyThreadState = PyEval_SaveThread();
|
||||
}
|
||||
}
|
||||
|
@ -25,12 +25,23 @@ public:
|
||||
|
||||
void addPythonPath(char *path);
|
||||
|
||||
|
||||
CutterPythonPlugin *loadPlugin(const char *pluginName);
|
||||
|
||||
void restoreThread();
|
||||
void saveThread();
|
||||
|
||||
PyObject *getCutterPluginModule() { return cutterPluginModule; }
|
||||
|
||||
/*!
|
||||
* \brief RAII Helper class to call restoreThread() and saveThread() automatically
|
||||
*
|
||||
* As long as an object of this class is in scope, the Python thread will remain restored.
|
||||
*/
|
||||
class ThreadHolder
|
||||
{
|
||||
public:
|
||||
ThreadHolder() { getInstance()->restoreThread(); }
|
||||
~ThreadHolder() { getInstance()->saveThread(); }
|
||||
};
|
||||
|
||||
signals:
|
||||
void willShutDown();
|
||||
|
||||
@ -38,6 +49,7 @@ private:
|
||||
QString customPythonHome;
|
||||
wchar_t *pythonHome = nullptr;
|
||||
PyThreadState *pyThreadState = nullptr;
|
||||
int pyThreadStateCounter = 0;
|
||||
|
||||
PyObject *cutterPluginModule;
|
||||
};
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "Cutter.h"
|
||||
#include "common/Helpers.h"
|
||||
#include "plugins/PluginManager.h"
|
||||
|
||||
R2PluginsDialog::R2PluginsDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
@ -51,7 +52,7 @@ R2PluginsDialog::R2PluginsDialog(QWidget *parent) :
|
||||
}
|
||||
qhelpers::adjustColumns(ui->RAsmTreeWidget, 0);
|
||||
|
||||
for (CutterPlugin *plugin : Core()->getCutterPlugins()) {
|
||||
for (CutterPlugin *plugin : Plugins()->getPlugins()) {
|
||||
QTreeWidgetItem *item = new QTreeWidgetItem();
|
||||
item->setText(0, plugin->name);
|
||||
item->setText(1, plugin->description);
|
||||
|
130
src/plugins/PluginManager.cpp
Normal file
130
src/plugins/PluginManager.cpp
Normal file
@ -0,0 +1,130 @@
|
||||
|
||||
#ifdef CUTTER_ENABLE_PYTHON
|
||||
#include <Python.h>
|
||||
#endif
|
||||
|
||||
#include "PluginManager.h"
|
||||
#include "PythonManager.h"
|
||||
#include "CutterPlugin.h"
|
||||
#include "CutterPythonPlugin.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QCoreApplication>
|
||||
#include <QPluginLoader>
|
||||
|
||||
Q_GLOBAL_STATIC(PluginManager, uniqueInstance)
|
||||
|
||||
PluginManager *PluginManager::getInstance()
|
||||
{
|
||||
return uniqueInstance;
|
||||
}
|
||||
|
||||
PluginManager::PluginManager()
|
||||
{
|
||||
}
|
||||
|
||||
PluginManager::~PluginManager()
|
||||
{
|
||||
}
|
||||
|
||||
void PluginManager::loadPlugins()
|
||||
{
|
||||
assert(plugins.isEmpty());
|
||||
|
||||
QDir pluginsDir(qApp->applicationDirPath());
|
||||
#if defined(Q_OS_WIN)
|
||||
if (pluginsDir.dirName().toLower() == "debug" || pluginsDir.dirName().toLower() == "release")
|
||||
pluginsDir.cdUp();
|
||||
#elif defined(Q_OS_MAC)
|
||||
if (pluginsDir.dirName() == "MacOS") {
|
||||
pluginsDir.cdUp();
|
||||
pluginsDir.cdUp();
|
||||
pluginsDir.cdUp();
|
||||
}
|
||||
#endif
|
||||
if (!pluginsDir.cd("plugins")) {
|
||||
return;
|
||||
}
|
||||
|
||||
QDir nativePluginsDir = pluginsDir;
|
||||
if (nativePluginsDir.cd("native")) {
|
||||
loadNativePlugins(nativePluginsDir);
|
||||
}
|
||||
|
||||
QDir pythonPluginsDir = pluginsDir;
|
||||
if (pythonPluginsDir.cd("python")) {
|
||||
loadPythonPlugins(pythonPluginsDir.absolutePath());
|
||||
}
|
||||
|
||||
qInfo() << "Loaded" << plugins.length() << "plugin(s).";
|
||||
}
|
||||
|
||||
|
||||
void PluginManager::destroyPlugins()
|
||||
{
|
||||
for (CutterPlugin *plugin : plugins) {
|
||||
delete plugin;
|
||||
}
|
||||
}
|
||||
|
||||
void PluginManager::loadNativePlugins(const QDir &directory)
|
||||
{
|
||||
for (const QString &fileName : directory.entryList(QDir::Files)) {
|
||||
QPluginLoader pluginLoader(directory.absoluteFilePath(fileName));
|
||||
QObject *plugin = pluginLoader.instance();
|
||||
if (!plugin) {
|
||||
continue;
|
||||
}
|
||||
CutterPlugin *cutterPlugin = qobject_cast<CutterPlugin *>(plugin);
|
||||
if (!cutterPlugin) {
|
||||
continue;
|
||||
}
|
||||
cutterPlugin->setupPlugin(Core());
|
||||
plugins.append(cutterPlugin);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CUTTER_ENABLE_PYTHON
|
||||
|
||||
void PluginManager::loadPythonPlugins(const QDir &directory)
|
||||
{
|
||||
Python()->addPythonPath(directory.absolutePath().toLocal8Bit().data());
|
||||
|
||||
for (const QString &fileName : directory.entryList(QDir::Files)) {
|
||||
CutterPlugin *cutterPlugin = nullptr;
|
||||
QString moduleName;
|
||||
if (fileName.endsWith(".py")) {
|
||||
QStringList l = fileName.split(".py");
|
||||
moduleName = l[0];
|
||||
}
|
||||
cutterPlugin = loadPythonPlugin(moduleName.toLocal8Bit().constData());
|
||||
if (!cutterPlugin) {
|
||||
continue;
|
||||
}
|
||||
cutterPlugin->setupPlugin(Core());
|
||||
plugins.append(cutterPlugin);
|
||||
}
|
||||
|
||||
PythonManager::ThreadHolder threadHolder;
|
||||
}
|
||||
|
||||
CutterPlugin *PluginManager::loadPythonPlugin(const char *moduleName)
|
||||
{
|
||||
PythonManager::ThreadHolder threadHolder;
|
||||
PyObject *cutterPluginModule = Python()->getCutterPluginModule();
|
||||
CutterPythonPlugin *plugin = nullptr;
|
||||
if (!cutterPluginModule) {
|
||||
return static_cast<CutterPlugin *>(plugin);
|
||||
}
|
||||
|
||||
PyObject *pluginModule = PyImport_ImportModule(moduleName);
|
||||
if (!pluginModule) {
|
||||
qWarning() << "Couldn't load module for plugin:" << QString(moduleName);
|
||||
PyErr_PrintEx(10);
|
||||
} else {
|
||||
plugin = new CutterPythonPlugin(pluginModule);
|
||||
}
|
||||
|
||||
return plugin;
|
||||
}
|
||||
#endif
|
45
src/plugins/PluginManager.h
Normal file
45
src/plugins/PluginManager.h
Normal file
@ -0,0 +1,45 @@
|
||||
|
||||
#ifndef PLUGINMANAGER_H
|
||||
#define PLUGINMANAGER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QDir>
|
||||
|
||||
class CutterPlugin;
|
||||
|
||||
class PluginManager: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static PluginManager *getInstance();
|
||||
|
||||
PluginManager();
|
||||
~PluginManager();
|
||||
|
||||
/*!
|
||||
* \brief Load all plugins, should be called once on application start
|
||||
*/
|
||||
void loadPlugins();
|
||||
|
||||
/*!
|
||||
* \brief Destroy all loaded plugins, should be called once on application shutdown
|
||||
*/
|
||||
void destroyPlugins();
|
||||
|
||||
const QList<CutterPlugin *> &getPlugins() { return plugins; }
|
||||
|
||||
private:
|
||||
QList<CutterPlugin *> plugins;
|
||||
|
||||
void loadNativePlugins(const QDir &directory);
|
||||
|
||||
#ifdef CUTTER_ENABLE_PYTHON
|
||||
void loadPythonPlugins(const QDir &directory);
|
||||
CutterPlugin *loadPythonPlugin(const char *moduleName);
|
||||
#endif
|
||||
};
|
||||
|
||||
#define Plugins() (PluginManager::getInstance())
|
||||
|
||||
#endif //PLUGINMANAGER_H
|
Loading…
Reference in New Issue
Block a user