#lang scribble/manual @title{Racket FFI Interface for @tt{rktwebview_qt}} @author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] @section{Overview} The module @tt{racket-webview-qt.rkt} provides a Racket FFI wrapper around the native @tt{rktwebview_qt} library. It loads the shared library, initializes the native runtime, and exposes Racket functions for creating and controlling webview windows. The wrapper translates the low-level C interface into a Racket-oriented API based on structures, callbacks, and ordinary Racket values. The module provides: @itemlist[#:style 'compact @item{creation of HTTP(S) contexts} @item{creation and management of webview windows} @item{navigation and HTML loading} @item{JavaScript execution} @item{window geometry and visibility control} @item{native dialogs} @item{asynchronous event delivery} @item{version and cleanup utilities} ] @section{Requirements} The native backend requires Qt version @tt{6.10.2} or newer. The shared library @tt{rktwebview_qt} must therefore be built against Qt @tt{6.10.2} or a compatible later release. Earlier Qt versions are not supported. @section{Module Initialization} Loading the module performs several initialization steps automatically. @itemlist[#:style 'compact @item{determines the operating system and architecture} @item{sets Qt runtime environment variables} @item{loads the @tt{rktwebview_qt} shared library} @item{initializes the native runtime} @item{starts a background thread that processes native events} ] Currently the wrapper supports the following platforms: @itemlist[#:style 'compact @item{@tt{'linux}} @item{@tt{'windows}} ] If the current system is unsupported, loading the module raises an error. @section{Data Model} @subsection{The @tt{rkt-wv} Structure} Each webview window is represented by a transparent Racket structure. @defstruct*[rkt-wv ([win exact-integer?] [evt-queue any/c] [callback procedure?] [valid boolean?] [close-callback procedure?])]{ Represents a webview instance managed by the Racket wrapper. Fields: @itemlist[#:style 'compact @item{@tt{win}: the native integer window handle} @item{@tt{evt-queue}: internal queue of pending event strings} @item{@tt{callback}: user event callback} @item{@tt{valid}: mutable flag indicating whether the wrapper considers the window active} @item{@tt{close-callback}: procedure invoked when the window is closed} ] Although the structure is transparent, user code should normally treat it as an opaque handle. } @defproc[(rkt-wv-win [wv rkt-wv?]) exact-integer?]{ Returns the native window handle associated with @racket[wv]. } @section{HTTP(S) Contexts} A context represents the shared HTTP(S) environment used by webviews. Contexts correspond to native WebEngine profiles and determine properties such as: @itemlist[#:style 'compact @item{cookies and cache} @item{injected JavaScript} @item{trusted certificates} ] @defproc[(rkt-webview-new-context [boilerplate-js string?] [server-cert bytes?]) exact-integer?]{ Creates a new HTTP(S) context and returns its native identifier. Arguments: @itemlist[#:style 'compact @item{@racket[boilerplate-js]: JavaScript source injected into pages} @item{@racket[server-cert]: optional certificate data} ] The returned context identifier can be passed to @racket[rkt-webview-create] to create webviews within that context. } @section{Creating Webviews} @defproc[(rkt-webview-create [context exact-integer?] [parent (or/c #f rkt-wv?)] [evt-callback (-> rkt-wv? string? any)] [close-callback (-> any)]) rkt-wv?]{ Creates a new webview window in the given HTTP(S) context. Arguments: @itemlist[#:style 'compact @item{@racket[context]: context identifier returned by @racket[rkt-webview-new-context]} @item{@racket[parent]: optional parent webview} @item{@racket[evt-callback]: procedure invoked for each event} @item{@racket[close-callback]: procedure invoked when the window is closed} ] The result is a new @racket[rkt-wv] structure. Events generated by the native layer are delivered asynchronously through @racket[evt-callback]. } @section{Window Lifecycle} @defproc[(rkt-webview-close [wv rkt-wv?]) boolean?]{ Requests that the webview window be closed. The wrapper forwards the request to the native backend and schedules cleanup of the event-processing loop. Returns @racket[#t]. } @defproc[(rkt-webview-valid? [wv rkt-wv?]) boolean?]{ Returns whether the webview still exists. The wrapper first checks its internal validity flag and then queries the native runtime. } @defproc[(rkt-webview-exit) void?]{ Closes all webviews and stops the background event-processing thread. This function is also registered with the Racket plumber so that cleanup occurs automatically when the process exits. } @section{Window Configuration} @defproc[(rkt-webview-set-title! [wv rkt-wv?] [title string?]) symbol?]{ Sets the native window title. Returns a result symbol such as: @itemlist[#:style 'compact @item{@racket['oke]} @item{@racket['failed]} ] } @defproc[(rkt-webview-set-ou-token [wv rkt-wv?] [token string?]) boolean?]{ Associates an Organizational Unit token with the window. This token may be used by the native layer when accepting certain self-signed certificates. } @section{Navigation} @defproc[(rkt-webview-set-url! [wv rkt-wv?] [url string?]) symbol?]{ Navigates the webview to the given URL. Returns a result symbol such as: @itemlist[#:style 'compact @item{@racket['oke]} @item{@racket['set_navigate_failed]} ] } @defproc[(rkt-webview-set-html! [wv rkt-wv?] [html string?]) symbol?]{ Loads HTML directly into the webview. Returns a result symbol such as: @itemlist[#:style 'compact @item{@racket['oke]} @item{@racket['set_html_failed]} ] } @section{JavaScript Execution} @defproc[(rkt-webview-run-js [wv rkt-wv?] [js string?]) symbol?]{ Executes JavaScript without returning a value. Returns a result symbol such as: @itemlist[#:style 'compact @item{@racket['oke]} @item{@racket['eval_js_failed]} ] } @defproc[(rkt-webview-call-js [wv rkt-wv?] [js string?]) (list/c symbol? string?)]{ Executes JavaScript and returns: @racketblock[ (list result value) ] where: @itemlist[#:style 'compact @item{@racket[result] is the native result code} @item{@racket[value] is a JSON string containing the returned data} ] The JSON structure is generated by the native backend. } @section{Window Geometry} @defproc[(rkt-webview-move [wv rkt-wv?] [x exact-integer?] [y exact-integer?]) symbol?]{ Moves the webview window to the given screen coordinates. } @defproc[(rkt-webview-resize [wv rkt-wv?] [width exact-integer?] [height exact-integer?]) symbol?]{ Resizes the window. } @defproc[(rkt-webview-show [wv rkt-wv?]) symbol?]{ Shows the window. } @defproc[(rkt-webview-hide [wv rkt-wv?]) symbol?]{ Hides the window. } @defproc[(rkt-webview-show-normal [wv rkt-wv?]) symbol?]{ Restores the window to its normal state. } @defproc[(rkt-webview-maximize [wv rkt-wv?]) symbol?]{ Maximizes the window. } @defproc[(rkt-webview-minimize [wv rkt-wv?]) symbol?]{ Minimizes the window. } @defproc[(rkt-webview-present [wv rkt-wv?]) symbol?]{ Requests that the window be presented to the user. } @defproc[(rkt-webview-window-state [wv rkt-wv?]) symbol?]{ Returns the current window state. Possible results include: @itemlist[#:style 'compact @item{@racket['normal]} @item{@racket['minimized]} @item{@racket['maximized]} @item{@racket['hidden]} ] } @section{Developer Tools} @defproc[(rkt-webview-open-devtools [wv rkt-wv?]) symbol?]{ Opens the browser developer tools window. } @section{Native Dialogs} Dialog functions return immediately with a status code. The user’s choice is delivered asynchronously through the event callback. @defproc[(rkt-webview-choose-dir [wv rkt-wv?] [title string?] [base-dir string?]) symbol?]{ Requests a directory-selection dialog. } @defproc[(rkt-webview-file-open [wv rkt-wv?] [title string?] [base-dir string?] [extensions string?]) symbol?]{ Requests a file-open dialog. } @defproc[(rkt-webview-file-save [wv rkt-wv?] [title string?] [base-dir string?] [extensions string?]) symbol?]{ Requests a file-save dialog. } @defproc[(rkt-webview-messagebox [wv rkt-wv?] [title string?] [message string?] [submessage string?] [type symbol?]) symbol?]{ Shows a native message box. } @section{Event Delivery} Each webview has an associated event callback. The callback has the form: @racketblock[ (λ (wv event-json) ...) ] Arguments: @itemlist[#:style 'compact @item{@racket[wv]: the webview handle} @item{@racket[event-json]: JSON event string from the native backend} ] Typical event types include: @itemlist[#:style 'compact @item{@tt{"show"}} @item{@tt{"hide"}} @item{@tt{"move"}} @item{@tt{"resize"}} @item{@tt{"closed"}} @item{@tt{"page-loaded"}} @item{@tt{"navigation-request"}} @item{@tt{"js-evt"}} ] The wrapper does not parse the JSON payload. @section{Version Information} @defproc[(rkt-webview-version) (list/c list? list?)]{ Returns version information for the native backend. Example result: @racketblock[ (list (list 'webview-c-api 1 0 0) (list 'qt 6 10 2)) ] } @section{Example} @racketblock[ (define ctx (rkt-webview-new-context "" #"")) (define wv (rkt-webview-create ctx #f (λ (wv evt) (displayln evt)) (λ () (displayln "closed")))) (rkt-webview-set-title! wv "Example") (rkt-webview-set-url! wv "https://example.org") ] @section{Summary} The FFI module provides a thin Racket interface to the native @tt{rktwebview_qt} backend. Key characteristics: @itemlist[#:style 'compact @item{thin wrapper around the native C API} @item{asynchronous event delivery} @item{JSON-based event payloads} @item{simple Racket structures for webviews} ]