You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

178 lines
4.7 KiB

/* ============================================================
* Falkon - Qt web browser
* Copyright (C) 2018 David Rosca <nowrep@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#include "pythonplugin.h"
#include "plugins.h"
#include "datapaths.h"
#include "desktopfile.h"
#include <QDir>
#include <QCoreApplication>
#include <PyFalkon/pyfalkon_python.h>
extern "C" PyObject *PyInit_PyFalkon();
enum State
{
PythonUninitialized,
PythonInitialized,
PythonError
};
State state = PythonUninitialized;
PluginInterface *pluginInterface = nullptr;
QHash<PyObject*, PluginInterface*> pluginInstances;
static QStringList script_paths()
{
QStringList dirs = DataPaths::allPaths(DataPaths::Plugins);
for (int i = 0; i < dirs.count(); ++i) {
dirs[i].append(QSL("/python"));
}
return dirs;
}
static void cleanup()
{
if (state > PythonUninitialized) {
Py_Finalize();
state = PythonUninitialized;
}
}
static void set_path(const QStringList &scriptPaths)
{
const QString originalPath = QString::fromLocal8Bit(qgetenv("PYTHONPATH"));
QStringList paths = scriptPaths;
paths.append(originalPath);
qputenv("PYTHONPATH", paths.join(QL1C(':')).toLocal8Bit());
}
static State init()
{
if (state > PythonUninitialized) {
return state;
}
set_path(script_paths());
if (PyImport_AppendInittab("Falkon", PyInit_PyFalkon) != 0) {
PyErr_Print();
qWarning() << "Failed to initialize Falkon module!";
return state = PythonError;
}
Py_Initialize();
qAddPostRoutine(cleanup);
return state = PythonInitialized;
}
void pyfalkon_register_plugin(PluginInterface *plugin)
{
pluginInterface = plugin;
}
Plugins::Plugin pyfalkon_load_plugin(const QString &name)
{
QString fullPath;
if (QFileInfo(name).isAbsolute()) {
fullPath = name;
} else {
fullPath = DataPaths::locate(DataPaths::Plugins, QSL("python/") + name);
if (fullPath.isEmpty()) {
qWarning() << "Plugin" << name << "not found";
return Plugins::Plugin();
}
}
Plugins::Plugin plugin;
plugin.type = Plugins::Plugin::PythonPlugin;
plugin.pluginId = QSL("python:%1").arg(QFileInfo(name).fileName());
plugin.pluginSpec = Plugins::createSpec(DesktopFile(fullPath + QSL("/metadata.desktop")));
return plugin;
}
void pyfalkon_init_plugin(Plugins::Plugin *plugin)
{
if (init() != PythonInitialized) {
return;
}
PyObject *module = static_cast<PyObject*>(plugin->data.value<void*>());
if (module) {
plugin->instance = pluginInstances.value(module);
return;
}
const QString moduleName = plugin->pluginId.mid(7);
pluginInterface = nullptr;
module = PyImport_ImportModule(qPrintable(moduleName));
if (!module) {
PyErr_Print();
qWarning() << "Failed to import module" << moduleName;
return;
}
if (!pluginInterface) {
qWarning() << "No plugin registered! Falkon.registerPlugin() must be called from script.";
return;
}
pluginInstances[module] = pluginInterface;
plugin->instance = pluginInterface;
plugin->data = QVariant::fromValue(static_cast<void*>(module));
}
QVector<Plugins::Plugin> pyfalkon_load_available_plugins()
{
QVector<Plugins::Plugin> plugins;
const QStringList dirs = script_paths();
for (const QString &dir : dirs) {
const auto modules = QDir(dir).entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
for (const QFileInfo &info : modules) {
Plugins::Plugin plugin = pyfalkon_load_plugin(info.absoluteFilePath());
if (plugin.pluginSpec.name.isEmpty()) {
qWarning() << "Invalid plugin spec of" << info.absoluteFilePath() << "plugin";
continue;
}
plugins.append(plugin);
}
}
return plugins;
}
bool pyfalkon_run_script(const QByteArray &script)
{
if (init() != PythonInitialized) {
return false;
}
if (PyRun_SimpleString(script.constData()) != 0) {
PyErr_Print();
return false;
}
return true;
}