From 2dd1f66b57e97d741b8abecde1e480c0cfa203df Mon Sep 17 00:00:00 2001 From: Hans Dijkema Date: Mon, 2 Mar 2026 09:34:20 +0100 Subject: [PATCH] Initial --- .gitignore | 3 + example/index.html | 17 ++++ example/styles.css | 4 + js/boilerplate.js | 123 ++++++++++++++++++++++++ lib/dll/webview.dll | Bin 0 -> 106496 bytes racket-webview-ffi.rkt | 194 +++++++++++++++++++++++++++++++++++++ racket-webview.rkt | 196 ++++++++++++++++++++++++++++++++++++++ rtkwebview/CMakeLists.txt | 32 +++++++ 8 files changed, 569 insertions(+) create mode 100644 example/index.html create mode 100644 example/styles.css create mode 100644 js/boilerplate.js create mode 100644 lib/dll/webview.dll create mode 100644 racket-webview-ffi.rkt create mode 100644 racket-webview.rkt create mode 100644 rtkwebview/CMakeLists.txt diff --git a/.gitignore b/.gitignore index 39a4f9c..ae13504 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,6 @@ compiled/ # Dependency tracking files *.dep +# Other +webview +rktwebview/build diff --git a/example/index.html b/example/index.html new file mode 100644 index 0000000..6c2232d --- /dev/null +++ b/example/index.html @@ -0,0 +1,17 @@ + + + + + Example of racket webview + + + +

Example

+

+Please press this for something to happen. +

+

+Some input text: +

