#include "webviewwindow.h" #include "utils.h" #include "webviewqt.h" #include "rktwebview_qt.h" #include "rktutils.h" #include "command.h" #include #include #include #include #include #include #include #include #include #include #include #include /* static void displ(QSslCertificate & cert, QSslCertificate::SubjectInfo &a) { QStringList issuerInfo = cert.issuerInfo(a); int i, N; printf("%d\n", a); for(i = 0, N = issuerInfo.size(); i < N; i++) { printf("%d[%d]: %s\n", a, i, issuerInfo[i].toUtf8().constData()); } }; static void displ1(QSslCertificate &cert, QList l) { int i, N; for(i = 0, N = l.size(); i < N; i++) { displ(cert, l[i]); } }; */ WebviewWindow::WebviewWindow(QWebEngineProfile *profile, WebviewWindow *parent) : QMainWindow{parent} { static int profile_nr = 0; _view = nullptr; _must_close = false; _devtools = nullptr; _parent = parent; _window_created = false; _moved = 0; _resized = 0; _profile = profile; _navigation_event_sent = false; if (parent != nullptr) { setWindowModality(Qt::WindowModality::WindowModal); setWindowFlag(Qt::WindowType::Dialog, true); } connect(&_resize_timer, &QTimer::timeout, this, &WebviewWindow::triggerResize); connect(&_move_timer, &QTimer::timeout, this, &WebviewWindow::triggerMove); } void WebviewWindow::navigationRequested(QWebEngineNavigationRequest &req) { QWebEngineNavigationRequest::NavigationType t = req.navigationType(); if (t == QWebEngineNavigationRequest::NavigationType::TypedNavigation || t == QWebEngineNavigationRequest::RedirectNavigation) { _navigation_event_sent = false; req.accept(); } else { EventContainer e("navigation-request"); QString u = req.url().toString(); e["url"] = u; QString type; switch (req.navigationType()) { case QWebEngineNavigationRequest::NavigationType::LinkClickedNavigation: type = "link-clicked"; break; case QWebEngineNavigationRequest::NavigationType::TypedNavigation: type = "typed"; break; case QWebEngineNavigationRequest::NavigationType::FormSubmittedNavigation: type = "form-submit"; break; case QWebEngineNavigationRequest::NavigationType::BackForwardNavigation: type = "back-or-forward"; break; case QWebEngineNavigationRequest::NavigationType::ReloadNavigation: type = "reload"; break; case QWebEngineNavigationRequest::NavigationType::RedirectNavigation: type = "redirect"; break; default: type = "other"; break; } e["type"] = type; _container->triggerEvent(_view->id(), e); _navigation_event_sent = true; req.reject(); } } void WebviewWindow::handleCertificate(const QWebEngineCertificateError &certificateError) { /* QList certs = _view->page()->profile()->additionalTrustedCertificates(); auto dodisp = [](QList certs) { int i; for(i = 0; i < certs.size(); i++) { QSslCertificate cert = certs[i]; QList attrs; attrs.append(QSslCertificate::Organization); attrs.append(QSslCertificate::OrganizationalUnitName); attrs.append(QSslCertificate::CountryName); attrs.append(QSslCertificate::CommonName); displ1(cert, attrs); } }; dodisp(certs); dodisp(certificateError.certificateChain()); */ ERROR1("Certificate Error: %s\n", certificateError.description().toUtf8().constData()); QList chain = certificateError.certificateChain(); int i; for(i = 0; i < chain.size(); i++) { const QSslCertificate &cert = chain[i]; if (cert.isSelfSigned()) { QStringList l = cert.issuerInfo(QSslCertificate::OrganizationalUnitName); if (!l.empty()) { QString ou = l[0]; if (ou != "" && ou == _ou_token) { QWebEngineCertificateError &e = const_cast(certificateError); e.acceptCertificate(); } } } } } void WebviewWindow::processJsEvents() { QWebEnginePage *p = _view->page(); p->runJavaScript("if (window.rkt_get_events) { window.rkt_get_events(); } else { JSON.stringify([]); }", [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 js_evt = a[i].toObject(); EventContainer e("js-evt"); e["js-evt"] = js_evt; this->_container->triggerEvent(_view->id(), e); } } else { } } ); } void WebviewWindow::closeEvent(QCloseEvent *evt) { if (_must_close) { EventContainer e("closed"); _container->triggerEvent(_view->id(), e); _container->removeView(_view->id()); _view->deleteLater(); this->deleteLater(); if (_devtools != nullptr) { _devtools->close(); _devtools->deleteLater(); } } else { evt->ignore(); EventContainer e("can-close?"); _container->triggerEvent(_view->id(), e); } } void WebviewWindow::closeView() { _must_close = true; close(); } bool WebviewWindow::windowCreated() { return _window_created; } int WebviewWindow::moveCount() { return _moved; } int WebviewWindow::resizeCount() { return _resized; } void WebviewWindow::setOUToken(const QString &token) { _ou_token = token; } bool WebviewWindow::navigationEventSent() { return _navigation_event_sent; } 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); }); connect(page, &QWebEnginePage::loadStarted, this, [this]() { _container->onPageLoad(_view->id()); }); connect(page, &QWebEnginePage::navigationRequested, this, &WebviewWindow::navigationRequested); connect(page, &QWebEnginePage::certificateError, this, &WebviewWindow::handleCertificate); connect(page, &QWebEnginePage::windowCloseRequested, this, &WebviewWindow::closeView); connect(page, &QWebEnginePage::linkHovered, this, &WebviewWindow::linkHovered); connect(page, &QWebEnginePage::printRequestedByFrame, this, &WebviewWindow::evtRequested); } WebViewQt *WebviewWindow::view() { return _view; } void WebviewWindow::runJs(const QString &js) { QWebEnginePage *p = _view->page(); p->runJavaScript(js); } void WebviewWindow::callJs(const QString &js, Command *c) { QWebEnginePage *p = _view->page(); QString _js = QString("{\n") + " let f = function() {\n" + " " + js + "\n" + " };\n" + " try {\n" + " let obj = { oke: true, result: f(), exn: false };\n" + " obj;\n" + " } catch(e) {\n" + " let obj = { oke: false, result: false, exn: e.message };\n" + " obj;\n" + " }\n" + "}"; p->runJavaScript(_js, [c](const QVariant &v) { c->result = v; QJsonObject obj = v.toJsonObject(); bool ok = obj["oke"].toBool(); c->js_result_ok = ok; c->result = QString::fromUtf8(QJsonDocument(obj).toJson(QJsonDocument::JsonFormat::Compact)); c->done = true; }); } void WebviewWindow::openDevTools() { _devtools = new QMainWindow(this); QWebEngineView *devtools_view = new QWebEngineView(_devtools); _devtools->setCentralWidget(devtools_view); _devtools->resize(800, 600); _devtools->show(); _view->page()->setDevToolsPage(devtools_view->page()); connect(_devtools, &WebviewWindow::destroyed, this, [this](QObject *) { _devtools = nullptr; }); } void WebviewWindow::linkHovered(const QUrl &u) { QString s = u.toString(); EventContainer hover_event("link-hovered"); hover_event["url"] = s; _container->triggerEvent(_view->id(), hover_event); } void WebviewWindow::evtRequested(QWebEngineFrame frame) { if (frame.name() == "rkt-evt-frame") { processJsEvents(); } } void WebviewWindow::moveEvent(QMoveEvent *event) { _x = event->pos().x(); _y = event->pos().y(); _move_timer.setSingleShot(true); _move_timer.start(500); _moved += 1; //triggerMove(); } void WebviewWindow::triggerMove() { EventContainer xy("move"); xy["x"] = _x; xy["y"] = _y; _container->triggerEvent(_view->id(), xy); } QWebEngineProfile *WebviewWindow::profile() { return _profile; } void WebviewWindow::resizeEvent(QResizeEvent *event) { _w = event->size().width(); _h = event->size().height(); _resize_timer.setSingleShot(true); _resize_timer.start(500); _resized += 1; //triggerResize(); } void WebviewWindow::triggerResize() { EventContainer s("resize"); s["w"] = _w; s["h"] = _h; _container->triggerEvent(_view->id(), s); } void WebviewWindow::showEvent(QShowEvent *event) { _window_created = true; EventContainer show("show"); _container->triggerEvent(_view->id(), show); } void WebviewWindow::hideEvent(QHideEvent *event) { if (!_must_close) { EventContainer hide("hide"); _container->triggerEvent(_view->id(), hide); } }