This commit is contained in:
2026-03-03 09:39:15 +01:00
parent 769d5681d4
commit 35aae3b707
9 changed files with 136 additions and 40 deletions

View File

@@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.14)
project(rktwebview_qt LANGUAGES CXX) project(rktwebview_qt LANGUAGES CXX)
set(QT_DEBUG_FIND_PACKAGE ON)
set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON) set(CMAKE_AUTORCC ON)

View File

@@ -4,7 +4,7 @@
#include <string.h> #include <string.h>
#include <chrono> #include <chrono>
#include <stdint.h> #include <stdint.h>
#include <unistd.h> //#include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include "rktwebview_qt.h" #include "rktwebview_qt.h"
#include "webviewapp.h" #include "webviewapp.h"
@@ -18,10 +18,10 @@ uint64_t current_ms() {
// Main C Interface // Main C Interface
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
static int pipefd[2]; //static int pipefd[2];
static bool started = false; //static bool started = false;
static pid_t webview_process; //static pid_t webview_process;
static bool cannot_fork_or_pipe = false; //static bool cannot_fork_or_pipe = false;
Rktwebview_qt *handler = nullptr; Rktwebview_qt *handler = nullptr;
@@ -51,19 +51,21 @@ void rkt_webview_init()
} }
} }
int rkt_webview_create(int parent) int rkt_webview_create(int parent, void (*js_event_cb)(const char *))
{ {
//rkt_webview_init(); rkt_webview_init();
return handler->rktWebViewCreate(parent); return handler->rktWebViewCreate(parent, js_event_cb);
} }
void rkt_webview_close(int wv) void rkt_webview_close(int wv)
{ {
rkt_webview_init();
handler->rktWebViewClose(wv); handler->rktWebViewClose(wv);
} }
result_t rkt_webview_set_url(int wv, const char *url) result_t rkt_webview_set_url(int wv, const char *url)
{ {
rkt_webview_init();
result_t r = handler->rktSetUrl(wv, url); result_t r = handler->rktSetUrl(wv, url);
return r; return r;
} }
@@ -151,7 +153,7 @@ void rkt_webview_process_events(int for_ms)
int64_t end_ms = start_ms + for_ms; int64_t end_ms = start_ms + for_ms;
while (current_ms() < end_ms) { while (current_ms() < end_ms) {
usleep(500); // sleep 0.5 ms QThread::usleep(500); // sleep 0.5 ms
handler->doEvents(); handler->doEvents();
} }
} }

View File

