summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoraqua <aqua@iserlohn-fortress.net>2022-08-16 16:19:04 +0300
committeraqua <aqua@iserlohn-fortress.net>2022-08-16 16:19:04 +0300
commit616e680aa8af8f5056b5133dd44258c252ca656f (patch)
tree4c89c4fe2b9b2cc77c550c8d52d6d1058ee10846
parentAdd rView and WebView (diff)
downloadrekonq-616e680aa8af8f5056b5133dd44258c252ca656f.tar.xz
Turn WebEngine into a plugin
-rw-r--r--CMakeLists.txt1
-rw-r--r--plugins/webengine/CMakeLists.txt12
-rw-r--r--plugins/webengine/WebEngine.json4
-rw-r--r--plugins/webengine/webengineplugin.cpp (renamed from src/rview.cpp)7
-rw-r--r--plugins/webengine/webengineplugin.hpp23
-rw-r--r--plugins/webengine/webview.cpp (renamed from src/webengine/webview.cpp)0
-rw-r--r--plugins/webengine/webview.h (renamed from src/webengine/webview.h)2
-rw-r--r--src/CMakeLists.txt9
-rw-r--r--src/application.cpp37
-rw-r--r--src/application.h4
-rw-r--r--src/main.cpp11
-rw-r--r--src/plugins/CMakeLists.txt7
-rw-r--r--src/plugins/pluginloader.cpp17
-rw-r--r--src/plugins/pluginloader.h25
-rw-r--r--src/plugins/rplugininterface.hpp23
-rw-r--r--src/plugins/rview.hpp (renamed from src/rview.h)2
-rw-r--r--src/plugins/test/pluginloader.cpp40
17 files changed, 212 insertions, 12 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 025c40e0..ee184c79 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -102,6 +102,7 @@ feature_summary(WHAT ALL)
ADD_SUBDIRECTORY( src )
ADD_SUBDIRECTORY( icons )
+add_subdirectory(plugins/webengine)
# ================================================================================
diff --git a/plugins/webengine/CMakeLists.txt b/plugins/webengine/CMakeLists.txt
new file mode 100644
index 00000000..8a11bc76
--- /dev/null
+++ b/plugins/webengine/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_library(WebEnginePlugin MODULE
+ webengineplugin.cpp webengineplugin.hpp
+ webview.cpp webview.h
+ ${PROJECT_SOURCE_DIR}/src/plugins/rplugininterface.hpp
+ ${PROJECT_SOURCE_DIR}/src/plugins/rview.hpp
+)
+target_include_directories(WebEnginePlugin PRIVATE ${PROJECT_SOURCE_DIR}/src/plugins)
+target_link_libraries(WebEnginePlugin PUBLIC Qt6::Core Qt6::WebEngineWidgets)
+
+if(TESTING)
+ add_test(NAME "load_plugin WebEnginePlugin" COMMAND load_plugin $<TARGET_FILE:WebEnginePlugin>)
+endif()
diff --git a/plugins/webengine/WebEngine.json b/plugins/webengine/WebEngine.json
new file mode 100644
index 00000000..03e2112c
--- /dev/null
+++ b/plugins/webengine/WebEngine.json
@@ -0,0 +1,4 @@
+{
+ "name": "WebEngine",
+ "schemes": [ "file", "http", "https" ]
+}
diff --git a/src/rview.cpp b/plugins/webengine/webengineplugin.cpp
index 2da3096c..cf6811dc 100644
--- a/src/rview.cpp
+++ b/plugins/webengine/webengineplugin.cpp
@@ -4,9 +4,10 @@
* SPDX-License-Identifier: GPL-3.0-only
* Copyright (C) 2022 aqua <aqua@iserlohn-fortress.net>
* ============================================================
- * Description: View Interface
+ * Description: WebEngine plugin View factory
* ============================================================ */
-#include "rview.h"
+#include "webengineplugin.hpp"
+#include "webview.h"
-rView::rView(const QUrl &url, QWidget *parent) : QWidget(parent) {}
+rView *WebEnginePlugin::view(const QUrl &url) { return new WebView(url, nullptr); }
diff --git a/plugins/webengine/webengineplugin.hpp b/plugins/webengine/webengineplugin.hpp
new file mode 100644
index 00000000..3ee63ff8
--- /dev/null
+++ b/plugins/webengine/webengineplugin.hpp
@@ -0,0 +1,23 @@
+/* ============================================================
+ * The rekonq project
+ * ============================================================
+ * SPDX-License-Identifier: GPL-3.0-only
+ * Copyright (C) 2022 aqua <aqua@iserlohn-fortress.net>
+ * ============================================================
+ * Description: WebEngine plugin View factory
+ * ============================================================ */
+
+#pragma once
+
+#include <rplugininterface.hpp>
+
+class WebEnginePlugin final : public RekonqPluginInterface {
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID RekonqPluginInterface_iid FILE "WebEngine.json")
+ Q_INTERFACES(RekonqPluginInterface)
+
+public:
+ WebEnginePlugin() = default;
+
+ rView *view(const QUrl &url) override;
+};
diff --git a/src/webengine/webview.cpp b/plugins/webengine/webview.cpp
index 1aef01e2..1aef01e2 100644
--- a/src/webengine/webview.cpp
+++ b/plugins/webengine/webview.cpp
diff --git a/src/webengine/webview.h b/plugins/webengine/webview.h
index b838c5ac..0b8d0dae 100644
--- a/src/webengine/webview.h
+++ b/plugins/webengine/webview.h
@@ -9,7 +9,7 @@
#pragma once
-#include "rview.h"
+#include "rview.hpp"
class QWebEngineView;
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 4aa141c9..5f154e3f 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,6 +1,7 @@
### ------- sub dirs -------
ADD_SUBDIRECTORY( data )
+add_subdirectory(plugins)
### ------- SETTING REKONQ FILES..
@@ -216,15 +217,17 @@ ADD_DEFINITIONS ( ${KDE4_DEFINITIONS} )
add_executable(rekonq
main.cpp application.cpp application.h
# ----------------------------------------
- rview.cpp rview.h webengine/webview.cpp webengine/webview.h
+ plugins/rplugininterface.hpp plugins/rview.hpp
)
### --------------- TARGETTING LINK LIBRARIES...
target_link_libraries(rekonq
- Qt6::Widgets Qt6::WebEngineWidgets
- SingleApplication::SingleApplication)
+ Qt6::Widgets
+ SingleApplication::SingleApplication
+ pluginloader
+)
# Nepomuk optional target link libraries
IF(SOPRANO_FOUND AND NepomukCore_FOUND)
diff --git a/src/application.cpp b/src/application.cpp
index 54a7db88..9e34e5e2 100644
--- a/src/application.cpp
+++ b/src/application.cpp
@@ -10,8 +10,9 @@
* ============================================================ */
#include "application.h"
-#include "rview.h"
-#include "webengine/webview.h"
+#include "plugins/pluginloader.h"
+#include "plugins/rplugininterface.hpp"
+#include <QPluginLoader>
// ---------------------------------------------------------------------------------------------------------------
// Ctor and Dtor
@@ -42,9 +43,29 @@ Application::~Application()
// Destroy all web apps
for (auto *webApp : m_webApps) delete webApp;
+
+ // Unload all plugins
+ for (auto *plugin : m_plugins) {
+ plugin->unload();
+ delete plugin;
+ }
}
// ---------------------------------------------------------------------------------------------------------------
+// Plugin management
+
+bool Application::registerPlugin(const QString &path)
+{
+ auto *loader = new PluginLoader(path);
+ if (!loader->load()) {
+ delete loader;
+ return false;
+ }
+
+ m_plugins.append(loader);
+ return true;
+}
+// ---------------------------------------------------------------------------------------------------------------
/*
int Application::newInstance()
{
@@ -388,7 +409,17 @@ void Application::setWindowInfo(RekonqWindow *w)
rView *Application::newWebApp(const QUrl &url)
{
- auto *view = new WebView(url);
+ RekonqPluginInterface *interface = nullptr;
+ for (auto *plugin : m_plugins)
+ if (plugin->hasScheme(url.scheme())) {
+ interface = plugin->interface();
+ break;
+ }
+
+ if (interface == nullptr) return nullptr;
+
+ auto *view = interface->view(url);
+ Q_CHECK_PTR(view);
// tab->installEventFilter(this);
m_webApps.append(view);
diff --git a/src/application.h b/src/application.h
index 761bc89b..407a8681 100644
--- a/src/application.h
+++ b/src/application.h
@@ -18,6 +18,7 @@
// Forward Declarations
class rView;
+class PluginLoader;
// class RekonqWindow;
// class WebTab;
@@ -38,6 +39,8 @@ public:
Application(int &argc, char *argv[]);
~Application() override;
+ bool registerPlugin(const QString &path);
+
// int newInstance();
static Application *instance() { return (qobject_cast<Application *>(QCoreApplication::instance())); }
@@ -107,6 +110,7 @@ private slots:
// void pageCreated(WebPage *);
private:
+ QList<PluginLoader *> m_plugins;
// RekonqWindowList m_rekonqWindows;
QList<rView *> m_webApps;
};
diff --git a/src/main.cpp b/src/main.cpp
index 20c30c68..6db6f36c 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -19,6 +19,9 @@ static const char *description = "A lightweight Web Browser based on Qt WebEngin
int main(int argc, char **argv)
{
+ // When loading QtWebEngine from a plugin, set Qt::AA_ShareOpenGLContexts using QCoreApplication::setAttribute
+ QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true);
+
Application app(argc, argv);
// Set application data
QCoreApplication::setApplicationName(QL1S("rekonq"));
@@ -34,13 +37,19 @@ int main(int argc, char **argv)
QCommandLineOption options_incognito("incognito", QCoreApplication::translate("main", "Open in incognito mode"));
QCommandLineOption options_webapp("webapp",
QCoreApplication::translate("main", "Open URL as web app (in a simple window)"));
- parser.addOptions({options_incognito, options_webapp});
+ QCommandLineOption options_plugin({"l", "load"}, QCoreApplication::translate("main", "Add plugin to load path"),
+ "path");
+ parser.addOptions({options_incognito, options_webapp, options_plugin});
// Define the positional arguments
parser.addPositionalArgument("URL", QCoreApplication::translate("main", "Location to open"));
parser.process(app);
+ if (parser.isSet(options_plugin)) {
+ for (const auto &plugin : parser.values(options_plugin)) app.registerPlugin(plugin);
+ }
+
const auto positionalArguments = parser.positionalArguments();
if (parser.isSet(options_webapp))
positionalArguments.isEmpty() ? app.newWebApp() : app.newWebApp(QUrl::fromUserInput(positionalArguments.first()));
diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt
new file mode 100644
index 00000000..01b13ae1
--- /dev/null
+++ b/src/plugins/CMakeLists.txt
@@ -0,0 +1,7 @@
+add_library(pluginloader STATIC pluginloader.cpp pluginloader.h)
+target_link_libraries(pluginloader PUBLIC Qt6::Core Qt6::Widgets)
+
+if(TESTING)
+ add_executable(load_plugin test/pluginloader.cpp)
+ target_link_libraries(load_plugin GTest::gtest GTest::gtest_main Qt6::Core)
+endif()
diff --git a/src/plugins/pluginloader.cpp b/src/plugins/pluginloader.cpp
new file mode 100644
index 00000000..ad5dbc14
--- /dev/null
+++ b/src/plugins/pluginloader.cpp
@@ -0,0 +1,17 @@
+/* ============================================================
+ * The rekonq project
+ * ============================================================
+ * SPDX-License-Identifier: GPL-3.0-only
+ * Copyright (C) 2022 aqua <aqua@iserlohn-fortress.net>
+ * ============================================================
+ * Description: rekonq plugin loader
+ * ============================================================ */
+
+#include "pluginloader.h"
+#include <QJsonArray>
+
+PluginLoader::PluginLoader(const QString &fileName, QObject *parent) : QPluginLoader(fileName, parent)
+{
+ const auto metadata = metaData()["MetaData"].toObject();
+ for (const auto &value : metadata["schemes"].toArray()) { m_schemes.append(value.toString()); }
+}
diff --git a/src/plugins/pluginloader.h b/src/plugins/pluginloader.h
new file mode 100644
index 00000000..f764da9f
--- /dev/null
+++ b/src/plugins/pluginloader.h
@@ -0,0 +1,25 @@
+/* ============================================================
+ * The rekonq project
+ * ============================================================
+ * SPDX-License-Identifier: GPL-3.0-only
+ * Copyright (C) 2022 aqua <aqua@iserlohn-fortress.net>
+ * ============================================================
+ * Description: rekonq plugin loader
+ * ============================================================ */
+
+#pragma once
+
+#include "rplugininterface.hpp"
+#include <QPluginLoader>
+
+class PluginLoader : public QPluginLoader {
+
+public:
+ explicit PluginLoader(const QString &path, QObject *parent = nullptr);
+ [[nodiscard]] bool hasScheme(const QString &scheme) { return m_schemes.contains(scheme); }
+
+ [[nodiscard]] RekonqPluginInterface *interface() { return qobject_cast<RekonqPluginInterface *>(instance()); }
+
+private:
+ QStringList m_schemes;
+};
diff --git a/src/plugins/rplugininterface.hpp b/src/plugins/rplugininterface.hpp
new file mode 100644
index 00000000..16186591
--- /dev/null
+++ b/src/plugins/rplugininterface.hpp
@@ -0,0 +1,23 @@
+/* ============================================================
+ * The rekonq project
+ * ============================================================
+ * SPDX-License-Identifier: GPL-3.0-only
+ * Copyright (C) 2022 aqua <aqua@iserlohn-fortress.net>
+ * ============================================================
+ * Description: rekonq plugin interface
+ * ============================================================ */
+
+#pragma once
+
+#include "rview.hpp"
+#include <QtPlugin>
+
+class RekonqPluginInterface : public QObject {
+ Q_OBJECT
+
+public:
+ virtual rView *view(const QUrl &url) = 0;
+};
+
+#define RekonqPluginInterface_iid "rekonq.3.RekongPluginInterface"
+Q_DECLARE_INTERFACE(RekonqPluginInterface, RekonqPluginInterface_iid)
diff --git a/src/rview.h b/src/plugins/rview.hpp
index 4f4cc897..71bf5ddf 100644
--- a/src/rview.h
+++ b/src/plugins/rview.hpp
@@ -16,7 +16,7 @@ class rView : public QWidget {
Q_OBJECT
public:
- explicit rView(const QUrl &url = QUrl(), QWidget *parent = nullptr);
+ explicit rView(const QUrl &url = QUrl(), QWidget *parent = nullptr) : QWidget(parent) {}
signals:
void iconChanged(const QIcon &);
diff --git a/src/plugins/test/pluginloader.cpp b/src/plugins/test/pluginloader.cpp
new file mode 100644
index 00000000..83b30c40
--- /dev/null
+++ b/src/plugins/test/pluginloader.cpp
@@ -0,0 +1,40 @@
+#include <QJsonArray>
+#include <QPluginLoader>
+#include <gtest/gtest.h>
+#include <iostream>
+
+char *pluginPath;
+
+class PluginLoaderTest : public ::testing::Test {
+
+protected:
+ void SetUp() override { loader = new QPluginLoader; }
+ void TearDown() override { delete loader; }
+
+ QPluginLoader *loader = nullptr;
+};
+
+TEST_F(PluginLoaderTest, InterfaceTest)
+{
+ // Ensure plugin loads
+ loader->setFileName(pluginPath);
+ EXPECT_TRUE(loader->load()) << "For plugin: " << pluginPath << '\n' << qUtf8Printable(loader->errorString());
+
+ // Ensure plugin has metadata
+ const auto metadata = loader->metaData()["MetaData"].toObject();
+ EXPECT_TRUE(metadata.contains("name"));
+ EXPECT_FALSE(metadata["name"].toString().isEmpty());
+ EXPECT_TRUE(metadata.contains("schemes"));
+ EXPECT_FALSE(metadata["schemes"].toArray().isEmpty());
+}
+
+int main(int argc, char **argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ if (argc != 2) {
+ std::cerr << "Usage: " << argv[0] << " [path to plugin]" << std::endl;
+ return -1;
+ }
+ pluginPath = argv[1];
+ return RUN_ALL_TESTS();
+}