Better profile support, only 1 web server per context, multiple windows per context

This commit is contained in:
2026-03-12 00:23:27 +01:00
parent 7d234bc834
commit d99c5a1725
13 changed files with 314 additions and 168 deletions

View File

@@ -9,6 +9,10 @@
#include <QJsonDocument>
#include <QJsonObject>
#include <QAbstractEventDispatcher>
#include <QWebEngineProfile>
#include <QWebEngineProfileBuilder>
#include <QWebEngineScriptCollection>
#include <QWebEngineScript>
#include "command.h"
#include <QFileDialog>
@@ -29,14 +33,12 @@ void Rktwebview_qt::processCommand(Command *cmd)
}
break;
case COMMAND_CREATE: {
int parent = cmd->args[0].toInt();
rkt_wv_context_t context = cmd->args[0].toInt();
rktwebview_t parent = cmd->args[1].toInt();
void *f = cmd->args[1].value<void *>();
void *f = cmd->args[2].value<void *>();
event_cb_t js_event_cb = reinterpret_cast <event_cb_t>(f);
bool has_scp = cmd->args[2].toBool();
QByteArray scp_pem = cmd->args[3].toByteArray();
WebviewWindow *p;
if (_views.contains(parent)) {
p = _views[parent];
@@ -44,22 +46,28 @@ void Rktwebview_qt::processCommand(Command *cmd)
p = nullptr;
}
WebviewWindow *w = new WebviewWindow(p, has_scp, scp_pem);
WebViewQt *view = new WebViewQt(nextHandle(), w);
w->addView(view, this);
if (!_contexts.contains(context)) {
cmd->result = -1;
cmd->done = true;
} else {
QWebEngineProfile *profile = _contexts[context];
WebviewWindow *w = new WebviewWindow(profile, p);
WebViewQt *view = new WebViewQt(nextHandle(), w);
w->addView(view, this);
int id = view->id();
int id = view->id();
_views[id] = w;
_view_js_callbacks[id] = js_event_cb;
_views[id] = w;
_view_js_callbacks[id] = js_event_cb;
w->show();
while(!w->windowCreated()) {
doEvents();
w->show();
while(!w->windowCreated()) {
doEvents();
}
cmd->result = id;
cmd->done = true;
}
cmd->result = id;
cmd->done = true;
}
break;
case COMMAND_CLOSE: {
@@ -370,17 +378,68 @@ int Rktwebview_qt::nextHandle()
return h;
}
int Rktwebview_qt::rktWebViewCreate(int parent, event_cb_t js_evt_cb, const char *optional_server_cert_pem)
rkt_wv_context_t Rktwebview_qt::newContext(const char *boilerplate_js, const char *optional_server_cert_pem)
{
QWebEngineProfileBuilder b;
if (optional_server_cert_pem != nullptr) {
QByteArray scp = QByteArray(optional_server_cert_pem);
QList<QSslCertificate> certs;
QSslCertificate cert(scp);
certs.append(cert);
b.setAdditionalTrustedCertificates(certs);
}
_context_counter += 1;
QString name = QString::asprintf("profile-%d", _context_counter);
QString code = "if (window.rkt_event_queue === undefined) { window.rkt_event_queue = []; }\n"
"window.rkt_send_event = function(obj) {\n"
" console.log('Sending event: ' + obj);\n"
" window.rkt_event_queue.push(obj);\n"
"};\n"
"window.rkt_get_events = function() {\n"
" let q = window.rkt_event_queue;\n"
" window.rkt_event_queue = [];\n"
" let json_q = JSON.stringify(q);\n"
" return json_q;\n"
"};\n"
"";
QList<QWebEngineScript> scripts;
QWebEngineProfile *p = b.createProfile(name);
QWebEngineScriptCollection *col = p->scripts();
QWebEngineScript s1;
s1.setInjectionPoint(QWebEngineScript::InjectionPoint::DocumentReady);
s1.setName("eventing");
s1.setSourceCode(code);
s1.setWorldId(QWebEngineScript::MainWorld);
scripts.append(s1);
QWebEngineScript s2;
s2.setInjectionPoint(QWebEngineScript::InjectionPoint::DocumentReady);
s2.setName("boilerplate");
s2.setSourceCode(boilerplate_js);
s2.setWorldId(QWebEngineScript::MainWorld);
scripts.append(s2);
col->insert(scripts);
QWebEngineScriptCollection *c = p->scripts();
QList<QWebEngineScript> l = c->toList();
printf("%d\n", l.size());
_contexts[_context_counter] = p;
return _context_counter;
}
int Rktwebview_qt::rktWebViewCreate(rkt_wv_context_t context, rktwebview_t parent, event_cb_t js_evt_cb)
{
Command c(COMMAND_CREATE);
c.args.push_back(context);
c.args.push_back(parent);
void *function = reinterpret_cast<void *>(js_evt_cb);
QVariant f(QVariant::fromValue(function));
c.args.push_back(f);
bool has_scp = (optional_server_cert_pem != nullptr);
c.args.push_back(has_scp);
QByteArray scp = (optional_server_cert_pem == nullptr) ? QByteArray("") : QByteArray(optional_server_cert_pem);
c.args.push_back(scp);
postCommand(&c);
@@ -659,7 +718,7 @@ void Rktwebview_qt::onPageLoad(rktwebview_t w)
void Rktwebview_qt::pageLoaded(rktwebview_t w, bool ok)
{
runJs(w,
/*runJs(w,
"if (window.rkt_event_queue === undefined) { window.rkt_event_queue = []; }\n"
"window.rkt_send_event = function(obj) {\n"
" console.log('Sending event: ' + obj);\n"
@@ -672,6 +731,20 @@ void Rktwebview_qt::pageLoaded(rktwebview_t w, bool ok)
" return json_q;\n"
"};\n"
);
*/
if (!ok) {
// Inject code of the profile to this page
WebviewWindow *win = _views[w];
QWebEngineProfile *p = win->profile();
QWebEngineScriptCollection *col = p->scripts();
QList<QWebEngineScript> l = col->toList();
int i;
for(i = 0; i < l.size(); i++) {
runJs(w, l[i].sourceCode().toUtf8().constData());
}
}
// trigger page loaded.
EventContainer e("page-loaded");
@@ -775,6 +848,8 @@ Rktwebview_qt::Rktwebview_qt(Rktwebview_qt **handler) :
_argc = 1;
_argv[0] = const_cast<char *>("Rktwebview_qt");
_context_counter = 0;
_current_handle = 0;
_handler = handler;
@@ -800,3 +875,19 @@ Rktwebview_qt::Rktwebview_qt(Rktwebview_qt **handler) :
*_handler = nullptr;
}
Rktwebview_qt::~Rktwebview_qt()
{
QList<int> win_keys = _views.keys();
int i, N;
for(i = 0, N = win_keys.size(); i < N; i++) {
WebviewWindow *w = _views[win_keys[i]];
delete w;
}
QList<int> c_keys = _contexts.keys();
for(i = 0, N = c_keys.size(); i < N; i++) {
QWebEngineProfile *p = _contexts[c_keys[i]];
delete p;
}
}