Files
racket-webview/scrbl/racket-webview-qt.scrbl
2026-03-16 20:04:30 +01:00

447 lines
10 KiB
Racket
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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 users 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}
]