This commit is contained in:
2026-03-25 01:27:39 +01:00
parent eb4e15c66b
commit 8fe7e726a4
26 changed files with 1896 additions and 517 deletions

View File

@@ -1,6 +1,6 @@
#include "rktwebview_qt.h"
#include "webviewqt.h"
#include "rktwebview.h"
#include "rktwebview_types.h"
#include "webviewwindow.h"
#include "rktutils.h"
#include <QApplication>
@@ -29,6 +29,92 @@ static inline char *copyString(const char *s)
void Rktwebview_qt::processCommand(Command *cmd)
{
switch(cmd->cmd) {
case COMMAND_QUIT: { // Quit application
_app->quit();
}
break;
case COMMAND_NEW_CONTEXT: {
QString boilerplate_js = cmd->args[0].toString();
bool has_pem = cmd->args[1].toBool();
QString optional_server_cert_pem = cmd->args[2].toString();
fprintf(stderr, "bjs: %s\n", boilerplate_js.toUtf8().constData());
fprintf(stderr, "oscp: %s\n", optional_server_cert_pem.toUtf8().constData());
QWebEngineProfileBuilder b;
if (has_pem) {
QByteArray scp = optional_server_cert_pem.toUtf8();
fprintf(stderr, "Installing cert: %s\n", scp.constData());
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_evt_frame_el = null;\n"
"window.rkt_evt_frame_win = null;\n"
"window.rkt_send_event = function(obj) {\n"
" //console.log('Sending event: ' + obj);\n"
" window.rkt_event_queue.push(obj);\n"
" if (window.rkt_evt_frame_el) {\n"
" window.rkt_evt_frame_win.print();\n"
" }\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"
"// add hidden hover element to body if necessary\n"
"setInterval(function () {\n"
" if (window.rkt_evt_frame_el === null || window.rkt_evt_frame_el === undefined) {\n"
" window.rkt_evt_frame_el = document.createElement('iframe');\n"
" window.rkt_evt_frame_el.style.display = 'none';\n"
" window.rkt_evt_frame_el.setAttribute('id', 'rkt-evt-frame');\n"
" window.rkt_evt_frame_el.setAttribute('name', 'rkt-evt-frame');\n"
" document.body.append(window.rkt_evt_frame_el);\n"
" window.rkt_evt_frame_win = window.rkt_evt_frame_el.contentWindow;\n"
" } else {"
" if (window.rkt_event_queue.length > 0) {\n"
" window.rkt_evt_frame_win.print();\n"
" }\n"
" }\n"
"},\n"
"10);\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();
_contexts[_context_counter] = p;
cmd->result = _context_counter;
cmd->done = true;
}
break;
case COMMAND_CREATE: {
rkt_wv_context_t context = cmd->args[0].toInt();
rktwebview_t parent = cmd->args[1].toInt();
@@ -151,6 +237,7 @@ void Rktwebview_qt::processCommand(Command *cmd)
QString js = cmd->args[1].toString();
if (_views.contains(wv)) {
WebviewWindow *w = _views[wv];
fprintf(stderr, "Running %s\n", js.toUtf8().constData());
w->runJs(js);
cmd->result = true;
} else {
@@ -367,78 +454,20 @@ int Rktwebview_qt::nextHandle()
return h;
}
rkt_wv_context_t Rktwebview_qt::newContext(const char *boilerplate_js, const char *optional_server_cert_pem)
rkt_wv_context_t Rktwebview_qt::newContext(const QString &boilerplate_js, bool has_pem, const QString &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);
Command c(COMMAND_NEW_CONTEXT);
QString code = "if (window.rkt_event_queue === undefined) { window.rkt_event_queue = []; }\n"
"window.rkt_evt_frame_el = null;\n"
"window.rkt_evt_frame_win = null;\n"
"window.rkt_send_event = function(obj) {\n"
" //console.log('Sending event: ' + obj);\n"
" window.rkt_event_queue.push(obj);\n"
" if (window.rkt_evt_frame_el) {\n"
" window.rkt_evt_frame_win.print();\n"
" }\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"
"// add hidden hover element to body if necessary\n"
"setInterval(function () {\n"
" if (window.rkt_evt_frame_el === null || window.rkt_evt_frame_el === undefined) {\n"
" window.rkt_evt_frame_el = document.createElement('iframe');\n"
" window.rkt_evt_frame_el.style.display = 'none';\n"
" window.rkt_evt_frame_el.setAttribute('id', 'rkt-evt-frame');\n"
" window.rkt_evt_frame_el.setAttribute('name', 'rkt-evt-frame');\n"
" document.body.append(window.rkt_evt_frame_el);\n"
" window.rkt_evt_frame_win = window.rkt_evt_frame_el.contentWindow;\n"
" } else {"
" if (window.rkt_event_queue.length > 0) {\n"
" window.rkt_evt_frame_win.print();\n"
" }\n"
" }\n"
"},\n"
"10);\n"
"";
c.args.push_back(boilerplate_js);
c.args.push_back(has_pem);
c.args.push_back(optional_server_cert_pem);
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);
postCommand(&c);
QWebEngineScript s2;
s2.setInjectionPoint(QWebEngineScript::InjectionPoint::DocumentReady);
s2.setName("boilerplate");
s2.setSourceCode(boilerplate_js);
s2.setWorldId(QWebEngineScript::MainWorld);
scripts.append(s2);
while(!c.done) { doEvents(); }
col->insert(scripts);
QWebEngineScriptCollection *c = p->scripts();
QList<QWebEngineScript> l = c->toList();
_contexts[_context_counter] = p;
return _context_counter;
int id = c.result.toInt();
return id;
}
int Rktwebview_qt::rktWebViewCreate(rkt_wv_context_t context, rktwebview_t parent, event_cb_t js_evt_cb)
@@ -512,6 +541,8 @@ result_t Rktwebview_qt::rktSetHtml(rktwebview_t wv, const char *html)
rkt_data_t *Rktwebview_qt::rktCallJs(rktwebview_t wv, const char *js)
{
fprintf(stderr, "calljs: %s\n", js);
Command c(COMMAND_CALL_JS);
QString _js(js);
c.args.push_back(wv);
@@ -523,16 +554,17 @@ rkt_data_t *Rktwebview_qt::rktCallJs(rktwebview_t wv, const char *js)
r->kind = js_result;
r->data.js_result.result = c.js_result_ok ? result_t::oke : result_t::eval_js_failed;
r->data.js_result.value = copyString(c.result.toString().toUtf8());
fprintf(stderr, "js-result: %s\n", r->data.js_result.value);
return r;
}
result_t Rktwebview_qt::rktRunJs(rktwebview_t wv, const char *js)
result_t Rktwebview_qt::rktRunJs(rktwebview_t wv, const QString &js)
{
fprintf(stderr, "rktRunJs: %s\n", js.toUtf8().constData());
Command c(COMMAND_RUN_JS);
QString _js(js);
c.args.push_back(wv);
c.args.push_back(_js);
c.args.push_back(js);
postCommand(&c);
while(!c.done) { doEvents(); }
bool r = c.result.toBool();
@@ -604,6 +636,12 @@ window_state_t Rktwebview_qt::rktWindowState(rktwebview_t w)
return ws;
}
void Rktwebview_qt::rktQuit()
{
Command c(COMMAND_QUIT);
postCommand(&c);
}
result_t Rktwebview_qt::fileDlg(rktwebview_t w, const char *title, const char *base, const char *filters,QFileDialog::FileMode mode, QFileDialog::AcceptMode am, QString evt_ok, QString evt_cancel)
{
if (_views.contains(w)) {
@@ -836,6 +874,7 @@ void Rktwebview_qt::deleteApp()
void Rktwebview_qt::initApp()
{
_app = new QApplication(_argc, _argv);
_app->setQuitOnLastWindowClosed(false);
// See Qt 6.10 remark at doEvents.
//connect(&_evt_loop_timer, &QTimer::timeout, this, &Rktwebview_qt::stopEventloop);
@@ -843,17 +882,17 @@ void Rktwebview_qt::initApp()
// Because we are using processEvents only (Qt 6.10), we need this dispatcher to
// handle deferred Deletes.
const auto *eventDispatcher = QThread::currentThread()->eventDispatcher();
/*const auto *eventDispatcher = QThread::currentThread()->eventDispatcher();
QObject::connect(eventDispatcher, &QAbstractEventDispatcher::aboutToBlock,
QThread::currentThread(), []{
if (QThread::currentThread()->loopLevel() == 0)
QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
}
);
*/
}
void Rktwebview_qt::runJs(rktwebview_t wv, const char *js)
{
if (_views.contains(wv)) {
@@ -888,7 +927,7 @@ void Rktwebview_qt::doEvents()
//QTime ct = QTime::currentTime();
//QTime expire = QTime::currentTime().addMSecs(2);
//while(QTime::currentTime() <= expire) {
_app->processEvents();
//_app->processEvents();
//}
// Qt 6.10 --> this leads to a core dump
@@ -901,6 +940,7 @@ void Rktwebview_qt::doEvents()
//_evt_loop.exec();
_app->exec();
}*/
QThread::usleep(500);
}
void Rktwebview_qt::stopEventloop()
@@ -912,15 +952,15 @@ void Rktwebview_qt::stopEventloop()
Rktwebview_qt::Rktwebview_qt() : QObject()
Rktwebview_qt::Rktwebview_qt(int argc, char *argv[]) : QObject()
{
_argc = 1;
_argv[0] = const_cast<char *>("Rktwebview_qt");
_context_counter = 0;
_current_handle = 0;
_evt_loop_depth = 0;
_argc = argc;
_argv = argv;
_app = nullptr;
}