@@ -47,7 +47,7 @@ typedef enum {
RKTWEBVIEW_QT_EXPORT void rkt_webview_init(); RKTWEBVIEW_QT_EXPORT void rkt_webview_init();
RKTWEBVIEW_QT_EXPORT void rkt_webview_process_events(int for_ms); RKTWEBVIEW_QT_EXPORT void rkt_webview_process_events(int for_ms);
RKTWEBVIEW_QT_EXPORT int rkt_webview_create(int parent); RKTWEBVIEW_QT_EXPORT int rkt_webview_create(int parent, void (*js_event_cb)(const char *msg));
RKTWEBVIEW_QT_EXPORT void rkt_webview_close(int wv); RKTWEBVIEW_QT_EXPORT void rkt_webview_close(int wv);
RKTWEBVIEW_QT_EXPORT result_t rkt_webview_set_url(int wv, const char *url); RKTWEBVIEW_QT_EXPORT result_t rkt_webview_set_url(int wv, const char *url);
RKTWEBVIEW_QT_EXPORT result_t rkt_webview_set_html(int wv, const char *html); RKTWEBVIEW_QT_EXPORT result_t rkt_webview_set_html(int wv, const char *html);

View File

@@ -5,6 +5,8 @@
#include <QApplication> #include <QApplication>
#include <QTimer> #include <QTimer>
#include <QSemaphore> #include <QSemaphore>
#include <QJsonDocument>
#include <QJsonObject>
#define COMMAND_QUIT 1 #define COMMAND_QUIT 1
#define COMMAND_CLOSE 2 #define COMMAND_CLOSE 2
@@ -25,9 +27,15 @@ public:
} }
}; };
static QString jsonString(QJsonObject obj)
{
QJsonDocument doc(obj);
QString j = QString::fromUtf8(doc.toJson(QJsonDocument::JsonFormat::Compact));
return j;
}
void Rktwebview_qt::processCommands() void Rktwebview_qt::processCommands()
{ {
printf("COmmand processing\n");
while(!_command_queue.empty()) { while(!_command_queue.empty()) {
Command *cmd = _command_queue.dequeue(); Command *cmd = _command_queue.dequeue();
@@ -39,6 +47,10 @@ void Rktwebview_qt::processCommands()
break; break;
case COMMAND_CREATE: { case COMMAND_CREATE: {
int parent = cmd->args[0].toInt(); int parent = cmd->args[0].toInt();
void *f = cmd->args[1].value<void *>();
void (*js_event_cb)(const char *msg) = reinterpret_cast <void(*)(const char *)>(f);
QWidget *p; QWidget *p;
if (_views.contains(parent)) { if (_views.contains(parent)) {
p = _views[parent]; p = _views[parent];
@@ -53,6 +65,7 @@ void Rktwebview_qt::processCommands()
int id = view->id(); int id = view->id();
_views[id] = w; _views[id] = w;
_view_js_callbacks[id] = js_event_cb;
w->show(); w->show();
@@ -98,10 +111,9 @@ void Rktwebview_qt::processCommands()
} }
} }
void Rktwebview_qt::interruptEventLoop() void Rktwebview_qt::processJsEventQueue()
{ {
printf("Exeting application event loop\n");
//_app->quit();
} }
void Rktwebview_qt::removeView(int id) void Rktwebview_qt::removeView(int id)
@@ -115,10 +127,13 @@ int Rktwebview_qt::nextHandle()
return h; return h;
} }
int Rktwebview_qt::rktWebViewCreate(int parent) int Rktwebview_qt::rktWebViewCreate(int parent, void (*js_evt_cb)(const char *))
{ {
Command c(COMMAND_CREATE); Command c(COMMAND_CREATE);
c.args.push_back(parent); c.args.push_back(parent);
void *function = reinterpret_cast<void *>(js_evt_cb);
QVariant f(QVariant::fromValue(function));
c.args.push_back(f);
_command_queue.enqueue(&c); _command_queue.enqueue(&c);
@@ -153,6 +168,30 @@ result_t Rktwebview_qt::rktSetUrl(rktwebview_t wv, const char *url)
return r ? result_t::oke : result_t::set_navigate_failed; return r ? result_t::oke : result_t::set_navigate_failed;
} }
void Rktwebview_qt::pageLoaded(rktwebview_t w, bool ok)
{
// Inject event handling code for the javascript side
runJs(w, "window.rkt_event_queue = [];\n"
"window.rkt_send_event = function(obj) { window.rkt_event_queue.push(obj); };\n"
"window.rkt_get_events = function() { "
" let q = window.rkt_event_queue; "
" window.rkt_event_queue = [];"
" let json_q = JSON.stringify(q);"
" return json_q;"
"};");
// trigger page loaded.
QJsonObject obj;
obj["event"] = "page-loaded";
obj["oke"] = ok;
triggerEvent(w, jsonString(obj));
}
void Rktwebview_qt::triggerEvent(rktwebview_t wv, const QString &msg)
{
}
void Rktwebview_qt::rktQuit() void Rktwebview_qt::rktQuit()
{ {
QList<int> keys = _views.keys(); QList<int> keys = _views.keys();
@@ -168,13 +207,18 @@ void Rktwebview_qt::rktQuit()
while(!c.done) { doEvents(); } while(!c.done) { doEvents(); }
} }
void Rktwebview_qt::runJs(rktwebview_t wv, const char *js)
{
if (_views.contains(wv)) {
QString _js(js);
WebViewQt *view = _views[wv]->view();
view->runJs(_js);
}
}
void Rktwebview_qt::doEvents() void Rktwebview_qt::doEvents()
{ {
//_quit_event_loop.start(2000);
//_app->exec();
//processCommands();
_app->processEvents(); _app->processEvents();
} }
Rktwebview_qt::Rktwebview_qt(Rktwebview_qt **handler) : Rktwebview_qt::Rktwebview_qt(Rktwebview_qt **handler) :
@@ -189,8 +233,7 @@ Rktwebview_qt::Rktwebview_qt(Rktwebview_qt **handler) :
_app = new QApplication(_argc, _argv); _app = new QApplication(_argc, _argv);
connect(&_process_commands, &QTimer::timeout, this, &Rktwebview_qt::processCommands); connect(&_process_commands, &QTimer::timeout, this, &Rktwebview_qt::processCommands);
connect(&_quit_event_loop, &QTimer::timeout, this, &Rktwebview_qt::interruptEventLoop); _process_commands.start(10);
_process_commands.start(1000);
*_handler = nullptr; *_handler = nullptr;
} }

View File

