#lang racket/base (require ffi/unsafe ffi/unsafe/define ffi/unsafe/atomic ffi/unsafe/os-thread ffi/unsafe/cvector racket/async-channel racket/runtime-path racket/port data/queue json racket/string racket/path "utils.rkt" ) (provide rkt-wv rkt-wv-win rkt-webview-new-context rkt-webview-create rkt-webview-close rkt-webview-set-ou-token rkt-webview-set-url! rkt-webview-set-html! rkt-webview-run-js rkt-webview-call-js rkt-webview-move rkt-webview-resize rkt-webview-show rkt-webview-hide rkt-webview-show-normal rkt-webview-maximize rkt-webview-minimize rkt-webview-window-state rkt-webview-set-title! rkt-webview-present rkt-webview-exit rkt-webview-valid? rkt-webview-open-devtools rkt-webview-choose-dir rkt-webview-file-open rkt-webview-file-save rkt-webview-messagebox rkt-webview-version rkt-webview-set-loglevel rkt-webview-info ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; FFI Library ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define lib-type 'release) (define os (system-type 'os*)) (define arch (system-type 'arch)) (define supported-os '(windows linux)) (unless (ormap (λ (o) (eq? os o)) supported-os) (error (format "OS currently not supported: ~a. Supported: ~a." os supported-os))) (define-runtime-path lib-dir "lib") #| (define libraries-to-preload (cond ([eq? os 'windows] '(Qt6Core.dll Qt6Positioning.dll Qt6Gui.dll Qt6Widgets.dll Qt6Svg.dll Qt6Network.dll Qt6OpenGL.dll Qt6PrintSupport.dll Qt6Qml.dll Qt6QmlModels.dll Qt6QmlWorkerScript.dll Qt6QmlMeta.dll Qt6Quick.dll Qt6QuickWidgets.dll Qt6WebChannel.dll Qt6WebEngineCore.dll Qt6WebEngineWidgets.dll )) ([eq? os 'linux] '(libQt6XcbQpa ;libQt6WaylandClient ;libQt6EglFSDeviceIntegration libQt6Core libQt6Positioning libQt6Gui libQt6Widgets libQt6Svg libQt6Network libQt6OpenGL libQt6PrintSupport libQt6Qml libQt6QmlModels libQt6QmlWorkerScript libQt6QmlMeta libQt6Quick libQt6QuickWidgets libQt6WebChannel libQt6WebEngineCore libQt6WebEngineWidgets )) ) ) |# (define ffi-library (cond ([eq? os 'windows] 'rktwebview.dll) ([eq? os 'linux] 'librktwebview.so) ) ) (define os-lib-dir (build-path lib-dir (symbol->string os) (symbol->string arch))) (define (libname 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 (define quiet-call #t) (define rktwebview-prg (if (eq? os 'windows) "rktwebview_prg.exe" "rktwebview_prg")) (define webengine-process (if (eq? os 'windows) "QtWebEngineProcess.exe" "QtWebEngineProcess")) ;;; Preload libraries #| (for-each (λ (lib-symbol) (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 ;#:custodian (current-custodian)) ) ) libraries-to-preload) |# ;;; Actual FFI integration (define webview-lib-file (libname ffi-library)) (define webview-lib (with-handlers ([exn:fail? (λ (exp) (cond ([eq? os 'linux] (error (format (string-append "Cannot load ~a.\n" "Make sure you installed Qt6 on your system\n" "NB. the minimum Qt version that is supported is Qt 6.10.\n" "This probably means you will need to install it separately from\n" "the standard distro packages (e.g. libqt6webenginewidgets6 on\n" "debian based systems).\n" "\n" "Exception:\n\n~a") ffi-library exp))) (else (error (format "Cannot load ~a for os ~a\n\nException:\n\n~a" ffi-library os exp)))) ) ]) (ffi-lib webview-lib-file '("6" #f) #:get-lib-dirs (list os-lib-dir) ;#:custodian (current-custodian) ) ) ) (define-ffi-definer define-rktwebview webview-lib) ;;; Callbacks from the OS library ;(define callback-box (box '())) ;(define (applier thunk) ; (thunk)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Types / Functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define _rkt_loglevel_t (_enum '(error = 1 warning = 2 info = 3 debug = 4) ) ) (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 webview_missing_dependency = 6 webview_canceled = 7 webview_invalid_state = 8 webview_invalid_argument = 9 webview_unspecified = 10 webview_dispatch_failed = 11 move_failed = 12 resize_failed = 13 choose_dir_failed = 14 open_file_failed = 15 save_file_failed = 16 failed = 17 invalid_handle = 18 ) ) ) (define _rkt_window_state_t (_enum '(invalid = -1 normal = 0 minimized = 1 maximized = 2 hidden = 3 normal_active = 16 maximized_active = 18 ) ) ) (define _rkt_data_kind (_enum '(version = -1 event = 2 js-result = 3 metrics = 4 ) ) ) (define _rkt_messagetype_t (_enum '(info = 1 error = 2 warning = 3 yes-no = 4 oke-cancel = 5 ) ) ) (define-cstruct _rkt_version_t ( [api-major _int] [api-minor _int] [api-patch _int] ) ) (define-cstruct _rkt_metrics_t ([shm_usage _int] [shm_free_depth _int] [shm_free_size _int] [shm_item_depth _int] [shm_item_size _int] [shm_item_usage_factor _double] [open_windows _int] [function_calls _int] [events _int] [log_file _string*/utf-8] ) ) (define-cstruct _rkt_evt_t ([w _int] [evt _pointer] )) (define-cstruct _rkt_js_result_t ([result _rkt_result_t] [value _pointer] )) (define-cstruct _rkt_data_t ([kind _rkt_data_kind] [data (_union _rkt_version_t _rkt_evt_t _rkt_js_result_t _rkt_metrics_t)] ) ) ;RKTWEBVIEW_EXPORT void rkt_webview_env(const char *env_cmds[]); (define-rktwebview rkt_webview_env (_fun _cvector -> _void)) ;RKTWEBVIEW_QT_EXPORT void rkt_webview_init(int &argc, char **argv); (define-rktwebview rkt_webview_init (_fun -> _void)) ;RKTWEBVIEW_QT_EXPORT void rkt_webview_cleanup(); (define-rktwebview rkt_webview_cleanup (_fun -> _void)) ;RKTWEBVIEW_EXPORT void rkt_webview_set_loglevel(rkt_webview_loglevel_t l); (define-rktwebview rkt_webview_set_loglevel (_fun _rkt_loglevel_t -> _void)) ;RKTWEBVIEW_EXPORT rkt_data_t *rkt_webview_info(); (define-rktwebview rkt_webview_info (_fun -> _rkt_data_t-pointer/null)) ;RKTWEBVIEW_EXPORT int rkt_webview_events_waiting(); (define-rktwebview rkt_webview_events_waiting (_fun -> _int)) ;RKTWEBVIEW_EXPORT rkt_data_t *rkt_webview_get_event(); (define-rktwebview rkt_webview_get_event (_fun -> _rkt_data_t-pointer/null)) ;RKTWEBVIEW_QT_EXPORT rkt_wv_context_t rkt_webview_new_context(const char *boilerplate_js, ; const char *optional_server_cert_pem); (define-rktwebview rkt_webview_new_context (_fun _string/utf-8 _bytes -> _int)) ;RKTWEBVIEW_QT_EXPORT void rkt_webview_process_events(int for_ms); ;(define-rktwebview rkt_webview_process_events ; (_fun _int -> _void)) ;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(rkt_wv_context_t context, ; rktwebview_t parent) (define-rktwebview rkt_webview_create (_fun _int _int -> _int)) ;RKTWEBVIEW_QT_EXPORT void rkt_webview_close(int wv); (define-rktwebview rkt_webview_close (_fun _int -> _void)) ;void rkt_webview_set_ou_token(rktwebview_t wv, const char *token) (define-rktwebview rkt_webview_set_ou_token (_fun _int _string/utf-8 -> _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_data_t-pointer)) ;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_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)) (define-syntax def-rkt-wv (syntax-rules () ((_ name) (define-rktwebview name (_fun _int -> _rkt_result_t))))) ;RKTWEBVIEW_QT_EXPORT result_t rkt_webview_hide(rktwebview_t w); (def-rkt-wv rkt_webview_hide) ;RKTWEBVIEW_QT_EXPORT result_t rkt_webview_show(rktwebview_t w); (def-rkt-wv rkt_webview_show) ;RKTWEBVIEW_QT_EXPORT result_t rkt_webview_show_normal(rktwebview_t w); (def-rkt-wv rkt_webview_show_normal) ;RKTWEBVIEW_QT_EXPORT result_t rkt_webview_present(rktwebview_t w); (def-rkt-wv rkt_webview_present) ;RKTWEBVIEW_QT_EXPORT result_t rkt_webview_maximize(rktwebview_t w); (def-rkt-wv rkt_webview_maximize) ;RKTWEBVIEW_QT_EXPORT result_t rkt_webview_minimize(rktwebview_t w); (def-rkt-wv rkt_webview_minimize) ;RKTWEBVIEW_QT_EXPORT bool rkt_webview_valid(rktwebview_t wv); (define-rktwebview rkt_webview_valid (_fun _int -> _int)) ;RKTWEBVIEW_QT_EXPORT window_state_t rkt_webview_window_state(rktwebview_t w); (define-rktwebview rkt_webview_window_state (_fun _int -> _rkt_window_state_t)) ;RKTWEBVIEW_QT_EXPORT result_t rkt_webview_set_title(rktwebview_t wv, const char *title); (define-rktwebview rkt_webview_set_title (_fun _int _string/utf-8 -> _rkt_result_t)) ;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_result_t)) ;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_result_t)) ;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_result_t)) ;RKTWEBVIEW_QT_EXPORT result_t rkt_webview_message_box( ; rktwebview_t w, ; const char *title, ; const char *message, ; const char *submessage, ; rkt_messagetype_t type); (define-rktwebview rkt_webview_message_box (_fun _int _string/utf-8 _string/utf-8 _string/utf-8 _rkt_messagetype_t -> _rkt_result_t)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Initialize and start library ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;(define process-events 'process) ;(define (stop-event-processing) ; (set! process-events 'stop) ; (while (eq? process-events 'stop) ; (sleep 0.001))) ;(define (start-event-processing) ; (thread (λ () ; (letrec ((f (λ () ; (rkt_webview_process_events 1) ; (sleep 0.001) ; (if (eq? process-events 'process) ; (f) ; (begin ; (displayln "Stopping event processing") ; (set! process-events 'stopped) ; 'done))))) ; (f))))) (define rkt_env (when (or (eq? os 'windows) (eq? os 'linux)) (let ((env (list (string-append "QT_PLUGIN_PATH=" (path->string (build-path os-lib-dir))) (string-append "QTWEBENGINEPROCESS_PATH=" (path->string (build-path os-lib-dir webengine-process))) (string-append "QTWEBENGINE_RESOURCES_PATH=" (path->string (build-path os-lib-dir "resources"))) (string-append "QTWEBENGINE_LOCALES_PATH=" (path->string (build-path os-lib-dir "translations" "qtwebengine_locales"))) (string-append "RKT_WEBVIEW_PRG=" (path->string (build-path os-lib-dir rktwebview-prg)))))) (when (eq? os 'linux) (set! env (append env (list (string-append "QT_QPA_PLATFORM=" "xcb") (string-append "LD_LIBRARY_PATH=" (string-append (path->string (build-path os-lib-dir)) ":" (path->string (build-path os-lib-dir "platforms")) ))))) ) (append env (list #f))))) ;(define env_array (_array _string/utf-8 (length rkt_env))) ;(let ((i 0)) ; (while (< i (length rkt_env)) ; (array-set! env_array i (list-ref rkt_env i)) ; (set! i (+ i 1)))) (rkt_webview_env (list->cvector rkt_env _string/utf-8)) (rkt_webview_init) ;(set! quiet-call (start-event-processing)) (define evt-cb-hash (make-hash)) (define (start-event-processing) (thread (λ () (letrec ((f (λ () (let ((waiting (rkt_webview_events_waiting))) ;(displayln (format "Events waiting: ~a" waiting)) (while (> waiting 0) (let* ((rkt-evt (rkt_webview_get_event))) ;(displayln rkt-evt) (if (eq? rkt-evt #f) (displayln (format "Unexpected: event = nullptr")) (let ((data (rkt_data_t-data rkt-evt))) ;(displayln data) (let ((e (union-ref data 1))) ; (displayln e) (let ((wv (rkt_evt_t-w e))) ;(displayln wv) (let ((evt (cast (rkt_evt_t-evt e) _pointer _string*/utf-8))) ; (displayln evt) (rkt_webview_free_data rkt-evt) (let ((cb (hash-ref evt-cb-hash wv #f))) (unless (eq? cb #f) (cb evt))))) ) ) ) ) (set! waiting (- waiting 1)) ) ) (sleep 0.005) (f)) )) (f))) ) ) (define evt-processing-thread (start-event-processing)) (define (stop-event-processing) (kill-thread evt-processing-thread)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Provided features ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define-struct rkt-wv (win evt-queue callback [valid #:mutable] [close-callback #:mutable]) #:transparent ) (define rkt-wv-store (make-hash)) (define (rkt-process-events handle) (if (> (queue-length (rkt-wv-evt-queue handle)) 0) (let ((evt (dequeue! (rkt-wv-evt-queue handle)))) (if (symbol? evt) (if (eq? evt 'quit) (begin (hash-remove! rkt-wv-store (rkt-wv-win handle)) 'quit) (begin (displayln (format "Unexpected data in event queue: ~a" evt)) (rkt-process-events handle))) (begin ((rkt-wv-callback handle) handle evt) (rkt-process-events handle))) ) 'done) ) (define (rkt-webview-new-context boilerplate-js server-cert) (rkt_webview_new_context boilerplate-js server-cert)) (define (rkt-webview-create context parent evt-callback close-callback) (let* ((evt-queue (make-queue)) (parent-win (if (eq? parent #f) 0 (rkt-wv-win parent))) ) (let ((wv (rkt_webview_create context parent-win))) (hash-set! evt-cb-hash wv (λ (evt) (enqueue! evt-queue evt))) ; (λ (rkt-evt) ; (let* ((e (union-ref (rkt_data_t-data rkt-evt) 1)) ; (evt (cast (rkt_evt_t-evt e) _pointer _string*/utf-8))) ; (rkt_webview_free_data rkt-evt) ; Free event data ASAP ; (enqueue! evt-queue evt) ; ))))) (let ((handle (make-rkt-wv wv evt-queue evt-callback #t close-callback))) (thread (λ () (sleep 0.01) (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) (hash-remove! evt-cb-hash (rkt-wv-win handle)) ((rkt-wv-close-callback handle)) #t) (define (rkt-webview-set-loglevel l) (rkt_webview_set_loglevel l)) (define (rkt-webview-info) (let* ((d (rkt_webview_info)) (r (union-ref (rkt_data_t-data d) 3)) ) (let ((res (list (list 'shm-usage (rkt_metrics_t-shm_usage r)) (list 'shm-freelist (rkt_metrics_t-shm_free_depth r) (rkt_metrics_t-shm_free_size r)) (list 'shm-alloc (rkt_metrics_t-shm_item_depth r) (rkt_metrics_t-shm_item_size r) (rkt_metrics_t-shm_item_usage_factor r)) (list 'open-windows (rkt_metrics_t-open_windows r)) (list 'calls (rkt_metrics_t-function_calls r)) (list 'events (rkt_metrics_t-events r)) (list 'log-file (rkt_metrics_t-log_file r)) ))) (rkt_webview_free_data d) res))) (define (rkt-webview-set-ou-token handle token) (rkt_webview_set_ou_token (rkt-wv-win handle) token) #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-set-title! wv title) (rkt_webview_set_title (rkt-wv-win wv) title)) (define (rkt-webview-run-js wv js) (rkt_webview_run_js (rkt-wv-win wv) js)) (define (rkt-webview-call-js 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_free_data d) (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-syntax def-rkt-wrapper-wv (syntax-rules () ((_ name c-name) (define (name wv) (c-name (rkt-wv-win wv)))))) (def-rkt-wrapper-wv rkt-webview-show rkt_webview_show) (def-rkt-wrapper-wv rkt-webview-hide rkt_webview_hide) (def-rkt-wrapper-wv rkt-webview-show-normal rkt_webview_show_normal) (def-rkt-wrapper-wv rkt-webview-minimize rkt_webview_minimize) (def-rkt-wrapper-wv rkt-webview-maximize rkt_webview_maximize) (def-rkt-wrapper-wv rkt-webview-present rkt_webview_present) (def-rkt-wrapper-wv rkt-webview-window-state rkt_webview_window_state) (define (rkt-webview-open-devtools wv) (rkt_webview_open_devtools (rkt-wv-win wv))) (define (rkt-webview-choose-dir wv title base-dir) (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_free_data d) ; (list result value))) (define (rkt-webview-file-open wv title base-dir permitted-exts) (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_free_data d) ; (list result value))) (define (rkt-webview-file-save wv title base-dir permitted-exts) (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_free_data d) ; (list result value))) (define (rkt-webview-messagebox wv title message submessage type) (rkt_webview_message_box (rkt-wv-win wv) title message submessage type)) (define (rkt-webview-version) (let ((d (rkt_webview_version))) (let ((v (union-ref (rkt_data_t-data d) 0))) (let ((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)) ) ) ) ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Administration ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define (rkt-webview-valid? wv) (if (eq? (rkt-wv-valid wv) #f) #f (if (= (rkt_webview_valid (rkt-wv-win 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)) (rkt_webview_cleanup) (stop-event-processing) ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Cleanup on exit ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (set! quiet-call (plumber-add-flush! (current-plumber) (λ (handle) (rkt-webview-exit))))