+ + diff --git a/example/styles.css b/example/styles.css new file mode 100644 index 0000000..68be6c5 --- /dev/null +++ b/example/styles.css @@ -0,0 +1,4 @@ +body { + font-family: Arial; + font-size: 11pt; +} \ No newline at end of file diff --git a/js/boilerplate.js b/js/boilerplate.js new file mode 100644 index 0000000..a8246dd --- /dev/null +++ b/js/boilerplate.js @@ -0,0 +1,123 @@ + +window._web_wire_evt_queue = []; + +window._web_wire_queue_worker = function() { + if (typeof web_ui_wire_handle_event === 'function') { + while (window._web_wire_evt_queue.length > 0) { + let evt = window._web_wire_evt_queue.shift(); + web_ui_wire_handle_event(JSON.stringify(evt)); + } + } + window.setTimeout(window._web_wire_queue_worker, 5); +}; +window.setTimeout(window._web_wire_queue_worker, 15); + +window._web_wire_put_evt = function(evt) { window._web_wire_evt_queue.push(evt); }; + +window._web_wire_event_info = function(e, id, evt) { + let obj = {}; + if (e == 'input') { + obj['data'] = evt.data; + obj['dataTransfer'] = evt.dataTransfer; + obj['inputType'] = evt.inputType; + obj['isComposing'] = evt.isComposing; + obj['value'] = document.getElementById(id).value; + } else if (e == 'change') { + obj['value'] = document.getElementById(id).value; + } else if (e == 'mousemove' || e == 'mouseover' || e == 'mouseenter' || + e == 'mouseleave' || e == 'click' || e == 'dblclick' || e == 'contextmenu' || + e == 'mousedown' || e == 'mouseup' ) { + obj['altKey'] = evt.altKey; + obj['buttons'] = evt.buttons; + obj['clientX'] = evt.clientX; + obj['clientY'] = evt.clientY; + obj['ctrlKey'] = evt.ctrlKey; + obj['metaKey'] = evt.metaKey; + obj['movementX'] = evt.movementX; + obj['movementY'] = evt.movementY; + obj['screenX'] = evt.screenX; + obj['screenY'] = evt.screenY; + obj['shiftKey'] = evt.shiftKey; + obj['x'] = evt.x; + obj['y'] = evt.y; + } else if (e == 'keydown' || e == 'keyup' || e == 'keypress') { + obj['key'] = evt.key; + obj['code'] = evt.code; + obj['altKey'] = evt.altKey; + obj['ctrlKey'] = evt.ctrlKey; + obj['metaKey'] = evt.metaKey; + obj['repeat'] = evt.repeat; + obj['shiftKey'] = evt.shiftKey; + } + // More events can be added like pointerEvent, clipboardEvent, etc. + return obj; +}; + +window._web_wire_get_evts = function() { + let v = _web_wire_evt_queue; + _web_wire_evt_queue = []; + return JSON.stringify(v); // This needs no extra type info, as it is internally used only +}; + +window._web_wire_bind_evt_ids = function(win_nr, selector, event_kind) { + try { + let nodelist = document.querySelectorAll(selector); + if (nodelist === undefined || nodelist === null) { + return 'json:[]'; + } + let ids = []; + nodelist.forEach(function(el) { + let el_id = el.getAttribute('id'); + let el_tag = el.nodeName; + let el_type = el.getAttribute('type'); + if (el_type === null) { el_type = ''; } + if (el_id !== null) { + el.addEventListener(event_kind, + function(e) { + let obj = {evt: event_kind, id: el_id, selector: selector, window: win_nr, + js_evt: window._web_wire_event_info(event_kind, el_id, e) }; + window._web_wire_put_evt(obj); + } + ); + let info = [ el_id, el_tag, el_type ]; + ids.push(info); + } + }); + return 'json:' + JSON.stringify(ids); + } catch(e) { + return 'json:[]'; + } +}; + +window._web_wire_resize_timeout = false; +window.addEventListener('resize', function() { + clearTimeout(window._web_wire_resize_timeout); + let f = function() { + let obj = { selector: 'global', evt: 'window-resize', h: window.outerWidth, w: window.outerHeight }; + window._web_wire_put_evt(obj); + }; + window._web_wire_resize_timeout = setTimeout(f, 250); +}); + +window._web_wire_x = window.screenX; +window._web_wire_y = window.screenY; +window._web_wire_move_interval = setInterval(function() { + let x = window.screenX; + let y = window.screenY; + if (x != window._web_wire_x || y != window._web_wire_y) { + window._web_wire_x = x; + window._web_wire_y = y; + let obj = { selector: 'global', evt: 'window-move', x: x, y: y }; + window._web_wire_put_evt(obj); + } +}, 500); + +document.addEventListener('readystatechange', event => { + + // When window loaded ( external resources are loaded too- `css`,`src`, etc...) + if (event.target.readyState === "complete") { + let obj = { selector: 'global', evt: 'html-loaded' }; + window._web_wire_put_evt(obj); + } +}); + diff --git a/lib/dll/webview.dll b/lib/dll/webview.dll new file mode 100644 index 0000000000000000000000000000000000000000..9343d55d9fb34fb11d5c7e62f011e22c95a92b6a GIT binary patch literal 106496 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

+;kEr>7WJWqrZVVb zp_jO9Bg~7q6W<+{h~Y7YfoSNl;(jp}lCa`FOQP$5O6wZ3${RTfj{ZVf(M3I#_#U55 z@ka3mo%~wuMzrLpI~W+mcV(k#m-ib$zn4gCe&HbzKHeXI5dqKR&Li2c0F~C4V5QcH z=+O$`qulI=IPulbQKgPO#@`8`n5siL#6U!*3a_u~d$wQWwWmxIt^zGc zuoU~uu}#uDaWMX~*QnV#KvU~ti1Q8{p;;--Q29La98cjP>J>(^&xUvON_?|jsLs+y zcZb+n!8MY-48DYpWM7l8d0~5^^A`A{-^OcAUVK`yL=wZgG>*;S`&$fODWcI&^fR(J ziSex}Pgn0lAfk@(@=}hR7C`?d?MuLMQ*?kL1H@!IVo+j~)K%(jR694=$ z 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 (queue-length item-queue) 0) + (let* ((entry (dequeue! item-queue)) + (id (car entry)) + (item (cadr entry)) + (cb (hash-ref callback-hash id + (λ args #f))) + (context (rkt_item_t-context item)) + (data (rkt_item_t-data item)) + ) + (cb context data) + (rkt_webview_destroy_item item) + (dispatch) + ) + (begin + (sleep 0.05) + (dispatch)))))) + (dispatch)))) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Functions +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;RKTWEBVIEW_EXPORT rkt_webview_t *rkt_create_webview() +(define-rktwebview rkt_create_webview + (_fun -> _rkt_webview_t)) + +;RKTWEBVIEW_EXPORT result_t rkt_navigate(rkt_webview_t *wv, const char *url) +(define-rktwebview rkt_webview_navigate + (_fun _rkt_webview_t _string/utf-8 -> _result_t)) + +;RKTWEBVIEW_EXPORT result_t rkt_set_html(rkt_webview_t *wv, const char *html) +(define-rktwebview rkt_webview_set_html + (_fun _rkt_webview_t _string/utf-8 -> _result_t)) + +;RKTWEBVIEW_EXPORT bool rkt_webview_valid(rkt_webview_t *handle) +(define-rktwebview rkt_webview_valid + (_fun _rkt_webview_t -> _int)) + +;RKTWEBVIEW_EXPORT result_t rkt_run_js(rkt_webview_t *handle, const char *js); +(define-rktwebview rkt_webview_run_js + (_fun _rkt_webview_t _string/utf-8 -> _result_t)) + +;RKTWEBVIEW_EXPORT char *rkt_webview_call_js(rkt_webview_t *handle, const char *js); +;(define-rktwebview rkt_webview_call_js +; (_fun _rkt_webview_t _string/utf-8 -> _rkt_item_t)) + +;RKTWEBVIEW_EXPORT int rkt_webview_pending_events(rkt_webview_t *wv); +(define-rktwebview rkt_webview_pending_events + (_fun _rkt_webview_t -> _int)) + +;RKTWEBVIEW_EXPORT item_t rkt_webview_get_event(rkt_webview_t *wv); +(define-rktwebview rkt_webview_get_event + (_fun _rkt_webview_t -> _rkt_item_t)) + +;RKTWEBVIEW_EXPORT void rkt_webview_register_queue_callback(rkt_webview_t *wv, void(*cb)(item_t item)); +(define-rktwebview rkt_webview_register_queue_callback + (_fun _rkt_webview_t _int + (_fun #:keep callback-box #:async-apply apply-async + _int _rkt_item_t -> _void) -> _void)) + +(define (rkt_webview_set_event_callback! wv id cb) + (hash-set! callback-hash id cb) + (rkt_webview_register_queue_callback wv id std-callback) + ) + +(define (rkt_webview_clear_event_callback! wv id) + (hash-remove! callback-hash id) + (rkt_webview_register_queue_callback wv #f)) + +;RKTWEBVIEW_EXPORT void (item_t item) +(define-rktwebview rkt_webview_destroy_item + (_fun _rkt_item_t -> _void)) + +;RKTWEBVIEW_EXPORT result_t rkt_webview_devtools(rkt_webview_t *wv) +(define-rktwebview rkt_webview_devtools + (_fun _rkt_webview_t -> _result_t)) + +;RKTWEBVIEW_EXPORT reason_t rkt_webview_last_reason(rkt_webview_t *wv) +(define-rktwebview rkt_webview_last_reason + (_fun _rkt_webview_t -> _reason_t)) + +(define (rkt_webview_item_data item) + (rkt_item_t-data item)) + diff --git a/racket-webview.rkt b/racket-webview.rkt new file mode 100644 index 0000000..e1d1582 --- /dev/null +++ b/racket-webview.rkt @@ -0,0 +1,196 @@ +#lang racket/base + +(require "racket-webview-ffi.rkt" + "utils.rkt" + web-server/servlet + web-server/servlet-env + web-server/http + net/url + racket/runtime-path + racket/file + racket/string + racket/path + racket/port + json + ) + +(provide webview-create + webview-devtools + webview-has-events? + webview-event-count + webview-get-event + webview-set-event-callback! + webview-clear-event-callback! + webview-bind + webview-run-js + ;webview-call-js + ) + +(define current-servlet-port 8083) +(define current-window-nr 1) + +(define-runtime-path js-path "js") + +(define (default-boilerplate-js) + (let ((file (build-path js-path "boilerplate.js"))) + (file->string file))) + +(define-struct wv + (handle port window-nr + [file-getter #:mutable] + [boilerplate-js #:mutable] + [webserver-thread #:mutable])) + +(define (process-html wv-handle path out) + (let ((html (file->string path)) + (boilerplate-js (wv-boilerplate-js wv-handle))) + (set! html (string-replace html "" + (string-append "" "\n" + "" "\n"))) + (display html out))) + +(define (process-file wv-handle ext path out) + (let ((content (file->bytes path))) + (write bytes out))) + +(define (web-serve wv-handle req) + (let* ((path (url->string (request-uri req))) + (file-getter (wv-file-getter wv-handle))) + (let* ((file-to-serve (build-path (file-getter path))) + (ext-bytes (path-get-extension file-to-serve)) + (ext (if (eq? ext-bytes #f) #f + (string->symbol (string-downcase (substring (bytes->string/utf-8 ext-bytes) 1))))) + ) + (if (file-exists? file-to-serve) + (response/output + (λ (out) + (if (or (eq? ext 'html) (eq? ext 'htm)) + (process-html wv-handle file-to-serve out) + (process-file wv-handle ext file-to-serve out)) + )) + (response/output + #:code 404 + (λ (out) + (displayln (format "~a not found" path) out))) + ) + ) + ) + ) + +(define (start-web-server h) + (thread (λ () + (serve/servlet + (λ (req) (web-serve h req)) + #:listen-ip "127.0.0.1" + #:port (wv-port h) + #:command-line? #t + #:servlet-path "" + #:stateless? #t + ;#:launch-browser #f + #:servlet-regexp #rx"")))) + +(define (webview-create file-getter #:boilerplate-js [bj (default-boilerplate-js)]) + (let* ((wv (rkt_create_webview)) + (h (make-wv wv current-servlet-port current-window-nr file-getter bj #f)) + (base-req (format "http://127.0.0.1:~a" + (wv-port h))) + ) + (set-wv-webserver-thread! h (start-web-server h)) + (rkt_webview_navigate (wv-handle h) base-req) + (set! current-servlet-port (+ current-servlet-port 1)) + (set! current-window-nr (+ current-window-nr 1)) + h)) + +(define (webview-devtools wv) + (rkt_webview_devtools (wv-handle wv))) + +(define (webview-parse-event evt) + (let ((wv-d0 (with-input-from-string evt read-json))) + ;(displayln wv-d0) + (let ((wv-d1 (with-input-from-string (hash-ref wv-d0 'data) read-json))) + ;(displayln wv-d1) + (let ((wv-d2 (with-input-from-string (car wv-d1) read-json))) + ;(displayln wv-d2) + wv-d2)))) + +(define (webview-set-event-callback! wv cb) + (rkt_webview_set_event_callback! (wv-handle wv) (wv-window-nr wv) + (λ (context data) + (let ((e (webview-parse-event data))) + (cb context e))))) + +(define (webview-clear-event-callback! wv) + (rkt_webview_clear_event_callback! (wv-handle wv) (wv-window-nr wv))) + + +(define (webview-get-event wv) + (if (> (rkt_webview_pending_events (wv-handle wv)) 0) + (let ((item (rkt_webview_get_event (wv-handle wv)))) + (let ((data (rkt_webview_item_data item))) + (rkt_webview_destroy_item item) + (let ((wv-d0 (with-input-from-string data read-json))) + ;(displayln wv-d0) + (let ((wv-d1 (with-input-from-string (hash-ref wv-d0 'data) read-json))) + ;(displayln wv-d1) + (let ((wv-d2 (with-input-from-string (car wv-d1) read-json))) + ;(displayln wv-d2) + wv-d2 + ) + ) + ) + ) + ) + #f) + ) + +(define (webview-has-events? wv) + (>= (rkt_webview_pending_events (wv-handle wv)) 1) + ) + +(define (webview-event-count wv) + (rkt_webview_pending_events (wv-handle wv))) + +(define (webview-bind wv selector event) + (let ((sel (if (symbol? selector) + (format "#~a" selector) + selector)) + (evt (format "~a" event))) + (rkt_webview_run_js (wv-handle wv) + (format "window._web_wire_bind_evt_ids(~a, '~a', '~a')" + (wv-window-nr wv) sel evt)))) + +(define (webview-run-js wv js) + (rkt_webview_run_js (wv-handle wv) js)) + +(define (webview-call-js wv js) + (let ((result (rkt_webview_call_js (wv-handle wv) js))) + result)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; testing +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define-runtime-path example-path "example") + +(define (file-getter file) + (displayln (format "file-getter: ~a" file)) + (let ((f (if (string=? file "/") "index.html" file))) + (when (string-prefix? f "/") + (set! f (substring f 1))) + (let ((p (build-path example-path f))) + (displayln p) + p))) + +(define (test) + (let ((h (webview-create file-getter))) + (displayln (webview-has-events? h)) + + (while (not (webview-has-events? h)) + (displayln "Waiting...") + (sleep 1)) + (let ((evt (webview-get-event h))) + (when (string=? (hash-ref evt 'evt) "html-loaded") + (webview-bind h "button" "click"))) + h)) \ No newline at end of file diff --git a/rtkwebview/CMakeLists.txt b/rtkwebview/CMakeLists.txt new file mode 100644 index 0000000..eb5b5c7 --- /dev/null +++ b/rtkwebview/CMakeLists.txt @@ -0,0 +1,32 @@ +cmake_minimum_required(VERSION 3.16) + +project(rktwebview LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +include_directories(../webview/core/include) +include_directories(../webview/build/Release/_deps/microsoft_web_webview2-src/build/native/include) +link_directories(../webview/build/Release/core) +link_directories(build/Release) + +add_library(rktwebview SHARED + rktwebview_global.h + rktwebview.cpp + rktwebview.h + + + json.h + json.cpp + main.cpp +) + +add_executable(rktwebview_test + main.cpp +) + + +target_link_libraries(rktwebview webview_static) +target_link_libraries(rktwebview_test rktwebview) + +target_compile_definitions(rktwebview PRIVATE RKTWEBVIEW_LIBRARY)