documentation

This commit is contained in:
2026-04-01 16:23:56 +02:00
parent 5ee62d0064
commit ab666368b1
27 changed files with 1080 additions and 164 deletions

195
scrbl/menu.scrbl Normal file
View File

@@ -0,0 +1,195 @@
#lang scribble/manual
@(require racket/base
scribble/core
(for-label racket/base
racket/string
net/url
json
"../private/menu.rkt"))
@title{menu}
@author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]]
@defmodule[menu]
Menu data structures used by the webview library.
This module provides constructors, predicates, traversal helpers, mutation
operations, and JSON conversion for menu trees.
@section{Overview}
A menu is represented as a tree. A menu consists of menu items, and a menu item
may optionally contain a submenu.
Menu identifiers are symbols. Menu item titles are strings. Icons are stored as
strings and may be supplied either as @racket[#f], strings, or URL values.
The module does not display menus itself. It provides the menu data structure
used by higher layers.
@section{Internal Representation}
Internally, menus are represented by transparent structure values. These
structure constructors and predicates are not exported directly. The public API
uses constructor procedures and helper functions operating on those internal
values.
@section{Predicates}
@defproc[(is-wv-menu? [mnu any/c]) boolean?]{
Returns @racket[#t] if @racket[mnu] is a valid menu tree and @racket[#f]
otherwise.
A value is recognized as a menu if it is an internal menu structure whose item
list is a list of internal menu items, and every submenu recursively also
satisfies @racket[is-wv-menu?].
}
@section{Constructors}
@defproc[(wv-menu [item-or-id any/c] ...)
any/c]{
Creates a menu.
If the first argument is a symbol, it is used as the menu identifier and removed
from the remaining arguments. Otherwise the menu identifier is @racket[#f].
If the first remaining argument is itself a list, that list is used as the item
list. Otherwise all remaining arguments are treated as menu items.
This means the following forms are accepted:
@racketblock[
(wv-menu item ...)
(wv-menu 'some-id item ...)
(wv-menu (list item ...))
(wv-menu 'some-id (list item ...))
]
The result is a value satisfying @racket[is-wv-menu?].
}
@defproc[(wv-menu-item [id symbol?]
[title string?]
[#:icon-url icon-url (or/c boolean? string? url?) #f]
[#:callback callback procedure? (λ args #t)]
[#:submenu submenu (or/c boolean? any/c) #f]
[#:separator separator boolean? #f])
any/c]{
Creates a menu item.
@racket[id] must be a symbol and @racket[title] must be a string.
@racket[icon-url] must be @racket[#f], a string, or a URL value. If it is a URL
value, it is converted to a string using @racket[url->string] before being
stored.
@racket[submenu] must be @racket[#f] or a value satisfying
@racket[is-wv-menu?].
@racket[separator] must be a boolean.
If any argument does not satisfy these conditions, an exception is raised.
}
@section{Traversal and Lookup}
@defproc[(wv-menu-for-each [menu any/c] [cb procedure?]) boolean?]{
Traverses @racket[menu] depth-first and calls @racket[cb] for each menu item.
If a menu item contains a submenu, that submenu is traversed recursively.
The callback is invoked only for menu items that are reached by the traversal.
The function returns @racket[#t].
}
@defproc[(with-wv-menu-item [menu any/c] [id symbol?] [cb procedure?]) any/c]{
Finds the menu item identified by @racket[id] and applies @racket[cb] to it.
If @racket[menu] does not satisfy @racket[is-wv-menu?], an exception is raised.
If @racket[id] is not a symbol, an exception is raised.
If no item with the given id can be found, an exception is raised.
After the callback has been applied, the original @racket[menu] value is
returned.
}
@section{Mutation}
@defproc[(wv-menu-set-title! [menu any/c] [id symbol?] [title string?])
any/c]{
Sets the title of the menu item identified by @racket[id].
@racket[title] must be a string. The function returns the original
@racket[menu] value.
}
@defproc[(wv-menu-set-icon! [menu any/c] [id symbol?]
[icon-url (or/c boolean? string? url?)])
any/c]{
Sets the icon URL of the menu item identified by @racket[id].
@racket[icon-url] must be @racket[#f], a string, or a URL value. If it is a URL
value, it is converted to a string using @racket[url->string] before being
stored.
The function returns the original @racket[menu] value.
}
@defproc[(wv-menu-set-callback! [menu any/c] [id symbol?] [cb procedure?])
any/c]{
Sets the callback of the menu item identified by @racket[id].
@racket[cb] must be a procedure. The function returns the original
@racket[menu] value.
}
@section{Conversion}
@defproc[(wv-menu->json [menu any/c]) string?]{
Converts @racket[menu] to a JSON string.
The conversion first builds a hash-based representation of the menu and then
writes that representation with @racket[write-json].
In the JSON representation:
@itemlist[#:style 'compact
@item{the top-level object contains the keys @racket['menu] and @racket['id]}
@item{menu item identifiers are converted to strings}
@item{menu item titles are written under the key @racket['name]}
@item{an icon is written only if it is not @racket[#f]}
@item{a submenu is written recursively only if it is not @racket[#f]}
@item{a separator flag is written only if it is not @racket[#f]}]
The @racket['id] field of the top-level menu is also converted to a string in
the JSON output.
}
@section{Accessors}
@defproc[(wv-menu-id [m any/c]) any/c]{
Returns the identifier of @racket[m].
}
@defproc[(wv-menu-item-id [mi any/c]) symbol?]{
Returns the identifier of the menu item @racket[mi].
}
@defproc[(wv-menu-item-callback [mi any/c]) procedure?]{
Returns the callback associated with the menu item @racket[mi].
}

60
scrbl/mimetypes.scrbl Normal file
View File

@@ -0,0 +1,60 @@
#lang scribble/manual
@(require racket/base
scribble/core
(for-label racket/base
racket/string
racket/file))
@title{mimetypes}
@author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]]
@defmodule[mimetypes]
MIME type utilities used by the webview library.
This module provides a mapping from file extensions to MIME types together with
a function to determine the MIME type of a file path.
@section{Overview}
The module is used by the local HTTPS server to determine the correct
@tt{Content-Type} header when serving files.
MIME types are determined based on the file extension.
@section{Function: path->mimetype}
@defproc[(path->mimetype [p path-string?]) string?]{
Returns the MIME type associated with @racket[p].
The file extension of @racket[p] is extracted and used to look up the
corresponding MIME type.
If the extension is not recognized, a default MIME type is returned.
}
@section{Mapping}
The module contains a predefined mapping from file extensions to MIME types.
Typical mappings include:
@itemlist[#:style 'compact
@item{@tt{.html} → @tt{text/html}}
@item{@tt{.css} → @tt{text/css}}
@item{@tt{.js} → @tt{application/javascript}}
@item{@tt{.json} → @tt{application/json}}
@item{@tt{.png} → @tt{image/png}}
@item{@tt{.jpg}, @tt{.jpeg} → @tt{image/jpeg}}
@item{@tt{.svg} → @tt{image/svg+xml}}]
The exact mapping is defined in the source code and can be extended if needed.
@section{Notes}
The returned MIME type is always a string suitable for use in HTTP response
headers.
File extensions are interpreted case-insensitively.

View File

@@ -0,0 +1,64 @@
#lang scribble/manual
@(require racket/base
scribble/core
scribble/manual
(for-label racket/base
racket/class
racket/string
racket/file
net/url
"../private/wv-context.rkt"
"../private/wv-window.rkt"
"../private/wv-element.rkt"
"../private/wv-input.rkt"
"../private/wv-dialog.rkt"
"../private/wv-settings.rkt"
"../private/rgba.rkt"
"../private/mimetypes.rkt"))
@title{Racket Webview}
@author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]]
@section{Overview}
Racket Webview is a class-oriented webview library built on top of a Qt-based
native runtime.
The library is layered. At the lowest level a native FFI layer is used. On top
of that, @racketmodname[racket-webview] provides a functional API. The
class-oriented API described in this manual is built from smaller modules on top
of that layer.
@section{Core Concepts}
The library is structured around two main concepts:
@itemlist[#:style 'compact
@item{a context, representing an isolated runtime with its own local HTTPS server}
@item{a window, representing a webview instance within such a context}]
A context manages local file serving, certificates, and settings. A window loads
content, handles events, and provides access to DOM elements.
@section{Modules}
The public API is divided into the following modules:
@itemlist[#:style 'compact
@item{@racketmodname[wv-context] — context creation and settings access}
@item{@racketmodname[wv-window] — window lifecycle, events, navigation, and dialogs}
@item{@racketmodname[wv-element] — DOM element wrapper}
@item{@racketmodname[wv-input] — typed input-element wrappers}
@item{@racketmodname[wv-dialog] — dialog windows}
@item{@racketmodname[wv-settings] — settings wrapper}
@item{@racketmodname[rgba] — RGBA color values}
@item{@racketmodname[mimetypes] — MIME type lookup}]
@section{Typical Usage}
A typical application creates a @racket[wv-context%] object and then creates one
or more @racket[wv-window%] objects within that context. DOM elements are
retrieved using @racket[(send window element 'id)], after which their state can
be read or modified using the element and input wrapper classes. Interaction
with the browser is handled through event callbacks and bindings.

View File

@@ -27,25 +27,38 @@ The module builds on the lower-level bindings from
A context encapsulates a native webview context together with a local HTTPS
server. Windows are created within a context and communicate through events and
JavaScript calls.
JavaScript calls. When an HTML file is
served, the context's CSS boilerplate is injected immediately before the
closing @tt{</head>} tag.
@section{Contexts}
@defproc[(webview-new-context
[file-getter procedure?]
[#:boilerplate-js boilerplate-js string?
(webview-default-boilerplate-js)])
(webview-default-boilerplate-js)]
[#:boilerplate-css boilerplate-css string?
(webview-default-boilerplate-css)])
wv-context?]{
Creates a new context.
The function:
@itemlist[#:style 'compact
@item{starts a local HTTPS server on a dynamically chosen port}
@item{generates a self-signed certificate}
@item{creates a native context}
@item{installs the provided JavaScript boilerplate}]
@item{installs the provided JavaScript boilerplate in the native context}
@item{stores the provided CSS boilerplate in the context}]
The @racket[file-getter] procedure maps request paths to files.
The @racket[file-getter] procedure maps request paths to files. The
@racket[#:boilerplate-js] argument provides JavaScript support code passed to
the native context constructor. The javascript is injected by the native
QtWebEngine software. The @racket[#:boilerplate-css] argument provides
CSS boilerplate that is stored in the context and injected into served HTML
documents.
Certificate files are removed automatically when the context is garbage
collected.
@@ -58,6 +71,7 @@ Returns the base URL of the context.
This URL can be used to construct URLs from relative path information.
}
@defproc[(wv-context? [v any/c]) boolean?]{
Recognizes context values.
}
@@ -147,6 +161,17 @@ Replaces the current document contents.
X-expressions are converted to strings before being passed to JavaScript.
}
@defproc[(webview-set-menu! [wv wv-win?] [menu is-wv-menu?])
symbol?]{
Installs @racket[menu] in @racket[wv].
The menu is converted to JSON using @racket[wv-menu->json] and then passed to
the browser by evaluating JavaScript through @racket[webview-run-js].
The result is the symbol returned by @racket[webview-run-js].
}
@defproc[(webview-set-title! [wv wv-win?] [title string?]) symbol?]{
Sets the window title.
}
@@ -525,9 +550,23 @@ Recognizes lists of filter entries.
@section{Utilities}
@defproc[(webview-default-boilerplate-js [f procedure?] ...)
@defproc[(webview-default-boilerplate-js [custom-js procedure?] ...)
string?]{
Returns the default JavaScript boilerplate.
The result is constructed by concatenating the contents of @tt{js/*.js}.
If an additional procedure is supplied, its returned string is appended
to that JavaScript.
}
@defproc[(webview-default-boilerplate-css [custom-css procedure?] ...)
string?]{
Returns the default CSS boilerplate.
The result is constructed by concatenating the contents of @tt{js/*.css}.
If an additional procedure is supplied, its returned string is appended to that CSS.
}
@defproc[(webview-standard-file-getter

96
scrbl/rgba.scrbl Normal file
View File

@@ -0,0 +1,96 @@
#lang scribble/manual
@(require racket/base
scribble/core
(for-label racket/base
racket/string
racket/contract))
@title{rgba}
@author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]]
@defmodule[rgba]
RGBA color support used by the webview library.
This module exports a transparent @racket[rgba] structure together with
predicates and conversion procedures for working with CSS-style color values.
@section{Overview}
An @racket[rgba] value represents a color using red, green, blue, and alpha
components.
The module provides:
@itemlist[#:style 'compact
@item{the @racket[rgba] structure type}
@item{predicates for validating component values}
@item{conversion from strings to @racket[rgba] values}
@item{conversion from @racket[rgba] values to CSS color strings}]
The intended external representation is the CSS form:
@racketblock[
"rgba(r,g,b,a)"
]
@section{Predicates}
@defproc[(rgba/color? [v any/c]) boolean?]{
Recognizes valid red, green, and blue component values.
A valid color component is an exact integer in the range from @racket[0] to
@racket[255], inclusive.
}
@defproc[(rgba/alpha? [v any/c]) boolean?]{
Recognizes valid alpha component values.
A valid alpha component is a real number in the range from @racket[0] to
@racket[1], inclusive.
}
@section{Structure Type}
@defstruct*[rgba ([r rgba/color?]
[g rgba/color?]
[b rgba/color?]
[a rgba/alpha?])]{
Represents one RGBA color value.
The fields @racket[r], @racket[g], and @racket[b] are the red, green, and blue
components. The field @racket[a] is the alpha component.
The structure is transparent.
}
@section{Conversion}
@defproc[(rgba->string [c rgba?]) string?]{
Converts @racket[c] to a CSS color string.
The result has the form:
@racketblock[
"rgba(r,g,b,a)"
]
}
@defproc[(string->rgba [s string?]) (or/c rgba? #f)]{
Attempts to parse @racket[s] as a CSS RGBA color string.
If parsing succeeds, the result is an @racket[rgba] value. If parsing fails, the
result is @racket[#f].
The accepted input format is the one produced by @racket[rgba->string], namely:
@racketblock[
"rgba(r,g,b,a)"
]
}

View File

@@ -24,6 +24,10 @@ windows. It owns the underlying webview context, provides the base URL used by
those windows, and gives access to persistent settings through
@racketmodname[wv-settings].
A context stores both JavaScript and CSS boilerplate. The JavaScript boilerplate
is passed to the native runtime, while the CSS boilerplate is injected into HTML
documents served by the local HTTPS server.
This module exports the @racket[wv-context%] class.
@defclass[wv-context% object% ()]{
@@ -40,10 +44,17 @@ to access that value, its base URL, and a settings object.
(webview-standard-file-getter base-path)]
[context-js procedure?
(λ () "")]
[context-css procedure?
(λ () "")]
[boilerplate-js string?
(webview-default-boilerplate-js context-js)]
[boilerplate-css string?
(webview-default-boilerplate-css context-css)]
[ini any/c
(error "You need to provide a 'ini' file settings interface for settings, e.g. simple-ini/class")])]{
(error
(string-append "You need to provide a 'ini' "
"file settings interface for "
"settings, e.g. simple-ini/class"))])]{
Creates a new context object.
@@ -56,9 +67,14 @@ The constructor accepts the following initialization fields.
@racket[(webview-standard-file-getter base-path)].}
@item{@racket[context-js] is a procedure producing additional JavaScript for
the context. Its default value is @racket[(λ () "")].}
@item{@racket[context-css] is a procedure producing additional CSS for the
context. Its default value is @racket[(λ () "")].}
@item{@racket[boilerplate-js] is the JavaScript boilerplate installed into the
underlying webview context. Its default value is
@racket[(webview-default-boilerplate-js context-js)].}
@item{@racket[boilerplate-css] is the CSS boilerplate stored in the context
and injected into HTML documents. Its default value is
@racket[(webview-default-boilerplate-css context-css)].}
@item{@racket[ini] is the settings backend used to construct the associated
@racket[wv-settings%] object. No default backend is provided; omitting it
raises an error.}]

83
scrbl/wv-dialog.scrbl Normal file
View File

@@ -0,0 +1,83 @@
#lang scribble/manual
@(require racket/base
racket/class
scribble/core
(for-label racket/base
racket/class
"../private/wv-window.rkt"))
@title{wv-dialog}
@author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]]
@defmodule[wv-dialog]
Dialog-window wrapper built on top of @racket[wv-window%].
This module exports the @racket[wv-dialog%] class. It is a specialized window
class whose initial size and position are derived from its parent window.
@section{Overview}
A @racket[wv-dialog%] object is a @racket[wv-window%] that initializes itself as
a dialog relative to its parent window.
The class inherits the window lifecycle, event handling, navigation, and dialog
support from @racket[wv-window%]. Its only specialization in the current source
is the implementation of @racket[init-size].
@section{Class: wv-dialog%}
@defclass[wv-dialog% wv-window% ()]{
Represents a dialog window centered relative to its parent window.
The class inherits the fields @racket[parent], @racket[settings],
@racket[wv-context], @racket[html-path], @racket[x], @racket[y],
@racket[width], and @racket[height] from @racket[wv-window%].
@defconstructor[()]{
Creates a dialog window.
The constructor does not define additional initialization arguments of its own.
Construction is delegated to @racket[wv-window%] through @racket[super-new].
}
@defmethod[(init-size) any/c]{
Initializes the dialog size and position relative to its parent window.
The method reads the parent window geometry from the inherited @racket[parent]
field:
@itemlist[#:style 'compact
@item{@racket[x] and @racket[y] of the parent window}
@item{@racket[width] and @racket[height] of the parent window}]
It then determines the dialog width and height from @racket[settings], using the
keys @racket['width] and @racket['height]. If a stored value is absent, the
constructor fields @racket[width] and @racket[height] are used if present.
Otherwise both dimensions default to @racket[400].
The dialog position is then computed so that the dialog is centered within the
parent window:
@racketblock[
(let ((xx (/ (- pw dw) 2))
(yy (/ (- ph dh) 2)))
...)
]
The resulting coordinates are rounded, converted to exact integers, and applied
using:
@racketblock[
(send this move x y)
(send this resize dw dh)
]
This method overrides the inherited @racket[init-size] implementation from
@racket[wv-window%].
}
}

View File

@@ -83,7 +83,7 @@ If a parent is supplied, the underlying lower-level parent window is passed to
@racket[webview-create].
}
@defmethod[(context) any/c]{
@defmethod[(context) (is-a?/c wv-context%)]{
Returns the window context object supplied at construction.
}
@@ -268,6 +268,37 @@ internal cache.
The returned value is the list produced by @racket[webview-unbind!].
}
@defmethod[(set-menu! [menu is-wv-menu?])
(is-a?/c wv-window%)]{
Installs @racket[menu] in this window and returns this window.
The accepted argument follows the contract of @racket[webview-set-menu!]. The
method delegates to:
@racketblock[
(webview-set-menu! wv menu)
]
}
@defmethod[(connect-menu! [id symbol?] [callback procedure?])
(is-a?/c wv-window%)]{
Connects @racket[callback] to the menu item identified by @racket[id].
The method installs a binding for the @racket['menu-item-choosen] event by
delegating to:
@racketblock[
(send this bind! id 'menu-item-choosen
(λ (el evt data)
(callback)))
]
The callback is invoked without arguments when the corresponding menu item is
chosen.
}
@defmethod[(set-title! [title string?]) any/c]{
Sets the window title.