diff --git a/rktwebview_qt/CMakeLists.txt b/rktwebview_qt/CMakeLists.txt index 8b5d597..8f0efa6 100644 --- a/rktwebview_qt/CMakeLists.txt +++ b/rktwebview_qt/CMakeLists.txt @@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.14) project(rktwebview_qt LANGUAGES CXX) +set(QT_DEBUG_FIND_PACKAGE ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) diff --git a/rktwebview_qt/rktwebview.cpp b/rktwebview_qt/rktwebview.cpp index c1380ec..07ee3c5 100644 --- a/rktwebview_qt/rktwebview.cpp +++ b/rktwebview_qt/rktwebview.cpp @@ -4,7 +4,7 @@ #include #include #include -#include +//#include #include #include "rktwebview_qt.h" #include "webviewapp.h" @@ -18,10 +18,10 @@ uint64_t current_ms() { // Main C Interface ///////////////////////////////////////////////////////////////////// -static int pipefd[2]; -static bool started = false; -static pid_t webview_process; -static bool cannot_fork_or_pipe = false; +//static int pipefd[2]; +//static bool started = false; +//static pid_t webview_process; +//static bool cannot_fork_or_pipe = false; 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(); - return handler->rktWebViewCreate(parent); + rkt_webview_init(); + return handler->rktWebViewCreate(parent, js_event_cb); } void rkt_webview_close(int wv) { + rkt_webview_init(); handler->rktWebViewClose(wv); } result_t rkt_webview_set_url(int wv, const char *url) { + rkt_webview_init(); result_t r = handler->rktSetUrl(wv, url); return r; } @@ -151,7 +153,7 @@ void rkt_webview_process_events(int for_ms) int64_t end_ms = start_ms + for_ms; while (current_ms() < end_ms) { - usleep(500); // sleep 0.5 ms + QThread::usleep(500); // sleep 0.5 ms handler->doEvents(); } } diff --git a/rktwebview_qt/rktwebview.h b/rktwebview_qt/rktwebview.h index 61e22ec..4d43590 100644 --- a/rktwebview_qt/rktwebview.h +++ b/rktwebview_qt/rktwebview.h @@ -47,7 +47,7 @@ typedef enum { RKTWEBVIEW_QT_EXPORT void rkt_webview_init(); 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 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); diff --git a/rktwebview_qt/rktwebview_qt.cpp b/rktwebview_qt/rktwebview_qt.cpp index 62b02f3..c475862 100644 --- a/rktwebview_qt/rktwebview_qt.cpp +++ b/rktwebview_qt/rktwebview_qt.cpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include #define COMMAND_QUIT 1 #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() { - printf("COmmand processing\n"); while(!_command_queue.empty()) { Command *cmd = _command_queue.dequeue(); @@ -39,6 +47,10 @@ void Rktwebview_qt::processCommands() break; case COMMAND_CREATE: { int parent = cmd->args[0].toInt(); + + void *f = cmd->args[1].value(); + void (*js_event_cb)(const char *msg) = reinterpret_cast (f); + QWidget *p; if (_views.contains(parent)) { p = _views[parent]; @@ -53,6 +65,7 @@ void Rktwebview_qt::processCommands() int id = view->id(); _views[id] = w; + _view_js_callbacks[id] = js_event_cb; 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) @@ -115,10 +127,13 @@ int Rktwebview_qt::nextHandle() return h; } -int Rktwebview_qt::rktWebViewCreate(int parent) +int Rktwebview_qt::rktWebViewCreate(int parent, void (*js_evt_cb)(const char *)) { Command c(COMMAND_CREATE); c.args.push_back(parent); + void *function = reinterpret_cast(js_evt_cb); + QVariant f(QVariant::fromValue(function)); + c.args.push_back(f); _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; } +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() { QList keys = _views.keys(); @@ -168,13 +207,18 @@ void Rktwebview_qt::rktQuit() 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() { - //_quit_event_loop.start(2000); - //_app->exec(); - //processCommands(); _app->processEvents(); - } Rktwebview_qt::Rktwebview_qt(Rktwebview_qt **handler) : @@ -189,8 +233,7 @@ Rktwebview_qt::Rktwebview_qt(Rktwebview_qt **handler) : _app = new QApplication(_argc, _argv); connect(&_process_commands, &QTimer::timeout, this, &Rktwebview_qt::processCommands); - connect(&_quit_event_loop, &QTimer::timeout, this, &Rktwebview_qt::interruptEventLoop); - _process_commands.start(1000); + _process_commands.start(10); *_handler = nullptr; } diff --git a/rktwebview_qt/rktwebview_qt.h b/rktwebview_qt/rktwebview_qt.h index fd92878..86afa91 100644 --- a/rktwebview_qt/rktwebview_qt.h +++ b/rktwebview_qt/rktwebview_qt.h @@ -21,22 +21,21 @@ class RKTWEBVIEW_QT_EXPORT Rktwebview_qt : public QObject { Q_OBJECT private: - QApplication *_app; - rktwebview_t _current_handle; - QHash _views; + QApplication *_app; + rktwebview_t _current_handle; + QHash _views; + QHash _view_js_callbacks; - QQueue _command_queue; - QTimer _process_commands; - QTimer _quit_event_loop; + QQueue _command_queue; + QTimer _process_commands; - Rktwebview_qt **_handler; + Rktwebview_qt **_handler; int _argc; char *_argv[1]; public slots: void processCommands(); - void interruptEventLoop(); public: void removeView(int id); @@ -44,17 +43,24 @@ public: public: int nextHandle(); public: - int rktWebViewCreate(int parent = 0); // threadsafe + int rktWebViewCreate(int parent, void(*js_evt_cb)(const char *msg)); void rktWebViewClose(int wv); void rktQuit(); - void runJs(rktwebview_t wv, const char *js); // threadsafe - item_t callJs(rktwebview_t wv, const char *js); // threadsafe + void runJs(rktwebview_t wv, const char *js); + item_t callJs(rktwebview_t wv, const char *js); - void setHtml(rktwebview_t wv, const char *html); // threadsafe - void navigate(rktwebview_t wv, const char *url); // threadsafe + void setHtml(rktwebview_t wv, const char *html); + void navigate(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: void doEvents(); diff --git a/rktwebview_qt/webviewqt.cpp b/rktwebview_qt/webviewqt.cpp index d7a0a89..b3357c8 100644 --- a/rktwebview_qt/webviewqt.cpp +++ b/rktwebview_qt/webviewqt.cpp @@ -1,4 +1,6 @@ #include "webviewqt.h" +#include +#include WebViewQt::WebViewQt(int id, QWidget *parent) : QWebEngineView(parent) @@ -11,9 +13,8 @@ int WebViewQt::id() const return _id; } -void WebViewQt::runJs(const char *js) +QString WebViewQt::runJs(const QString &js) { - } diff --git a/rktwebview_qt/webviewqt.h b/rktwebview_qt/webviewqt.h index 8e65c3f..d979396 100644 --- a/rktwebview_qt/webviewqt.h +++ b/rktwebview_qt/webviewqt.h @@ -2,17 +2,23 @@ #define WEBVIEWQT_H #include +#include class WebViewQt : public QWebEngineView { + Q_OBJECT private: - int _id; + int _id; public: int id() const; public: - void runJs(const char *js); + QString runJs(const QString &js); + +signals: + void pageLoaded(WebViewQt *, bool ok); + public: WebViewQt(int id, QWidget *parent = nullptr); diff --git a/rktwebview_qt/webviewwindow.cpp b/rktwebview_qt/webviewwindow.cpp index d97e9a7..18cf159 100644 --- a/rktwebview_qt/webviewwindow.cpp +++ b/rktwebview_qt/webviewwindow.cpp @@ -2,6 +2,32 @@ #include "webviewqt.h" #include "rktwebview_qt.h" +#include +#include +#include +#include + +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) { @@ -13,6 +39,11 @@ void WebviewWindow::addView(WebViewQt *v, Rktwebview_qt *c) _container = c; _view = v; this->setCentralWidget(v); + + QWebEnginePage *page = _view->page(); + connect(page, &QWebEnginePage::loadFinished, this, [this](bool ok) { + _container->pageLoaded(_view->id(), ok); + }); } WebViewQt *WebviewWindow::view() @@ -24,4 +55,5 @@ WebviewWindow::WebviewWindow(QWidget *parent) : QMainWindow{parent} { _view = nullptr; + connect(&_process_js_events, &QTimer::timeout, this, &WebviewWindow::processJsEvents); } diff --git a/rktwebview_qt/webviewwindow.h b/rktwebview_qt/webviewwindow.h index c54797f..8b91411 100644 --- a/rktwebview_qt/webviewwindow.h +++ b/rktwebview_qt/webviewwindow.h @@ -2,6 +2,7 @@ #define WEBVIEWWINDOW_H #include +#include class WebViewQt; class Rktwebview_qt; @@ -10,8 +11,12 @@ class WebviewWindow : public QMainWindow { Q_OBJECT private: - Rktwebview_qt *_container; - WebViewQt *_view; + Rktwebview_qt *_container; + WebViewQt *_view; + QTimer _process_js_events; + +public slots: + void processJsEvents(); protected: void closeEvent(QCloseEvent *evt);