Much work, using Qt 6.10 on Linux for better https support

This commit is contained in:
2026-03-11 17:57:55 +01:00
parent 989c3d328a
commit 7d234bc834
16 changed files with 541 additions and 217 deletions

View File

@@ -17,7 +17,7 @@ Some input text: <input type="Text" id="inp1" value="Default input value" />
Some input date: <input type="Date" id="inp2" value="2026-01-01" /> Some input date: <input type="Date" id="inp2" value="2026-01-01" />
</p> </p>
<p> <p>
Some color input: <input type="Color" id="inp3" value="#8732422" /> Some color input: <input type="Color" id="inp3" value="#873242" />
</p> </p>
<div id="test" class="yellow"> <div id="test" class="yellow">

View File

@@ -34,6 +34,7 @@
<div class="buttons"> <div class="buttons">
<button class="btn-2" id="dialog-button">Open a dialog</button> <button class="btn-2" id="dialog-button">Open a dialog</button>
<button class="btn-1" id="select-dir-button">Select a directory</button> <button class="btn-1" id="select-dir-button">Select a directory</button>
<button class="btn-2" id="devtools">Open Devtools</button>
</div> </div>
<h2>Menu responses</h2> <h2>Menu responses</h2>
<table> <table>

View File

@@ -11,13 +11,17 @@
example-1-window% example-1-window%
) )
(define ww-debug displayln)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Example 1 ;; Example 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-runtime-path html-start "example-1.html") (define-runtime-path html-start "example-1.html")
(define-runtime-path dialog-html "example-1-dialog.html") (define-runtime-path dialog-html "example-1-dialog.html")
(define-runtime-path cur-dir ".")
#|
(define test-menu (menu 'main-menu (define test-menu (menu 'main-menu
(menu-item 'm-file "File" (menu-item 'm-file "File"
#:submenu #:submenu
@@ -46,33 +50,34 @@
) )
) )
)) ))
|#
(define example-1-dialog% (define example-1-dialog%
(class ww-webview-dialog% (class wv-dialog%
(inherit-field settings) (inherit-field settings)
(super-new [html-file dialog-html] (super-new [window-context 'example-1-dialog]
[width 400] [file-not-found-handler (root-file-not-found-handler "example-1-dialog.html")]
[height 300]) )
(define/override (html-loaded) (define/override (page-loaded oke)
(super html-loaded) (super page-loaded oke)
(ww-debug "html-loaded for example-1-dialog%") ;(ww-debug "html-loaded for example-1-dialog%")
(let* ((btn (send this element 'ok-btn))) (send this bind! 'ok-btn 'click (λ (el evt data)
(send btn connect 'click (λ (data) (send this close)))
(send this close))))
(let* ((inp1 (send this element 'inp1)) (let* ((inp1 (send this element 'inp1 'text))
(inp2 (send this element 'inp2)) (inp2 (send this element 'inp2 'text))
(inp3 (send this element 'inp3))) (inp3 (send this element 'inp3 'text)))
(send inp1 set! (send settings get 'inp1 "<input 1 not set yet>")) (send inp1 set! (send settings get 'inp1 "<input 1 not set yet>"))
(send inp2 set! (send settings get 'inp2 "<input 2 not set yet>")) (send inp2 set! (send settings get 'inp2 "<input 2 not set yet>"))
(send inp3 set! (send settings get 'inp3 "<input 3 not set yet>")) (send inp3 set! (send settings get 'inp3 "<input 3 not set yet>"))
(send inp1 on-change! (send this bind! 'inp1 'change (λ (el evt data)
(λ (val) (displayln (format "~a ~a ~a" el evt data))
(send settings set! 'inp1 val))) (displayln (format "get = ~a" (send el get)))
(send inp2 on-change! (λ (val) (send settings set! 'inp2 val))) (send settings set! 'inp1 (send el get))))
(send inp3 on-change! (λ (val) (send settings set! 'inp3 val))) (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)))) var))))
(define example-1-window% (define example-1-window%
(class ww-webview% (class wv-window%
(inherit-field settings) (inherit-field settings app-context)
(super-new [html-file html-start] (super-new [file-not-found-handler (root-file-not-found-handler "example-1.html")]
[window-context 'example-1-main]
) )
(define go-on-counter #f) (define go-on-counter #f)
@@ -97,14 +103,21 @@
(define counter-inc 1) (define counter-inc 1)
(define counter-thread #f) (define counter-thread #f)
(define div-counter #f) (define div-counter #f)
(define my-dir (send settings get 'folder ".")) (define my-dir (send settings get/global 'folder "."))
(define/override (can-close?) (define/override (can-close?)
(eq? counter-thread #f)) (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) (set! go-on-counter #f)
)
(define/public (reset-counter)
(stop-counter)
(set! counter-thread #f) (set! counter-thread #f)
) )
@@ -117,25 +130,26 @@
(send this update-counter)) (send this update-counter))
(define/public (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)) (when (and (> c-counter 0) (<= c-counter 100))
(send div-counter set-style! (send div-counter set-style!
(css-style '((background white))))) '((background white))))
(when (and (> c-counter 100) (<= c-counter 200)) (when (and (> c-counter 100) (<= c-counter 200))
(send div-counter set-style! (send div-counter set-style!
(css-style '((background green) (color white))))) '((background green) (color white))))
(when (and (> c-counter 200) (<= c-counter 300)) (when (and (> c-counter 200) (<= c-counter 300))
(send div-counter set-style! (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)) (when (and (> c-counter 300) (<= c-counter 400))
(send div-counter set-style! (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)) (when (and (> c-counter 400))
(send div-counter set-style! (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) (define/public (start-counter)
(send start-stop-btn set-innerHTML! "Stop Counter")
(set! counter-thread (set! counter-thread
(thread (thread
(λ () (λ ()
@@ -150,65 +164,68 @@
(define/public (set-folder new-dir) (define/public (set-folder new-dir)
(set! my-dir 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))) (let ((el (send this element 'folder)))
(send el set-inner-html! (format "Selected folder: <b>~a</b>" my-dir)) (send el set-innerHTML! (format "Selected folder: <b>~a</b>" my-dir))
) )
) )
(define/override (choose-dir) (define/override (choose-dir)
(let ((handle (super choose-dir "Select a folder" my-dir))) (let ((result (super choose-dir "Select a folder" my-dir)))
(displayln (format "choosen dir handle: ~a" handle)) (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) (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) ;(define/override (handle-navigate url type kind)
(send this reset-counter) ; (send this reset-counter)
(super handle-navigate url type kind)) ; (super handle-navigate url type kind))
(define/override (html-loaded) (define/override (page-loaded oke)
(ww-debug "HTML LOADED") (ww-debug "HTML LOADED")
(super html-loaded) (super page-loaded oke)
(set! div-counter (send this element 'div-counter)) (set! div-counter (send this element 'div-counter))
(send this update-counter) (send this update-counter)
(send this set-folder my-dir) (send this set-folder my-dir)
(ww-debug "CONNECTING BUTTONS") (ww-debug "CONNECTING BUTTONS")
(let* ((dialog-btn (send this element 'dialog-button)) (send this bind! 'dialog-button 'click (λ (el evt data)
(start-stop-btn (send this element 'start-stop-button)) (send this prefs)))
(choose-dir-btn (send this element 'select-dir-button))
) (set! start-stop-btn (send this element 'start-stop-button))
(send dialog-btn connect 'click (send this bind! 'start-stop-button 'click
(λ (data) (send this prefs))) (λ (el evt data)
(if (eq? counter-thread #f)
(send start-stop-btn connect 'click (begin
(λ (data) (send this start-counter)
(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"))
) )
) (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) (c-open 0)
(div-close (send this element 'div-close)) (div-close (send this element 'div-close))
(c-close 0) (c-close 0)
@@ -250,7 +267,7 @@
(λ () (send this choose-dir))) (λ () (send this choose-dir)))
) )
) )|#
) )
(begin (begin
@@ -261,7 +278,9 @@
(define (run-example) (define (run-example)
(let* ((ini (new ini% [file 'web-racket-example1])) (let* ((ini (new ini% [file 'web-racket-example1]))
(settings (new ww-simple-ini% [ini ini] [section 'example-1-window])) (window (new example-1-window%
(window (new example-1-window% [settings settings])) [app-context 'example-1]
[ini ini]
[base-dir cur-dir]))
) )
window)) window))

View File

@@ -722,4 +722,3 @@
(addMimeType "Zip Archive" "application/zip" '(zip) "Wikipedia: Zip") (addMimeType "Zip Archive" "application/zip" '(zip) "Wikipedia: Zip")
(addMimeType "ZVUE Media Manager" "application/vnd.handheld-entertainment+xml" '(zmm) "IANA: ZVUE Media Manager") (addMimeType "ZVUE Media Manager" "application/vnd.handheld-entertainment+xml" '(zmm) "IANA: ZVUE Media Manager")
(addMimeType "Zzazz Deck" "application/vnd.zzazz.deck+xml" '(zaz) "IANA: Zzazz") (addMimeType "Zzazz Deck" "application/vnd.zzazz.deck+xml" '(zaz) "IANA: Zzazz")

View File

@@ -39,6 +39,7 @@
rkt-webview-choose-dir rkt-webview-choose-dir
rkt-webview-file-open rkt-webview-file-open
rkt-webview-file-save rkt-webview-file-save
rkt-webview-version
) )
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -48,6 +49,7 @@
(define lib-type 'release) (define lib-type 'release)
(define os (system-type 'os*)) (define os (system-type 'os*))
(define arch (system-type 'arch))
(define supported-os '(windows linux)) (define supported-os '(windows linux))
(unless (ormap (λ (o) (eq? os o)) supported-os) (unless (ormap (λ (o) (eq? os o)) supported-os)
@@ -77,7 +79,27 @@
Qt6WebEngineWidgets.dll Qt6WebEngineWidgets.dll
)) ))
([eq? os 'linux] ([eq? os 'linux]
'()) '(libQt6XcbQpa
;libQt6WaylandClient
;libQt6EglFSDeviceIntegration
libQt6Core
libQt6Positioning
libQt6Gui
libQt6Widgets
libQt6Svg
libQt6Network
libQt6OpenGL
libQt6PrintSupport
libQt6Qml
libQt6QmlModels
libQt6QmlWorkerScript
libQt6QmlMeta
libQt6Quick
libQt6QuickWidgets
libQt6WebChannel
libQt6WebEngineCore
libQt6WebEngineWidgets
))
) )
) )
@@ -88,26 +110,51 @@
) )
) )
(define os-lib-dir (build-path lib-dir (symbol->string os) (symbol->string arch)))
(define (libname lib-symbol) (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 ; c:\qt\6.10.2\msvc2022_64\bin\windeployqt.exe rktwebview_qt_test.exe
(when (eq? os 'windows) (define quiet-call #t)
(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")))
)
(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 ;;; Preload libraries
(for-each (λ (lib-symbol) (for-each (λ (lib-symbol)
(let ((load-lib (libname lib-symbol))) (let* ((libn (if (list? lib-symbol) (car lib-symbol) lib-symbol))
(ffi-lib load-lib))) (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) libraries-to-preload)
;;; Actual FFI integration ;;; Actual FFI integration
@@ -130,7 +177,7 @@
ffi-library os exp)))) 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) (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 (define-cstruct _rkt_evt_t
([w _int] ([w _int]
[evt _pointer] [evt _pointer]
@@ -180,6 +245,13 @@
[value _pointer] [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); ;RKTWEBVIEW_QT_EXPORT void rkt_webview_init(int &argc, char **argv);
(define-rktwebview rkt_webview_init (define-rktwebview rkt_webview_init
(_fun -> _void)) (_fun -> _void))
@@ -188,10 +260,23 @@
(define-rktwebview rkt_webview_process_events (define-rktwebview rkt_webview_process_events
(_fun _int -> _void)) (_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 (define-rktwebview rkt_webview_create
(_fun _int (_fun #:keep callback-box #:async-apply applier (_fun _int
_rkt_evt_t-pointer -> _void) -> _int)) (_fun #:keep callback-box #:async-apply applier
_rkt_data_t-pointer -> _void)
_bytes
-> _int))
;RKTWEBVIEW_QT_EXPORT void rkt_webview_close(int wv); ;RKTWEBVIEW_QT_EXPORT void rkt_webview_close(int wv);
(define-rktwebview rkt_webview_close (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); ;RKTWEBVIEW_QT_EXPORT rkt_js_result_t *rkt_webview_call_js(rktwebview_t wv, const char *js);
(define-rktwebview rkt_webview_call_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); ;RKTWEBVIEW_QT_EXPORT result_t rkt_webview_open_devtools(int wv);
(define-rktwebview rkt_webview_open_devtools (define-rktwebview rkt_webview_open_devtools
(_fun _int -> _rkt_result_t)) (_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); ;RKTWEBVIEW_QT_EXPORT result_t rkt_webview_move(rktwebview_t w, int x, int y);
(define-rktwebview rkt_webview_move (define-rktwebview rkt_webview_move
(_fun _int _int _int -> _rkt_result_t)) (_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); ;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 (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); ;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 (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); ;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 (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))))) (f)))))
(rkt_webview_init) (rkt_webview_init)
(start-event-processing) (set! quiet-call (start-event-processing))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Provided features ;; Provided features
@@ -323,27 +400,29 @@
(define (rkt-process-events handle) (define (rkt-process-events handle)
(if (> (queue-length (rkt-wv-evt-queue handle)) 0) (if (> (queue-length (rkt-wv-evt-queue handle)) 0)
(let ((e (dequeue! (rkt-wv-evt-queue handle)))) (let ((data (dequeue! (rkt-wv-evt-queue handle))))
(if (symbol? e) (if (symbol? data)
(if (eq? e 'quit) (if (eq? data 'quit)
(begin (begin
(hash-remove! rkt-wv-store (rkt-wv-win handle)) (hash-remove! rkt-wv-store (rkt-wv-win handle))
'quit) 'quit)
(rkt-process-events handle)) (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-wv-callback handle) handle evt)
(rkt_webview_destroy_event e) (rkt_webview_free_data data)
(rkt-process-events handle))) (rkt-process-events handle)))
) )
'done)) '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)) (let* ((evt-queue (make-queue))
(parent-win (if (eq? parent #f) 0 (rkt-wv-win parent))) (parent-win (if (eq? parent #f) 0 (rkt-wv-win parent)))
) )
(let ((wv (rkt_webview_create parent-win (let ((wv (rkt_webview_create parent-win
(λ (rkt-evt) (λ (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))) (let ((handle (make-rkt-wv wv evt-queue evt-callback #t close-callback)))
(thread (λ () (thread (λ ()
(sleep 1) (sleep 1)
@@ -385,10 +464,11 @@
(rkt_webview_run_js (rkt-wv-win wv) js)) (rkt_webview_run_js (rkt-wv-win wv) js))
(define (rkt-webview-call-js 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)) (value (cast (rkt_js_result_t-value r) _pointer _string*/utf-8))
(result (rkt_js_result_t-result r))) (result (rkt_js_result_t-result r)))
(rkt_webview_destroy_js_result r) (rkt_webview_free_data d)
(list result value))) (list result value)))
(define (rkt-webview-resize wv w h) (define (rkt-webview-resize wv w h)
@@ -415,26 +495,47 @@
(rkt_webview_open_devtools (rkt-wv-win wv))) (rkt_webview_open_devtools (rkt-wv-win wv)))
(define (rkt-webview-choose-dir wv title base-dir) (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)) (value (cast (rkt_js_result_t-value r) _pointer _string*/utf-8))
(result (rkt_js_result_t-result r))) (result (rkt_js_result_t-result r)))
(rkt_webview_destroy_js_result r) (rkt_webview_free_data d)
(list result value))) (list result value)))
(define (rkt-webview-file-open wv title base-dir permitted-exts) (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)) (value (cast (rkt_js_result_t-value r) _pointer _string*/utf-8))
(result (rkt_js_result_t-result r))) (result (rkt_js_result_t-result r)))
(rkt_webview_destroy_js_result r) (rkt_webview_free_data d)
(list result value))) (list result value)))
(define (rkt-webview-file-save wv title base-dir permitted-exts) (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)) (value (cast (rkt_js_result_t-value r) _pointer _string*/utf-8))
(result (rkt_js_result_t-result r))) (result (rkt_js_result_t-result r)))
(rkt_webview_destroy_js_result r) (rkt_webview_free_data d)
(list result value))) (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 ;; Administration
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -459,9 +560,10 @@
;; Cleanup on exit ;; Cleanup on exit
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(plumber-add-flush! (current-plumber) (set! quiet-call
(λ (handle) (plumber-add-flush! (current-plumber)
(rkt-webview-exit))) (λ (handle)
(rkt-webview-exit))))

View File

@@ -1,6 +1,7 @@
#lang racket/base #lang racket/base
(require "racket-webview-qt.rkt" (require "racket-webview-qt.rkt"
"racket-webview-version.rkt"
"utils.rkt" "utils.rkt"
"mimetypes.rkt" "mimetypes.rkt"
"rgba.rkt" "rgba.rkt"
@@ -99,6 +100,11 @@
webview-standard-file-getter webview-standard-file-getter
webview-version
wv-base-url
wv-window-nr
test test
) )
@@ -393,12 +399,13 @@
(cert (generate-self-signed-cert 2048 365 '("127.0.0.1" "localhost") (cert (generate-self-signed-cert 2048 365 '("127.0.0.1" "localhost")
"NL" "Dijkema" "NL" "Dijkema"
#:ou (wv-cert-ou-token h))) #:ou (wv-cert-ou-token h)))
(server-cert (certificate cert))
(event-processor (λ (wv evt) (event-processor (λ (wv evt)
(event-callback h (util-parse-event evt)))) (event-callback h (util-parse-event evt))))
(close-callback (λ () (close-callback (λ ()
(remove-cert-files h))) (remove-cert-files h)))
(ph (if (wv? p) (wv-handle p) #f)) (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-handle! h internal-handle)
(set-wv-window-nr! h (rkt-wv-win internal-handle)) (set-wv-window-nr! h (rkt-wv-win internal-handle))
internal-handle)) internal-handle))
@@ -870,7 +877,11 @@
(wva webview-attr/date g:date? string->date) (wva webview-attr/date g:date? string->date)
(wva webview-attr/time g:time? string->time) (wva webview-attr/time g:time? string->time)
(wva webview-attr/datetime g:datetime string->datetime) (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 ;; testing

View File

@@ -26,6 +26,7 @@
#define COMMAND_FILE_OPEN 20 #define COMMAND_FILE_OPEN 20
#define COMMAND_FILE_SAVE 21 #define COMMAND_FILE_SAVE 21
#define COMMAND_SET_OU_TOKEN 22 #define COMMAND_SET_OU_TOKEN 22
#define COMMAND_SET_CERTIFICATE 23
class Command class Command
{ {

View File

@@ -1,14 +1,15 @@
#include "rktwebview.h" #include "rktwebview.h"
#include <QThread> #include <QThread>
#include <QFile>
static int _argc; static int _argc;
static char **_argv; static char **_argv;
void eventCb(rkt_event_t *e) void eventCb(rkt_data_t *e)
{ {
printf("event: %s\n", e->event); printf("event: %s\n", e->data.event.event);
rkt_webview_destroy_event(e); rkt_webview_free_data(e);
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[])
@@ -20,7 +21,9 @@ int main(int argc, char *argv[])
_argv = argv; _argv = argv;
rkt_webview_init(); rkt_webview_init();
wv1 = rkt_webview_create(0, eventCb);
wv1 = rkt_webview_create(0, eventCb, nullptr);
rkt_webview_move(wv1, 200, 300); rkt_webview_move(wv1, 200, 300);
rkt_webview_resize(wv1, 800, 600); rkt_webview_resize(wv1, 800, 600);
rkt_webview_set_url(wv1, "https://wikipedia.org"); //"http://127.0.0.1:8083"); 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) { if (i == 3) {
rkt_js_result_t *r = rkt_webview_call_js(wv1, "{ let a = 7 * 6; console.log('a = ' + a); return a; }"); 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->result, r->value); 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) { if (i == 4) {
rkt_js_result_t *r = rkt_webview_call_js(wv1, "let el = document.getElementById('hi');el.value = '10';"); 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->result, r->value); 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) { if (i == 6) {
rkt_js_result_t *r = rkt_webview_call_js(wv1, "document.body.innerHTML = '<h1>Hi!</h1>'; return document.body.innerHTML;"); rkt_data_t *r = rkt_webview_call_js(wv1, "document.body.innerHTML = '<h1>Hi!</h1>'; return document.body.innerHTML;");
printf("rkt_js_result: %d: %s\n", r->result, r->value); 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) { if (i == 10) {
wv2 = rkt_webview_create(wv1, eventCb); wv2 = rkt_webview_create(wv1, eventCb, nullptr);
rkt_webview_move(wv2, 400, 200); rkt_webview_move(wv2, 400, 200);
rkt_webview_resize(wv2, 800, 600); rkt_webview_resize(wv2, 800, 600);
rkt_webview_set_url(wv2, "https://127.0.0.1"); rkt_webview_set_url(wv2, "https://127.0.0.1");

View File

@@ -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(); 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) 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; 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_webview_init();
rkt_js_result_t *r = handler->rktCallJs(wv, js); rkt_data_t *r = handler->rktCallJs(wv, js);
return r; 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) result_t rkt_webview_move(rktwebview_t wv, int x, int y)
{ {
rkt_webview_init(); rkt_webview_init();
@@ -184,19 +168,19 @@ result_t rkt_webview_set_title(rktwebview_t wv, const char *title)
return handler->rktWindowSetTitle(wv, 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(); rkt_webview_init();
return handler->rktChooseDir(w, title, base_dir); 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(); rkt_webview_init();
return handler->rktFileOpen(w, title, base_dir, permitted_exts); 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(); rkt_webview_init();
return handler->rktFileSave(w, title, base_dir, permitted_exts); 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(); rkt_webview_init();
handler->rktSetOUToken(wv, token); 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<rkt_data_t *>(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;
}

View File

@@ -3,6 +3,10 @@
#include "rktwebview_qt_global.h" #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" { extern "C" {
typedef int rktwebview_t; typedef int rktwebview_t;
@@ -12,8 +16,6 @@ typedef struct {
char *event; char *event;
} rkt_event_t; } rkt_event_t;
typedef void (*event_cb_t)(rkt_event_t *);
typedef enum { typedef enum {
no_result_yet = -1, no_result_yet = -1,
oke = 0, oke = 0,
@@ -51,27 +53,53 @@ typedef enum {
maximized_active = 18 maximized_active = 18
} window_state_t; } 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_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(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 void rkt_webview_close(rktwebview_t wv);
RKTWEBVIEW_QT_EXPORT bool rkt_webview_valid(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 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 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_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_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 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 rkt_data_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 result_t rkt_webview_open_devtools(rktwebview_t wv); 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_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_resize(rktwebview_t w, int width, int height);
RKTWEBVIEW_QT_EXPORT result_t rkt_webview_hide(rktwebview_t w); 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 result_t rkt_webview_minimize(rktwebview_t w);
RKTWEBVIEW_QT_EXPORT window_state_t rkt_webview_window_state(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_data_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_data_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_file_save(rktwebview_t w, const char *title, const char *base_dir, const char *permitted_exts);
} }

View File

@@ -12,6 +12,14 @@
#include "command.h" #include "command.h"
#include <QFileDialog> #include <QFileDialog>
static inline char *copyString(const char *s)
{
int l = strlen(s);
char *cpy = static_cast<char *>(malloc(l + 1));
memcpy(cpy, s, l + 1);
return cpy;
}
void Rktwebview_qt::processCommand(Command *cmd) void Rktwebview_qt::processCommand(Command *cmd)
{ {
switch(cmd->cmd) { switch(cmd->cmd) {
@@ -26,6 +34,9 @@ void Rktwebview_qt::processCommand(Command *cmd)
void *f = cmd->args[1].value<void *>(); void *f = cmd->args[1].value<void *>();
event_cb_t js_event_cb = reinterpret_cast <event_cb_t>(f); event_cb_t js_event_cb = reinterpret_cast <event_cb_t>(f);
bool has_scp = cmd->args[2].toBool();
QByteArray scp_pem = cmd->args[3].toByteArray();
WebviewWindow *p; WebviewWindow *p;
if (_views.contains(parent)) { if (_views.contains(parent)) {
p = _views[parent]; p = _views[parent];
@@ -33,7 +44,7 @@ void Rktwebview_qt::processCommand(Command *cmd)
p = nullptr; p = nullptr;
} }
WebviewWindow *w = new WebviewWindow(p); WebviewWindow *w = new WebviewWindow(p, has_scp, scp_pem);
WebViewQt *view = new WebViewQt(nextHandle(), w); WebViewQt *view = new WebViewQt(nextHandle(), w);
w->addView(view, this); w->addView(view, this);
@@ -359,13 +370,17 @@ int Rktwebview_qt::nextHandle()
return h; 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); Command c(COMMAND_CREATE);
c.args.push_back(parent); c.args.push_back(parent);
void *function = reinterpret_cast<void *>(js_evt_cb); void *function = reinterpret_cast<void *>(js_evt_cb);
QVariant f(QVariant::fromValue(function)); QVariant f(QVariant::fromValue(function));
c.args.push_back(f); 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); 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; 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); Command c(COMMAND_CALL_JS);
QString _js(js); QString _js(js);
@@ -436,9 +451,10 @@ rkt_js_result_t *Rktwebview_qt::rktCallJs(rktwebview_t wv, const char *js)
postCommand(&c); postCommand(&c);
while(!c.done) { doEvents(); } while(!c.done) { doEvents(); }
rkt_js_result_t *r = static_cast<rkt_js_result_t *>(malloc(sizeof(rkt_js_result_t))); rkt_data_t *r = static_cast<rkt_data_t *>(malloc(sizeof(rkt_data_t)));
r->result = c.js_result_ok ? result_t::oke : result_t::eval_js_failed; r->kind = js_result;
r->value = strdup(c.result.toString().toUtf8()); 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; return r;
} }
@@ -520,7 +536,7 @@ window_state_t Rktwebview_qt::rktWindowState(rktwebview_t w)
return ws; 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); Command c(COMMAND_CHOOSE_DIR);
c.args.push_back(w); 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; bool oke = c.js_result_ok;
rkt_js_result_t *r = static_cast<rkt_js_result_t *>(malloc(sizeof(rkt_js_result_t))); rkt_data_t *r = static_cast<rkt_data_t *>(malloc(sizeof(rkt_js_result_t)));
r->result = c.js_result_ok ? result_t::oke : result_t::choose_dir_failed; r->kind = js_result;
r->data.js_result.result = c.js_result_ok ? result_t::oke : result_t::choose_dir_failed;
r->value = strdup(c.result.toString().toUtf8()); r->data.js_result.value = copyString(c.result.toString().toUtf8());
return r; 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); Command c(COMMAND_FILE_OPEN);
c.args.push_back(w); 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; bool oke = c.js_result_ok;
rkt_js_result_t *r = static_cast<rkt_js_result_t *>(malloc(sizeof(rkt_js_result_t))); rkt_data_t *r = static_cast<rkt_data_t *>(malloc(sizeof(rkt_data_t)));
r->result = c.js_result_ok ? result_t::oke : result_t::choose_dir_failed; r->kind = js_result;
r->data.js_result.result = c.js_result_ok ? result_t::oke : result_t::choose_dir_failed;
r->value = strdup(c.result.toString().toUtf8()); r->data.js_result.value = copyString(c.result.toString().toUtf8());
return r; 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); Command c(COMMAND_FILE_SAVE);
c.args.push_back(w); 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; bool oke = c.js_result_ok;
rkt_js_result_t *r = static_cast<rkt_js_result_t *>(malloc(sizeof(rkt_js_result_t))); rkt_data_t *r = static_cast<rkt_data_t *>(malloc(sizeof(rkt_data_t)));
r->result = c.js_result_ok ? result_t::oke : result_t::choose_dir_failed; r->kind = js_result;
r->data.js_result.result = c.js_result_ok ? result_t::oke : result_t::choose_dir_failed;
r->value = strdup(c.result.toString().toUtf8()); r->data.js_result.value = copyString(c.result.toString().toUtf8());
return r; return r;
} }
@@ -672,11 +688,12 @@ void Rktwebview_qt::triggerEvent(rktwebview_t wv, const QString &msg)
{ {
if (_view_js_callbacks.contains(wv)) { if (_view_js_callbacks.contains(wv)) {
event_cb_t js_event_cb = _view_js_callbacks[wv]; event_cb_t js_event_cb = _view_js_callbacks[wv];
char *evt = strdup(msg.toUtf8().constData()); char *evt = copyString(msg.toUtf8().constData());
rkt_event_t *e = static_cast<rkt_event_t *>(malloc(sizeof(rkt_event_t))); rkt_data_t *d = static_cast<rkt_data_t *>(malloc(sizeof(rkt_data_t)));
e->wv = wv; d->kind = rkt_data_kind_t::event;
e->event = evt; d->data.event.wv = wv;
js_event_cb(e); d->data.event.event = evt;
js_event_cb(d);
} }
} }
@@ -726,21 +743,29 @@ void Rktwebview_qt::customEvent(QEvent *event)
void Rktwebview_qt::doEvents() void Rktwebview_qt::doEvents()
{ {
//_app->processEvents(); //QTime ct = QTime::currentTime();
if (_evt_loop_depth == 0) { //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_depth += 1;
_evt_loop_timer.setSingleShot(true); _evt_loop_timer.setSingleShot(true);
_evt_loop_timer.start(2); _evt_loop_timer.start(2);
//_evt_loop.exec(); //_evt_loop.exec();
_app->exec(); _app->exec();
} }*/
} }
void Rktwebview_qt::stopEventloop() void Rktwebview_qt::stopEventloop()
{ {
//_evt_loop.exit(0); //_evt_loop.exit(0);
_app->exit(0); //_app->exit(0);
_evt_loop_depth -= 1; //_evt_loop_depth -= 1;
} }
@@ -760,15 +785,18 @@ Rktwebview_qt::Rktwebview_qt(Rktwebview_qt **handler) :
connect(&_process_events, &QTimer::timeout, this, &Rktwebview_qt::processJsEventQueues); connect(&_process_events, &QTimer::timeout, this, &Rktwebview_qt::processJsEventQueues);
_process_events.start(5); _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(); // Because we are using processEvents only (Qt 6.10), we need this dispatcher to
//QObject::connect(eventDispatcher, &QAbstractEventDispatcher::aboutToBlock, // handle deferred Deletes.
// QThread::currentThread(), []{ const auto *eventDispatcher = QThread::currentThread()->eventDispatcher();
// if (QThread::currentThread()->loopLevel() == 0) QObject::connect(eventDispatcher, &QAbstractEventDispatcher::aboutToBlock,
// QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete); QThread::currentThread(), []{
// } if (QThread::currentThread()->loopLevel() == 0)
// ); QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
}
);
*_handler = nullptr; *_handler = nullptr;
} }

View File

@@ -64,7 +64,7 @@ public:
public: public:
int nextHandle(); int nextHandle();
public: 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 rktWebViewClose(int wv);
void rktSetOUToken(rktwebview_t wv, const char *ou_token); void rktSetOUToken(rktwebview_t wv, const char *ou_token);
void rktQuit(); void rktQuit();
@@ -73,7 +73,7 @@ public:
result_t rktSetUrl(rktwebview_t wv, const char *url); result_t rktSetUrl(rktwebview_t wv, const char *url);
result_t rktSetHtml(rktwebview_t wv, const char *html); result_t rktSetHtml(rktwebview_t wv, const char *html);
result_t rktRunJs(rktwebview_t wv, const char *js); 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 rktMove(rktwebview_t wv, int x, int y);
result_t rktResize(rktwebview_t wv, int w, int h); result_t rktResize(rktwebview_t wv, int w, int h);
@@ -85,9 +85,9 @@ public:
result_t rktShowNormalWindow(rktwebview_t w); result_t rktShowNormalWindow(rktwebview_t w);
window_state_t rktWindowState(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_data_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_data_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 *rktFileSave(rktwebview_t w, const char *title, const char *base_dir, const char *permitted_exts);
result_t rktWindowSetTitle(rktwebview_t wv, const char *title); result_t rktWindowSetTitle(rktwebview_t wv, const char *title);
@@ -110,7 +110,7 @@ public:
public: public:
Rktwebview_qt(Rktwebview_qt **handler); Rktwebview_qt(Rktwebview_qt **handler);
}; };

View File

@@ -4,7 +4,7 @@
#include <QJsonDocument> #include <QJsonDocument>
WebViewQt::WebViewQt(int id, WebviewWindow *window) WebViewQt::WebViewQt(int id, WebviewWindow *window)
: QWebEngineView(window) : QWebEngineView(window->profile(), window)
{ {
_id = id; _id = id;
_window = window; _window = window;

View File

@@ -10,13 +10,37 @@
#include <QJsonObject> #include <QJsonObject>
#include <QWebEngineScriptCollection> #include <QWebEngineScriptCollection>
#include <QWebEngineScript> #include <QWebEngineScript>
#include <QWebEngineProfile>
#include <QWebEngineProfileBuilder>
#include <QWebEnginePage>
#include <QMoveEvent> #include <QMoveEvent>
#include <QWindow> #include <QWindow>
#include <QWebEngineProfileBuilder>
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<QSslCertificate::SubjectInfo > 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} : QMainWindow{parent}
{ {
static int profile_nr = 0;
_view = nullptr; _view = nullptr;
_must_close = false; _must_close = false;
@@ -27,6 +51,22 @@ WebviewWindow::WebviewWindow(WebviewWindow *parent)
_moved = 0; _moved = 0;
_resized = 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<QSslCertificate> certs;
certs.append(cert);
b.setAdditionalTrustedCertificates(certs);
_profile = b.createProfile(name);
} else {
_profile = QWebEngineProfile::defaultProfile();
}
if (parent != nullptr) { if (parent != nullptr) {
setWindowModality(Qt::WindowModality::WindowModal); setWindowModality(Qt::WindowModality::WindowModal);
setWindowFlag(Qt::WindowType::Dialog, true); setWindowFlag(Qt::WindowType::Dialog, true);
@@ -36,9 +76,63 @@ WebviewWindow::WebviewWindow(WebviewWindow *parent)
connect(&_move_timer, &QTimer::timeout, this, &WebviewWindow::triggerMove); 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) void WebviewWindow::handleCertificate(const QWebEngineCertificateError &certificateError)
{ {
/*
QList<QSslCertificate> certs = _view->page()->profile()->additionalTrustedCertificates();
auto dodisp = [](QList<QSslCertificate> certs)
{
int i;
for(i = 0; i < certs.size(); i++) {
QSslCertificate cert = certs[i];
QList<QSslCertificate::SubjectInfo> 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<QSslCertificate> chain = certificateError.certificateChain(); QList<QSslCertificate> chain = certificateError.certificateChain();
int i; int i;
for(i = 0; i < chain.size(); i++) { for(i = 0; i < chain.size(); i++) {
@@ -88,6 +182,7 @@ void WebviewWindow::closeEvent(QCloseEvent *evt)
EventContainer e("closed"); EventContainer e("closed");
_container->triggerEvent(_view->id(), e); _container->triggerEvent(_view->id(), e);
_container->removeView(_view->id()); _container->removeView(_view->id());
_view->deleteLater();
this->deleteLater(); this->deleteLater();
if (_devtools != nullptr) { if (_devtools != nullptr) {
_devtools->deleteLater(); _devtools->deleteLater();
@@ -131,7 +226,14 @@ void WebviewWindow::addView(WebViewQt *v, Rktwebview_qt *c)
_view = v; _view = v;
this->setCentralWidget(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 // Inject event handling code for the javascript side
QWebEngineScriptCollection &col = page->scripts(); QWebEngineScriptCollection &col = page->scripts();
@@ -160,6 +262,8 @@ void WebviewWindow::addView(WebViewQt *v, Rktwebview_qt *c)
connect(page, &QWebEnginePage::loadStarted, this, [this]() { connect(page, &QWebEnginePage::loadStarted, this, [this]() {
_container->onPageLoad(_view->id()); _container->onPageLoad(_view->id());
}); });
connect(page, &QWebEnginePage::navigationRequested, this, &WebviewWindow::navigationRequested);
connect(page, &QWebEnginePage::certificateError, this, &WebviewWindow::handleCertificate); connect(page, &QWebEnginePage::certificateError, this, &WebviewWindow::handleCertificate);
} }
@@ -231,6 +335,11 @@ void WebviewWindow::triggerMove()
_container->triggerEvent(_view->id(), xy); _container->triggerEvent(_view->id(), xy);
} }
QWebEngineProfile *WebviewWindow::profile()
{
return _profile;
}
void WebviewWindow::resizeEvent(QResizeEvent *event) void WebviewWindow::resizeEvent(QResizeEvent *event)
{ {
_w = event->size().width(); _w = event->size().width();

View File

@@ -4,6 +4,8 @@
#include <QMainWindow> #include <QMainWindow>
#include <QTimer> #include <QTimer>
#include <QWebEngineCertificateError> #include <QWebEngineCertificateError>
#include <QWebEngineProfile>
#include <QWebEngineNavigationRequest>
class WebViewQt; class WebViewQt;
class Rktwebview_qt; class Rktwebview_qt;
@@ -33,8 +35,11 @@ private:
QString _ou_token; QString _ou_token;
QWebEngineProfile *_profile;
private slots: private slots:
void handleCertificate(const QWebEngineCertificateError &certificateError); void handleCertificate(const QWebEngineCertificateError &certificateError);
void navigationRequested(QWebEngineNavigationRequest &req);
public slots: public slots:
void processJsEvents(); void processJsEvents();
@@ -60,12 +65,15 @@ public:
void openDevTools(); void openDevTools();
public: public:
explicit WebviewWindow(WebviewWindow *parent = nullptr); explicit WebviewWindow(WebviewWindow *parent, bool has_scp, QByteArray scp_pem);
private slots: private slots:
void triggerResize(); void triggerResize();
void triggerMove(); void triggerMove();
public:
QWebEngineProfile *profile();
signals: signals:
// QWidget interface // QWidget interface