mirror of
https://github.com/rizinorg/cutter.git
synced 2024-12-21 12:26:11 +00:00
Add PluginManager
This commit is contained in:
parent
280e10d154
commit
986041380c
@ -2617,16 +2617,6 @@ QList<QString> CutterCore::getColorThemes()
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CutterCore::setCutterPlugins(QList<CutterPlugin *> plugins)
|
|
||||||
{
|
|
||||||
this->plugins = plugins;
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<CutterPlugin *> CutterCore::getCutterPlugins()
|
|
||||||
{
|
|
||||||
return plugins;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString CutterCore::ansiEscapeToHtml(const QString &text)
|
QString CutterCore::ansiEscapeToHtml(const QString &text)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
|
@ -723,9 +723,6 @@ public:
|
|||||||
|
|
||||||
void message(const QString &msg, bool debug = false);
|
void message(const QString &msg, bool debug = false);
|
||||||
|
|
||||||
void setCutterPlugins(QList<CutterPlugin*> plugins);
|
|
||||||
QList<CutterPlugin*> getCutterPlugins();
|
|
||||||
|
|
||||||
QStringList getSectionList();
|
QStringList getSectionList();
|
||||||
|
|
||||||
RCoreLocked core() const;
|
RCoreLocked core() const;
|
||||||
@ -787,7 +784,6 @@ private:
|
|||||||
|
|
||||||
bool emptyGraph = false;
|
bool emptyGraph = false;
|
||||||
|
|
||||||
QList<CutterPlugin*> plugins;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ccClass : public CutterCore
|
class ccClass : public CutterCore
|
||||||
|
@ -230,7 +230,8 @@ SOURCES += \
|
|||||||
dialogs/LoadNewTypesDialog.cpp \
|
dialogs/LoadNewTypesDialog.cpp \
|
||||||
widgets/SdbWidget.cpp \
|
widgets/SdbWidget.cpp \
|
||||||
plugins/CutterPythonPlugin.cpp \
|
plugins/CutterPythonPlugin.cpp \
|
||||||
common/PythonManager.cpp
|
common/PythonManager.cpp \
|
||||||
|
plugins/PluginManager.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
Cutter.h \
|
Cutter.h \
|
||||||
@ -343,7 +344,8 @@ HEADERS += \
|
|||||||
dialogs/LoadNewTypesDialog.h \
|
dialogs/LoadNewTypesDialog.h \
|
||||||
widgets/SdbWidget.h \
|
widgets/SdbWidget.h \
|
||||||
plugins/CutterPythonPlugin.h \
|
plugins/CutterPythonPlugin.h \
|
||||||
common/PythonManager.h
|
common/PythonManager.h \
|
||||||
|
plugins/PluginManager.h
|
||||||
|
|
||||||
FORMS += \
|
FORMS += \
|
||||||
dialogs/AboutDialog.ui \
|
dialogs/AboutDialog.ui \
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#ifdef CUTTER_ENABLE_JUPYTER
|
#ifdef CUTTER_ENABLE_JUPYTER
|
||||||
#include "common/JupyterConnection.h"
|
#include "common/JupyterConnection.h"
|
||||||
#endif
|
#endif
|
||||||
#include "plugins/CutterPythonPlugin.h"
|
#include "plugins/PluginManager.h"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QFileOpenEvent>
|
#include <QFileOpenEvent>
|
||||||
@ -119,7 +119,7 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadPlugins();
|
Plugins()->loadPlugins();
|
||||||
|
|
||||||
mainWindow = new MainWindow();
|
mainWindow = new MainWindow();
|
||||||
installEventFilter(mainWindow);
|
installEventFilter(mainWindow);
|
||||||
@ -170,11 +170,7 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc
|
|||||||
|
|
||||||
CutterApplication::~CutterApplication()
|
CutterApplication::~CutterApplication()
|
||||||
{
|
{
|
||||||
QList<CutterPlugin *> plugins = Core()->getCutterPlugins();
|
Plugins()->destroyPlugins();
|
||||||
for (CutterPlugin *plugin : plugins) {
|
|
||||||
delete plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
delete mainWindow;
|
delete mainWindow;
|
||||||
Python()->shutdown();
|
Python()->shutdown();
|
||||||
}
|
}
|
||||||
@ -205,51 +201,6 @@ bool CutterApplication::event(QEvent *e)
|
|||||||
return QApplication::event(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()
|
bool CutterApplication::loadTranslations()
|
||||||
{
|
{
|
||||||
const QString &language = Config()->getCurrLocale().bcp47Name();
|
const QString &language = Config()->getCurrLocale().bcp47Name();
|
||||||
|
@ -22,8 +22,6 @@ public:
|
|||||||
return mainWindow;
|
return mainWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadPlugins();
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool event(QEvent *e);
|
bool event(QEvent *e);
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include "ui_MainWindow.h"
|
#include "ui_MainWindow.h"
|
||||||
#include "common/Helpers.h"
|
#include "common/Helpers.h"
|
||||||
#include "CutterConfig.h"
|
#include "CutterConfig.h"
|
||||||
|
#include "plugins/PluginManager.h"
|
||||||
|
|
||||||
// Qt Headers
|
// Qt Headers
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
@ -276,8 +277,7 @@ void MainWindow::initUI()
|
|||||||
&MainWindow::updateTasksIndicator);
|
&MainWindow::updateTasksIndicator);
|
||||||
|
|
||||||
/* Setup plugins interfaces */
|
/* Setup plugins interfaces */
|
||||||
QList<CutterPlugin *> plugins = core->getCutterPlugins();
|
for (auto plugin : Plugins()->getPlugins()) {
|
||||||
for (auto plugin : plugins) {
|
|
||||||
plugin->setupInterface(this);
|
plugin->setupInterface(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,6 +67,7 @@ void PythonManager::initialize()
|
|||||||
PyImport_AppendInittab("CutterBindings", &PyInit_CutterBindings);
|
PyImport_AppendInittab("CutterBindings", &PyInit_CutterBindings);
|
||||||
Py_Initialize();
|
Py_Initialize();
|
||||||
PyEval_InitThreads();
|
PyEval_InitThreads();
|
||||||
|
pyThreadStateCounter = 1; // we have the thread now => 1
|
||||||
|
|
||||||
RegQtResImporter();
|
RegQtResImporter();
|
||||||
|
|
||||||
@ -109,34 +110,19 @@ void PythonManager::addPythonPath(char *path) {
|
|||||||
saveThread();
|
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()
|
void PythonManager::restoreThread()
|
||||||
{
|
{
|
||||||
if (pyThreadState) {
|
pyThreadStateCounter++;
|
||||||
|
if (pyThreadStateCounter == 1 && pyThreadState) {
|
||||||
PyEval_RestoreThread(pyThreadState);
|
PyEval_RestoreThread(pyThreadState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PythonManager::saveThread()
|
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);
|
void addPythonPath(char *path);
|
||||||
|
|
||||||
|
|
||||||
CutterPythonPlugin *loadPlugin(const char *pluginName);
|
|
||||||
|
|
||||||
void restoreThread();
|
void restoreThread();
|
||||||
void saveThread();
|
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:
|
signals:
|
||||||
void willShutDown();
|
void willShutDown();
|
||||||
|
|
||||||
@ -38,6 +49,7 @@ private:
|
|||||||
QString customPythonHome;
|
QString customPythonHome;
|
||||||
wchar_t *pythonHome = nullptr;
|
wchar_t *pythonHome = nullptr;
|
||||||
PyThreadState *pyThreadState = nullptr;
|
PyThreadState *pyThreadState = nullptr;
|
||||||
|
int pyThreadStateCounter = 0;
|
||||||
|
|
||||||
PyObject *cutterPluginModule;
|
PyObject *cutterPluginModule;
|
||||||
};
|
};
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "Cutter.h"
|
#include "Cutter.h"
|
||||||
#include "common/Helpers.h"
|
#include "common/Helpers.h"
|
||||||
|
#include "plugins/PluginManager.h"
|
||||||
|
|
||||||
R2PluginsDialog::R2PluginsDialog(QWidget *parent) :
|
R2PluginsDialog::R2PluginsDialog(QWidget *parent) :
|
||||||
QDialog(parent),
|
QDialog(parent),
|
||||||
@ -51,7 +52,7 @@ R2PluginsDialog::R2PluginsDialog(QWidget *parent) :
|
|||||||
}
|
}
|
||||||
qhelpers::adjustColumns(ui->RAsmTreeWidget, 0);
|
qhelpers::adjustColumns(ui->RAsmTreeWidget, 0);
|
||||||
|
|
||||||
for (CutterPlugin *plugin : Core()->getCutterPlugins()) {
|
for (CutterPlugin *plugin : Plugins()->getPlugins()) {
|
||||||
QTreeWidgetItem *item = new QTreeWidgetItem();
|
QTreeWidgetItem *item = new QTreeWidgetItem();
|
||||||
item->setText(0, plugin->name);
|
item->setText(0, plugin->name);
|
||||||
item->setText(1, plugin->description);
|
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