Files
racket-webview/private/racket-webview-qt.rkt
2026-03-04 01:41:14 +01:00

314 lines
10 KiB
Racket

#lang racket/base
(require ffi/unsafe
ffi/unsafe/define
ffi/unsafe/atomic
ffi/unsafe/os-thread
racket/async-channel
racket/runtime-path
racket/port
data/queue
json
racket/string
racket/path
)
(provide rkt-wv
rkt-wv-win
rkt-webview-create
rkt-webview-close
rkt-webview-set-url!
rkt-webview-set-html!
rkt-webview-run-js
rkt-webview-call-js
rkt-webview-move
rkt-webview-resize
rkt-webview-exit
rkt-webview-valid?
rkt-webview-open-devtools
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; FFI Library
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define lib-type 'release)
(define-runtime-path lib-dir ".")
; (if (eq? (system-type 'os*) 'windows)
; "..\\lib"
; "../lib"))
(define libname (let ((os (system-type 'os*)))
(cond ((eq? os 'windows) (format "rktwebview.dll"))
((eq? os 'linux) (format "librktwebview.so"))
(else (error (format "OS ~a not supported" os)))))
)
;(set! libname "../rktwebview/build/Release/rktwebview.dll")
;(set! libname "../rktwebview/build/Release/librktwebview.so")
(if (eq? (system-type 'os*) 'windows)
(set! libname "..\\rktwebview_qt\\build\\Release\\rktwebview_qt.dll")
(set! libname "../rktwebview_qt/build/Release/librktwebview_qt.so"))
(set! libname "rktwebview_qt.dll")
(current-directory (build-path lib-dir "..\\rktwebview_qt\\build\\Release"))
;(define webview-lib-file (normalize-path (build-path lib-dir libname)))
(define webview-lib-file libname)
(displayln (format "~a - ~a" (current-directory) webview-lib-file))
; c:\qt\6.10.2\msvc2022_64\bin\windeployqt.exe rktwebview_qt_test.exe
(putenv "QT_PLUGIN_PATH" (path->string (current-directory)))
(putenv "QTWEBENGINEPROCESS_PATH"
"c:\\devel\\racket\\racket-webview\\rktwebview_qt\\build\\Release\\QtWebEngineProcess.exe")
(putenv "QTWEBENGINE_RESOURCES_PATH"
"c:\\devel\\racket\\racket-webview\\rktwebview_qt\\build\\Release\\resources")
(putenv "QTWEBENGINE_LOCALES_PATH"
"c:\\devel\\racket\\racket-webview\\rktwebview_qt\\build\\Release\\translations\\qtwebengine_locales")
(define libs '(Qt6Core.dll
Qt6Positioning.dll
;Qt6Concurrent.dll
Qt6Gui.dll
Qt6Widgets.dll
;qwindows.dll
Qt6Svg.dll
Qt6Network.dll
Qt6OpenGL.dll
;Qt6OpenGLWidgets.dll
Qt6PrintSupport.dll
Qt6Qml.dll
;Qt6Xml.dll
Qt6QmlModels.dll
Qt6QmlWorkerScript.dll
Qt6QmlMeta.dll
Qt6Quick.dll
Qt6QuickWidgets.dll
Qt6WebChannel.dll
Qt6WebEngineCore.dll
;Qt6WebEngineQuick.dll
Qt6WebEngineWidgets.dll
))
(for-each (λ (l)
(let ((lib (symbol->string l)))
(displayln (format "~a: ~a" lib (ffi-lib lib)))))
libs)
(define webview-lib (ffi-lib webview-lib-file))
(define-ffi-definer define-rktwebview webview-lib)
(define callback-box (box '()))
(define (applier thunk)
(thunk))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Types / Functions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define _rkt_result_t
(_enum '(no_result_yet = -1
oke = 0
set_html_failed = 1
set_navigate_failed = 2
eval_js_failed = 3
no_devtools_on_platform = 4
no_delegate_for_context = 5
move_failed = 12
resize_failed = 13
)
)
)
(define-cstruct _rkt_evt_t
([w _int]
[evt _pointer]
))
(define-cstruct _rkt_js_result_t
([result _rkt_result_t]
[value _pointer]
))
;RKTWEBVIEW_QT_EXPORT void rkt_webview_init(int &argc, char **argv);
(define-rktwebview rkt_webview_init
(_fun -> _void))
;RKTWEBVIEW_QT_EXPORT void rkt_webview_process_events(int for_ms);
(define-rktwebview rkt_webview_process_events
(_fun _int -> _void))
;RKTWEBVIEW_QT_EXPORT int rkt_webview_create(int parent);
(define-rktwebview rkt_webview_create
(_fun _int (_fun #:keep callback-box #:async-apply applier
_rkt_evt_t-pointer -> _void) -> _int))
;RKTWEBVIEW_QT_EXPORT void rkt_webview_close(int wv);
(define-rktwebview rkt_webview_close
(_fun _int -> _void))
;RKTWEBVIEW_QT_EXPORT result_t rkt_webview_set_url(int wv, const char *url);
(define-rktwebview rkt_webview_set_url
(_fun _int _string/utf-8 -> _rkt_result_t))
;RKTWEBVIEW_QT_EXPORT result_t rkt_webview_set_html(int wv, const char *html);
(define-rktwebview rkt_webview_set_html
(_fun _int _string/utf-8 -> _rkt_result_t))
;RKTWEBVIEW_QT_EXPORT result_t rkt_webview_run_js(int wv, const char *js);
(define-rktwebview rkt_webview_run_js
(_fun _int _string/utf-8 -> _rkt_result_t))
;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))
;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 -> _int))
;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))
;RKTWEBVIEW_QT_EXPORT result_t rkt_webview_resize(rktwebview_t w, int width, int height);
(define-rktwebview rkt_webview_resize
(_fun _int _int _int -> _rkt_result_t))
;RKTWEBVIEW_QT_EXPORT bool rkt_webview_valid(rktwebview_t wv);
(define-rktwebview rkt_webview_valid
(_fun _int -> _int))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Initialize and start library
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define process-events #t)
(define (stop-event-processing)
(set! process-events #f))
(define (start-event-processing)
(thread (λ ()
(letrec ((f (λ ()
(rkt_webview_process_events 1)
(sleep 0.001)
(if process-events
(f)
(begin
(displayln "Stopping event processing")
'done)))))
(f)))))
(rkt_webview_init)
(start-event-processing)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Provided features
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(define-struct rkt-wv
(win evt-queue callback [valid #:mutable])
#:transparent
)
(define rkt-wv-store (make-hash))
(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)
(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)))
((rkt-wv-callback handle) handle evt)
(rkt_webview_destroy_event e)
(rkt-process-events handle)))
)
'done))
(define (rkt-webview-create parent evt-callback)
(let ((evt-queue (make-queue)))
(let ((wv (rkt_webview_create parent
(λ (rkt-evt)
(enqueue! evt-queue rkt-evt)))))
(let ((handle (make-rkt-wv wv evt-queue evt-callback #t)))
(thread (λ ()
(sleep 1)
(letrec ((f (λ ()
(let ((r (rkt-process-events handle)))
(if (eq? r 'quit)
(begin
(set-rkt-wv-valid! handle #f)
(displayln "Quitting event loop")
'done)
(begin
;(displayln "Waiting for events.")
(sleep 0.01)
(f)))))))
(f))))
(hash-set! rkt-wv-store (rkt-wv-win handle) handle)
handle))))
(define (rkt-webview-close handle)
(rkt_webview_close (rkt-wv-win handle))
(enqueue! (rkt-wv-evt-queue handle) 'quit)
#t)
(define (rkt-webview-set-url! wv url)
(rkt_webview_set_url (rkt-wv-win wv) url))
(define (rkt-webview-set-html! wv html)
(rkt_webview_set_html (rkt-wv-win wv) html))
(define (rkt-webview-run-js wv js)
(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) js))
(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)
(list result value)))
(define (rkt-webview-resize wv w h)
(rkt_webview_resize (rkt-wv-win wv) w h))
(define (rkt-webview-move wv x y)
(rkt_webview_move (rkt-wv-win wv) x y))
(define (rkt-webview-open-devtools wv)
(rkt_webview_open_devtools (rkt-wv-win wv)))
(define (rkt-webview-valid? wv)
(if (eq? (rkt-wv-valid wv) #f)
#f
(if (= (rkt_webview_valid wv) 0)
#f
#t)))
(define (rkt-webview-exit)
(let ((open-windows (hash->list rkt-wv-store)))
(for-each (λ (kv)
(let ((win (car kv))
(handle (cdr kv)))
(rkt-webview-close handle)))
open-windows))
(stop-event-processing))