From 8ab1f8d796d8f35a65e38fdd03d51824a41d1dab Mon Sep 17 00:00:00 2001 From: Akshay Nair Date: Sat, 26 Jul 2025 16:16:54 +0530 Subject: Add simple js rpc for decorations via custom scheme --- src/main.cpp | 2 ++ src/schemes/NullRpcSchemeHandler.hpp | 47 ++++++++++++++++++++++++++++++++++++ src/schemes/schemes.hpp | 16 ++++++++++++ src/widgets/BrowserApp.cpp | 4 ++- src/widgets/BrowserApp.hpp | 2 +- src/widgets/DevtoolsWindow.hpp | 31 ++++++++++++++++++++++++ src/widgets/EdgeDecoration.cpp | 24 ++++++++++++++++-- src/widgets/WebView.cpp | 38 +++++++++++++++++++++++++---- src/widgets/WebView.hpp | 37 +++++++++++----------------- 9 files changed, 169 insertions(+), 32 deletions(-) create mode 100644 src/schemes/NullRpcSchemeHandler.hpp create mode 100644 src/schemes/schemes.hpp create mode 100644 src/widgets/DevtoolsWindow.hpp (limited to 'src') diff --git a/src/main.cpp b/src/main.cpp index fbe1fbd..76afb90 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,8 +1,10 @@ #include #include "App.hpp" +#include "schemes/schemes.hpp" int main(int argc, char *argv[]) { + register_all_schemes(); const QApplication qt_app(argc, argv); App app; diff --git a/src/schemes/NullRpcSchemeHandler.hpp b/src/schemes/NullRpcSchemeHandler.hpp new file mode 100644 index 0000000..b1d5168 --- /dev/null +++ b/src/schemes/NullRpcSchemeHandler.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include +#include +#include +#include + +class NullRPCSchemeHandler : public QWebEngineUrlSchemeHandler { + Q_OBJECT + +public: + static NullRPCSchemeHandler &instance() { + static NullRPCSchemeHandler handler; + return handler; + } + + void requestStarted(QWebEngineUrlRequestJob *job) override { + auto url = job->requestUrl(); + qDebug() << "REQ" << url << url.host(); + + if (url.host().isEmpty() || url.host() == "noop") { + job->reply("text/html", new QBuffer(job)); + return; + } + + if (url.host() == "log") { + qDebug() << url.query(); + job->reply("text/plain", new QBuffer(job)); + return; + } + + QUrlQuery query(url.query()); + emit message_received(url.host(), query); + + QByteArray data = "{}"; + QBuffer *buffer = new QBuffer(job); + buffer->setData(data); + buffer->open(QIODevice::ReadOnly); + job->reply("text/plain", buffer); + } + +signals: + void message_received(const QString &action, QUrlQuery params); + +private: + NullRPCSchemeHandler() = default; +}; diff --git a/src/schemes/schemes.hpp b/src/schemes/schemes.hpp new file mode 100644 index 0000000..f04dc4d --- /dev/null +++ b/src/schemes/schemes.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +void register_nullrpc_scheme() { + QWebEngineUrlScheme scheme("nullrpc"); + scheme.setFlags( + QWebEngineUrlScheme::SecureScheme | QWebEngineUrlScheme::LocalScheme | + QWebEngineUrlScheme::LocalAccessAllowed | QWebEngineUrlScheme::ServiceWorkersAllowed | + QWebEngineUrlScheme::ContentSecurityPolicyIgnored | QWebEngineUrlScheme::FetchApiAllowed); + scheme.setSyntax(QWebEngineUrlScheme::Syntax::Path); + QWebEngineUrlScheme::registerScheme(scheme); +} + +void register_all_schemes() { register_nullrpc_scheme(); } diff --git a/src/widgets/BrowserApp.cpp b/src/widgets/BrowserApp.cpp index d096f01..922c5cc 100644 --- a/src/widgets/BrowserApp.cpp +++ b/src/widgets/BrowserApp.cpp @@ -7,6 +7,7 @@ #include "WindowActionRouter.hpp" #include "events/NotificationReceivedEvent.hpp" #include "events/WinCreatedEvent.hpp" +#include "schemes/NullRpcSchemeHandler.hpp" #include "widgets/BrowserWindow.hpp" #include "widgets/BrowserApp.hpp" @@ -36,7 +37,7 @@ BrowserApp::BrowserApp(Configuration &configuration) : configuration(configurati } // Initializes profile - for (auto *profile : profiles) { + for (auto *profile : profiles()) { setup_profile(profile); } @@ -52,6 +53,7 @@ void BrowserApp::setup_profile(QWebEngineProfile *profile) { WindowActionRouter::instance().dispatch_event(event); }); profile->setPersistentPermissionsPolicy(configuration.permission_persistance_policy()); + profile->installUrlSchemeHandler("nullrpc", &NullRPCSchemeHandler::instance()); } BrowserWindow *BrowserApp::create_window(const QStringList &urls) { diff --git a/src/widgets/BrowserApp.hpp b/src/widgets/BrowserApp.hpp index dcfe6f4..d29dc1b 100644 --- a/src/widgets/BrowserApp.hpp +++ b/src/widgets/BrowserApp.hpp @@ -19,7 +19,7 @@ protected: private: Configuration &configuration; QWebEngineProfile default_profile{"default"}; - QList profiles{&default_profile}; + QList profiles() { return {&default_profile}; } void setup_profile(QWebEngineProfile *profile); }; diff --git a/src/widgets/DevtoolsWindow.hpp b/src/widgets/DevtoolsWindow.hpp new file mode 100644 index 0000000..b277c89 --- /dev/null +++ b/src/widgets/DevtoolsWindow.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include +#include +#include +#include + +#include "utils.hpp" + +class DevtoolsWindow : public QMainWindow { + Q_OBJECT + +public: + DevtoolsWindow(QWebEngineProfile *profile, QWidget *parent = nullptr, + Qt::WindowFlags flags = Qt::WindowFlags()) + : QMainWindow(parent, flags) { + webengineview = new QWebEngineView(profile, this); + this->setCentralWidget(webengineview); + } + + DELEGATE(webengineview, page, page) + +signals: + void closed(); + +protected: + void closeEvent(QCloseEvent * /* event */) override { emit closed(); } + +private: + QWebEngineView *webengineview; +}; diff --git a/src/widgets/EdgeDecoration.cpp b/src/widgets/EdgeDecoration.cpp index 7f5a59f..5277e6c 100644 --- a/src/widgets/EdgeDecoration.cpp +++ b/src/widgets/EdgeDecoration.cpp @@ -4,13 +4,26 @@ #include #include +#include "LuaRuntime.hpp" #include "widgets/WebView.hpp" #include "widgets/WebViewStack.hpp" #include "widgets/EdgeDecoration.hpp" QString default_html_layout = R"HTML( - {{body}} + + + {{body}} )HTML"; EdgeDecoration::EdgeDecoration(bool vertical, QWebEngineProfile *profile, QWidget *parent) @@ -50,9 +65,14 @@ void EdgeDecoration::setup_webview() { if (!webview.has_value()) { webview = new WebView(WebViewStack::next_webview_id++, profile, this); layout()->addWidget(webview.value()); + webview.value()->enable_rpc_api(); + webview.value()->expose_rpc_function("tab_select", [](RpcArgs args) { + LuaRuntime::instance().webview_selected(args.at("view").toInt()); + }); } - webview.value()->setHtml(QString(default_html_layout).replace("{{body}}", html_content)); + webview.value()->setHtml(QString(default_html_layout).replace("{{body}}", html_content), + QUrl("nullrpc://noop")); if (vertical) webview.value()->setFixedWidth(size); else diff --git a/src/widgets/WebView.cpp b/src/widgets/WebView.cpp index 0ec2a74..604a502 100644 --- a/src/widgets/WebView.cpp +++ b/src/widgets/WebView.cpp @@ -1,7 +1,12 @@ #include +#include #include #include +#include +#include +#include "LuaRuntime.hpp" +#include "schemes/NullRpcSchemeHandler.hpp" #include "widgets/WebView.hpp" WebView::WebView(uint32_t webview_id, QWebEngineProfile *profile, QWidget *parent_node) @@ -23,10 +28,10 @@ void WebView::open_devtools() { } void WebView::scroll_increment(int deltax, int deltay) { - auto code = QString(R"((() => { + auto code = QString(R"JS((() => { const $el = document.scrollingElement; $el.scrollTo($el.scrollLeft + %1, $el.scrollTop + %2); - })())") + })())JS") .arg(deltax) .arg(deltay); @@ -34,12 +39,35 @@ void WebView::scroll_increment(int deltax, int deltay) { } void WebView::scroll_to_top() { - auto code = QString(R"(document.scrollingElement.scrollTo(0, 0))"); + auto code = QString(R"JS(document.scrollingElement.scrollTo(0, 0))JS"); page()->runJavaScript(code); } void WebView::scroll_to_bottom() { - auto code = - QString(R"(document.scrollingElement.scrollTo(0, document.scrollingElement.scrollHeight))"); + auto code = QString( + R"JS(document.scrollingElement.scrollTo(0, document.scrollingElement.scrollHeight))JS"); page()->runJavaScript(code); } + +void WebView::enable_rpc_api() { + auto &nullrpc = NullRPCSchemeHandler::instance(); + connect(&nullrpc, &NullRPCSchemeHandler::message_received, this, &WebView::on_rpc_message); +} + +void WebView::expose_rpc_function(const QString &name, const RpcFunc &action) { + exposed_functions.insert({name, action}); +} + +void WebView::on_rpc_message(const QString &action, const QUrlQuery ¶ms) { + if (!exposed_functions.contains(action)) { + qDebug() << "function not defined:" << action; + return; + } + + RpcArgs args; + for (auto pair : params.queryItems()) + args.insert(pair); + + auto func = exposed_functions.at(action); + func(args); +} diff --git a/src/widgets/WebView.hpp b/src/widgets/WebView.hpp index 0900ea6..5be9831 100644 --- a/src/widgets/WebView.hpp +++ b/src/widgets/WebView.hpp @@ -1,35 +1,22 @@ #pragma once #include +#include +#include +#include #include #include #include +#include #include +#include +#include #include "utils.hpp" +#include "widgets/DevtoolsWindow.hpp" -class DevtoolsWindow : public QMainWindow { - Q_OBJECT - -public: - DevtoolsWindow(QWebEngineProfile *profile, QWidget *parent = nullptr, - Qt::WindowFlags flags = Qt::WindowFlags()) - : QMainWindow(parent, flags) { - webengineview = new QWebEngineView(profile, this); - this->setCentralWidget(webengineview); - } - - DELEGATE(webengineview, page, page) - -signals: - void closed(); - -protected: - void closeEvent(QCloseEvent * /* event */) override { emit closed(); } - -private: - QWebEngineView *webengineview; -}; +using RpcArgs = std::unordered_map; +using RpcFunc = std::function; class WebView : public QWebEngineView { Q_OBJECT @@ -40,11 +27,15 @@ public: void scroll_increment(int deltax, int deltay); void scroll_to_top(); void scroll_to_bottom(); + void enable_rpc_api(); + void expose_rpc_function(const QString &name, const RpcFunc &action); DEFINE_GETTER(get_id, id) private: uint32_t id; - DevtoolsWindow *devtools_window = nullptr; + std::unordered_map exposed_functions; + + void on_rpc_message(const QString &action, const QUrlQuery ¶ms); }; -- cgit v1.3.1