From 7d234bc834693670720225f70a0d20176bff6c49 Mon Sep 17 00:00:00 2001 From: Hans Dijkema Date: Wed, 11 Mar 2026 17:57:55 +0100 Subject: [PATCH] Much work, using Qt 6.10 on Linux for better https support --- example/index.html | 2 +- example1/example-1.html | 1 + example1/example.rkt | 159 ++++++++------- private/lib/linux/x86_64/librktwebview_qt.so | Bin 201328 -> 202120 bytes private/mimetypes.rkt | 1 - private/racket-webview-qt.rkt | 200 ++++++++++++++----- private/racket-webview.rkt | 15 +- rktwebview_qt/command.h | 1 + rktwebview_qt/main.cpp | 28 ++- rktwebview_qt/rktwebview.cpp | 58 +++--- rktwebview_qt/rktwebview.h | 50 ++++- rktwebview_qt/rktwebview_qt.cpp | 106 ++++++---- rktwebview_qt/rktwebview_qt.h | 12 +- rktwebview_qt/webviewqt.cpp | 2 +- rktwebview_qt/webviewwindow.cpp | 113 ++++++++++- rktwebview_qt/webviewwindow.h | 10 +- 16 files changed, 541 insertions(+), 217 deletions(-) diff --git a/example/index.html b/example/index.html index 688829c..f2b9088 100644 --- a/example/index.html +++ b/example/index.html @@ -17,7 +17,7 @@ Some input text: Some input date:

-Some color input: +Some color input:

diff --git a/example1/example-1.html b/example1/example-1.html index 9b67683..bd07432 100644 --- a/example1/example-1.html +++ b/example1/example-1.html @@ -34,6 +34,7 @@
+

Menu responses

diff --git a/example1/example.rkt b/example1/example.rkt index 0d8b11c..5d11a26 100644 --- a/example1/example.rkt +++ b/example1/example.rkt @@ -11,13 +11,17 @@ example-1-window% ) +(define ww-debug displayln) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Example 1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define-runtime-path html-start "example-1.html") (define-runtime-path dialog-html "example-1-dialog.html") +(define-runtime-path cur-dir ".") +#| (define test-menu (menu 'main-menu (menu-item 'm-file "File" #:submenu @@ -46,33 +50,34 @@ ) ) )) +|# (define example-1-dialog% - (class ww-webview-dialog% + (class wv-dialog% (inherit-field settings) - (super-new [html-file dialog-html] - [width 400] - [height 300]) + (super-new [window-context 'example-1-dialog] + [file-not-found-handler (root-file-not-found-handler "example-1-dialog.html")] + ) - (define/override (html-loaded) - (super html-loaded) + (define/override (page-loaded oke) + (super page-loaded oke) - (ww-debug "html-loaded for example-1-dialog%") - (let* ((btn (send this element 'ok-btn))) - (send btn connect 'click (λ (data) - (send this close)))) + ;(ww-debug "html-loaded for example-1-dialog%") + (send this bind! 'ok-btn 'click (λ (el evt data) + (send this close))) - (let* ((inp1 (send this element 'inp1)) - (inp2 (send this element 'inp2)) - (inp3 (send this element 'inp3))) + (let* ((inp1 (send this element 'inp1 'text)) + (inp2 (send this element 'inp2 'text)) + (inp3 (send this element 'inp3 'text))) (send inp1 set! (send settings get 'inp1 "")) (send inp2 set! (send settings get 'inp2 "")) (send inp3 set! (send settings get 'inp3 "")) - (send inp1 on-change! - (λ (val) - (send settings set! 'inp1 val))) - (send inp2 on-change! (λ (val) (send settings set! 'inp2 val))) - (send inp3 on-change! (λ (val) (send settings set! 'inp3 val))) + (send this bind! 'inp1 'change (λ (el evt data) + (displayln (format "~a ~a ~a" el evt data)) + (displayln (format "get = ~a" (send el get))) + (send settings set! 'inp1 (send el get)))) + (send this bind! 'inp2 'change (λ (el evt data) (send settings set! 'inp2 (send el get)))) + (send this bind! 'inp3 'change (λ (el evt data) (send settings set! 'inp3 (send el get)))) ) ) ) @@ -86,10 +91,11 @@ var)))) (define example-1-window% - (class ww-webview% + (class wv-window% - (inherit-field settings) - (super-new [html-file html-start] + (inherit-field settings app-context) + (super-new [file-not-found-handler (root-file-not-found-handler "example-1.html")] + [window-context 'example-1-main] ) (define go-on-counter #f) @@ -97,14 +103,21 @@ (define counter-inc 1) (define counter-thread #f) (define div-counter #f) - (define my-dir (send settings get 'folder ".")) + (define my-dir (send settings get/global 'folder ".")) (define/override (can-close?) (eq? counter-thread #f)) - (define/public (reset-counter) + (define start-stop-btn #f) + + (define/public (stop-counter) + (send start-stop-btn set-innerHTML! "Start Counter") (set! go-on-counter #f) + ) + + (define/public (reset-counter) + (stop-counter) (set! counter-thread #f) ) @@ -117,25 +130,26 @@ (send this update-counter)) (define/public (update-counter) - (send div-counter set-inner-html! (format "Count = ~a" c-counter)) + (send div-counter set-innerHTML! (format "Count = ~a" c-counter)) (when (and (> c-counter 0) (<= c-counter 100)) (send div-counter set-style! - (css-style '((background white))))) + '((background white)))) (when (and (> c-counter 100) (<= c-counter 200)) (send div-counter set-style! - (css-style '((background green) (color white))))) + '((background green) (color white)))) (when (and (> c-counter 200) (<= c-counter 300)) (send div-counter set-style! - (css-style '((background yellow) (font-size: 120%))))) + '((background yellow) (color black) (font-size: 120%)))) (when (and (> c-counter 300) (<= c-counter 400)) (send div-counter set-style! - (css-style '((color white) (background orange) (font-size 110%))))) + '((color white) (background orange) (font-size 110%)))) (when (and (> c-counter 400)) (send div-counter set-style! - (css-style '((color white) (background red) (font-size 120%) (font-weight bold))))) + '((color white) (background red) (font-size 120%) (font-weight bold)))) ) (define/public (start-counter) + (send start-stop-btn set-innerHTML! "Stop Counter") (set! counter-thread (thread (λ () @@ -150,65 +164,68 @@ (define/public (set-folder new-dir) (set! my-dir new-dir) - (send settings set 'folder new-dir) + (send settings set/global! 'folder new-dir) (let ((el (send this element 'folder))) - (send el set-inner-html! (format "Selected folder: ~a" my-dir)) + (send el set-innerHTML! (format "Selected folder: ~a" my-dir)) ) ) (define/override (choose-dir) - (let ((handle (super choose-dir "Select a folder" my-dir))) - (displayln (format "choosen dir handle: ~a" handle)) + (let ((result (super choose-dir "Select a folder" my-dir))) + (displayln (format "choosen dir handle: ~a" result)) + (unless (eq? result 'canceled) + (send this set-folder result)) ) ) - (define/override (dir-choosen handle choosen dir) - (displayln (format "dir-choosen: ~a ~a ~a" handle choosen dir)) - (when choosen - (send this set-folder dir))) - (define/public (prefs) - (new example-1-dialog% [parent this] [settings (send this clone-settings 'example-1-dialog)])) + (stop-counter) + (set! go-on-counter #f) + (new example-1-dialog% + [parent this] + ) + ) ; (send this clone-settings 'example-1-dialog)])) - (define/override (handle-navigate url type kind) - (send this reset-counter) - (super handle-navigate url type kind)) + ;(define/override (handle-navigate url type kind) + ; (send this reset-counter) + ; (super handle-navigate url type kind)) - (define/override (html-loaded) + (define/override (page-loaded oke) (ww-debug "HTML LOADED") - (super html-loaded) + (super page-loaded oke) (set! div-counter (send this element 'div-counter)) (send this update-counter) (send this set-folder my-dir) (ww-debug "CONNECTING BUTTONS") - (let* ((dialog-btn (send this element 'dialog-button)) - (start-stop-btn (send this element 'start-stop-button)) - (choose-dir-btn (send this element 'select-dir-button)) - ) - (send dialog-btn connect 'click - (λ (data) (send this prefs))) - - (send start-stop-btn connect 'click - (λ (data) - (if (eq? counter-thread #f) - (begin - (send this start-counter) - (send start-stop-btn set-inner-html! "Stop Counter")) - (begin - (send this reset-counter) - (send start-stop-btn set-inner-html! "Start Counter")) + (send this bind! 'dialog-button 'click (λ (el evt data) + (send this prefs))) + + (set! start-stop-btn (send this element 'start-stop-button)) + (send this bind! 'start-stop-button 'click + (λ (el evt data) + (if (eq? counter-thread #f) + (begin + (send this start-counter) ) - ) + (begin + (send this reset-counter) + ) + ) ) - (send choose-dir-btn connect 'click - (λ (data) - (send this choose-dir))) - ) + ) + + (send this bind! 'devtools 'click + (λ (el evt data) (send this devtools))) + + (send this bind! 'select-dir-button 'click + (λ (el evt data) + (send this choose-dir))) - (ww-debug "SETTING MENU") - (let* ((div-open (send this element 'div-open)) + + ;(ww-debug "SETTING MENU") + #|(let* ((div-open (send this element 'div-open)) (c-open 0) (div-close (send this element 'div-close)) (c-close 0) @@ -250,7 +267,7 @@ (λ () (send this choose-dir))) ) - ) + )|# ) (begin @@ -261,7 +278,9 @@ (define (run-example) (let* ((ini (new ini% [file 'web-racket-example1])) - (settings (new ww-simple-ini% [ini ini] [section 'example-1-window])) - (window (new example-1-window% [settings settings])) + (window (new example-1-window% + [app-context 'example-1] + [ini ini] + [base-dir cur-dir])) ) window)) diff --git a/private/lib/linux/x86_64/librktwebview_qt.so b/private/lib/linux/x86_64/librktwebview_qt.so index 10af4ac5ca940536ab6a0afd2121656c839d9655..e0ff9e76a821884da61419319fa2834c0c43110f 100755 GIT binary patch delta 68443 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�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

