1
mirror of https://invent.kde.org/network/falkon.git synced 2024-12-19 18:26:34 +01:00

WIP: Shared QML engine for plugins

This commit is contained in:
David Rosca 2019-04-23 10:39:12 +02:00
parent ee4dbad676
commit 7ddb3b8985
No known key found for this signature in database
GPG Key ID: EBC3FC294452C6D8
19 changed files with 258 additions and 306 deletions

View File

@ -157,11 +157,10 @@ set(SRCS ${SRCS}
plugins/plugins.cpp
plugins/speeddial.cpp
plugins/ocssupport.cpp
plugins/qml/qmlplugincontext.cpp
plugins/qml/qmlpluginloader.cpp
plugins/qml/qmlplugin.cpp
plugins/qml/qmlplugins.cpp
plugins/qml/qmlplugininterface.cpp
plugins/qml/qmlengine.cpp
plugins/qml/qmlstaticdata.cpp
plugins/qml/api/bookmarks/qmlbookmarktreenode.cpp
plugins/qml/api/bookmarks/qmlbookmarks.cpp

View File

@ -25,7 +25,8 @@
#include "../config.h"
#include "desktopfile.h"
#include "qml/qmlplugins.h"
#include "qml/qmlplugin.h"
#include "qml/qmlpluginloader.h"
#include "qml/qmlplugininterface.h"
#include <iostream>
@ -61,6 +62,7 @@ Plugins::Plugins(QObject* parent)
if (!MainApplication::isTestModeEnabled()) {
loadPythonSupport();
}
QmlPlugins::registerQmlTypes();
}
QList<Plugins::Plugin> Plugins::availablePlugins()
@ -279,7 +281,7 @@ void Plugins::loadAvailablePlugins()
plugin = loadPythonPlugin(pluginPath);
} else if (type == QL1S("Extension/Qml")) {
// QmlPlugin
plugin = QmlPlugin::loadPlugin(pluginPath);
plugin = loadQmlPlugin(pluginPath);
} else {
qWarning() << "Invalid type" << type << "of" << pluginPath << "plugin";
}
@ -370,7 +372,7 @@ Plugins::Plugin Plugins::loadPlugin(const QString &id)
return loadPythonPlugin(name);
case Plugin::QmlPlugin:
return QmlPlugin::loadPlugin(name);
return loadQmlPlugin(name);
default:
return Plugin();
@ -429,6 +431,29 @@ Plugins::Plugin Plugins::loadPythonPlugin(const QString &name)
return f(name);
}
Plugins::Plugin Plugins::loadQmlPlugin(const QString &name)
{
QString fullPath;
if (QFileInfo(name).isAbsolute()) {
fullPath = name;
} else {
fullPath = DataPaths::locate(DataPaths::Plugins, name);
if (fullPath.isEmpty()) {
qWarning() << "QML plugin" << name << "not found";
return Plugins::Plugin();
}
}
Plugins::Plugin plugin;
plugin.type = Plugins::Plugin::QmlPlugin;
plugin.pluginId = QSL("qml:%1").arg(QFileInfo(name).fileName());
plugin.pluginPath = fullPath;
DesktopFile desktopFile(fullPath + QSL("/metadata.desktop"));
plugin.pluginSpec = Plugins::createSpec(desktopFile);
plugin.data = QVariant::fromValue(new QmlPluginLoader(plugin));
return plugin;
}
bool Plugins::initPlugin(PluginInterface::InitState state, Plugin *plugin)
{
if (!plugin) {
@ -449,7 +474,7 @@ bool Plugins::initPlugin(PluginInterface::InitState state, Plugin *plugin)
break;
case Plugin::QmlPlugin:
QmlPlugin::initPlugin(plugin);
initQmlPlugin(plugin);
break;
default:
@ -508,3 +533,24 @@ void Plugins::initPythonPlugin(Plugin *plugin)
f(plugin);
}
void Plugins::initQmlPlugin(Plugin *plugin)
{
Q_ASSERT(plugin->type == Plugins::Plugin::QmlPlugin);
const QString name = plugin->pluginSpec.name;
auto qmlPluginLoader = plugin->data.value<QmlPluginLoader*>();
if (!qmlPluginLoader) {
qWarning() << "Failed to cast from data";
return;
}
qmlPluginLoader->createComponent();
if (!qmlPluginLoader->instance()) {
qWarning() << "Failed to create component for" << name << "plugin:" << qmlPluginLoader->errorString();
return;
}
plugin->instance = qobject_cast<PluginInterface*>(qmlPluginLoader->instance());
}

View File

@ -114,10 +114,12 @@ private:
Plugin loadInternalPlugin(const QString &name);
Plugin loadSharedLibraryPlugin(const QString &name);
Plugin loadPythonPlugin(const QString &name);
Plugin loadQmlPlugin(const QString &name);
bool initPlugin(PluginInterface::InitState state, Plugin *plugin);
void initInternalPlugin(Plugin *plugin);
void initSharedLibraryPlugin(Plugin *plugin);
void initPythonPlugin(Plugin *plugin);
void initQmlPlugin(Plugin *plugin);
void registerAvailablePlugin(const Plugin &plugin);

View File

@ -21,10 +21,11 @@
#include "statusbar.h"
#include "pluginproxy.h"
#include "qml/api/fileutils/qmlfileutils.h"
#include "qml/qmlengine.h"
#include "qml/qmlplugincontext.h"
#include "qml/qmlstaticdata.h"
#include <QQuickWidget>
#include <QQmlContext>
#include <QQmlEngine>
QmlBrowserAction::QmlBrowserAction(QObject *parent)
: QObject(parent)
@ -217,13 +218,10 @@ void QmlBrowserActionButton::setIcon(const QString &icon)
if (!m_popup) {
return;
}
auto qmlEngine = qobject_cast<QmlEngine*>(m_popup->creationContext()->engine());
if (!qmlEngine) {
return;
}
const QString pluginPath = qmlEngine->extensionPath();
QIcon qicon = QmlStaticData::instance().getIcon(m_iconUrl, pluginPath);
#if 0
QIcon qicon = QmlStaticData::instance().getIcon(m_iconUrl, QmlPluginContext::contextForObject(this)->pluginPath());
AbstractButtonInterface::setIcon(qicon);
#endif
}
void QmlBrowserActionButton::setBadgeText(const QString &badgeText)

