diff options
Diffstat (limited to '')
| -rw-r--r-- | init.lua | 12 | ||||
| -rw-r--r-- | lua/null-browser/extras/tabline.lua | 3 | ||||
| -rw-r--r-- | spec/main.cpp | 2 | ||||
| -rw-r--r-- | src/main.cpp | 2 | ||||
| -rw-r--r-- | src/schemes/NullRpcSchemeHandler.hpp | 47 | ||||
| -rw-r--r-- | src/schemes/schemes.hpp | 16 | ||||
| -rw-r--r-- | src/widgets/BrowserApp.cpp | 4 | ||||
| -rw-r--r-- | src/widgets/BrowserApp.hpp | 2 | ||||
| -rw-r--r-- | src/widgets/DevtoolsWindow.hpp | 31 | ||||
| -rw-r--r-- | src/widgets/EdgeDecoration.cpp | 24 | ||||
| -rw-r--r-- | src/widgets/WebView.cpp | 38 | ||||
| -rw-r--r-- | src/widgets/WebView.hpp | 37 |
12 files changed, 179 insertions, 39 deletions
@@ -68,12 +68,12 @@ end require 'null-browser.extras.tabline'.init() -- Decorations config -web.event.add_listener('WinCreated', { - callback = function(event) - web.decorations.bottom.enable({ win = event.win_id }) - start_clock(event.win_id) - end, -}) +-- web.event.add_listener('WinCreated', { +-- callback = function(event) +-- web.decorations.bottom.enable({ win = event.win_id }) +-- start_clock(event.win_id) +-- end, +-- }) web.keymap.set('n', '<space>gg', function() if web.decorations.bottom.is_enabled({ win = 0 }) then diff --git a/lua/null-browser/extras/tabline.lua b/lua/null-browser/extras/tabline.lua index c278df5..e8edbae 100644 --- a/lua/null-browser/extras/tabline.lua +++ b/lua/null-browser/extras/tabline.lua @@ -41,7 +41,8 @@ function tabline.tabs_html() local text = index .. ': ' .. view.title .. ' (' .. view.url .. ')' local classes = 'tab' if web.view.current() == view.id then classes = classes .. ' current' end - local html = '<div class="' .. classes .. '">' .. text .. '</div>' + local onclick = '__nullbrowser.tab_select({ view: ' .. view.id .. ' })' + local html = '<div class="' .. classes .. '" onclick="' .. onclick .. '">' .. text .. '</div>' views_html = views_html .. html end diff --git a/spec/main.cpp b/spec/main.cpp index 6de21e2..83ab694 100644 --- a/spec/main.cpp +++ b/spec/main.cpp @@ -1,8 +1,10 @@ #include <QtCore> +#include "schemes/schemes.hpp" #include "testUtils.h" int main(int argc, char **argv) { + register_all_schemes(); QApplication app(argc, argv); int exit_code_app = run_app_tests(); 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 <QApplication> #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 <QWebEngineUrlRequestJob> +#include <QWebEngineUrlSchemeHandler> +#include <QtCore> +#include <qurlquery.h> + +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 <QWebEngineUrlScheme> +#include <qwebengineurlscheme.h> + +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<QWebEngineProfile *> profiles{&default_profile}; + QList<QWebEngineProfile *> 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 <QMainWindow> +#include <QWebEngineProfile> +#include <QWebEngineView> +#include <QtCore> + +#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 <qlabel.h> #include <qwebengineview.h> +#include "LuaRuntime.hpp" #include "widgets/WebView.hpp" #include "widgets/WebViewStack.hpp" #include "widgets/EdgeDecoration.hpp" QString default_html_layout = R"HTML( - {{body}} + <script> + window.__nullbrowser ||= (() => { + const invoke = (action, opts = {}) => { + const urlParams = new URLSearchParams(opts); + const url = `nullrpc://${action}?${urlParams.toString()}`; + return fetch(url).then(r => r.json().catch(_ => null)); + }; + const api = new Proxy({}, { + get: (_, action) => (options = {}) => invoke(action, options), + }); + return api; + })(); + </script> <style> :where(html, body) { margin: 0; @@ -20,6 +33,8 @@ QString default_html_layout = R"HTML( overflow: hidden; } </style> + + {{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 <QMainWindow> +#include <QWebEngineUrlRequestInterceptor> #include <QWebEngineView> #include <QtCore> +#include <qwebenginepage.h> +#include <qwebengineprofile.h> +#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 <QMainWindow> +#include <QWebEngineUrlRequestInterceptor> +#include <QWebEngineUrlRequestJob> +#include <QWebEngineUrlSchemeHandler> #include <QWebEngineView> #include <QtCore> #include <cstdint> +#include <functional> #include <qtypes.h> +#include <qurlquery.h> +#include <unordered_map> #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<QString, QVariant>; +using RpcFunc = std::function<void(RpcArgs)>; 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<QString, RpcFunc> exposed_functions; + + void on_rpc_message(const QString &action, const QUrlQuery ¶ms); }; |