@@ -21,22 +21,21 @@ class RKTWEBVIEW_QT_EXPORT Rktwebview_qt : public QObject
{ {
Q_OBJECT Q_OBJECT
private: private:
QApplication *_app; QApplication *_app;
rktwebview_t _current_handle; rktwebview_t _current_handle;
QHash<int, WebviewWindow *> _views; QHash<int, WebviewWindow *> _views;
QHash<int, void(*)(const char *msg)> _view_js_callbacks;
QQueue<Command *> _command_queue; QQueue<Command *> _command_queue;
QTimer _process_commands; QTimer _process_commands;
QTimer _quit_event_loop;
Rktwebview_qt **_handler; Rktwebview_qt **_handler;
int _argc; int _argc;
char *_argv[1]; char *_argv[1];
public slots: public slots:
void processCommands(); void processCommands();
void interruptEventLoop();
public: public:
void removeView(int id); void removeView(int id);
@@ -44,17 +43,24 @@ public:
public: public:
int nextHandle(); int nextHandle();
public: public:
int rktWebViewCreate(int parent = 0); // threadsafe int rktWebViewCreate(int parent, void(*js_evt_cb)(const char *msg));
void rktWebViewClose(int wv); void rktWebViewClose(int wv);
void rktQuit(); void rktQuit();
void runJs(rktwebview_t wv, const char *js); // threadsafe void runJs(rktwebview_t wv, const char *js);
item_t callJs(rktwebview_t wv, const char *js); // threadsafe item_t callJs(rktwebview_t wv, const char *js);
void setHtml(rktwebview_t wv, const char *html); // threadsafe void setHtml(rktwebview_t wv, const char *html);
void navigate(rktwebview_t wv, const char *url); // threadsafe void navigate(rktwebview_t wv, const char *url);
result_t rktSetUrl(rktwebview_t wv, const char *url); result_t rktSetUrl(rktwebview_t wv, const char *url);
public:
// Events for the backend
void pageLoaded(rktwebview_t w, bool ok);
public:
void triggerEvent(rktwebview_t wv, const QString &msg);
public: public:
void doEvents(); void doEvents();

View File

@@ -1,4 +1,6 @@
#include "webviewqt.h" #include "webviewqt.h"
#include <QWebEnginePage>
#include <QJsonDocument>
WebViewQt::WebViewQt(int id, QWidget *parent) WebViewQt::WebViewQt(int id, QWidget *parent)
: QWebEngineView(parent) : QWebEngineView(parent)
@@ -11,9 +13,8 @@ int WebViewQt::id() const
return _id; return _id;
} }
void WebViewQt::runJs(const char *js) QString WebViewQt::runJs(const QString &js)
{ {
} }

View File

@@ -2,17 +2,23 @@
#define WEBVIEWQT_H #define WEBVIEWQT_H
#include <QWebEngineView> #include <QWebEngineView>
#include <QTimer>
class WebViewQt : public QWebEngineView class WebViewQt : public QWebEngineView
{ {
Q_OBJECT
private: private:
int _id; int _id;
public: public:
int id() const; int id() const;
public: public:
void runJs(const char *js); QString runJs(const QString &js);
signals:
void pageLoaded(WebViewQt *, bool ok);
public: public:
WebViewQt(int id, QWidget *parent = nullptr); WebViewQt(int id, QWidget *parent = nullptr);

View File

@@ -2,6 +2,32 @@
#include "webviewqt.h" #include "webviewqt.h"
#include "rktwebview_qt.h" #include "rktwebview_qt.h"
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonParseError>
#include <QJsonObject>
void WebviewWindow::processJsEvents()
{
QWebEnginePage *p = _view->page();
p->runJavaScript("window.getPendingEvents();",
[this](const QVariant &v) {
QString s = v.toString();
QJsonParseError err;
QJsonDocument doc(QJsonDocument::fromJson(s.toUtf8(), &err));
if (err.error == QJsonParseError::NoError) {
QJsonArray a = doc.array();
int i, N;
for(i = 0, N = a.size(); i < N; i++) {
QJsonObject evt = a[i].toObject();
QJsonDocument doc_out(evt);
QString msg = doc_out.toJson(QJsonDocument::JsonFormat::Compact);
this->_container->triggerJsEvent(_view->id(), msg);
}
}
}
);
}
void WebviewWindow::closeEvent(QCloseEvent *evt) void WebviewWindow::closeEvent(QCloseEvent *evt)
{ {
@@ -13,6 +39,11 @@ void WebviewWindow::addView(WebViewQt *v, Rktwebview_qt *c)
_container = c; _container = c;
_view = v; _view = v;
this->setCentralWidget(v); this->setCentralWidget(v);
QWebEnginePage *page = _view->page();
connect(page, &QWebEnginePage::loadFinished, this, [this](bool ok) {
_container->pageLoaded(_view->id(), ok);
});
} }
WebViewQt *WebviewWindow::view() WebViewQt *WebviewWindow::view()
@@ -24,4 +55,5 @@ WebviewWindow::WebviewWindow(QWidget *parent)
: QMainWindow{parent} : QMainWindow{parent}
{ {
_view = nullptr; _view = nullptr;
connect(&_process_js_events, &QTimer::timeout, this, &WebviewWindow::processJsEvents);
} }

View File

@@ -2,6 +2,7 @@
#define WEBVIEWWINDOW_H #define WEBVIEWWINDOW_H
#include <QMainWindow> #include <QMainWindow>
#include <QTimer>
class WebViewQt; class WebViewQt;
class Rktwebview_qt; class Rktwebview_qt;
@@ -10,8 +11,12 @@ class WebviewWindow : public QMainWindow
{ {
Q_OBJECT Q_OBJECT
private: private:
Rktwebview_qt *_container; Rktwebview_qt *_container;
WebViewQt *_view; WebViewQt *_view;
QTimer _process_js_events;
public slots:
void processJsEvents();
protected: protected:
void closeEvent(QCloseEvent *evt); void closeEvent(QCloseEvent *evt);