View File

@ -18,30 +18,24 @@
#include "qmlaction.h"
#include "qztools.h"
#include "qml/api/fileutils/qmlfileutils.h"
#include "qml/qmlengine.h"
#include "qml/qmlplugincontext.h"
#include "qml/qmlstaticdata.h"
#include <QQmlEngine>
QmlAction::QmlAction(QAction *action, QmlEngine *engine, QObject *parent)
QmlAction::QmlAction(QAction *action, QObject *parent)
: QObject(parent)
, m_action(action)
{
QmlEngine *qmlEngine = qobject_cast<QmlEngine*>(engine);
m_pluginPath = qmlEngine->extensionPath();
Q_ASSERT(m_action);
connect(m_action, &QAction::triggered, this, &QmlAction::triggered);
}
void QmlAction::setProperties(const QVariantMap &map)
{
if (!m_action) {
return;
}
for (auto it = map.cbegin(); it != map.cend(); it++) {
const QString key = it.key();
if (key == QSL("icon")) {
QString iconPath = map.value(key).toString();
QIcon icon = QmlStaticData::instance().getIcon(iconPath, m_pluginPath);
QIcon icon = QmlStaticData::instance().getIcon(iconPath, QmlPluginContext::contextForObject(this)->pluginPath());
m_action->setIcon(icon);
} else if (key == QSL("shortcut")) {
m_action->setShortcut(QKeySequence(map.value(key).toString()));
@ -51,7 +45,7 @@ void QmlAction::setProperties(const QVariantMap &map)
}
}
void QmlAction::update(const QVariantMap &map)
void QmlAction::update(const QVariantMap &map)
{
setProperties(map);
}

View File

@ -21,7 +21,7 @@
#include <QAction>
#include <QVariantMap>
class QmlEngine;
class QQmlEngine;
/**
* @brief The class exposing Action API to QML
@ -30,7 +30,7 @@ class QmlAction : public QObject
{
Q_OBJECT
public:
explicit QmlAction(QAction *action, QmlEngine *engine, QObject *parent = nullptr);
explicit QmlAction(QAction *action, QObject *parent = nullptr);
void setProperties(const QVariantMap &map);
/**
* @brief Updates the properties of the action
@ -46,5 +46,4 @@ Q_SIGNALS:
private:
QAction *m_action = nullptr;
QString m_pluginPath;
};

View File

@ -18,61 +18,51 @@
#include "qmlmenu.h"
#include "qztools.h"
#include "qml/api/fileutils/qmlfileutils.h"
#include "qml/qmlengine.h"
#include "qml/qmlplugincontext.h"
#include "qml/qmlstaticdata.h"
QmlMenu::QmlMenu(QMenu *menu, QQmlEngine *engine, QObject *parent)
#include <QQmlEngine>
QmlMenu::QmlMenu(QMenu *menu, QObject *parent)
: QObject(parent)
, m_menu(menu)
{
QQmlEngine::setObjectOwnership(this, QQmlEngine::JavaScriptOwnership);
m_engine = qobject_cast<QmlEngine*>(engine);
m_pluginPath = m_engine->extensionPath();
Q_ASSERT(m_menu);
connect(m_menu, &QMenu::triggered, this, &QmlMenu::triggered);
}
QmlAction *QmlMenu::addAction(const QVariantMap &map)
QJSValue QmlMenu::addAction(const QVariantMap &map)
{
if (!m_menu) {
return nullptr;
}
QAction *action = new QAction();
QmlAction *qmlAction = new QmlAction(action, m_engine, this);
QmlAction *qmlAction = new QmlAction(action, this);
QQmlEngine::setContextForObject(qmlAction, QmlPluginContext::contextForObject(this));
action->setParent(qmlAction);
qmlAction->setProperties(map);
m_menu->addAction(action);
return qmlAction;
return qmlEngine(this)->newQObject(qmlAction);
}
QmlMenu *QmlMenu::addMenu(const QVariantMap &map)
QJSValue QmlMenu::addMenu(const QVariantMap &map)
{
if (!m_menu) {
return nullptr;
}
QMenu *newMenu = new QMenu();
for (auto it = map.cbegin(); it != map.cend(); it++) {
const QString key = it.key();
if (key == QSL("icon")) {
const QString iconPath = map.value(key).toString();
const QIcon icon = QmlStaticData::instance().getIcon(iconPath, m_pluginPath);
const QIcon icon = QmlStaticData::instance().getIcon(iconPath, QmlPluginContext::contextForObject(this)->pluginPath());
newMenu->setIcon(icon);
continue;
}
newMenu->setProperty(key.toUtf8(), map.value(key));
}
m_menu->addMenu(newMenu);
QmlMenu *newQmlMenu = new QmlMenu(newMenu, m_engine, this);
return newQmlMenu;
QmlMenu *newQmlMenu = new QmlMenu(newMenu, this);
QQmlEngine::setContextForObject(newQmlMenu, QmlPluginContext::contextForObject(this));
connect(newQmlMenu, &QObject::destroyed, newMenu, &QObject::deleteLater);
return qmlEngine(this)->newQObject(newQmlMenu);
}
void QmlMenu::addSeparator()
{
if (!m_menu) {
return;
}
m_menu->addSeparator();
}

View File

@ -18,10 +18,9 @@
#pragma once
#include "qmlaction.h"
#include <QMenu>
#include <QQmlEngine>
class QmlEngine;
#include <QMenu>
#include <QJSValue>
/**
* @brief The class exposing WebView contextmenu to QML as Menu API
@ -30,7 +29,7 @@ class QmlMenu : public QObject
{
Q_OBJECT
public:
explicit QmlMenu(QMenu *menu, QQmlEngine *engine, QObject *parent = nullptr);
explicit QmlMenu(QMenu *menu, QObject *parent = nullptr);
/**
* @brief Adds action to menu
* @param A JavaScript object containing properties for action.
@ -38,14 +37,14 @@ public:
* and shortcut in form string.
* @return action of type [QmlAction](@ref QmlAction)
*/
Q_INVOKABLE QmlAction *addAction(const QVariantMap &map);
Q_INVOKABLE QJSValue addAction(const QVariantMap &map);
/**
* @brief Adds sub-menu to menu
* @param A JavaScript object containing properties of menu.
* The icon property must be in form of url of the path.
* @return menu of type [QmlMenu](@ref QmlMenu)
*/
Q_INVOKABLE QmlMenu *addMenu(const QVariantMap &map);
Q_INVOKABLE QJSValue addMenu(const QVariantMap &map);
/**
* @brief Adds a separator to menu
*/
@ -59,6 +58,4 @@ Q_SIGNALS:
private:
QMenu *m_menu = nullptr;
QString m_pluginPath;
QmlEngine *m_engine = nullptr;
};