flRTpBl5i*@pFd$K6jpfW)dF9sfrx?lFW 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 os) (symbol->string arch))) + (define (libname lib-symbol) - (build-path lib-dir (symbol->string os) (symbol->string lib-symbol))) + (build-path os-lib-dir (symbol->string lib-symbol))) ; c:\qt\6.10.2\msvc2022_64\bin\windeployqt.exe rktwebview_qt_test.exe -(when (eq? os 'windows) - (putenv "QT_PLUGIN_PATH" - (path->string (build-path lib-dir (symbol->string os)))) - (putenv "QTWEBENGINEPROCESS_PATH" - (path->string (build-path lib-dir (symbol->string os) "QtWebEngineProcess.exe"))) - (putenv "QTWEBENGINE_RESOURCES_PATH" - (path->string (build-path lib-dir (symbol->string os) "resources"))) - (putenv "QTWEBENGINE_LOCALES_PATH" - (path->string (build-path lib-dir (symbol->string os) "translations" "qtwebengine_locales"))) - ) +(define quiet-call #t) +(set! quiet-call + (when (or (eq? os 'windows) (eq? os 'linux)) + (putenv "QT_PLUGIN_PATH" + (path->string (build-path os-lib-dir))) + (putenv "QTWEBENGINEPROCESS_PATH" + (path->string (build-path os-lib-dir "QtWebEngineProcess.exe"))) + (putenv "QTWEBENGINE_RESOURCES_PATH" + (path->string (build-path os-lib-dir "resources"))) + (putenv "QTWEBENGINE_LOCALES_PATH" + (path->string (build-path os-lib-dir "translations" "qtwebengine_locales"))) + (when (eq? os 'linux) + (putenv "QT_QPA_PLATFORM" "xcb") + (putenv "LD_LIBRARY_PATH" + (string-append + (path->string (build-path os-lib-dir)) ":" + (path->string (build-path os-lib-dir "platforms")) + ) + ) + ) + ) + ) + ;;; Preload libraries (for-each (λ (lib-symbol) - (let ((load-lib (libname lib-symbol))) - (ffi-lib load-lib))) + (let* ((libn (if (list? lib-symbol) (car lib-symbol) lib-symbol)) + (versions (if (list? lib-symbol) (cons (cadr lib-symbol) '(#f)) (list #f))) + (load-lib (if (list? lib-symbol) + (if (eq? (caddr lib-symbol) #f) + (symbol->string libn) + (libname libn)) + (libname libn))) + ) + ;(displayln (format "loading ~a" load-lib)) + (ffi-lib load-lib versions) + ) + ) libraries-to-preload) ;;; Actual FFI integration @@ -130,7 +177,7 @@ ffi-library os exp)))) ) ]) - (ffi-lib webview-lib-file))) + (ffi-lib webview-lib-file '("6" #f) #:get-lib-dirs (list os-lib-dir)))) (define-ffi-definer define-rktwebview webview-lib) @@ -170,6 +217,24 @@ ) ) +(define _rkt_data_kind + (_enum '(version = -1 + event = 2 + js-result = 3 + ) + ) + ) + +(define-cstruct _rkt_version_t + ([qt-major _int] + [qt-minor _int] + [qt-patch _int] + [api-major _int] + [api-minor _int] + [api-patch _int] + ) + ) + (define-cstruct _rkt_evt_t ([w _int] [evt _pointer] @@ -180,6 +245,13 @@ [value _pointer] )) +(define-cstruct _rkt_data_t + ([kind _rkt_data_kind] + [data (_union _rkt_version_t _rkt_evt_t _rkt_js_result_t)] + ) + ) + + ;RKTWEBVIEW_QT_EXPORT void rkt_webview_init(int &argc, char **argv); (define-rktwebview rkt_webview_init (_fun -> _void)) @@ -188,10 +260,23 @@ (define-rktwebview rkt_webview_process_events (_fun _int -> _void)) -;RKTWEBVIEW_QT_EXPORT int rkt_webview_create(int parent); +;RKTWEBVIEW_QT_EXPORT void rkt_webview_free_data(rkt_data_t *d); +(define-rktwebview rkt_webview_free_data + (_fun _rkt_data_t-pointer -> _void)) + +;RKTWEBVIEW_QT_EXPORT rkt_data_t *rkt_webview_version(); +(define-rktwebview rkt_webview_version + (_fun -> _rkt_data_t-pointer)) + +;RKTWEBVIEW_QT_EXPORT int rkt_webview_create(rktwebview_t parent, +; event_cb_t js_event_cb, +; const char *optional_server_cert_pem); (define-rktwebview rkt_webview_create - (_fun _int (_fun #:keep callback-box #:async-apply applier - _rkt_evt_t-pointer -> _void) -> _int)) + (_fun _int + (_fun #:keep callback-box #:async-apply applier + _rkt_data_t-pointer -> _void) + _bytes + -> _int)) ;RKTWEBVIEW_QT_EXPORT void rkt_webview_close(int wv); (define-rktwebview rkt_webview_close @@ -215,20 +300,12 @@ ;RKTWEBVIEW_QT_EXPORT rkt_js_result_t *rkt_webview_call_js(rktwebview_t wv, const char *js); (define-rktwebview rkt_webview_call_js - (_fun _int _string/utf-8 -> _rkt_js_result_t-pointer)) + (_fun _int _string/utf-8 -> _rkt_data_t-pointer)) -;RKTWEBVIEW_QT_EXPORT result_t rkt_webview_destroy_js_result(rkt_js_result_t *r); -(define-rktwebview rkt_webview_destroy_js_result - (_fun _rkt_js_result_t-pointer -> _rkt_result_t)) - ;RKTWEBVIEW_QT_EXPORT result_t rkt_webview_open_devtools(int wv); (define-rktwebview rkt_webview_open_devtools (_fun _int -> _rkt_result_t)) -;RKTWEBVIEW_QT_EXPORT result_t rkt_webview_destroy_event(rkt_event_t e); -(define-rktwebview rkt_webview_destroy_event - (_fun _rkt_evt_t-pointer -> _rkt_result_t)) - ;RKTWEBVIEW_QT_EXPORT result_t rkt_webview_move(rktwebview_t w, int x, int y); (define-rktwebview rkt_webview_move (_fun _int _int _int -> _rkt_result_t)) @@ -275,15 +352,15 @@ ;RKTWEBVIEW_QT_EXPORT rkt_js_result_t *rkt_webview_choose_dir(rktwebview_t w, const char *title, const char *base_dir); (define-rktwebview rkt_webview_choose_dir - (_fun _int _string/utf-8 _string/utf-8 -> _rkt_js_result_t-pointer)) + (_fun _int _string/utf-8 _string/utf-8 -> _rkt_data_t-pointer)) ;RKTWEBVIEW_QT_EXPORT rkt_js_result_t *rkt_webview_file_open(rktwebview_t w, const char *title, const char *base_dir, const char *permitted_exts); (define-rktwebview rkt_webview_file_open - (_fun _int _string/utf-8 _string/utf-8 _string/utf-8 -> _rkt_js_result_t-pointer)) + (_fun _int _string/utf-8 _string/utf-8 _string/utf-8 -> _rkt_data_t-pointer)) ;RKTWEBVIEW_QT_EXPORT rkt_js_result_t *rkt_webview_file_save(rktwebview_t w, const char *title, const char *base_dir, const char *permitted_exts); (define-rktwebview rkt_webview_file_save - (_fun _int _string/utf-8 _string/utf-8 _string/utf-8 -> _rkt_js_result_t-pointer)) + (_fun _int _string/utf-8 _string/utf-8 _string/utf-8 -> _rkt_data_t-pointer)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -308,7 +385,7 @@ (f))))) (rkt_webview_init) -(start-event-processing) +(set! quiet-call (start-event-processing)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Provided features @@ -323,27 +400,29 @@ (define (rkt-process-events handle) (if (> (queue-length (rkt-wv-evt-queue handle)) 0) - (let ((e (dequeue! (rkt-wv-evt-queue handle)))) - (if (symbol? e) - (if (eq? e 'quit) + (let ((data (dequeue! (rkt-wv-evt-queue handle)))) + (if (symbol? data) + (if (eq? data 'quit) (begin (hash-remove! rkt-wv-store (rkt-wv-win handle)) 'quit) (rkt-process-events handle)) - (let ((evt (cast (rkt_evt_t-evt e) _pointer _string*/utf-8))) + (let* ((e (union-ref (rkt_data_t-data data) 1)) + (evt (cast (rkt_evt_t-evt e) _pointer _string*/utf-8))) ((rkt-wv-callback handle) handle evt) - (rkt_webview_destroy_event e) + (rkt_webview_free_data data) (rkt-process-events handle))) ) 'done)) -(define (rkt-webview-create parent evt-callback close-callback) +(define (rkt-webview-create parent evt-callback close-callback server-cert) (let* ((evt-queue (make-queue)) (parent-win (if (eq? parent #f) 0 (rkt-wv-win parent))) ) (let ((wv (rkt_webview_create parent-win (λ (rkt-evt) - (enqueue! evt-queue rkt-evt))))) + (enqueue! evt-queue rkt-evt)) + server-cert))) (let ((handle (make-rkt-wv wv evt-queue evt-callback #t close-callback))) (thread (λ () (sleep 1) @@ -385,10 +464,11 @@ (rkt_webview_run_js (rkt-wv-win wv) js)) (define (rkt-webview-call-js wv js) - (let* ((r (rkt_webview_call_js (rkt-wv-win wv) js)) + (let* ((d (rkt_webview_call_js (rkt-wv-win wv) js)) + (r (union-ref (rkt_data_t-data d) 2)) (value (cast (rkt_js_result_t-value r) _pointer _string*/utf-8)) (result (rkt_js_result_t-result r))) - (rkt_webview_destroy_js_result r) + (rkt_webview_free_data d) (list result value))) (define (rkt-webview-resize wv w h) @@ -415,26 +495,47 @@ (rkt_webview_open_devtools (rkt-wv-win wv))) (define (rkt-webview-choose-dir wv title base-dir) - (let* ((r (rkt_webview_choose_dir (rkt-wv-win wv) title base-dir)) + (let* ((d (rkt_webview_choose_dir (rkt-wv-win wv) title base-dir)) + (r (union-ref (rkt_data_t-data d) 2)) (value (cast (rkt_js_result_t-value r) _pointer _string*/utf-8)) (result (rkt_js_result_t-result r))) - (rkt_webview_destroy_js_result r) + (rkt_webview_free_data d) (list result value))) (define (rkt-webview-file-open wv title base-dir permitted-exts) - (let* ((r (rkt_webview_file_open (rkt-wv-win wv) title base-dir permitted-exts)) + (let* ((d (rkt_webview_file_open (rkt-wv-win wv) title base-dir permitted-exts)) + (r (union-ref (rkt_data_t-data d) 2)) (value (cast (rkt_js_result_t-value r) _pointer _string*/utf-8)) (result (rkt_js_result_t-result r))) - (rkt_webview_destroy_js_result r) + (rkt_webview_free_data d) (list result value))) (define (rkt-webview-file-save wv title base-dir permitted-exts) - (let* ((r (rkt_webview_file_save (rkt-wv-win wv) title base-dir permitted-exts)) + (let* ((d (rkt_webview_file_save (rkt-wv-win wv) title base-dir permitted-exts)) + (r (union-ref (rkt_data_t-data d) 2)) (value (cast (rkt_js_result_t-value r) _pointer _string*/utf-8)) (result (rkt_js_result_t-result r))) - (rkt_webview_destroy_js_result r) + (rkt_webview_free_data d) (list result value))) +(define (rkt-webview-version) + (let ((d (rkt_webview_version))) + (let ((v (union-ref (rkt_data_t-data d) 0))) + (let ((qt-major (rkt_version_t-qt-major v)) + (qt-minor (rkt_version_t-qt-minor v)) + (qt-patch (rkt_version_t-qt-patch v)) + (api-major (rkt_version_t-api-major v)) + (api-minor (rkt_version_t-api-minor v)) + (api-patch (rkt_version_t-api-patch v)) + ) + (rkt_webview_free_data d) + (list (list 'webview-c-api api-major api-minor api-patch) + (list 'qt qt-major qt-minor qt-patch)) + ) + ) + ) + ) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Administration ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -459,9 +560,10 @@ ;; Cleanup on exit ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(plumber-add-flush! (current-plumber) - (λ (handle) - (rkt-webview-exit))) +(set! quiet-call + (plumber-add-flush! (current-plumber) + (λ (handle) + (rkt-webview-exit)))) diff --git a/private/racket-webview.rkt b/private/racket-webview.rkt index 4100fcf..d9b35e6 100644 --- a/private/racket-webview.rkt +++ b/private/racket-webview.rkt @@ -1,6 +1,7 @@ #lang racket/base (require "racket-webview-qt.rkt" + "racket-webview-version.rkt" "utils.rkt" "mimetypes.rkt" "rgba.rkt" @@ -99,6 +100,11 @@ webview-standard-file-getter + webview-version + + wv-base-url + wv-window-nr + test ) @@ -393,12 +399,13 @@ (cert (generate-self-signed-cert 2048 365 '("127.0.0.1" "localhost") "NL" "Dijkema" #:ou (wv-cert-ou-token h))) + (server-cert (certificate cert)) (event-processor (λ (wv evt) (event-callback h (util-parse-event evt)))) (close-callback (λ () (remove-cert-files h))) (ph (if (wv? p) (wv-handle p) #f)) - (wv (let ((internal-handle (rkt-webview-create ph event-processor close-callback))) + (wv (let ((internal-handle (rkt-webview-create ph event-processor close-callback server-cert))) (set-wv-handle! h internal-handle) (set-wv-window-nr! h (rkt-wv-win internal-handle)) internal-handle)) @@ -870,7 +877,11 @@ (wva webview-attr/date g:date? string->date) (wva webview-attr/time g:time? string->time) (wva webview-attr/datetime g:datetime string->datetime) -(wvv webview-attr/boolean boolean? (λ (e) (if (string=? e "true") #t #f))) +(wva webview-attr/boolean boolean? (λ (e) (if (string=? e "true") #t #f))) + +(define (webview-version) + (cons (list 'webview webview-major webview-minor webview-patch) + (rkt-webview-version))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; testing diff --git a/rktwebview_qt/command.h b/rktwebview_qt/command.h index fea5d76..ca484de 100644 --- a/rktwebview_qt/command.h +++ b/rktwebview_qt/command.h @@ -26,6 +26,7 @@ #define COMMAND_FILE_OPEN 20 #define COMMAND_FILE_SAVE 21 #define COMMAND_SET_OU_TOKEN 22 +#define COMMAND_SET_CERTIFICATE 23 class Command { diff --git a/rktwebview_qt/main.cpp b/rktwebview_qt/main.cpp index 604e3d8..66a0e89 100644 --- a/rktwebview_qt/main.cpp +++ b/rktwebview_qt/main.cpp @@ -1,14 +1,15 @@ #include "rktwebview.h" #include +#include static int _argc; static char **_argv; -void eventCb(rkt_event_t *e) +void eventCb(rkt_data_t *e) { - printf("event: %s\n", e->event); - rkt_webview_destroy_event(e); + printf("event: %s\n", e->data.event.event); + rkt_webview_free_data(e); } int main(int argc, char *argv[]) @@ -20,7 +21,9 @@ int main(int argc, char *argv[]) _argv = argv; rkt_webview_init(); - wv1 = rkt_webview_create(0, eventCb); + + wv1 = rkt_webview_create(0, eventCb, nullptr); + rkt_webview_move(wv1, 200, 300); rkt_webview_resize(wv1, 800, 600); rkt_webview_set_url(wv1, "https://wikipedia.org"); //"http://127.0.0.1:8083"); @@ -35,23 +38,26 @@ int main(int argc, char *argv[]) } if (i == 3) { - rkt_js_result_t *r = rkt_webview_call_js(wv1, "{ let a = 7 * 6; console.log('a = ' + a); return a; }"); - printf("rkt_js_result: %d: %s\n", r->result, r->value); + rkt_data_t *r = rkt_webview_call_js(wv1, "{ let a = 7 * 6; console.log('a = ' + a); return a; }"); + printf("rkt_js_result: %d: %s\n", r->data.js_result.result, r->data.js_result.value); + rkt_webview_free_data(r); } if (i == 4) { - rkt_js_result_t *r = rkt_webview_call_js(wv1, "let el = document.getElementById('hi');el.value = '10';"); - printf("rkt_js_result: %d: %s\n", r->result, r->value); + rkt_data_t *r = rkt_webview_call_js(wv1, "let el = document.getElementById('hi');el.value = '10';"); + printf("rkt_js_result: %d: %s\n", r->data.js_result.result, r->data.js_result.value); + rkt_webview_free_data(r); } if (i == 6) { - rkt_js_result_t *r = rkt_webview_call_js(wv1, "document.body.innerHTML = '

Hi!

'; return document.body.innerHTML;"); - printf("rkt_js_result: %d: %s\n", r->result, r->value); + rkt_data_t *r = rkt_webview_call_js(wv1, "document.body.innerHTML = '

Hi!

'; return document.body.innerHTML;"); + printf("rkt_js_result: %d: %s\n", r->data.js_result.result, r->data.js_result.value); + rkt_webview_free_data(r); } if (i == 10) { - wv2 = rkt_webview_create(wv1, eventCb); + wv2 = rkt_webview_create(wv1, eventCb, nullptr); rkt_webview_move(wv2, 400, 200); rkt_webview_resize(wv2, 800, 600); rkt_webview_set_url(wv2, "https://127.0.0.1"); diff --git a/rktwebview_qt/rktwebview.cpp b/rktwebview_qt/rktwebview.cpp index 43366d4..d8a4cc6 100644 --- a/rktwebview_qt/rktwebview.cpp +++ b/rktwebview_qt/rktwebview.cpp @@ -32,10 +32,10 @@ void rkt_webview_init() } } -int rkt_webview_create(rktwebview_t parent, event_cb_t js_event_cb) +int rkt_webview_create(rktwebview_t parent, event_cb_t js_event_cb, const char *optional_server_cert_pem) { rkt_webview_init(); - return handler->rktWebViewCreate(parent, js_event_cb); + return handler->rktWebViewCreate(parent, js_event_cb, optional_server_cert_pem); } void rkt_webview_close(rktwebview_t wv) @@ -66,10 +66,10 @@ result_t rkt_webview_run_js(rktwebview_t wv, const char *js) return r; } -rkt_js_result_t *rkt_webview_call_js(rktwebview_t wv, const char *js) +rkt_data_t *rkt_webview_call_js(rktwebview_t wv, const char *js) { rkt_webview_init(); - rkt_js_result_t *r = handler->rktCallJs(wv, js); + rkt_data_t *r = handler->rktCallJs(wv, js); return r; } @@ -95,22 +95,6 @@ void rkt_webview_process_events(int for_ms) } } - -result_t rkt_webview_destroy_event(rkt_event_t *e) -{ - free(e->event); - free(e); - return result_t::oke; -} - -result_t rkt_webview_destroy_js_result(rkt_js_result_t *r) -{ - free(r->value); - free(r); - return result_t::oke; -} - - result_t rkt_webview_move(rktwebview_t wv, int x, int y) { rkt_webview_init(); @@ -184,19 +168,19 @@ result_t rkt_webview_set_title(rktwebview_t wv, const char *title) return handler->rktWindowSetTitle(wv, title); } -rkt_js_result_t *rkt_webview_choose_dir(rktwebview_t w, const char *title, const char *base_dir) +rkt_data_t *rkt_webview_choose_dir(rktwebview_t w, const char *title, const char *base_dir) { rkt_webview_init(); return handler->rktChooseDir(w, title, base_dir); } -rkt_js_result_t *rkt_webview_file_open(rktwebview_t w, const char *title, const char *base_dir, const char *permitted_exts) +rkt_data_t *rkt_webview_file_open(rktwebview_t w, const char *title, const char *base_dir, const char *permitted_exts) { rkt_webview_init(); return handler->rktFileOpen(w, title, base_dir, permitted_exts); } -rkt_js_result_t *rkt_webview_file_save(rktwebview_t w, const char *title, const char *base_dir, const char *permitted_exts) +rkt_data_t *rkt_webview_file_save(rktwebview_t w, const char *title, const char *base_dir, const char *permitted_exts) { rkt_webview_init(); return handler->rktFileSave(w, title, base_dir, permitted_exts); @@ -207,3 +191,31 @@ void rkt_webview_set_ou_token(rktwebview_t wv, const char *token) rkt_webview_init(); handler->rktSetOUToken(wv, token); } + +void rkt_webview_free_data(rkt_data_t *d) +{ + if (d->kind == version) { + free(d); + } else if (d->kind == event) { + free(d->data.event.event); + free(d); + } else if (d->kind == js_result) { + free(d->data.js_result.value); + free(d); + } else { + fprintf(stderr, "UNEXPECTED: data kind %d cannot be freed\n", d->kind); + } +} + +rkt_data_t *rkt_webview_version() +{ + rkt_data_t *d = static_cast(malloc(sizeof(rkt_data_t))); + d->kind = version; + d->data.version.api_major = RKT_WEBVIEW_API_MAJOR; + d->data.version.api_minor = RKT_WEBVIEW_API_MINOR; + d->data.version.api_patch = RKT_WEBVIEW_API_PATCH; + d->data.version.qt_major = QT_VERSION_MAJOR; + d->data.version.qt_minor = QT_VERSION_MINOR; + d->data.version.qt_patch = QT_VERSION_PATCH; + return d; +} diff --git a/rktwebview_qt/rktwebview.h b/rktwebview_qt/rktwebview.h index bf06380..6c19a44 100644 --- a/rktwebview_qt/rktwebview.h +++ b/rktwebview_qt/rktwebview.h @@ -3,6 +3,10 @@ #include "rktwebview_qt_global.h" +#define RKT_WEBVIEW_API_MAJOR 0 +#define RKT_WEBVIEW_API_MINOR 1 +#define RKT_WEBVIEW_API_PATCH 1 + extern "C" { typedef int rktwebview_t; @@ -12,8 +16,6 @@ typedef struct { char *event; } rkt_event_t; -typedef void (*event_cb_t)(rkt_event_t *); - typedef enum { no_result_yet = -1, oke = 0, @@ -51,27 +53,53 @@ typedef enum { maximized_active = 18 } window_state_t; +typedef struct { + int qt_major; + int qt_minor; + int qt_patch; + int api_major; + int api_minor; + int api_patch; +} rkt_version_t; + +typedef enum { + version = 1, + event = 2, + js_result = 3 +} rkt_data_kind_t; + +typedef struct { + rkt_data_kind_t kind; + union { + rkt_version_t version; + rkt_event_t event; + rkt_js_result_t js_result; + } data; +} rkt_data_t; + +typedef void (*event_cb_t)(rkt_data_t *); + 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(rktwebview_t parent, event_cb_t js_event_cb); +RKTWEBVIEW_QT_EXPORT void rkt_webview_free_data(rkt_data_t *d); + +RKTWEBVIEW_QT_EXPORT rkt_data_t *rkt_webview_version(); + +RKTWEBVIEW_QT_EXPORT int rkt_webview_create(rktwebview_t parent, event_cb_t js_event_cb, const char *optional_server_cert_pem); RKTWEBVIEW_QT_EXPORT void rkt_webview_close(rktwebview_t wv); RKTWEBVIEW_QT_EXPORT bool rkt_webview_valid(rktwebview_t wv); RKTWEBVIEW_QT_EXPORT result_t rkt_webview_set_title(rktwebview_t wv, const char *title); RKTWEBVIEW_QT_EXPORT void rkt_webview_set_ou_token(rktwebview_t wv, const char *token); - RKTWEBVIEW_QT_EXPORT result_t rkt_webview_set_url(rktwebview_t wv, const char *url); RKTWEBVIEW_QT_EXPORT result_t rkt_webview_set_html(rktwebview_t wv, const char *html); RKTWEBVIEW_QT_EXPORT result_t rkt_webview_run_js(rktwebview_t wv, const char *js); -RKTWEBVIEW_QT_EXPORT rkt_js_result_t *rkt_webview_call_js(rktwebview_t wv, const char *js); -RKTWEBVIEW_QT_EXPORT result_t rkt_webview_destroy_js_result(rkt_js_result_t *r); +RKTWEBVIEW_QT_EXPORT rkt_data_t *rkt_webview_call_js(rktwebview_t wv, const char *js); RKTWEBVIEW_QT_EXPORT result_t rkt_webview_open_devtools(rktwebview_t wv); -RKTWEBVIEW_QT_EXPORT result_t rkt_webview_destroy_event(rkt_event_t *e); - RKTWEBVIEW_QT_EXPORT result_t rkt_webview_move(rktwebview_t w, int x, int y); RKTWEBVIEW_QT_EXPORT result_t rkt_webview_resize(rktwebview_t w, int width, int height); RKTWEBVIEW_QT_EXPORT result_t rkt_webview_hide(rktwebview_t w); @@ -82,9 +110,9 @@ RKTWEBVIEW_QT_EXPORT result_t rkt_webview_maximize(rktwebview_t w); RKTWEBVIEW_QT_EXPORT result_t rkt_webview_minimize(rktwebview_t w); RKTWEBVIEW_QT_EXPORT window_state_t rkt_webview_window_state(rktwebview_t w); -RKTWEBVIEW_QT_EXPORT rkt_js_result_t *rkt_webview_choose_dir(rktwebview_t w, const char *title, const char *base_dir); -RKTWEBVIEW_QT_EXPORT rkt_js_result_t *rkt_webview_file_open(rktwebview_t w, const char *title, const char *base_dir, const char *permitted_exts); -RKTWEBVIEW_QT_EXPORT rkt_js_result_t *rkt_webview_file_save(rktwebview_t w, const char *title, const char *base_dir, const char *permitted_exts); +RKTWEBVIEW_QT_EXPORT rkt_data_t *rkt_webview_choose_dir(rktwebview_t w, const char *title, const char *base_dir); +RKTWEBVIEW_QT_EXPORT rkt_data_t *rkt_webview_file_open(rktwebview_t w, const char *title, const char *base_dir, const char *permitted_exts); +RKTWEBVIEW_QT_EXPORT rkt_data_t *rkt_webview_file_save(rktwebview_t w, const char *title, const char *base_dir, const char *permitted_exts); } diff --git a/rktwebview_qt/rktwebview_qt.cpp b/rktwebview_qt/rktwebview_qt.cpp index f4fa58c..0dc6ded 100644 --- a/rktwebview_qt/rktwebview_qt.cpp +++ b/rktwebview_qt/rktwebview_qt.cpp @@ -12,6 +12,14 @@ #include "command.h" #include +static inline char *copyString(const char *s) +{ + int l = strlen(s); + char *cpy = static_cast(malloc(l + 1)); + memcpy(cpy, s, l + 1); + return cpy; +} + void Rktwebview_qt::processCommand(Command *cmd) { switch(cmd->cmd) { @@ -26,6 +34,9 @@ void Rktwebview_qt::processCommand(Command *cmd) void *f = cmd->args[1].value(); event_cb_t js_event_cb = reinterpret_cast (f); + bool has_scp = cmd->args[2].toBool(); + QByteArray scp_pem = cmd->args[3].toByteArray(); + WebviewWindow *p; if (_views.contains(parent)) { p = _views[parent]; @@ -33,7 +44,7 @@ void Rktwebview_qt::processCommand(Command *cmd) p = nullptr; } - WebviewWindow *w = new WebviewWindow(p); + WebviewWindow *w = new WebviewWindow(p, has_scp, scp_pem); WebViewQt *view = new WebViewQt(nextHandle(), w); w->addView(view, this); @@ -359,13 +370,17 @@ int Rktwebview_qt::nextHandle() return h; } -int Rktwebview_qt::rktWebViewCreate(int parent, event_cb_t js_evt_cb) +int Rktwebview_qt::rktWebViewCreate(int parent, event_cb_t js_evt_cb, const char *optional_server_cert_pem) { 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); + bool has_scp = (optional_server_cert_pem != nullptr); + c.args.push_back(has_scp); + QByteArray scp = (optional_server_cert_pem == nullptr) ? QByteArray("") : QByteArray(optional_server_cert_pem); + c.args.push_back(scp); postCommand(&c); @@ -427,7 +442,7 @@ result_t Rktwebview_qt::rktSetHtml(rktwebview_t wv, const char *html) return r ? result_t::oke : result_t::set_html_failed; } -rkt_js_result_t *Rktwebview_qt::rktCallJs(rktwebview_t wv, const char *js) +rkt_data_t *Rktwebview_qt::rktCallJs(rktwebview_t wv, const char *js) { Command c(COMMAND_CALL_JS); QString _js(js); @@ -436,9 +451,10 @@ rkt_js_result_t *Rktwebview_qt::rktCallJs(rktwebview_t wv, const char *js) postCommand(&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()); + rkt_data_t *r = static_cast(malloc(sizeof(rkt_data_t))); + 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()); return r; } @@ -520,7 +536,7 @@ window_state_t Rktwebview_qt::rktWindowState(rktwebview_t w) return ws; } -rkt_js_result_t *Rktwebview_qt::rktChooseDir(rktwebview_t w, const char *title, const char *base_dir) +rkt_data_t *Rktwebview_qt::rktChooseDir(rktwebview_t w, const char *title, const char *base_dir) { Command c(COMMAND_CHOOSE_DIR); c.args.push_back(w); @@ -537,15 +553,15 @@ rkt_js_result_t *Rktwebview_qt::rktChooseDir(rktwebview_t w, const char *title, bool oke = c.js_result_ok; - rkt_js_result_t *r = static_cast(malloc(sizeof(rkt_js_result_t))); - r->result = c.js_result_ok ? result_t::oke : result_t::choose_dir_failed; - - r->value = strdup(c.result.toString().toUtf8()); + rkt_data_t *r = static_cast(malloc(sizeof(rkt_js_result_t))); + r->kind = js_result; + r->data.js_result.result = c.js_result_ok ? result_t::oke : result_t::choose_dir_failed; + r->data.js_result.value = copyString(c.result.toString().toUtf8()); return r; } -rkt_js_result_t *Rktwebview_qt::rktFileOpen(rktwebview_t w, const char *title, const char *base_dir, const char *permitted_exts) +rkt_data_t *Rktwebview_qt::rktFileOpen(rktwebview_t w, const char *title, const char *base_dir, const char *permitted_exts) { Command c(COMMAND_FILE_OPEN); c.args.push_back(w); @@ -565,15 +581,15 @@ rkt_js_result_t *Rktwebview_qt::rktFileOpen(rktwebview_t w, const char *title, c bool oke = c.js_result_ok; - rkt_js_result_t *r = static_cast(malloc(sizeof(rkt_js_result_t))); - r->result = c.js_result_ok ? result_t::oke : result_t::choose_dir_failed; - - r->value = strdup(c.result.toString().toUtf8()); + rkt_data_t *r = static_cast(malloc(sizeof(rkt_data_t))); + r->kind = js_result; + r->data.js_result.result = c.js_result_ok ? result_t::oke : result_t::choose_dir_failed; + r->data.js_result.value = copyString(c.result.toString().toUtf8()); return r; } -rkt_js_result_t *Rktwebview_qt::rktFileSave(rktwebview_t w, const char *title, const char *base_dir, const char *permitted_exts) +rkt_data_t *Rktwebview_qt::rktFileSave(rktwebview_t w, const char *title, const char *base_dir, const char *permitted_exts) { Command c(COMMAND_FILE_SAVE); c.args.push_back(w); @@ -593,10 +609,10 @@ rkt_js_result_t *Rktwebview_qt::rktFileSave(rktwebview_t w, const char *title, c bool oke = c.js_result_ok; - rkt_js_result_t *r = static_cast(malloc(sizeof(rkt_js_result_t))); - r->result = c.js_result_ok ? result_t::oke : result_t::choose_dir_failed; - - r->value = strdup(c.result.toString().toUtf8()); + rkt_data_t *r = static_cast(malloc(sizeof(rkt_data_t))); + r->kind = js_result; + r->data.js_result.result = c.js_result_ok ? result_t::oke : result_t::choose_dir_failed; + r->data.js_result.value = copyString(c.result.toString().toUtf8()); return r; } @@ -672,11 +688,12 @@ 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); + char *evt = copyString(msg.toUtf8().constData()); + rkt_data_t *d = static_cast(malloc(sizeof(rkt_data_t))); + d->kind = rkt_data_kind_t::event; + d->data.event.wv = wv; + d->data.event.event = evt; + js_event_cb(d); } } @@ -726,21 +743,29 @@ void Rktwebview_qt::customEvent(QEvent *event) void Rktwebview_qt::doEvents() { - //_app->processEvents(); - if (_evt_loop_depth == 0) { + //QTime ct = QTime::currentTime(); + //QTime expire = QTime::currentTime().addMSecs(2); + //while(QTime::currentTime() <= expire) { + _app->processEvents(); + //} + + // Qt 6.10 --> this leads to a core dump + // together with the stopEventloop stuff. + // Qt 6.4 seem stable. + /*if (_evt_loop_depth == 0) { _evt_loop_depth += 1; _evt_loop_timer.setSingleShot(true); _evt_loop_timer.start(2); //_evt_loop.exec(); _app->exec(); - } + }*/ } void Rktwebview_qt::stopEventloop() { //_evt_loop.exit(0); - _app->exit(0); - _evt_loop_depth -= 1; + //_app->exit(0); + //_evt_loop_depth -= 1; } @@ -760,15 +785,18 @@ Rktwebview_qt::Rktwebview_qt(Rktwebview_qt **handler) : connect(&_process_events, &QTimer::timeout, this, &Rktwebview_qt::processJsEventQueues); _process_events.start(5); - connect(&_evt_loop_timer, &QTimer::timeout, this, &Rktwebview_qt::stopEventloop); + // See Qt 6.10 remark at doEvents. + //connect(&_evt_loop_timer, &QTimer::timeout, this, &Rktwebview_qt::stopEventloop); - //const auto *eventDispatcher = QThread::currentThread()->eventDispatcher(); - //QObject::connect(eventDispatcher, &QAbstractEventDispatcher::aboutToBlock, - // QThread::currentThread(), []{ - // if (QThread::currentThread()->loopLevel() == 0) - // QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); - // } - // ); + // Because we are using processEvents only (Qt 6.10), we need this dispatcher to + // handle deferred Deletes. + 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; } diff --git a/rktwebview_qt/rktwebview_qt.h b/rktwebview_qt/rktwebview_qt.h index abf088d..dcb7f72 100644 --- a/rktwebview_qt/rktwebview_qt.h +++ b/rktwebview_qt/rktwebview_qt.h @@ -64,7 +64,7 @@ public: public: int nextHandle(); public: - int rktWebViewCreate(int parent, event_cb_t js_evt_cb); + int rktWebViewCreate(int parent, event_cb_t js_evt_cb, const char *optional_server_cert_pem); void rktWebViewClose(int wv); void rktSetOUToken(rktwebview_t wv, const char *ou_token); void rktQuit(); @@ -73,7 +73,7 @@ public: result_t rktSetUrl(rktwebview_t wv, const char *url); result_t rktSetHtml(rktwebview_t wv, const char *html); result_t rktRunJs(rktwebview_t wv, const char *js); - rkt_js_result_t *rktCallJs(rktwebview_t wv, const char *js); + rkt_data_t *rktCallJs(rktwebview_t wv, const char *js); result_t rktMove(rktwebview_t wv, int x, int y); result_t rktResize(rktwebview_t wv, int w, int h); @@ -85,9 +85,9 @@ public: result_t rktShowNormalWindow(rktwebview_t w); window_state_t rktWindowState(rktwebview_t w); - rkt_js_result_t *rktChooseDir(rktwebview_t w, const char *title, const char *base_dir); - rkt_js_result_t * rktFileOpen(rktwebview_t w, const char *title, const char *base_dir, const char *permitted_exts); - rkt_js_result_t * rktFileSave(rktwebview_t w, const char *title, const char *base_dir, const char *permitted_exts); + rkt_data_t *rktChooseDir(rktwebview_t w, const char *title, const char *base_dir); + rkt_data_t *rktFileOpen(rktwebview_t w, const char *title, const char *base_dir, const char *permitted_exts); + rkt_data_t *rktFileSave(rktwebview_t w, const char *title, const char *base_dir, const char *permitted_exts); result_t rktWindowSetTitle(rktwebview_t wv, const char *title); @@ -110,7 +110,7 @@ public: public: Rktwebview_qt(Rktwebview_qt **handler); - }; +}; diff --git a/rktwebview_qt/webviewqt.cpp b/rktwebview_qt/webviewqt.cpp index 9526b5e..0d575ea 100644 --- a/rktwebview_qt/webviewqt.cpp +++ b/rktwebview_qt/webviewqt.cpp @@ -4,7 +4,7 @@ #include WebViewQt::WebViewQt(int id, WebviewWindow *window) - : QWebEngineView(window) + : QWebEngineView(window->profile(), window) { _id = id; _window = window; diff --git a/rktwebview_qt/webviewwindow.cpp b/rktwebview_qt/webviewwindow.cpp index 47c2870..8bcd6ea 100644 --- a/rktwebview_qt/webviewwindow.cpp +++ b/rktwebview_qt/webviewwindow.cpp @@ -10,13 +10,37 @@ #include #include #include +#include +#include +#include #include #include +#include -WebviewWindow::WebviewWindow(WebviewWindow *parent) +/* +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(WebviewWindow *parent, bool has_scp, QByteArray scp_pem) : QMainWindow{parent} { + static int profile_nr = 0; + _view = nullptr; _must_close = false; @@ -27,6 +51,22 @@ WebviewWindow::WebviewWindow(WebviewWindow *parent) _moved = 0; _resized = 0; + QWebEngineProfileBuilder b; + if (has_scp) { + profile_nr += 1; + char buf[100]; + sprintf(buf, "profile-%d", profile_nr); + QString name(buf); + QSslCertificate cert(scp_pem); + + QList certs; + certs.append(cert); + b.setAdditionalTrustedCertificates(certs); + _profile = b.createProfile(name); + } else { + _profile = QWebEngineProfile::defaultProfile(); + } + if (parent != nullptr) { setWindowModality(Qt::WindowModality::WindowModal); setWindowFlag(Qt::WindowType::Dialog, true); @@ -36,9 +76,63 @@ WebviewWindow::WebviewWindow(WebviewWindow *parent) connect(&_move_timer, &QTimer::timeout, this, &WebviewWindow::triggerMove); } +void WebviewWindow::navigationRequested(QWebEngineNavigationRequest &req) +{ + if (req.navigationType() == QWebEngineNavigationRequest::NavigationType::TypedNavigation) { + req.accept(); + } else { + EventContainer e("navigation-request"); + + e["url"] = req.url().toString(); + + 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); + + 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()); +*/ + + fprintf(stderr, "Certificate Error: %s\n", certificateError.description().toUtf8().constData()); QList chain = certificateError.certificateChain(); int i; for(i = 0; i < chain.size(); i++) { @@ -88,6 +182,7 @@ void WebviewWindow::closeEvent(QCloseEvent *evt) EventContainer e("closed"); _container->triggerEvent(_view->id(), e); _container->removeView(_view->id()); + _view->deleteLater(); this->deleteLater(); if (_devtools != nullptr) { _devtools->deleteLater(); @@ -131,7 +226,14 @@ void WebviewWindow::addView(WebViewQt *v, Rktwebview_qt *c) _view = v; this->setCentralWidget(v); - QWebEnginePage *page = _view->page(); + QWebEnginePage *page; + + if (_profile == nullptr) { + page = _view->page(); + } else { + page = new QWebEnginePage(_profile, this); + _view->setPage(page); + } // Inject event handling code for the javascript side QWebEngineScriptCollection &col = page->scripts(); @@ -160,6 +262,8 @@ void WebviewWindow::addView(WebViewQt *v, Rktwebview_qt *c) connect(page, &QWebEnginePage::loadStarted, this, [this]() { _container->onPageLoad(_view->id()); }); + connect(page, &QWebEnginePage::navigationRequested, this, &WebviewWindow::navigationRequested); + connect(page, &QWebEnginePage::certificateError, this, &WebviewWindow::handleCertificate); } @@ -231,6 +335,11 @@ void WebviewWindow::triggerMove() _container->triggerEvent(_view->id(), xy); } +QWebEngineProfile *WebviewWindow::profile() +{ + return _profile; +} + void WebviewWindow::resizeEvent(QResizeEvent *event) { _w = event->size().width(); diff --git a/rktwebview_qt/webviewwindow.h b/rktwebview_qt/webviewwindow.h index 94d27d6..d86a8af 100644 --- a/rktwebview_qt/webviewwindow.h +++ b/rktwebview_qt/webviewwindow.h @@ -4,6 +4,8 @@ #include #include #include +#include +#include class WebViewQt; class Rktwebview_qt; @@ -33,8 +35,11 @@ private: QString _ou_token; + QWebEngineProfile *_profile; + private slots: void handleCertificate(const QWebEngineCertificateError &certificateError); + void navigationRequested(QWebEngineNavigationRequest &req); public slots: void processJsEvents(); @@ -60,12 +65,15 @@ public: void openDevTools(); public: - explicit WebviewWindow(WebviewWindow *parent = nullptr); + explicit WebviewWindow(WebviewWindow *parent, bool has_scp, QByteArray scp_pem); private slots: void triggerResize(); void triggerMove(); +public: + QWebEngineProfile *profile(); + signals: // QWidget interface