diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 74775e35..1561f4da 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -1,375 +1,374 @@ add_definitions(-DFALKON_SHAREDLIBRARY) set(CMAKE_CXX_STANDARD 14) # Enable C++14, with cmake >= 3.1 set(CMAKE_CXX_EXTENSIONS OFF) # Don't enable gcc-specific extensions set(SRCS 3rdparty/qtsingleapplication/qtsingleapplication.cpp 3rdparty/qtsingleapplication/qtlocalpeer.cpp ) if(CMAKE_BUILD_TYPE STREQUAL "Debug") set(SRCS ${SRCS} ${CMAKE_SOURCE_DIR}/tests/modeltest/modeltest.cpp) include_directories(${CMAKE_SOURCE_DIR}/tests/modeltest) endif() include_directories( 3rdparty adblock app autofill bookmarks cookies downloads history navigation network notifications opensearch other plugins popupwindow preferences session sidebar tabwidget tools webengine webtab ) include_directories(${OPENSSL_INCLUDE_DIR}) set(SRCS ${SRCS} 3rdparty/fancytabwidget.cpp 3rdparty/lineedit.cpp 3rdparty/processinfo.cpp 3rdparty/squeezelabelv1.cpp 3rdparty/squeezelabelv2.cpp 3rdparty/stylehelper.cpp adblock/adblockaddsubscriptiondialog.cpp adblock/adblockurlinterceptor.cpp adblock/adblockdialog.cpp adblock/adblockicon.cpp adblock/adblockmanager.cpp adblock/adblockmatcher.cpp adblock/adblockrule.cpp adblock/adblocksearchtree.cpp adblock/adblocksubscription.cpp adblock/adblocktreewidget.cpp adblock/adblockplugin.cpp app/autosaver.cpp app/browserwindow.cpp app/commandlineoptions.cpp app/datapaths.cpp app/mainapplication.cpp app/mainmenu.cpp app/profilemanager.cpp app/proxystyle.cpp app/qzcommon.cpp app/settings.cpp autofill/autofill.cpp autofill/autofillicon.cpp autofill/autofillnotification.cpp autofill/autofillwidget.cpp autofill/passwordbackends/databaseencryptedpasswordbackend.cpp autofill/passwordbackends/databasepasswordbackend.cpp autofill/passwordbackends/passwordbackend.cpp autofill/passwordmanager.cpp bookmarks/bookmarkitem.cpp bookmarks/bookmarks.cpp bookmarks/bookmarksexport/bookmarksexportdialog.cpp bookmarks/bookmarksexport/bookmarksexporter.cpp bookmarks/bookmarksexport/htmlexporter.cpp bookmarks/bookmarksicon.cpp bookmarks/bookmarksimport/bookmarksimportdialog.cpp bookmarks/bookmarksimport/bookmarksimporter.cpp bookmarks/bookmarksimport/firefoximporter.cpp bookmarks/bookmarksimport/htmlimporter.cpp bookmarks/bookmarksimport/chromeimporter.cpp bookmarks/bookmarksimport/ieimporter.cpp bookmarks/bookmarksimport/operaimporter.cpp bookmarks/bookmarksitemdelegate.cpp bookmarks/bookmarksmanager.cpp bookmarks/bookmarksmenu.cpp bookmarks/bookmarksmodel.cpp bookmarks/bookmarkstoolbarbutton.cpp bookmarks/bookmarkstoolbar.cpp bookmarks/bookmarkstools.cpp bookmarks/bookmarkstreeview.cpp bookmarks/bookmarkswidget.cpp cookies/cookiejar.cpp cookies/cookiemanager.cpp downloads/downloaditem.cpp downloads/downloadmanager.cpp downloads/downloadoptionsdialog.cpp downloads/downloadsbutton.cpp history/history.cpp history/historyitem.cpp history/historymanager.cpp history/historymenu.cpp history/historymodel.cpp history/historytreeview.cpp navigation/completer/locationcompleter.cpp navigation/completer/locationcompleterdelegate.cpp navigation/completer/locationcompletermodel.cpp navigation/completer/locationcompleterrefreshjob.cpp navigation/completer/locationcompleterview.cpp navigation/downicon.cpp navigation/goicon.cpp navigation/locationbar.cpp navigation/locationbarpopup.cpp navigation/navigationbar.cpp navigation/navigationbartoolbutton.cpp navigation/navigationbarconfigdialog.cpp navigation/navigationcontainer.cpp navigation/reloadstopbutton.cpp navigation/siteicon.cpp navigation/websearchbar.cpp network/networkmanager.cpp network/networkurlinterceptor.cpp network/schemehandlers/extensionschemehandler.cpp network/schemehandlers/falkonschemehandler.cpp network/sslerrordialog.cpp notifications/desktopnotification.cpp notifications/desktopnotificationsfactory.cpp opensearch/editsearchengine.cpp opensearch/opensearchengine.cpp opensearch/opensearchenginedelegate.cpp opensearch/opensearchreader.cpp opensearch/searchenginesdialog.cpp opensearch/searchenginesmanager.cpp other/aboutdialog.cpp other/browsinglibrary.cpp other/clearprivatedata.cpp other/checkboxdialog.cpp other/iconchooser.cpp other/licenseviewer.cpp other/qzsettings.cpp other/siteinfo.cpp other/siteinfowidget.cpp other/statusbar.cpp other/updater.cpp other/useragentmanager.cpp other/protocolhandlerdialog.cpp other/protocolhandlermanager.cpp plugins/pluginproxy.cpp 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 plugins/qml/api/topsites/qmlmostvisitedurl.cpp plugins/qml/api/topsites/qmltopsites.cpp plugins/qml/api/history/qmlhistoryitem.cpp plugins/qml/api/history/qmlhistory.cpp plugins/qml/api/cookies/qmlcookie.cpp plugins/qml/api/cookies/qmlcookies.cpp plugins/qml/api/tabs/qmltab.cpp plugins/qml/api/tabs/qmltabs.cpp plugins/qml/api/notifications/qmlnotifications.cpp plugins/qml/api/clipboard/qmlclipboard.cpp plugins/qml/api/windows/qmlwindow.cpp plugins/qml/api/windows/qmlwindows.cpp plugins/qml/api/browseraction/qmlbrowseraction.cpp plugins/qml/api/sidebar/qmlsidebar.cpp plugins/qml/api/menus/qmlmenu.cpp plugins/qml/api/menus/qmlaction.cpp plugins/qml/api/menus/qmlwebhittestresult.cpp plugins/qml/api/settings/qmlsettings.cpp plugins/qml/api/events/qmlqzobjects.cpp plugins/qml/api/events/qmlmouseevent.cpp plugins/qml/api/events/qmlwheelevent.cpp plugins/qml/api/events/qmlkeyevent.cpp plugins/qml/api/userscript/qmluserscript.cpp plugins/qml/api/userscript/qmluserscripts.cpp plugins/qml/api/userscript/qmlexternaljsobject.cpp plugins/qml/api/extensionscheme/qmlextensionscheme.cpp plugins/qml/api/extensionscheme/qmlwebengineurlrequestjob.cpp plugins/qml/api/fileutils/qmlfileutils.cpp plugins/qml/api/qmlenums.cpp popupwindow/popuplocationbar.cpp popupwindow/popupstatusbarmessage.cpp popupwindow/popupwebview.cpp popupwindow/popupwindow.cpp preferences/acceptlanguage.cpp preferences/autofillmanager.cpp preferences/jsoptions.cpp preferences/pluginlistdelegate.cpp preferences/pluginsmanager.cpp preferences/preferences.cpp preferences/thememanager.cpp preferences/useragentdialog.cpp session/recoveryjsobject.cpp session/restoremanager.cpp session/sessionmanager.cpp session/sessionmanagerdialog.cpp sidebar/bookmarkssidebar.cpp sidebar/historysidebar.cpp sidebar/sidebar.cpp tabwidget/combotabbar.cpp tabwidget/tabbar.cpp tabwidget/tabicon.cpp tabwidget/tabmodel.cpp tabwidget/tabmrumodel.cpp tabwidget/tabtreemodel.cpp tabwidget/tabstackedwidget.cpp tabwidget/tabwidget.cpp tabwidget/tabcontextmenu.cpp tools/abstractbuttoninterface.cpp tools/aesinterface.cpp tools/animatedwidget.cpp tools/buttonwithmenu.cpp tools/certificateinfowidget.cpp tools/clickablelabel.cpp tools/closedtabsmanager.cpp tools/closedwindowsmanager.cpp tools/colors.cpp tools/delayedfilewatcher.cpp tools/desktopfile.cpp tools/docktitlebarwidget.cpp tools/enhancedmenu.cpp tools/focusselectlineedit.cpp tools/headerview.cpp tools/horizontallistwidget.cpp tools/html5permissions/html5permissionsdialog.cpp tools/html5permissions/html5permissionsmanager.cpp tools/html5permissions/html5permissionsnotification.cpp tools/iconprovider.cpp tools/listitemdelegate.cpp tools/mactoolbutton.cpp tools/menubar.cpp tools/pagethumbnailer.cpp tools/progressbar.cpp tools/qztools.cpp tools/removeitemfocusdelegate.cpp tools/scripts.cpp tools/sqldatabase.cpp tools/toolbutton.cpp tools/treewidget.cpp tools/wheelhelper.cpp webengine/javascript/autofilljsobject.cpp webengine/javascript/externaljsobject.cpp webengine/loadrequest.cpp webengine/webhittestresult.cpp webengine/webinspector.cpp webengine/webpage.cpp webengine/webview.cpp webengine/webscrollbar.cpp webengine/webscrollbarmanager.cpp webtab/searchtoolbar.cpp webtab/tabbedwebview.cpp webtab/webtab.cpp ) if (HAVE_LIBINTL) set(SRCS ${SRCS} plugins/qml/api/i18n/qmli18n.cpp) endif() if (WIN32) set(SRCS ${SRCS} other/registerqappassociation.cpp) endif() if (APPLE) set(SRCS ${SRCS} tools/disablewindowtabbbing.mm) endif() # TODO: use ki18n_wrap_ui? qt5_wrap_ui(SRCS adblock/adblockaddsubscriptiondialog.ui adblock/adblockdialog.ui autofill/autofillnotification.ui autofill/autofillwidget.ui autofill/passwordbackends/masterpassworddialog.ui bookmarks/bookmarksexport/bookmarksexportdialog.ui bookmarks/bookmarksimport/bookmarksimportdialog.ui bookmarks/bookmarksmanager.ui bookmarks/bookmarkswidget.ui cookies/cookiemanager.ui downloads/downloaditem.ui downloads/downloadmanager.ui downloads/downloadoptionsdialog.ui history/historymanager.ui navigation/navigationbarconfigdialog.ui network/sslerrordialog.ui notifications/desktopnotification.ui opensearch/editsearchengine.ui opensearch/searchenginesdialog.ui other/aboutdialog.ui other/browsinglibrary.ui other/clearprivatedata.ui other/iconchooser.ui other/protocolhandlerdialog.ui other/siteinfo.ui other/siteinfowidget.ui preferences/acceptlanguage.ui preferences/addacceptlanguage.ui preferences/autofillmanager.ui preferences/jsoptions.ui preferences/pluginslist.ui preferences/preferences.ui preferences/thememanager.ui preferences/useragentdialog.ui session/sessionmanagerdialog.ui sidebar/bookmarkssidebar.ui sidebar/historysidebar.ui tools/certificateinfowidget.ui tools/docktitlebarwidget.ui tools/html5permissions/html5permissionsdialog.ui tools/html5permissions/html5permissionsnotification.ui webengine/jsalert.ui webengine/jsconfirm.ui webengine/jsprompt.ui webtab/searchtoolbar.ui ) qt5_add_resources(SRCS data/data.qrc data/html.qrc data/icons.qrc data/breeze-fallback.qrc adblock/adblock.qrc ) add_library(FalkonPrivate SHARED ${SRCS}) get_property(QT_WEBENGINE_INCLUDE_DIRS TARGET Qt5::WebEngine PROPERTY INTERFACE_INCLUDE_DIRECTORIES) target_include_directories(FalkonPrivate SYSTEM PUBLIC ${QT_WEBENGINE_INCLUDE_DIRS}) target_link_libraries(FalkonPrivate Qt5::Widgets Qt5::WebEngineWidgets Qt5::Network Qt5::Sql Qt5::PrintSupport Qt5::QuickWidgets Qt5::WebChannel KF5::Archive ${OPENSSL_CRYPTO_LIBRARY} ) if (UNIX AND NOT APPLE) if (NOT NO_X11) target_link_libraries(FalkonPrivate XCB::XCB Qt5::X11Extras) endif() set_target_properties(FalkonPrivate PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION "3") install(TARGETS FalkonPrivate ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} LIBRARY NAMELINK_SKIP) endif() if (WIN32) target_link_libraries(FalkonPrivate Qt5::WinExtras) endif() if (APPLE) target_link_libraries(FalkonPrivate "-framework CoreServices -framework AppKit") endif() if (NOT DISABLE_DBUS) target_link_libraries(FalkonPrivate Qt5::DBus) endif() diff --git a/src/lib/plugins/plugins.cpp b/src/lib/plugins/plugins.cpp index 03f42264..45af0281 100644 --- a/src/lib/plugins/plugins.cpp +++ b/src/lib/plugins/plugins.cpp @@ -1,510 +1,556 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2010-2018 David Rosca * * 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 . * ============================================================ */ #include "pluginproxy.h" #include "plugininterface.h" #include "mainapplication.h" #include "speeddial.h" #include "settings.h" #include "datapaths.h" #include "adblock/adblockplugin.h" #include "../config.h" #include "desktopfile.h" #include "qml/qmlplugins.h" -#include "qml/qmlplugin.h" +#include "qml/qmlpluginloader.h" +#include "qml/qmlplugininterface.h" #include #include #include #include #include #include #include bool Plugins::Plugin::isLoaded() const { return instance; } bool Plugins::Plugin::isRemovable() const { return !pluginPath.isEmpty() && QFileInfo(pluginPath).isWritable(); } bool Plugins::Plugin::operator==(const Plugin &other) const { return type == other.type && pluginId == other.pluginId; } Plugins::Plugins(QObject* parent) : QObject(parent) , m_pluginsLoaded(false) , m_speedDial(new SpeedDial(this)) { loadSettings(); if (!MainApplication::isTestModeEnabled()) { loadPythonSupport(); } + QmlPlugins::registerQmlTypes(); } QList Plugins::availablePlugins() { loadAvailablePlugins(); return m_availablePlugins; } bool Plugins::loadPlugin(Plugins::Plugin* plugin) { if (plugin->isLoaded()) { return true; } if (!initPlugin(PluginInterface::LateInitState, plugin)) { return false; } m_availablePlugins.removeOne(*plugin); m_availablePlugins.prepend(*plugin); refreshLoadedPlugins(); return plugin->isLoaded(); } void Plugins::unloadPlugin(Plugins::Plugin* plugin) { if (!plugin->isLoaded()) { return; } plugin->instance->unload(); emit pluginUnloaded(plugin->instance); plugin->instance = nullptr; m_availablePlugins.removeOne(*plugin); m_availablePlugins.append(*plugin); refreshLoadedPlugins(); } void Plugins::removePlugin(Plugins::Plugin *plugin) { if (!plugin->isRemovable()) { return; } if (plugin->isLoaded()) { unloadPlugin(plugin); } bool result = false; QFileInfo info(plugin->pluginPath); if (info.isDir()) { result = QDir(plugin->pluginPath).removeRecursively(); } else if (info.isFile()) { result = QFile::remove(plugin->pluginPath); } if (!result) { qWarning() << "Failed to remove" << plugin->pluginSpec.name; return; } m_availablePlugins.removeOne(*plugin); emit availablePluginsChanged(); } bool Plugins::addPlugin(const QString &id) { Plugin plugin = loadPlugin(id); if (plugin.type == Plugin::Invalid) { return false; } if (plugin.pluginSpec.name.isEmpty()) { qWarning() << "Invalid plugin spec of" << id << "plugin"; return false; } registerAvailablePlugin(plugin); emit availablePluginsChanged(); return true; } void Plugins::loadSettings() { QStringList defaultAllowedPlugins = { QSL("internal:adblock") }; // Enable KDE Frameworks Integration when running inside KDE session if (qgetenv("KDE_FULL_SESSION") == QByteArray("true")) { defaultAllowedPlugins.append(QSL("lib:KDEFrameworksIntegration.so")); } Settings settings; settings.beginGroup("Plugin-Settings"); m_allowedPlugins = settings.value("AllowedPlugins", defaultAllowedPlugins).toStringList(); settings.endGroup(); } void Plugins::shutdown() { foreach (PluginInterface* iPlugin, m_loadedPlugins) { iPlugin->unload(); } } PluginSpec Plugins::createSpec(const QJsonObject &metaData) { const QString tempIcon = DataPaths::path(DataPaths::Temp) + QL1S("/icon"); const QString tempMetadata = DataPaths::path(DataPaths::Temp) + QL1S("/metadata.desktop"); QFile::remove(tempIcon); QFile::remove(tempMetadata); QSettings settings(tempMetadata, QSettings::IniFormat); settings.beginGroup(QSL("Desktop Entry")); for (auto it = metaData.begin(); it != metaData.end(); ++it) { const QString value = it.value().toString(); if (it.key() == QL1S("Icon") && value.startsWith(QL1S("base64:"))) { QFile file(tempIcon); if (file.open(QFile::WriteOnly)) { file.write(QByteArray::fromBase64(value.mid(7).toUtf8())); settings.setValue(it.key(), tempIcon); } } else { settings.setValue(it.key(), it.value().toString()); } } settings.sync(); return createSpec(DesktopFile(tempMetadata)); } PluginSpec Plugins::createSpec(const DesktopFile &metaData) { PluginSpec spec; spec.name = metaData.name(); spec.description = metaData.comment(); spec.version = metaData.value(QSL("X-Falkon-Version")).toString(); spec.author = QSL("%1 <%2>").arg(metaData.value(QSL("X-Falkon-Author")).toString(), metaData.value(QSL("X-Falkon-Email")).toString()); spec.hasSettings = metaData.value(QSL("X-Falkon-Settings")).toBool(); const QString iconName = metaData.icon(); if (!iconName.isEmpty()) { if (QFileInfo::exists(iconName)) { spec.icon = QIcon(iconName).pixmap(32); } else { const QString relativeFile = QFileInfo(metaData.fileName()).dir().absoluteFilePath(iconName); if (QFileInfo::exists(relativeFile)) { spec.icon = QIcon(relativeFile).pixmap(32); } else { spec.icon = QIcon::fromTheme(iconName).pixmap(32); } } } return spec; } void Plugins::loadPlugins() { QDir settingsDir(DataPaths::currentProfilePath() + "/extensions/"); if (!settingsDir.exists()) { settingsDir.mkdir(settingsDir.absolutePath()); } foreach (const QString &pluginId, m_allowedPlugins) { Plugin plugin = loadPlugin(pluginId); if (plugin.type == Plugin::Invalid) { continue; } if (plugin.pluginSpec.name.isEmpty()) { qWarning() << "Invalid plugin spec of" << pluginId << "plugin"; continue; } if (!initPlugin(PluginInterface::StartupInitState, &plugin)) { qWarning() << "Failed to init" << pluginId << "plugin"; continue; } registerAvailablePlugin(plugin); } refreshLoadedPlugins(); std::cout << "Falkon: " << m_loadedPlugins.count() << " extensions loaded" << std::endl; } void Plugins::loadAvailablePlugins() { if (m_pluginsLoaded) { return; } m_pluginsLoaded = true; const QStringList dirs = DataPaths::allPaths(DataPaths::Plugins); // InternalPlugin registerAvailablePlugin(loadInternalPlugin(QSL("adblock"))); for (const QString &dir : dirs) { const auto files = QDir(dir).entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot); for (const QFileInfo &info : files) { Plugin plugin; const QString pluginPath = info.absoluteFilePath(); if (info.isFile() && QLibrary::isLibrary(pluginPath)) { // SharedLibraryPlugin if (info.baseName() != QL1S("PyFalkon")) { plugin = loadSharedLibraryPlugin(pluginPath); } } else if (info.isDir()) { const DesktopFile metaData(QDir(pluginPath).filePath(QSL("metadata.desktop"))); const QString type = metaData.value(QSL("X-Falkon-Type")).toString(); if (type == QL1S("Extension/Python")) { // PythonPlugin 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"; } } if (plugin.type == Plugin::Invalid) { continue; } if (plugin.pluginSpec.name.isEmpty()) { qWarning() << "Invalid plugin spec of" << pluginPath << "plugin"; continue; } registerAvailablePlugin(plugin); } } } void Plugins::registerAvailablePlugin(const Plugin &plugin) { if (!m_availablePlugins.contains(plugin)) { m_availablePlugins.append(plugin); } } void Plugins::refreshLoadedPlugins() { m_loadedPlugins.clear(); foreach (const Plugin &plugin, m_availablePlugins) { if (plugin.isLoaded()) { m_loadedPlugins.append(plugin.instance); } } emit availablePluginsChanged(); } void Plugins::loadPythonSupport() { const QStringList dirs = DataPaths::allPaths(DataPaths::Plugins); for (const QString &dir : dirs) { const auto files = QDir(dir).entryInfoList({QSL("PyFalkon*")}, QDir::Files); for (const QFileInfo &info : files) { m_pythonPlugin = new QLibrary(info.absoluteFilePath(), this); m_pythonPlugin->setLoadHints(QLibrary::ExportExternalSymbolsHint); if (!m_pythonPlugin->load()) { qWarning() << "Failed to load python support plugin" << m_pythonPlugin->errorString(); delete m_pythonPlugin; m_pythonPlugin = nullptr; } else { std::cout << "Falkon: Python plugin support initialized" << std::endl; return; } } } } Plugins::Plugin Plugins::loadPlugin(const QString &id) { QString name; Plugin::Type type = Plugin::Invalid; const int colon = id.indexOf(QL1C(':')); if (colon > -1) { const auto t = id.leftRef(colon); if (t == QL1S("internal")) { type = Plugin::InternalPlugin; } else if (t == QL1S("lib")) { type = Plugin::SharedLibraryPlugin; } else if (t == QL1S("python")) { type = Plugin::PythonPlugin; } else if (t == QL1S("qml")) { type = Plugin::QmlPlugin; } name = id.mid(colon + 1); } else { name = id; type = Plugin::SharedLibraryPlugin; } switch (type) { case Plugin::InternalPlugin: return loadInternalPlugin(name); case Plugin::SharedLibraryPlugin: return loadSharedLibraryPlugin(name); case Plugin::PythonPlugin: return loadPythonPlugin(name); case Plugin::QmlPlugin: - return QmlPlugin::loadPlugin(name); + return loadQmlPlugin(name); default: return Plugin(); } } Plugins::Plugin Plugins::loadInternalPlugin(const QString &name) { if (name == QL1S("adblock")) { Plugin plugin; plugin.type = Plugin::InternalPlugin; plugin.pluginId = QSL("internal:adblock"); plugin.internalInstance = new AdBlockPlugin(); plugin.pluginSpec = createSpec(DesktopFile(QSL(":adblock/metadata.desktop"))); return plugin; } else { return Plugin(); } } Plugins::Plugin Plugins::loadSharedLibraryPlugin(const QString &name) { QString fullPath; if (QFileInfo(name).isAbsolute()) { fullPath = name; } else { fullPath = DataPaths::locate(DataPaths::Plugins, name); if (fullPath.isEmpty()) { qWarning() << "Library plugin" << name << "not found"; return Plugin(); } } Plugin plugin; plugin.type = Plugin::SharedLibraryPlugin; plugin.pluginId = QSL("lib:%1").arg(QFileInfo(fullPath).fileName()); plugin.pluginPath = fullPath; plugin.pluginLoader = new QPluginLoader(fullPath); plugin.pluginSpec = createSpec(plugin.pluginLoader->metaData().value(QSL("MetaData")).toObject()); return plugin; } Plugins::Plugin Plugins::loadPythonPlugin(const QString &name) { if (!m_pythonPlugin) { qWarning() << "Python support plugin is not loaded"; return Plugin(); } auto f = (Plugin(*)(const QString &)) m_pythonPlugin->resolve("pyfalkon_load_plugin"); if (!f) { qWarning() << "Failed to resolve" << "pyfalkon_load_plugin"; return Plugin(); } 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) { return false; } switch (plugin->type) { case Plugin::InternalPlugin: initInternalPlugin(plugin); break; case Plugin::SharedLibraryPlugin: initSharedLibraryPlugin(plugin); break; case Plugin::PythonPlugin: initPythonPlugin(plugin); break; case Plugin::QmlPlugin: - QmlPlugin::initPlugin(plugin); + initQmlPlugin(plugin); break; default: return false; } if (!plugin->instance) { return false; } // DataPaths::currentProfilePath() + QL1S("/extensions") is duplicated in qmlsettings.cpp // If you change this, please change it there too. plugin->instance->init(state, DataPaths::currentProfilePath() + QL1S("/extensions")); if (!plugin->instance->testPlugin()) { emit pluginUnloaded(plugin->instance); plugin->instance = nullptr; return false; } return true; } void Plugins::initInternalPlugin(Plugin *plugin) { Q_ASSERT(plugin->type == Plugin::InternalPlugin); plugin->instance = plugin->internalInstance; } void Plugins::initSharedLibraryPlugin(Plugin *plugin) { Q_ASSERT(plugin->type == Plugin::SharedLibraryPlugin); plugin->instance = qobject_cast(plugin->pluginLoader->instance()); if (!plugin->instance) { qWarning() << "Loading" << plugin->pluginPath << "failed:" << plugin->pluginLoader->errorString(); } } void Plugins::initPythonPlugin(Plugin *plugin) { Q_ASSERT(plugin->type == Plugin::PythonPlugin); if (!m_pythonPlugin) { qWarning() << "Python support plugin is not loaded"; return; } auto f = (void(*)(Plugin *)) m_pythonPlugin->resolve("pyfalkon_init_plugin"); if (!f) { qWarning() << "Failed to resolve" << "pyfalkon_init_plugin"; return; } 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(); + 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(qmlPluginLoader->instance()); +} diff --git a/src/lib/plugins/plugins.h b/src/lib/plugins/plugins.h index 7481c2df..00d40691 100644 --- a/src/lib/plugins/plugins.h +++ b/src/lib/plugins/plugins.h @@ -1,140 +1,142 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2010-2018 David Rosca * * 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 . * ============================================================ */ #ifndef PLUGINLOADER_H #define PLUGINLOADER_H #include #include #include #include "qzcommon.h" #include "plugininterface.h" class QLibrary; class QPluginLoader; class SpeedDial; struct PluginSpec { QString name; QString description; QString author; QString version; QPixmap icon; bool hasSettings = false; bool operator==(const PluginSpec &other) const { return (this->name == other.name && this->description == other.description && this->author == other.author && this->version == other.version); } }; class FALKON_EXPORT Plugins : public QObject { Q_OBJECT public: struct Plugin { enum Type { Invalid = 0, InternalPlugin, SharedLibraryPlugin, PythonPlugin, QmlPlugin }; Type type = Invalid; QString pluginId; QString pluginPath; PluginSpec pluginSpec; PluginInterface *instance = nullptr; // InternalPlugin PluginInterface *internalInstance = nullptr; // SharedLibraryPlugin QPluginLoader *pluginLoader = nullptr; // Other QVariant data; bool isLoaded() const; bool isRemovable() const; bool operator==(const Plugin &other) const; }; explicit Plugins(QObject* parent = 0); QList availablePlugins(); bool loadPlugin(Plugin* plugin); void unloadPlugin(Plugin* plugin); void removePlugin(Plugin *plugin); bool addPlugin(const QString &id); void shutdown(); // SpeedDial SpeedDial* speedDial() { return m_speedDial; } static PluginSpec createSpec(const QJsonObject &metaData); static PluginSpec createSpec(const DesktopFile &metaData); public Q_SLOTS: void loadSettings(); void loadPlugins(); protected: QList m_loadedPlugins; Q_SIGNALS: void pluginUnloaded(PluginInterface* plugin); void availablePluginsChanged(); private: void loadPythonSupport(); Plugin loadPlugin(const QString &id); 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); void refreshLoadedPlugins(); void loadAvailablePlugins(); QList m_availablePlugins; QStringList m_allowedPlugins; bool m_pluginsLoaded; SpeedDial* m_speedDial; QList m_internalPlugins; QLibrary *m_pythonPlugin = nullptr; }; Q_DECLARE_METATYPE(Plugins::Plugin) #endif // PLUGINLOADER_H diff --git a/src/lib/plugins/qml/api/browseraction/qmlbrowseraction.cpp b/src/lib/plugins/qml/api/browseraction/qmlbrowseraction.cpp index 8ab4f250..ea32601c 100644 --- a/src/lib/plugins/qml/api/browseraction/qmlbrowseraction.cpp +++ b/src/lib/plugins/qml/api/browseraction/qmlbrowseraction.cpp @@ -1,261 +1,259 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2018 Anmol Gautam * * 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 . * ============================================================ */ #include "qmlbrowseraction.h" #include "qztools.h" #include "navigationbar.h" #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 -#include +#include QmlBrowserAction::QmlBrowserAction(QObject *parent) : QObject(parent) { m_button = new QmlBrowserActionButton(); connect(this, &QmlBrowserAction::identityChanged, m_button, &QmlBrowserActionButton::setId); connect(this, &QmlBrowserAction::nameChanged, m_button, &QmlBrowserActionButton::setName); connect(this, &QmlBrowserAction::titleChanged, m_button, &QmlBrowserActionButton::setTitle); connect(this, &QmlBrowserAction::toolTipChanged, m_button, &QmlBrowserActionButton::setToolTip); connect(this, &QmlBrowserAction::iconChanged, m_button, &QmlBrowserActionButton::setIcon); connect(this, &QmlBrowserAction::badgeTextChanged, m_button, &QmlBrowserActionButton::setBadgeText); connect(this, &QmlBrowserAction::popupChanged, m_button, &QmlBrowserActionButton::setPopup); connect(m_button, &QmlBrowserActionButton::clicked, this, &QmlBrowserAction::clicked); connect(mApp->plugins(), &PluginProxy::mainWindowCreated, this, &QmlBrowserAction::addButton); } void QmlBrowserAction::componentComplete() { const QList windows = mApp->windows(); for (BrowserWindow *window : windows) { addButton(window); } } QmlBrowserAction::~QmlBrowserAction() { const QList windows = mApp->windows(); for (BrowserWindow *window : windows) { removeButton(window); } } QmlBrowserActionButton *QmlBrowserAction::button() const { return m_button; } QmlBrowserAction::Locations QmlBrowserAction::location() const { return m_locations; } QString QmlBrowserAction::identity() const { return m_identity; } void QmlBrowserAction::setIdentity(const QString &identity) { m_identity = identity; emit identityChanged(m_identity); } QString QmlBrowserAction::name() const { return m_name; } void QmlBrowserAction::setName(const QString &name) { m_name = name; emit nameChanged(m_name); } QString QmlBrowserAction::title() const { return m_title; } void QmlBrowserAction::setTitle(const QString &title) { m_title = title; emit titleChanged(m_title); } QString QmlBrowserAction::toolTip() const { return m_toolTip; } void QmlBrowserAction::setToolTip(const QString &toolTip) { m_toolTip = toolTip; emit toolTipChanged(m_toolTip); } QString QmlBrowserAction::icon() const { return m_icon; } void QmlBrowserAction::setIcon(const QString &icon) { m_icon = icon; emit iconChanged(m_icon); } QString QmlBrowserAction::badgeText() const { return m_badgeText; } void QmlBrowserAction::setBadgeText(const QString &badgeText) { m_badgeText = badgeText; emit badgeTextChanged(m_badgeText); } QQmlComponent *QmlBrowserAction::popup() const { return m_popup; } void QmlBrowserAction::setPopup(QQmlComponent *popup) { m_popup = popup; emit popupChanged(m_popup); } void QmlBrowserAction::setLocation(const Locations &locations) { m_locations = locations; emit locationChanged(m_locations); } void QmlBrowserAction::addButton(BrowserWindow *window) { if (location().testFlag(NavigationToolBar)) { window->navigationBar()->addToolButton(button()); } if (location().testFlag(StatusBar)) { window->statusBar()->addButton(button()); } } void QmlBrowserAction::removeButton(BrowserWindow *window) { if (location().testFlag(NavigationToolBar)) { window->navigationBar()->removeToolButton(button()); } if (location().testFlag(StatusBar)) { window->statusBar()->removeButton(button()); } } QmlBrowserActionButton::QmlBrowserActionButton(QObject *parent) : AbstractButtonInterface(parent) { connect(this, &AbstractButtonInterface::clicked, this, &QmlBrowserActionButton::positionPopup); } QString QmlBrowserActionButton::id() const { return m_id; } void QmlBrowserActionButton::setId(const QString &id) { m_id = id; } QString QmlBrowserActionButton::name() const { return m_name; } void QmlBrowserActionButton::setName(const QString &name) { m_name = name; } void QmlBrowserActionButton::setTitle(const QString &title) { AbstractButtonInterface::setTitle(title); } void QmlBrowserActionButton::setToolTip(const QString &toolTip) { AbstractButtonInterface::setToolTip(toolTip); } void QmlBrowserActionButton::setIcon(const QString &icon) { m_iconUrl = icon; if (!m_popup) { return; } - auto qmlEngine = qobject_cast(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) { AbstractButtonInterface::setBadgeText(badgeText); } void QmlBrowserActionButton::setPopup(QQmlComponent *popup) { m_popup = popup; } void QmlBrowserActionButton::positionPopup(ClickController *clickController) { if (!m_popup) { qWarning() << "No popup to show"; return; } QQuickWidget *quickWidget = new QQuickWidget(); quickWidget->setContent(m_popup->url(), m_popup, m_popup->create(m_popup->creationContext())); QWidget *widget = new QWidget(); quickWidget->setParent(widget); widget->setWindowFlag(Qt::Popup); widget->setAttribute(Qt::WA_DeleteOnClose); widget->move(clickController->callPopupPosition(quickWidget->size())); connect(quickWidget, &QQuickWidget::destroyed, this, [clickController]{ clickController->callPopupClosed(); }); widget->show(); } diff --git a/src/lib/plugins/qml/api/menus/qmlaction.cpp b/src/lib/plugins/qml/api/menus/qmlaction.cpp index 4a410f01..c80c46e0 100644 --- a/src/lib/plugins/qml/api/menus/qmlaction.cpp +++ b/src/lib/plugins/qml/api/menus/qmlaction.cpp @@ -1,57 +1,51 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2018 Anmol Gautam * * 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 . * ============================================================ */ #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 -QmlAction::QmlAction(QAction *action, QmlEngine *engine, QObject *parent) +QmlAction::QmlAction(QAction *action, QObject *parent) : QObject(parent) , m_action(action) { - QmlEngine *qmlEngine = qobject_cast(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())); } else { m_action->setProperty(key.toUtf8(), map.value(key)); } } } -void QmlAction::update(const QVariantMap &map) +void QmlAction::update(const QVariantMap &map) { setProperties(map); } diff --git a/src/lib/plugins/qml/api/menus/qmlaction.h b/src/lib/plugins/qml/api/menus/qmlaction.h index 05fbf611..6eff89d9 100644 --- a/src/lib/plugins/qml/api/menus/qmlaction.h +++ b/src/lib/plugins/qml/api/menus/qmlaction.h @@ -1,50 +1,49 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2018 Anmol Gautam * * 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 . * ============================================================ */ #pragma once #include #include #include -class QmlEngine; +class QQmlEngine; /** * @brief The class exposing Action API to QML */ 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 * @param A JavaScript object containing the updated properties of the action. */ Q_INVOKABLE void update(const QVariantMap &map); Q_SIGNALS: /** * @brief This signal is emitted when the action is triggered. */ void triggered(); private: QAction *m_action = nullptr; - QString m_pluginPath; }; diff --git a/src/lib/plugins/qml/api/menus/qmlmenu.cpp b/src/lib/plugins/qml/api/menus/qmlmenu.cpp index 39d99688..19a87da1 100644 --- a/src/lib/plugins/qml/api/menus/qmlmenu.cpp +++ b/src/lib/plugins/qml/api/menus/qmlmenu.cpp @@ -1,78 +1,68 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2018 Anmol Gautam * * 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 . * ============================================================ */ #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 + +QmlMenu::QmlMenu(QMenu *menu, QObject *parent) : QObject(parent) , m_menu(menu) { - QQmlEngine::setObjectOwnership(this, QQmlEngine::JavaScriptOwnership); - - m_engine = qobject_cast(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(); } diff --git a/src/lib/plugins/qml/api/menus/qmlmenu.h b/src/lib/plugins/qml/api/menus/qmlmenu.h index def353c8..402baa00 100644 --- a/src/lib/plugins/qml/api/menus/qmlmenu.h +++ b/src/lib/plugins/qml/api/menus/qmlmenu.h @@ -1,64 +1,61 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2018 Anmol Gautam * * 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 . * ============================================================ */ #pragma once #include "qmlaction.h" -#include -#include -class QmlEngine; +#include +#include /** * @brief The class exposing WebView contextmenu to QML as Menu API */ 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. * The icon property must be in form of url of the path * 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 */ Q_INVOKABLE void addSeparator(); Q_SIGNALS: /** * @brief This signal is emitted when the menu is triggred */ void triggered(); private: QMenu *m_menu = nullptr; - QString m_pluginPath; - QmlEngine *m_engine = nullptr; }; diff --git a/src/lib/plugins/qml/api/sidebar/qmlsidebar.cpp b/src/lib/plugins/qml/api/sidebar/qmlsidebar.cpp index 247cf0f6..aa20411b 100644 --- a/src/lib/plugins/qml/api/sidebar/qmlsidebar.cpp +++ b/src/lib/plugins/qml/api/sidebar/qmlsidebar.cpp @@ -1,184 +1,182 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2018 Anmol Gautam * * 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 . * ============================================================ */ #include "qmlsidebar.h" #include "mainapplication.h" #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 #include -#include +#include QmlSideBar::QmlSideBar(QObject *parent) : QObject(parent) { m_sideBarHelper = new QmlSideBarHelper(this); connect(this, &QmlSideBar::titleChanged, m_sideBarHelper, &QmlSideBarHelper::setTitle); connect(this, &QmlSideBar::iconChanged, m_sideBarHelper, &QmlSideBarHelper::setIcon); connect(this, &QmlSideBar::shortcutChanged, m_sideBarHelper, &QmlSideBarHelper::setShortcut); connect(this, &QmlSideBar::checkableChanged, m_sideBarHelper, &QmlSideBarHelper::setCheckable); connect(this, &QmlSideBar::itemChanged, m_sideBarHelper, &QmlSideBarHelper::setItem); } QmlSideBar::~QmlSideBar() { SideBarManager::removeSidebar(m_sideBarHelper); } void QmlSideBar::componentComplete() { SideBarManager::addSidebar(name(), sideBar()); } QString QmlSideBar::name() const { return m_name; } SideBarInterface *QmlSideBar::sideBar() const { return m_sideBarHelper; } void QmlSideBar::setName(const QString &name) { m_name = name; emit nameChanged(m_name); } QString QmlSideBar::title() const { return m_title; } void QmlSideBar::setTitle(const QString &title) { m_title = title; emit titleChanged(title); } QString QmlSideBar::icon() const { return m_iconUrl; } void QmlSideBar::setIcon(const QString &icon) { m_iconUrl = icon; emit iconChanged(m_iconUrl); } QString QmlSideBar::shortcut() const { return m_shortcut; } void QmlSideBar::setShortcut(const QString &shortcut) { m_shortcut = shortcut; emit shortcutChanged(m_shortcut); } bool QmlSideBar::checkable() { return m_checkable; } void QmlSideBar::setCheckable(bool checkable) { m_checkable = checkable; emit checkableChanged(m_checkable); } QQmlComponent *QmlSideBar::item() const { return m_item; } void QmlSideBar::setItem(QQmlComponent *item) { m_item = item; emit itemChanged(m_item); } QmlSideBarHelper::QmlSideBarHelper(QObject *parent) : SideBarInterface(parent) { } QString QmlSideBarHelper::title() const { return m_title; } QAction *QmlSideBarHelper::createMenuAction() { QAction *action = new QAction(m_title); action->setShortcut(QKeySequence(m_shortcut)); action->setCheckable(m_checkable); if (!m_item) { return action; } - auto qmlEngine = qobject_cast(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; } QWidget *QmlSideBarHelper::createSideBarWidget(BrowserWindow *mainWindow) { Q_UNUSED(mainWindow) QQuickWidget *widget = new QQuickWidget(); widget->setContent(m_item->url(), m_item, m_item->create(m_item->creationContext())); widget->setResizeMode(QQuickWidget::SizeRootObjectToView); return widget; } void QmlSideBarHelper::setTitle(const QString &title) { m_title = title; } void QmlSideBarHelper::setIcon(const QString &icon) { m_iconUrl = icon; } void QmlSideBarHelper::setShortcut(const QString &shortcut) { m_shortcut = shortcut; } void QmlSideBarHelper::setCheckable(bool checkable) { m_checkable = checkable; } void QmlSideBarHelper::setItem(QQmlComponent *item) { m_item = item; } diff --git a/src/lib/plugins/qml/qmlengine.cpp b/src/lib/plugins/qml/qmlengine.cpp deleted file mode 100644 index 131d5b2a..00000000 --- a/src/lib/plugins/qml/qmlengine.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* ============================================================ -* Falkon - Qt web browser -* Copyright (C) 2018 Anmol Gautam -* -* 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 . -* ============================================================ */ -#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; -} diff --git a/src/lib/plugins/qml/qmlplugin.cpp b/src/lib/plugins/qml/qmlplugin.cpp deleted file mode 100644 index 043b204a..00000000 --- a/src/lib/plugins/qml/qmlplugin.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* ============================================================ -* Falkon - Qt web browser -* Copyright (C) 2018 Anmol Gautam -* -* 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 . -* ============================================================ */ -#include "qmlplugin.h" -#include "qmlplugins.h" -#include "qmlpluginloader.h" -#include "datapaths.h" -#include "desktopfile.h" - -#include -#include - -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(); - 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(qmlPluginLoader->instance()); -} diff --git a/src/lib/plugins/qml/qmlplugin.h b/src/lib/plugins/qml/qmlplugin.h deleted file mode 100644 index 7956de54..00000000 --- a/src/lib/plugins/qml/qmlplugin.h +++ /dev/null @@ -1,28 +0,0 @@ -/* ============================================================ -* Falkon - Qt web browser -* Copyright (C) 2018 Anmol Gautam -* -* 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 . -* ============================================================ */ -#pragma once - -#include "plugins.h" - -class QmlPlugin -{ -public: - explicit QmlPlugin(); - static Plugins::Plugin loadPlugin(const QString &name); - static void initPlugin(Plugins::Plugin *plugin); -}; diff --git a/src/lib/plugins/qml/qmlplugincontext.cpp b/src/lib/plugins/qml/qmlplugincontext.cpp new file mode 100644 index 00000000..3585f628 --- /dev/null +++ b/src/lib/plugins/qml/qmlplugincontext.cpp @@ -0,0 +1,58 @@ +/* ============================================================ +* Falkon - Qt web browser +* Copyright (C) 2019 David Rosca +* +* 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 . +* ============================================================ */ +#include "qmlplugincontext.h" + +#include +#include + +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(c); + if (p) { + return p; + } + c = c->parentContext(); + } + qCritical() << "Failed to get plugin context for object" << object; + Q_UNREACHABLE(); + return nullptr; +} diff --git a/src/lib/plugins/qml/qmlengine.h b/src/lib/plugins/qml/qmlplugincontext.h similarity index 64% rename from src/lib/plugins/qml/qmlengine.h rename to src/lib/plugins/qml/qmlplugincontext.h index 064774c9..a723ead9 100644 --- a/src/lib/plugins/qml/qmlengine.h +++ b/src/lib/plugins/qml/qmlplugincontext.h @@ -1,34 +1,40 @@ /* ============================================================ * Falkon - Qt web browser -* Copyright (C) 2018 Anmol Gautam +* Copyright (C) 2019 David Rosca * * 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 . * ============================================================ */ #pragma once -#include +#include -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; }; diff --git a/src/lib/plugins/qml/qmlplugininterface.cpp b/src/lib/plugins/qml/qmlplugininterface.cpp index 9363d15e..35435404 100644 --- a/src/lib/plugins/qml/qmlplugininterface.cpp +++ b/src/lib/plugins/qml/qmlplugininterface.cpp @@ -1,390 +1,392 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2018 Anmol Gautam * * 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 . * ============================================================ */ #include "qmlplugininterface.h" #include "mainapplication.h" #include "pluginproxy.h" #include "statusbar.h" #include "browserwindow.h" #include "navigationbar.h" #include "sidebar.h" #include "api/menus/qmlmenu.h" #include "api/menus/qmlwebhittestresult.h" #include "api/events/qmlqzobjects.h" #include "api/events/qmlmouseevent.h" #include "api/events/qmlwheelevent.h" #include "api/events/qmlkeyevent.h" #include "api/tabs/qmltab.h" #include "webpage.h" #include "qztools.h" -#include "qml/qmlengine.h" +#include "qml/qmlplugincontext.h" + #include #include #include #include +#include QmlPluginInterface::QmlPluginInterface() : m_qmlReusableTab(new QmlTab()) { + // QQmlEngine::setContextForObject(m_qmlReusableTab, QmlPluginContext::contextForObject(this)); } QmlPluginInterface::~QmlPluginInterface() { m_qmlReusableTab->deleteLater(); } void QmlPluginInterface::init(InitState state, const QString &settingsPath) { if (!m_init.isCallable()) { qWarning() << "Unable to call" << __FUNCTION__ << "on" << m_name << "plugin"; return; } QJSValueList args; args.append(state); args.append(settingsPath); m_init.call(args); } void QmlPluginInterface::unload() { if (!m_unload.isCallable()) { qWarning() << "Unable to call" << __FUNCTION__ << "on" << m_name << "plugin"; return; } m_unload.call(); for (QObject *childItem : qAsConst(m_childItems)) { childItem->deleteLater(); } emit qmlPluginUnloaded(); } bool QmlPluginInterface::testPlugin() { if (!m_testPlugin.isCallable()) { qWarning() << "Unable to call" << __FUNCTION__ << "on" << m_name << "plugin"; return false; } QJSValue ret = m_testPlugin.call(); return ret.toBool(); } void QmlPluginInterface::populateWebViewMenu(QMenu *menu, WebView *webview, const WebHitTestResult &webHitTestResult) { Q_UNUSED(webview) if (!m_populateWebViewMenu.isCallable()) { 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(); } void QmlPluginInterface::showSettings(QWidget *parent) { if (!m_settingsWindow) { qWarning() << "No dialog to show"; return; } QQuickWidget *widget = new QQuickWidget(); widget->setContent(m_settingsWindow->url(), m_settingsWindow, m_settingsWindow->create(m_settingsWindow->creationContext())); widget->show(); QzTools::centerWidgetToParent(widget, parent); } bool QmlPluginInterface::mouseDoubleClick(Qz::ObjectName type, QObject *obj, QMouseEvent *event) { Q_UNUSED(obj) if (!m_mouseDoubleClick.isCallable()) { 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; } bool QmlPluginInterface::mousePress(Qz::ObjectName type, QObject *obj, QMouseEvent *event) { Q_UNUSED(obj) if (!m_mousePress.isCallable()) { 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; } bool QmlPluginInterface::mouseRelease(Qz::ObjectName type, QObject *obj, QMouseEvent *event) { Q_UNUSED(obj) if (!m_mouseRelease.isCallable()) { 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; } bool QmlPluginInterface::mouseMove(Qz::ObjectName type, QObject *obj, QMouseEvent *event) { Q_UNUSED(obj) if (!m_mouseMove.isCallable()) { 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; } bool QmlPluginInterface::wheelEvent(Qz::ObjectName type, QObject *obj, QWheelEvent *event) { Q_UNUSED(obj) if (!m_wheelEvent.isCallable()) { 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; } bool QmlPluginInterface::keyPress(Qz::ObjectName type, QObject *obj, QKeyEvent *event) { Q_UNUSED(obj) if (!m_keyPress.isCallable()) { 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; } bool QmlPluginInterface::keyRelease(Qz::ObjectName type, QObject *obj, QKeyEvent *event) { Q_UNUSED(obj) if (!m_keyRelease.isCallable()) { 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; } bool QmlPluginInterface::acceptNavigationRequest(WebPage *page, const QUrl &url, QWebEnginePage::NavigationType type, bool isMainFrame) { if (!m_acceptNavigationRequest.isCallable()) { return true; } 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); return m_acceptNavigationRequest.call(args).toBool(); } QJSValue QmlPluginInterface::readInit() const { return m_init; } void QmlPluginInterface::setInit(const QJSValue &init) { m_init = init; } QJSValue QmlPluginInterface::readUnload() const { return m_unload; } void QmlPluginInterface::setUnload(const QJSValue &unload) { m_unload = unload; } QJSValue QmlPluginInterface::readTestPlugin() const { return m_testPlugin; } 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; } void QmlPluginInterface::setPopulateWebViewMenu(const QJSValue &value) { m_populateWebViewMenu = value; } QQmlComponent *QmlPluginInterface::settingsWindow() const { return m_settingsWindow; } void QmlPluginInterface::setSettingsWindow(QQmlComponent *settingsWindow) { m_settingsWindow = settingsWindow; } QJSValue QmlPluginInterface::readMouseDoubleClick() const { return m_mouseDoubleClick; } void QmlPluginInterface::setMouseDoubleClick(const QJSValue &mouseDoubleClick) { m_mouseDoubleClick = mouseDoubleClick; mApp->plugins()->registerAppEventHandler(PluginProxy::MouseDoubleClickHandler, this); } QJSValue QmlPluginInterface::readMousePress() const { return m_mousePress; } void QmlPluginInterface::setMousePress(const QJSValue &mousePress) { m_mousePress = mousePress; mApp->plugins()->registerAppEventHandler(PluginProxy::MousePressHandler, this); } QJSValue QmlPluginInterface::readMouseRelease() const { return m_mouseRelease; } void QmlPluginInterface::setMouseRelease(const QJSValue &mouseRelease) { m_mouseRelease = mouseRelease; mApp->plugins()->registerAppEventHandler(PluginProxy::MouseReleaseHandler, this); } QJSValue QmlPluginInterface::readMouseMove() const { return m_mouseMove; } void QmlPluginInterface::setMouseMove(const QJSValue &mouseMove) { m_mouseMove = mouseMove; mApp->plugins()->registerAppEventHandler(PluginProxy::MouseMoveHandler, this); } QJSValue QmlPluginInterface::readWheelEvent() const { return m_wheelEvent; } void QmlPluginInterface::setWheelEvent(const QJSValue &wheelEvent) { m_wheelEvent = wheelEvent; mApp->plugins()->registerAppEventHandler(PluginProxy::WheelEventHandler, this); } QJSValue QmlPluginInterface::readKeyPress() const { return m_keyPress; } void QmlPluginInterface::setKeyPress(const QJSValue &keyPress) { m_keyPress = keyPress; mApp->plugins()->registerAppEventHandler(PluginProxy::KeyPressHandler, this); } QJSValue QmlPluginInterface::readKeyRelease() const { return m_keyRelease; } void QmlPluginInterface::setKeyRelease(const QJSValue &keyRelease) { m_keyRelease = keyRelease; mApp->plugins()->registerAppEventHandler(PluginProxy::KeyReleaseHandler, this); } QJSValue QmlPluginInterface::readAcceptNavigationRequest() const { return m_acceptNavigationRequest; } void QmlPluginInterface::setAcceptNavigationRequest(const QJSValue &acceptNavigationRequest) { m_acceptNavigationRequest = acceptNavigationRequest; } QQmlListProperty QmlPluginInterface::childItems() { return QQmlListProperty(this, m_childItems); } diff --git a/src/lib/plugins/qml/qmlplugininterface.h b/src/lib/plugins/qml/qmlplugininterface.h index bc2251f0..aafbeea3 100644 --- a/src/lib/plugins/qml/qmlplugininterface.h +++ b/src/lib/plugins/qml/qmlplugininterface.h @@ -1,121 +1,118 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2018 Anmol Gautam * * 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 . * ============================================================ */ #pragma once #include #include #include #include "desktopfile.h" #include "plugininterface.h" class QmlTab; class QmlPluginInterface : public QObject, public PluginInterface { Q_OBJECT Q_INTERFACES(PluginInterface) Q_ENUM(InitState) Q_PROPERTY(QJSValue init READ readInit WRITE setInit) Q_PROPERTY(QJSValue unload READ readUnload WRITE setUnload) Q_PROPERTY(QJSValue testPlugin READ readTestPlugin WRITE setTestPlugin) Q_PROPERTY(QJSValue populateWebViewMenu READ readPopulateWebViewMenu WRITE setPopulateWebViewMenu) Q_PROPERTY(QQmlComponent* settingsWindow READ settingsWindow WRITE setSettingsWindow) Q_PROPERTY(QJSValue mouseDoubleClick READ readMouseDoubleClick WRITE setMouseDoubleClick) Q_PROPERTY(QJSValue mousePress READ readMousePress WRITE setMousePress) Q_PROPERTY(QJSValue mouseRelease READ readMouseRelease WRITE setMouseRelease) Q_PROPERTY(QJSValue mouseMove READ readMouseMove WRITE setMouseMove) Q_PROPERTY(QJSValue wheelEvent READ readWheelEvent WRITE setWheelEvent) Q_PROPERTY(QJSValue keyPress READ readKeyPress WRITE setKeyPress) Q_PROPERTY(QJSValue keyRelease READ readKeyRelease WRITE setKeyRelease) Q_PROPERTY(QJSValue acceptNavigationRequest READ readAcceptNavigationRequest WRITE setAcceptNavigationRequest) Q_PROPERTY(QQmlListProperty childItems READ childItems) Q_CLASSINFO("DefaultProperty", "childItems") public: explicit QmlPluginInterface(); ~QmlPluginInterface() override; 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; bool mouseDoubleClick(Qz::ObjectName type, QObject *obj, QMouseEvent *event) override; bool mousePress(Qz::ObjectName type, QObject *obj, QMouseEvent *event) override; bool mouseRelease(Qz::ObjectName type, QObject *obj, QMouseEvent *event) override; bool mouseMove(Qz::ObjectName type, QObject *obj, QMouseEvent *event) override; bool wheelEvent(Qz::ObjectName type, QObject *obj, QWheelEvent *event) override; bool keyPress(Qz::ObjectName type, QObject *obj, QKeyEvent *event) override; bool keyRelease(Qz::ObjectName type, QObject *obj, QKeyEvent *event) override; bool acceptNavigationRequest(WebPage *page, const QUrl &url, QWebEnginePage::NavigationType type, bool isMainFrame) override; Q_SIGNALS: void qmlPluginUnloaded(); private: - QQmlEngine *m_engine = nullptr; QString m_name; QJSValue m_init; QJSValue m_unload; QJSValue m_testPlugin; QJSValue m_populateWebViewMenu; QQmlComponent *m_settingsWindow = nullptr; QJSValue m_mouseDoubleClick; QJSValue m_mousePress; QJSValue m_mouseRelease; QJSValue m_mouseMove; QJSValue m_wheelEvent; QJSValue m_keyPress; QJSValue m_keyRelease; QJSValue m_acceptNavigationRequest; QList m_childItems; QmlTab *m_qmlReusableTab = nullptr; QJSValue readInit() const; void setInit(const QJSValue &init); QJSValue readUnload() const; void setUnload(const QJSValue &unload); QJSValue readTestPlugin() const; void setTestPlugin(const QJSValue &testPlugin); QJSValue readPopulateWebViewMenu() const; void setPopulateWebViewMenu(const QJSValue &value); QQmlComponent *settingsWindow() const; void setSettingsWindow(QQmlComponent *settingsWindow); QJSValue readMouseDoubleClick() const; void setMouseDoubleClick(const QJSValue &mouseDoubleClick); QJSValue readMousePress() const; void setMousePress(const QJSValue &mousePress); QJSValue readMouseRelease() const; void setMouseRelease(const QJSValue &mouseRelease); QJSValue readMouseMove() const; void setMouseMove(const QJSValue &mouseMove); QJSValue readWheelEvent() const; void setWheelEvent(const QJSValue &wheelEvent); QJSValue readKeyPress() const; void setKeyPress(const QJSValue &keyPress); QJSValue readKeyRelease() const; void setKeyRelease(const QJSValue &keyRelease); QJSValue readAcceptNavigationRequest() const; void setAcceptNavigationRequest(const QJSValue &acceptNavigationRequest); QQmlListProperty childItems(); }; diff --git a/src/lib/plugins/qml/qmlpluginloader.cpp b/src/lib/plugins/qml/qmlpluginloader.cpp index e036cdf8..1f18dea4 100644 --- a/src/lib/plugins/qml/qmlpluginloader.cpp +++ b/src/lib/plugins/qml/qmlpluginloader.cpp @@ -1,77 +1,85 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2018 Anmol Gautam * * 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 . * ============================================================ */ #include "qmlpluginloader.h" -#include "qmlengine.h" -#include -#include +#include "qmlplugincontext.h" +#include "qmlplugininterface.h" #include "../config.h" +#include +#include +#include +#include + #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(); +} + +QString QmlPluginLoader::errorString() const +{ + return m_component ? m_component->errorString() : QString(); +} + +QmlPluginInterface *QmlPluginLoader::instance() const +{ + return m_interface; } void QmlPluginLoader::createComponent() { - m_interface = qobject_cast(m_component->create(m_component->creationContext())); + initEngineAndComponent(); + m_interface = qobject_cast(m_component->create(m_context)); if (!m_interface) { + qWarning() << "Failed to create QmlPluginInterface!"; 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(); + m_component->deleteLater(); + m_component = nullptr; + m_context->deleteLater(); + m_context = nullptr; }); } -QQmlComponent *QmlPluginLoader::component() const -{ - return m_component; -} - -QmlPluginInterface *QmlPluginLoader::instance() const -{ - return m_interface; -} - 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 } diff --git a/src/lib/plugins/qml/qmlpluginloader.h b/src/lib/plugins/qml/qmlpluginloader.h index 881ab1e0..528eef8f 100644 --- a/src/lib/plugins/qml/qmlpluginloader.h +++ b/src/lib/plugins/qml/qmlpluginloader.h @@ -1,46 +1,49 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2018 Anmol Gautam * * 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 . * ============================================================ */ #pragma once -#include -#include +#include -#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 *) diff --git a/src/lib/plugins/qml/qmlplugins.cpp b/src/lib/plugins/qml/qmlplugins.cpp index fd9c2953..647e83a7 100644 --- a/src/lib/plugins/qml/qmlplugins.cpp +++ b/src/lib/plugins/qml/qmlplugins.cpp @@ -1,215 +1,219 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2018 Anmol Gautam * * 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 . * ============================================================ */ #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" #include "api/topsites/qmltopsites.h" #include "api/history/qmlhistoryitem.h" #include "api/history/qmlhistory.h" #include "api/cookies/qmlcookie.h" #include "api/cookies/qmlcookies.h" #include "api/tabs/qmltab.h" #include "api/tabs/qmltabs.h" #include "api/notifications/qmlnotifications.h" #include "api/clipboard/qmlclipboard.h" #include "api/windows/qmlwindow.h" #include "api/windows/qmlwindows.h" #include "api/browseraction/qmlbrowseraction.h" #include "api/sidebar/qmlsidebar.h" #include "api/menus/qmlmenu.h" #include "api/menus/qmlaction.h" #include "api/menus/qmlwebhittestresult.h" #include "api/settings/qmlsettings.h" #include "api/events/qmlqzobjects.h" #include "api/events/qmlkeyevent.h" #include "api/events/qmlmouseevent.h" #include "api/events/qmlwheelevent.h" #include "api/userscript/qmluserscript.h" #include "api/userscript/qmluserscripts.h" #include "api/userscript/qmlexternaljsobject.h" #include "api/extensionscheme/qmlextensionscheme.h" #include "api/extensionscheme/qmlwebengineurlrequestjob.h" #include "api/fileutils/qmlfileutils.h" #include "api/qmlenums.h" #include "qml/qmlstaticdata.h" #include #include // static void QmlPlugins::registerQmlTypes() { const char *url = "org.kde.falkon"; const int majorVersion = 1; const int minorVersion = 0; // PluginInterface qmlRegisterType(url, majorVersion, minorVersion, "PluginInterface"); // Bookmarks qmlRegisterUncreatableType(url, majorVersion, minorVersion, "BookmarkTreeNode", QSL("Unable to register type: BookmarkTreeNode")); qmlRegisterSingletonType(url, majorVersion, minorVersion, "Bookmarks", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * { Q_UNUSED(engine) Q_UNUSED(scriptEngine) return QmlStaticData::instance().getBookmarksSingleton(); }); // TopSites qmlRegisterUncreatableType(url, majorVersion, minorVersion, "MostVisitedURL", QSL("Unable to register type: MostVisitedURL")); qmlRegisterSingletonType(url, majorVersion, minorVersion, "TopSites", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * { Q_UNUSED(engine) Q_UNUSED(scriptEngine) return QmlStaticData::instance().getTopSitesSingleton(); }); // History qmlRegisterUncreatableType(url, majorVersion, minorVersion, "HistoryItem", QSL("Unable to register type: HistoryItem")); qmlRegisterSingletonType(url, majorVersion, minorVersion, "History", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * { Q_UNUSED(engine) Q_UNUSED(scriptEngine) return QmlStaticData::instance().getHistorySingleton(); }); // Cookies qmlRegisterUncreatableType(url, majorVersion, minorVersion, "Cookie", "Unable to register type: Cookie"); qmlRegisterSingletonType(url, majorVersion, minorVersion, "Cookies", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * { Q_UNUSED(engine) Q_UNUSED(scriptEngine) return QmlStaticData::instance().getCookiesSingleton(); }); // Tabs qmlRegisterUncreatableType(url, majorVersion, minorVersion, "Tab", QSL("Unable to register type: Tab")); qmlRegisterSingletonType(url, majorVersion, minorVersion, "Tabs", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * { Q_UNUSED(engine) Q_UNUSED(scriptEngine) return QmlStaticData::instance().getTabsSingleton(); }); // Notifications qmlRegisterSingletonType(url, majorVersion, minorVersion, "Notifications", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * { Q_UNUSED(scriptEngine) - QmlEngine *qmlEngine = qobject_cast(engine); +#if 0 + auto context = qobject_cast(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; }); // Clipboard qmlRegisterSingletonType(url, majorVersion, minorVersion, "Clipboard", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * { Q_UNUSED(engine) Q_UNUSED(scriptEngine) return QmlStaticData::instance().getClipboardSingleton(); }); // Windows qmlRegisterUncreatableType(url, majorVersion, minorVersion, "Window", QSL("Unable to register type: Window")); qmlRegisterSingletonType(url, majorVersion, minorVersion, "Windows", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * { Q_UNUSED(engine) Q_UNUSED(scriptEngine) return QmlStaticData::instance().getWindowsSingleton(); }); // BrowserAction qmlRegisterType(url, majorVersion, minorVersion, "BrowserAction"); // SideBar qmlRegisterType(url, majorVersion, minorVersion, "SideBar"); // Menu qmlRegisterUncreatableType(url, majorVersion, minorVersion, "Menu", QSL("Unable to register type: Menu")); // Action qmlRegisterUncreatableType(url, majorVersion, minorVersion, "Action", QSL("Unable to register type: Action")); // WebHitTestResult qmlRegisterUncreatableType(url, majorVersion, minorVersion, "WebHitTestResult", QSL("Unable to register type: WebHitTestResult")); // Settings qmlRegisterType(url, majorVersion, minorVersion, "Settings"); // Qz::Objects qmlRegisterUncreatableType(url, majorVersion, minorVersion, "QzObjects", QSL("Unable to register type: QzObjects")); // KeyEvents qmlRegisterUncreatableType(url, majorVersion, minorVersion, "KeyEvent", QSL("Unable to register type: KeyEvent")); // MouseEvents qmlRegisterUncreatableType(url, majorVersion, minorVersion, "MouseEvent", QSL("Unable to register type: MouseEvent")); // WheelEvents qmlRegisterUncreatableType(url, majorVersion, minorVersion, "WheelEvent", QSL("Unable to register type: WheelEvent")); // UserScripts qmlRegisterType(url, majorVersion, minorVersion, "UserScript"); qmlRegisterSingletonType(url, majorVersion, minorVersion, "UserScripts", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * { Q_UNUSED(engine) Q_UNUSED(scriptEngine) return QmlStaticData::instance().getUserScriptsSingleton(); }); qmlRegisterSingletonType(url, majorVersion, minorVersion, "ExternalJsObject", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * { Q_UNUSED(engine) Q_UNUSED(scriptEngine) return QmlStaticData::instance().getExternalJsObjectSingleton(); }); // ExtensionScheme qmlRegisterType(url, majorVersion, minorVersion, "ExtensionScheme"); qmlRegisterUncreatableType(url, majorVersion, minorVersion, "WebEngineUrlRequestJob", QSL("Unable to register type: WebEngineUrlRequestJob")); // FileUtils qmlRegisterSingletonType(url, majorVersion, minorVersion, "FileUtils", [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * { Q_UNUSED(scriptEngine) +#if 0 QmlEngine *qmlEngine = qobject_cast(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(url, majorVersion, minorVersion, "Enums", QSL("Unable to register type: Enums")); }