View File

@ -20,11 +20,12 @@
#include "qztools.h"
#include "sidebar.h"
#include "qml/api/fileutils/qmlfileutils.h"
#include "qml/qmlengine.h"
#include "qml/qmlplugincontext.h"
#include "qml/qmlstaticdata.h"
#include <QAction>
#include <QQuickWidget>
#include <QQmlContext>
#include <QQmlEngine>
QmlSideBar::QmlSideBar(QObject *parent)
: QObject(parent)
@ -137,13 +138,10 @@ QAction *QmlSideBarHelper::createMenuAction()
if (!m_item) {
return action;
}
auto qmlEngine = qobject_cast<QmlEngine*>(m_item->creationContext()->engine());
if (qmlEngine) {
return action;
}
const QString pluginPath = qmlEngine->extensionPath();
const QIcon icon = QmlStaticData::instance().getIcon(m_iconUrl, pluginPath);
#if 0
const QIcon icon = QmlStaticData::instance().getIcon(m_iconUrl, QmlPluginContext::contextForObject(this)->pluginPath());
action->setIcon(icon);
#endif
return action;
}

View File

@ -1,43 +0,0 @@
/* ============================================================
* Falkon - Qt web browser
* Copyright (C) 2018 Anmol Gautam <tarptaeya@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 "qmlengine.h"
QmlEngine::QmlEngine(QObject *parent)
: QQmlEngine(parent)
{
}
QString QmlEngine::extensionName()
{
return m_extensionName;
}
void QmlEngine::setExtensionName(const QString &name)
{
m_extensionName = name;
}
QString QmlEngine::extensionPath()
{
return m_extensionPath;
}
void QmlEngine::setExtensionPath(const QString &path)
{
m_extensionPath = path;
}

View File

@ -1,78 +0,0 @@
/* ============================================================
* Falkon - Qt web browser
* Copyright (C) 2018 Anmol Gautam <tarptaeya@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 "qmlplugin.h"
#include "qmlplugins.h"
#include "qmlpluginloader.h"
#include "datapaths.h"
#include "desktopfile.h"
#include <QFileInfo>
#include <QDir>
QmlPlugin::QmlPlugin()
{
}
Plugins::Plugin QmlPlugin::loadPlugin(const QString &name)
{
static bool qmlSupportLoaded = false;
if (!qmlSupportLoaded) {
QmlPlugins::registerQmlTypes();
qmlSupportLoaded = true;
}
QString fullPath;
if (QFileInfo(name).isAbsolute()) {
fullPath = name;
} else {
fullPath = DataPaths::locate(DataPaths::Plugins, name);
if (fullPath.isEmpty()) {
qWarning() << "QML plugin" << name << "not found";
return Plugins::Plugin();
}
}
Plugins::Plugin plugin;
plugin.type = Plugins::Plugin::QmlPlugin;
plugin.pluginId = QSL("qml:%1").arg(QFileInfo(name).fileName());
plugin.pluginPath = fullPath;
DesktopFile desktopFile(fullPath + QSL("/metadata.desktop"));
plugin.pluginSpec = Plugins::createSpec(desktopFile);
plugin.data = QVariant::fromValue(new QmlPluginLoader(plugin.pluginSpec.name, fullPath));
return plugin;
}
void QmlPlugin::initPlugin(Plugins::Plugin *plugin)
{
Q_ASSERT(plugin->type == Plugins::Plugin::QmlPlugin);
const QString name = plugin->pluginSpec.name;
auto qmlPluginLoader = plugin->data.value<QmlPluginLoader*>();
if (!qmlPluginLoader) {
qWarning() << "Failed to cast from data";
return;
}
qmlPluginLoader->createComponent();
if (!qmlPluginLoader->instance()) {
qWarning().noquote() << "Failed to create component for" << name << "plugin:" << qmlPluginLoader->component()->errorString();
return;
}
plugin->instance = qobject_cast<PluginInterface*>(qmlPluginLoader->instance());
}

View File

@ -1,28 +0,0 @@
/* ============================================================
* Falkon - Qt web browser
* Copyright (C) 2018 Anmol Gautam <tarptaeya@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/>.
* ============================================================ */
#pragma once
#include "plugins.h"
class QmlPlugin
{
public:
explicit QmlPlugin();
static Plugins::Plugin loadPlugin(const QString &name);
static void initPlugin(Plugins::Plugin *plugin);
};

