#include "rktwebview_qt.h" #include "webviewqt.h" #include "rktwebview.h" #include "webviewwindow.h" #include "rktutils.h" #include #include #include #include #include #include #define COMMAND_QUIT 1 #define COMMAND_CLOSE 2 #define COMMAND_CREATE 3 #define COMMAND_SET_URL 4 #define COMMAND_SET_HTML 5 #define COMMAND_RUN_JS 6 #define COMMAND_DEV_TOOLS 7 #define COMMAND_MOVE 8 #define COMMAND_RESIZE 9 #define COMMAND_CALL_JS 10 #define COMMAND_HIDE_WIN 11 #define COMMAND_SHOW_WIN 12 #define COMMAND_MAX_WIN 13 #define COMMAND_MIN_WIN 14 #define COMMAND_PRESENT_WIN 15 #define COMMAND_SHOW_NORMAL_WIN 16 #define COMMAND_WINDOW_STATUS 17 #define COMMAND_SET_TITLE 18 void Rktwebview_qt::processCommands() { while(!_command_queue.empty()) { Command *cmd = _command_queue.dequeue(); switch(cmd->cmd) { case COMMAND_QUIT: { _app->quit(); cmd->done = true; } break; case COMMAND_CREATE: { int parent = cmd->args[0].toInt(); void *f = cmd->args[1].value(); event_cb_t js_event_cb = reinterpret_cast (f); QWidget *p; if (_views.contains(parent)) { p = _views[parent]; } else { p = nullptr; } WebviewWindow *w = new WebviewWindow(p); WebViewQt *view = new WebViewQt(nextHandle(), w); w->addView(view, this); int id = view->id(); _views[id] = w; _view_js_callbacks[id] = js_event_cb; w->show(); while(!w->windowCreated()) { doEvents(); } cmd->result = id; cmd->done = true; } break; case COMMAND_CLOSE: { doEvents(); int wv = cmd->args[0].toInt(); if (_views.contains(wv)) { WebviewWindow *w= _views[wv]; _views.remove(wv); w->closeView(); cmd->result = true; } else { cmd->result = false; } cmd->done = true; } break; case COMMAND_SET_URL: { doEvents(); int wv = cmd->args[0].toInt(); QString url = cmd->args[1].toString(); if (_views.contains(wv)) { WebviewWindow *w = _views[wv]; WebViewQt *v = w->view(); QUrl u(url); v->setUrl(u); cmd->result = true; } else { cmd->result = false; } cmd->done = true; } break; case COMMAND_SET_HTML: { doEvents(); int wv = cmd->args[0].toInt(); QString html = cmd->args[1].toString(); if (_views.contains(wv)) { WebviewWindow *w = _views[wv]; WebViewQt *v = w->view(); v->setHtml(html); cmd->result = true; } else { cmd->result = false; } cmd->done = true; } break; case COMMAND_SET_TITLE: { doEvents(); int wv = cmd->args[0].toInt(); QString title = cmd->args[1].toString(); if (_views.contains(wv)) { WebviewWindow *w = _views[wv]; w->setWindowTitle(title); cmd->result = true; } else { cmd->result = false; } cmd->done = true; } break; case COMMAND_RUN_JS: { doEvents(); int wv = cmd->args[0].toInt(); QString js = cmd->args[1].toString(); if (_views.contains(wv)) { WebviewWindow *w = _views[wv]; w->runJs(js); cmd->result = true; } else { cmd->result = false; } cmd->done = true; } break; case COMMAND_CALL_JS: { doEvents(); int wv = cmd->args[0].toInt(); QString js = cmd->args[1].toString(); if (_views.contains(wv)) { WebviewWindow *w = _views[wv]; w->callJs(js, cmd); } else { cmd->result = false; cmd->js_result_ok = false; cmd->done = true; } } break; case COMMAND_DEV_TOOLS: { doEvents(); int wv = cmd->args[0].toInt(); if (_views.contains(wv)) { WebviewWindow *w = _views[wv]; w->openDevTools(); cmd->result = true; } else { cmd->result = false; } cmd->done = true; } break; case COMMAND_SHOW_WIN: case COMMAND_HIDE_WIN: case COMMAND_PRESENT_WIN: case COMMAND_MAX_WIN: case COMMAND_MIN_WIN: case COMMAND_SHOW_NORMAL_WIN: { doEvents(); int wv = cmd->args[0].toInt(); if (_views.contains(wv)) { WebviewWindow *w = _views[wv]; int c = cmd->cmd; if (c == COMMAND_SHOW_WIN) w->show(); else if (c == COMMAND_HIDE_WIN) w->hide(); else if (c == COMMAND_MAX_WIN) w->showMaximized(); else if (c == COMMAND_MIN_WIN) { w->showMinimized(); } else if (c == COMMAND_SHOW_NORMAL_WIN) w->showNormal(); else if (c == COMMAND_PRESENT_WIN) { w->show(); w->raise(); w->activateWindow(); } cmd->result = true; } else { cmd->result = false; } cmd->done = true; } break; case COMMAND_WINDOW_STATUS: { doEvents(); int wv = cmd->args[0].toInt(); window_state_t ws = window_state_t::invalid; if (_views.contains(wv)) { WebviewWindow *w = _views[wv]; if (w->isHidden()) { ws = window_state_t::hidden; } else if (w->isMinimized()) { ws = window_state_t::minimized; } else if (w->isMaximized()) { if (w->isActiveWindow()) { ws = window_state_t::maximized_active; } else { ws = window_state_t::maximized; } } else if (w->isVisible()) { if (w->isActiveWindow()) { ws = window_state_t::normal_active; } else { ws = window_state_t::normal; } } } cmd->result = static_cast(ws); cmd->done = true; } break; case COMMAND_MOVE: { doEvents(); int wv = cmd->args[0].toInt(); int x = cmd->args[1].toInt(); int y = cmd->args[2].toInt(); if (_views.contains(wv)) { WebviewWindow *w = _views[wv]; int move_count = w->moveCount(); w->move(x, y); while (w->moveCount() == move_count) { doEvents(); } cmd->result = true; } else { cmd->result = false; } cmd->done = true; } break; case COMMAND_RESIZE: { doEvents(); int wv = cmd->args[0].toInt(); int width = cmd->args[1].toInt(); int height = cmd->args[2].toInt(); if (_views.contains(wv)) { WebviewWindow *w = _views[wv]; int resize_count = w->resizeCount(); w->resize(width, height); while (w->resizeCount() == resize_count) { doEvents(); } cmd->result = true; } else { cmd->result = false; } cmd->done = true; } break; default: { cmd->result = false; cmd->done = true; } break; } } } void Rktwebview_qt::processJsEventQueues() { QList wvs = _views.keys(); int i, N; for(i = 0, N = wvs.length(); i < N; i++) { int wv = wvs[i]; if (_views.contains(wv)) { WebviewWindow *win = _views[wv]; win->processJsEvents(); } } } void Rktwebview_qt::removeView(int id) { if (_views.contains(id)) { WebviewWindow *win = _views[id]; _views.remove(id); _view_js_callbacks.remove(id); } } int Rktwebview_qt::nextHandle() { int h = ++_current_handle; return h; } int Rktwebview_qt::rktWebViewCreate(int parent, event_cb_t js_evt_cb) { 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); while(!c.done) { doEvents(); } int id = c.result.toInt(); return id; } void Rktwebview_qt::rktWebViewClose(int wv) { Command c(COMMAND_CLOSE); c.args.push_back(wv); _command_queue.enqueue(&c); while(!c.done) { doEvents(); } } result_t Rktwebview_qt::rktSetUrl(rktwebview_t wv, const char *url) { Command c(COMMAND_SET_URL); QString _url(url); c.args.push_back(wv); c.args.push_back(_url); _command_queue.enqueue(&c); while(!c.done) { doEvents(); } bool r = c.result.toBool(); return r ? result_t::oke : result_t::set_navigate_failed; } result_t Rktwebview_qt::rktSetHtml(rktwebview_t wv, const char *html) { Command c(COMMAND_SET_HTML); QString _html(html); c.args.push_back(wv); c.args.push_back(_html); _command_queue.enqueue(&c); while(!c.done) { doEvents(); } bool r = c.result.toBool(); return r ? result_t::oke : result_t::set_navigate_failed; } rkt_js_result_t *Rktwebview_qt::rktCallJs(rktwebview_t wv, const char *js) { Command c(COMMAND_CALL_JS); QString _js(js); c.args.push_back(wv); c.args.push_back(_js); _command_queue.enqueue(&c); while(!c.done) { doEvents(); } rkt_js_result_t *r = static_cast(malloc(sizeof(rkt_js_result_t))); r->result = c.js_result_ok ? result_t::oke : result_t::eval_js_failed; r->value = strdup(c.result.toString().toUtf8()); return r; } result_t Rktwebview_qt::rktRunJs(rktwebview_t wv, const char *js) { Command c(COMMAND_RUN_JS); QString _js(js); c.args.push_back(wv); c.args.push_back(_js); _command_queue.enqueue(&c); while(!c.done) { doEvents(); } bool r = c.result.toBool(); return r ? result_t::oke : result_t::eval_js_failed; } result_t Rktwebview_qt::rktMove(rktwebview_t wv, int x, int y) { Command c(COMMAND_MOVE); c.args.push_back(wv); c.args.push_back(x); c.args.push_back(y); _command_queue.enqueue(&c); while(!c.done) { doEvents(); } bool r = c.result.toBool(); return r ? result_t::oke : result_t::move_failed; } result_t Rktwebview_qt::rktResize(rktwebview_t wv, int w, int h) { Command c(COMMAND_RESIZE); c.args.push_back(wv); c.args.push_back(w); c.args.push_back(h); _command_queue.enqueue(&c); while(!c.done) { doEvents(); } bool r = c.result.toBool(); return r ? result_t::oke : result_t::resize_failed; } result_t Rktwebview_qt::rktHideWindow(rktwebview_t w) { return doWindow(w, COMMAND_HIDE_WIN); } result_t Rktwebview_qt::rktShowWindow(rktwebview_t w) { return doWindow(w, COMMAND_SHOW_WIN); } result_t Rktwebview_qt::rktPresentWindow(rktwebview_t w) { return doWindow(w, COMMAND_PRESENT_WIN); } result_t Rktwebview_qt::rktMaximizeWindow(rktwebview_t w) { return doWindow(w, COMMAND_MAX_WIN); } result_t Rktwebview_qt::rktMinimizeWindow(rktwebview_t w) { return doWindow(w, COMMAND_MIN_WIN); } result_t Rktwebview_qt::rktShowNormalWindow(rktwebview_t w) { return doWindow(w, COMMAND_SHOW_NORMAL_WIN); } window_state_t Rktwebview_qt::rktWindowState(rktwebview_t w) { Command c(COMMAND_WINDOW_STATUS); c.args.push_back(w); _command_queue.enqueue(&c); while(!c.done) { doEvents(); } int r = c.result.toInt(); window_state_t ws = static_cast(r); return ws; } result_t Rktwebview_qt::rktWindowSetTitle(rktwebview_t wv, const char *title) { Command c(COMMAND_SET_TITLE); c.args.push_back(wv); c.args.push_back(title); _command_queue.enqueue(&c); while(!c.done) { doEvents(); } bool r = c.result.toBool(); return r ? result_t::oke : result_t::resize_failed; } result_t Rktwebview_qt::doWindow(rktwebview_t w, int cmd) { Command c(cmd); c.args.push_back(w); _command_queue.enqueue(&c); while(!c.done) { doEvents(); } bool r = c.result.toBool(); return r ? result_t::oke : result_t::resize_failed; } bool Rktwebview_qt::rktValid(rktwebview_t wv) { return _views.contains(wv); } result_t Rktwebview_qt::rktOpenDevtools(rktwebview_t wv) { Command c(COMMAND_DEV_TOOLS); c.args.push_back(wv); _command_queue.enqueue(&c); while(!c.done) { doEvents(); } bool r = c.result.toBool(); return r ? result_t::oke : result_t::eval_js_failed; } void Rktwebview_qt::onPageLoad(rktwebview_t w) { } void Rktwebview_qt::pageLoaded(rktwebview_t w, bool ok) { 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" " 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" ); // trigger page loaded. EventContainer e("page-loaded"); e["oke"] = ok; triggerEvent(w, e); } void Rktwebview_qt::triggerEvent(rktwebview_t wv, const EventContainer &e) { triggerEvent(wv, mkEventJson(e)); } void Rktwebview_qt::triggerEvent(rktwebview_t wv, const QString &msg) { if (_view_js_callbacks.contains(wv)) { event_cb_t js_event_cb = _view_js_callbacks[wv]; char *evt = strdup(msg.toUtf8().constData()); rkt_event_t *e = static_cast(malloc(sizeof(rkt_event_t))); e->wv = wv; e->event = evt; js_event_cb(e); } } void Rktwebview_qt::rktQuit() { QList keys = _views.keys(); int i; for(i = 0; i < keys.size(); i++) { int view_handle = keys[i]; rktWebViewClose(view_handle); } Command c(COMMAND_QUIT); _command_queue.enqueue(&c); while(!c.done) { doEvents(); } } void Rktwebview_qt::runJs(rktwebview_t wv, const char *js) { if (_views.contains(wv)) { QString _js(js); WebviewWindow *win = _views[wv]; win->runJs(_js); } } void Rktwebview_qt::doEvents() { _app->processEvents(); } Rktwebview_qt::Rktwebview_qt(Rktwebview_qt **handler) : QObject() { _argc = 1; _argv[0] = const_cast("Rktwebview_qt"); _current_handle = 0; _handler = handler; _app = new QApplication(_argc, _argv); connect(&_process_commands, &QTimer::timeout, this, &Rktwebview_qt::processCommands); _process_commands.start(10); connect(&_process_events, &QTimer::timeout, this, &Rktwebview_qt::processJsEventQueues); _process_events.start(5); const auto *eventDispatcher = QThread::currentThread()->eventDispatcher(); QObject::connect(eventDispatcher, &QAbstractEventDispatcher::aboutToBlock, QThread::currentThread(), []{ if (QThread::currentThread()->loopLevel() == 0) QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); } ); *_handler = nullptr; }