View File

@ -0,0 +1,58 @@
/* ============================================================
* Falkon - Qt web browser
* Copyright (C) 2019 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 "qmlplugincontext.h"
#include <QtQml>
#include <QFileInfo>
QmlPluginContext::QmlPluginContext(const Plugins::Plugin &plugin, QQmlEngine *engine, QObject *parent)
: QQmlContext(engine, parent)
, m_plugin(plugin)
{
}
QString QmlPluginContext::pluginPath() const
{
return m_plugin.pluginPath;
}
QString QmlPluginContext::pluginName() const
{
return QFileInfo(m_plugin.pluginPath).fileName();
}
Plugins::Plugin QmlPluginContext::plugin() const
{
return m_plugin;
}
// static
QmlPluginContext *QmlPluginContext::contextForObject(const QObject *object)
{
QQmlContext *c = qmlContext(object);
while (c) {
QmlPluginContext *p = qobject_cast<QmlPluginContext*>(c);
if (p) {
return p;
}
c = c->parentContext();
}
qCritical() << "Failed to get plugin context for object" << object;
Q_UNREACHABLE();
return nullptr;
}

View File

@ -1,6 +1,6 @@
/* ============================================================
* Falkon - Qt web browser
* Copyright (C) 2018 Anmol Gautam <tarptaeya@gmail.com>
* Copyright (C) 2019 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
@ -17,18 +17,24 @@
* ============================================================ */
#pragma once
#include <QQmlEngine>
#include <QQmlContext>
class QmlEngine : public QQmlEngine
#include "plugins.h"
class QmlPluginContext : public QQmlContext
{
Q_OBJECT
public:
explicit QmlEngine(QObject *parent = nullptr);
QString extensionName();
void setExtensionName(const QString &name);
QString extensionPath();
void setExtensionPath(const QString &path);
explicit QmlPluginContext(const Plugins::Plugin &plugin, QQmlEngine *engine, QObject *parent = nullptr);
QString pluginPath() const;
QString pluginName() const;
Plugins::Plugin plugin() const;
static QmlPluginContext *contextForObject(const QObject *object);
private:
QString m_extensionName;
QString m_extensionPath;
Plugins::Plugin m_plugin;
};

View File

@ -31,15 +31,18 @@
#include "api/tabs/qmltab.h"
#include "webpage.h"
#include "qztools.h"
#include "qml/qmlengine.h"
#include "qml/qmlplugincontext.h"
#include <QDebug>
#include <QQuickWidget>
#include <QDialog>
#include <QVBoxLayout>
#include <QQmlEngine>
QmlPluginInterface::QmlPluginInterface()
: m_qmlReusableTab(new QmlTab())
{
// QQmlEngine::setContextForObject(m_qmlReusableTab, QmlPluginContext::contextForObject(this));
}
QmlPluginInterface::~QmlPluginInterface()
@ -95,11 +98,13 @@ void QmlPluginInterface::populateWebViewMenu(QMenu *menu, WebView *webview, cons
return;
}
QmlMenu *qmlMenu = new QmlMenu(menu, m_engine);
QmlMenu *qmlMenu = new QmlMenu(menu);
QQmlEngine::setContextForObject(qmlMenu, QmlPluginContext::contextForObject(this));
QmlWebHitTestResult *qmlWebHitTestResult = new QmlWebHitTestResult(webHitTestResult);
QQmlEngine::setContextForObject(qmlWebHitTestResult, QmlPluginContext::contextForObject(this));
QJSValueList args;
args.append(m_engine->newQObject(qmlMenu));
args.append(m_engine->newQObject(qmlWebHitTestResult));
args.append(qmlEngine(this)->newQObject(qmlMenu));
args.append(qmlEngine(this)->newQObject(qmlWebHitTestResult));
m_populateWebViewMenu.call(args);
menu->addSeparator();
}
@ -125,9 +130,10 @@ bool QmlPluginInterface::mouseDoubleClick(Qz::ObjectName type, QObject *obj, QMo
return false;
}
auto qmlMouseEvent = new QmlMouseEvent(event);
QQmlEngine::setContextForObject(qmlMouseEvent, QmlPluginContext::contextForObject(this));
QJSValueList args;
args.append(QmlQzObjects::ObjectName(type));
args.append(m_engine->newQObject(qmlMouseEvent));
args.append(qmlEngine(this)->newQObject(qmlMouseEvent));
m_mouseDoubleClick.call(args);
qmlMouseEvent->clear();
return false;
@ -140,9 +146,10 @@ bool QmlPluginInterface::mousePress(Qz::ObjectName type, QObject *obj, QMouseEve
return false;
}
auto qmlMouseEvent = new QmlMouseEvent(event);
QQmlEngine::setContextForObject(qmlMouseEvent, QmlPluginContext::contextForObject(this));
QJSValueList args;
args.append(QmlQzObjects::ObjectName(type));
args.append(m_engine->newQObject(qmlMouseEvent));
args.append(qmlEngine(this)->newQObject(qmlMouseEvent));
m_mousePress.call(args);
qmlMouseEvent->clear();
return false;
@ -155,9 +162,10 @@ bool QmlPluginInterface::mouseRelease(Qz::ObjectName type, QObject *obj, QMouseE
return false;
}
auto qmlMouseEvent = new QmlMouseEvent(event);
QQmlEngine::setContextForObject(qmlMouseEvent, QmlPluginContext::contextForObject(this));
QJSValueList args;
args.append(QmlQzObjects::ObjectName(type));
args.append(m_engine->newQObject(qmlMouseEvent));
args.append(qmlEngine(this)->newQObject(qmlMouseEvent));
m_mouseRelease.call(args);
qmlMouseEvent->clear();
return false;
@ -170,9 +178,10 @@ bool QmlPluginInterface::mouseMove(Qz::ObjectName type, QObject *obj, QMouseEven
return false;
}
auto qmlMouseEvent = new QmlMouseEvent(event);
QQmlEngine::setContextForObject(qmlMouseEvent, QmlPluginContext::contextForObject(this));
QJSValueList args;
args.append(QmlQzObjects::ObjectName(type));
args.append(m_engine->newQObject(qmlMouseEvent));
args.append(qmlEngine(this)->newQObject(qmlMouseEvent));
m_mouseMove.call(args);
qmlMouseEvent->clear();
return false;
@ -185,9 +194,10 @@ bool QmlPluginInterface::wheelEvent(Qz::ObjectName type, QObject *obj, QWheelEve
return false;
}
auto qmlWheelEvent = new QmlWheelEvent(event);
QQmlEngine::setContextForObject(qmlWheelEvent, QmlPluginContext::contextForObject(this));
QJSValueList args;
args.append(QmlQzObjects::ObjectName(type));
args.append(m_engine->newQObject(qmlWheelEvent));
args.append(qmlEngine(this)->newQObject(qmlWheelEvent));
m_wheelEvent.call(args);
qmlWheelEvent->clear();
return false;
@ -200,9 +210,10 @@ bool QmlPluginInterface::keyPress(Qz::ObjectName type, QObject *obj, QKeyEvent *
return false;
}
auto qmlKeyEvent = new QmlKeyEvent(event);
QQmlEngine::setContextForObject(qmlKeyEvent, QmlPluginContext::contextForObject(this));
QJSValueList args;
args.append(QmlQzObjects::ObjectName(type));
args.append(m_engine->newQObject(qmlKeyEvent));
args.append(qmlEngine(this)->newQObject(qmlKeyEvent));
m_keyPress.call(args);
qmlKeyEvent->clear();
return false;
@ -215,9 +226,10 @@ bool QmlPluginInterface::keyRelease(Qz::ObjectName type, QObject *obj, QKeyEvent
return false;
}
auto qmlKeyEvent = new QmlKeyEvent(event);
QQmlEngine::setContextForObject(qmlKeyEvent, QmlPluginContext::contextForObject(this));
QJSValueList args;
args.append(QmlQzObjects::ObjectName(type));
args.append(m_engine->newQObject(qmlKeyEvent));
args.append(qmlEngine(this)->newQObject(qmlKeyEvent));
m_keyRelease.call(args);
qmlKeyEvent->clear();
return false;
@ -230,7 +242,7 @@ bool QmlPluginInterface::acceptNavigationRequest(WebPage *page, const QUrl &url,
}
m_qmlReusableTab->setWebPage(page);
QJSValueList args;
args.append(m_engine->newQObject(m_qmlReusableTab));
args.append(qmlEngine(this)->newQObject(m_qmlReusableTab));
args.append(QString::fromUtf8(url.toEncoded()));
args.append(type);
args.append(isMainFrame);
@ -267,16 +279,6 @@ void QmlPluginInterface::setTestPlugin(const QJSValue &testPlugin)
m_testPlugin = testPlugin;
}
void QmlPluginInterface::setEngine(QQmlEngine *engine)
{
m_engine = engine;
}
void QmlPluginInterface::setName(const QString &name)
{
m_name = name;
}
QJSValue QmlPluginInterface::readPopulateWebViewMenu() const
{
return m_populateWebViewMenu;

View File

@ -53,8 +53,6 @@ public:
void init(InitState state, const QString &settingsPath) override;
void unload() override;
bool testPlugin() override;
void setEngine(QQmlEngine *engine);
void setName(const QString &name);
void populateWebViewMenu(QMenu *menu, WebView *webview, const WebHitTestResult &webHitTestResult) override;
void showSettings(QWidget *parent = nullptr) override;
@ -74,7 +72,6 @@ Q_SIGNALS:
void qmlPluginUnloaded();
private:
QQmlEngine *m_engine = nullptr;
QString m_name;
QJSValue m_init;
QJSValue m_unload;

View File

@ -16,42 +16,30 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* ============================================================ */
#include "qmlpluginloader.h"
#include "qmlengine.h"
#include <QQmlContext>
#include <QDir>
#include "qmlplugincontext.h"
#include "qmlplugininterface.h"
#include "../config.h"
#include <QDir>
#include <QFileInfo>
#include <QQmlEngine>
#include <QQmlComponent>
#if HAVE_LIBINTL
#include "qml/api/i18n/qmli18n.h"
#endif
QmlPluginLoader::QmlPluginLoader(const QString &name, const QString &path)
Q_GLOBAL_STATIC(QQmlEngine, s_engine)
QmlPluginLoader::QmlPluginLoader(const Plugins::Plugin &plugin)
: QObject()
, m_plugin(plugin)
{
m_name = name;
m_path = path;
initEngineAndComponent();
}
void QmlPluginLoader::createComponent()
QString QmlPluginLoader::errorString() const
{
m_interface = qobject_cast<QmlPluginInterface*>(m_component->create(m_component->creationContext()));
if (!m_interface) {
return;
}
m_interface->setEngine(m_engine);
m_interface->setName(m_name);
connect(m_interface, &QmlPluginInterface::qmlPluginUnloaded, this, [this] {
delete m_component;
delete m_engine;
initEngineAndComponent();
});
}
QQmlComponent *QmlPluginLoader::component() const
{
return m_component;
return m_component ? m_component->errorString() : QString();
}
QmlPluginInterface *QmlPluginLoader::instance() const
@ -59,19 +47,39 @@ QmlPluginInterface *QmlPluginLoader::instance() const
return m_interface;
}
void QmlPluginLoader::createComponent()
{
initEngineAndComponent();
m_interface = qobject_cast<QmlPluginInterface*>(m_component->create(m_context));
if (!m_interface) {
qWarning() << "Failed to create QmlPluginInterface!";
return;
}
connect(m_interface, &QmlPluginInterface::qmlPluginUnloaded, this, [this] {
m_component->deleteLater();
m_component = nullptr;
m_context->deleteLater();
m_context = nullptr;
});
}
void QmlPluginLoader::initEngineAndComponent()
{
m_engine = new QmlEngine();
m_component = new QQmlComponent(m_engine, QDir(m_path).filePath(QStringLiteral("main.qml")));
m_engine->setExtensionPath(m_path);
m_engine->setExtensionName(m_name);
if (m_component) {
return;
}
m_component = new QQmlComponent(s_engine(), QDir(m_plugin.pluginPath).filePath(QStringLiteral("main.qml")), this);
m_context = new QmlPluginContext(m_plugin, s_engine(), this);
#if HAVE_LIBINTL
auto i18n = new QmlI18n(m_name);
m_engine->globalObject().setProperty(QSL("__falkon_i18n"), m_engine->newQObject(i18n));
m_engine->evaluate(QSL("i18n = function (s) { return __falkon_i18n.i18n(s) };"));
m_engine->evaluate(QSL("i18np = function (s1, s2) { return __falkon_i18n.i18np(s1, s2) }"));
auto i18n = new QmlI18n(QFileInfo(m_plugin.pluginPath).fileName());
s_engine()->globalObject().setProperty(QSL("__falkon_i18n"), s_engine()->newQObject(i18n));
s_engine()->evaluate(QSL("i18n = function (s) { return __falkon_i18n.i18n(s) };"));
s_engine()->evaluate(QSL("i18np = function (s1, s2) { return __falkon_i18n.i18np(s1, s2) }"));
#else
m_engine->evaluate(QSL("i18n = function (s) { return s; };"));
m_engine->evaluate(QSL("i18np = function (s1, s2) { return s1; }"));
s_engine()->evaluate(QSL("i18n = function (s) { return s; };"));
s_engine()->evaluate(QSL("i18np = function (s1, s2) { return s1; }"));
#endif
}

View File

@ -17,30 +17,33 @@
* ============================================================ */
#pragma once
#include <QQmlEngine>
#include <QQmlComponent>
#include <QObject>
#include "qmlplugininterface.h"
#include "plugins.h"
class QmlEngine;
class QQmlComponent;
class QmlPluginContext;
class QmlPluginInterface;
class QmlPluginLoader : public QObject
{
Q_OBJECT
public:
explicit QmlPluginLoader(const QString &name, const QString &path);
void createComponent();
QQmlComponent *component() const;
explicit QmlPluginLoader(const Plugins::Plugin &plugin);
QString errorString() const;
QmlPluginInterface *instance() const;
void createComponent();
private:
QString m_path;
QString m_name;
QmlEngine *m_engine = nullptr;
void initEngineAndComponent();
Plugins::Plugin m_plugin;
QmlPluginContext *m_context = nullptr;
QQmlComponent *m_component = nullptr;
QmlPluginInterface *m_interface = nullptr;
void initEngineAndComponent();
};
Q_DECLARE_METATYPE(QmlPluginLoader *)

View File

@ -17,7 +17,7 @@
* ============================================================ */
#include "qmlplugins.h"
#include "qmlplugininterface.h"
#include "qmlengine.h"
#include "qmlplugincontext.h"
#include "api/bookmarks/qmlbookmarktreenode.h"
#include "api/bookmarks/qmlbookmarks.h"
#include "api/topsites/qmlmostvisitedurl.h"
@ -116,15 +116,17 @@ void QmlPlugins::registerQmlTypes()
qmlRegisterSingletonType<QmlNotifications>(url, majorVersion, minorVersion, "Notifications", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * {
Q_UNUSED(scriptEngine)
QmlEngine *qmlEngine = qobject_cast<QmlEngine*>(engine);
#if 0
auto context = qobject_cast<QmlEngine*>(engine);
if (!qmlEngine) {
qWarning() << "Unable to cast QQmlEngine * to QmlEngine *";
return nullptr;
}
QString filePath = qmlEngine->extensionPath();
#endif
auto *object = new QmlNotifications();
object->setPluginPath(filePath);
object->setPluginPath(QString());
return object;
});
@ -202,13 +204,15 @@ void QmlPlugins::registerQmlTypes()
qmlRegisterSingletonType<QmlFileUtils>(url, majorVersion, minorVersion, "FileUtils", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * {
Q_UNUSED(scriptEngine)
#if 0
QmlEngine *qmlEngine = qobject_cast<QmlEngine*>(engine);
if (!qmlEngine) {
qWarning() << "Unable to cast QQmlEngine * to QmlEngine *";
return nullptr;
}
QString filePath = qmlEngine->extensionPath();
return new QmlFileUtils(filePath);
#endif
return new QmlFileUtils(QString());
});
qmlRegisterUncreatableType<QmlEnums>(url, majorVersion, minorVersion, "Enums", QSL("Unable to register type: Enums"));