From f35f040efbf65ea33888fbcc583842606b03c0f5 Mon Sep 17 00:00:00 2001 From: Hans Dijkema Date: Mon, 6 Apr 2026 00:15:49 +0200 Subject: [PATCH] Moved some modules and added documentation --- main.rkt | 38 ++--- private/menu.rkt => menu.rkt | 0 private/mimetypes.rkt => mimetypes.rkt | 0 ...oader.rkt => racket-webview-downloader.rkt | 0 ...et-webview-qt.rkt => racket-webview-qt.rkt | 2 +- ...-version.rkt => racket-webview-version.rkt | 0 .../racket-webview.rkt => racket-webview.rkt | 2 +- private/rgba.rkt => rgba.rkt | 0 scrbl/menu.scrbl | 4 +- scrbl/mimetypes.scrbl | 2 +- scrbl/racket-webview-downloader.scrbl | 151 ++++++++++++++++++ scrbl/racket-webview-intro.scrbl | 36 +++-- scrbl/racket-webview-qt.scrbl | 52 +++++- scrbl/racket-webview.scrbl | 4 +- scrbl/rgba.scrbl | 2 +- scrbl/rktwebview-api.scrbl | 2 +- scrbl/rktwebviewqt-internals.scrbl | 2 + scrbl/wv-context.scrbl | 8 +- scrbl/wv-dialog.scrbl | 5 +- scrbl/wv-element.scrbl | 7 +- scrbl/wv-input.scrbl | 11 +- scrbl/wv-settings.scrbl | 5 +- scrbl/wv-window.scrbl | 13 +- private/wv-context.rkt => wv-context.rkt | 0 private/wv-dialog.rkt => wv-dialog.rkt | 0 private/wv-element.rkt => wv-element.rkt | 0 private/wv-input.rkt => wv-input.rkt | 0 private/wv-settings.rkt => wv-settings.rkt | 0 private/wv-window.rkt => wv-window.rkt | 0 29 files changed, 276 insertions(+), 70 deletions(-) rename private/menu.rkt => menu.rkt (100%) rename private/mimetypes.rkt => mimetypes.rkt (100%) rename private/racket-webview-downloader.rkt => racket-webview-downloader.rkt (100%) rename private/racket-webview-qt.rkt => racket-webview-qt.rkt (99%) rename private/racket-webview-version.rkt => racket-webview-version.rkt (100%) rename private/racket-webview.rkt => racket-webview.rkt (99%) rename private/rgba.rkt => rgba.rkt (100%) create mode 100644 scrbl/racket-webview-downloader.scrbl rename private/wv-context.rkt => wv-context.rkt (100%) rename private/wv-dialog.rkt => wv-dialog.rkt (100%) rename private/wv-element.rkt => wv-element.rkt (100%) rename private/wv-input.rkt => wv-input.rkt (100%) rename private/wv-settings.rkt => wv-settings.rkt (100%) rename private/wv-window.rkt => wv-window.rkt (100%) diff --git a/main.rkt b/main.rkt index ce1b375..af0a7af 100644 --- a/main.rkt +++ b/main.rkt @@ -1,25 +1,25 @@ #lang racket/base -(require "private/racket-webview-downloader.rkt") -(require "private/racket-webview.rkt") -(require "private/wv-context.rkt") -(require "private/wv-window.rkt") -(require "private/wv-dialog.rkt") -(require "private/wv-element.rkt") -(require "private/wv-input.rkt") -(require "private/rgba.rkt") -(require "private/mimetypes.rkt") -(require "private/menu.rkt") +(require "racket-webview-downloader.rkt") +(require "racket-webview.rkt") +(require "wv-context.rkt") +(require "wv-window.rkt") +(require "wv-dialog.rkt") +(require "wv-element.rkt") +(require "wv-input.rkt") +(require "rgba.rkt") +(require "mimetypes.rkt") +(require "menu.rkt") -(provide (all-from-out "private/wv-context.rkt" - "private/wv-window.rkt" - "private/wv-dialog.rkt" - "private/wv-element.rkt" - "private/wv-input.rkt" - "private/rgba.rkt" - "private/mimetypes.rkt" - "private/menu.rkt" - "private/racket-webview-downloader.rkt" +(provide (all-from-out "wv-context.rkt" + "wv-window.rkt" + "wv-dialog.rkt" + "wv-element.rkt" + "wv-input.rkt" + "rgba.rkt" + "mimetypes.rkt" + "menu.rkt" + "racket-webview-downloader.rkt" ) webview-set-loglevel webview-version diff --git a/private/menu.rkt b/menu.rkt similarity index 100% rename from private/menu.rkt rename to menu.rkt diff --git a/private/mimetypes.rkt b/mimetypes.rkt similarity index 100% rename from private/mimetypes.rkt rename to mimetypes.rkt diff --git a/private/racket-webview-downloader.rkt b/racket-webview-downloader.rkt similarity index 100% rename from private/racket-webview-downloader.rkt rename to racket-webview-downloader.rkt diff --git a/private/racket-webview-qt.rkt b/racket-webview-qt.rkt similarity index 99% rename from private/racket-webview-qt.rkt rename to racket-webview-qt.rkt index 78e8a44..61fee48 100644 --- a/private/racket-webview-qt.rkt +++ b/racket-webview-qt.rkt @@ -12,7 +12,7 @@ json racket/string racket/path - "utils.rkt" + "private/utils.rkt" "racket-webview-downloader.rkt" openssl/libssl ) diff --git a/private/racket-webview-version.rkt b/racket-webview-version.rkt similarity index 100% rename from private/racket-webview-version.rkt rename to racket-webview-version.rkt diff --git a/private/racket-webview.rkt b/racket-webview.rkt similarity index 99% rename from private/racket-webview.rkt rename to racket-webview.rkt index 0e4b7e7..efc56f0 100644 --- a/private/racket-webview.rkt +++ b/racket-webview.rkt @@ -2,7 +2,7 @@ (require "racket-webview-qt.rkt" "racket-webview-version.rkt" - "utils.rkt" + "private/utils.rkt" "mimetypes.rkt" "rgba.rkt" "menu.rkt" diff --git a/private/rgba.rkt b/rgba.rkt similarity index 100% rename from private/rgba.rkt rename to rgba.rkt diff --git a/scrbl/menu.scrbl b/scrbl/menu.scrbl index aec90bd..1b2bfe9 100644 --- a/scrbl/menu.scrbl +++ b/scrbl/menu.scrbl @@ -6,12 +6,12 @@ racket/string net/url json - "../private/menu.rkt")) + "../menu.rkt")) @title{menu} @author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] -@defmodule[menu] +@defmodule[racket-webview/menu] Menu data structures used by the webview library. diff --git a/scrbl/mimetypes.scrbl b/scrbl/mimetypes.scrbl index 9f19776..966f743 100644 --- a/scrbl/mimetypes.scrbl +++ b/scrbl/mimetypes.scrbl @@ -9,7 +9,7 @@ @title{mimetypes} @author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] -@defmodule[mimetypes] +@defmodule[racket-webview/mimetypes] MIME type utilities used by the webview library. diff --git a/scrbl/racket-webview-downloader.scrbl b/scrbl/racket-webview-downloader.scrbl new file mode 100644 index 0000000..a750d50 --- /dev/null +++ b/scrbl/racket-webview-downloader.scrbl @@ -0,0 +1,151 @@ +#lang scribble/manual + +@(require racket/base + scribble/core + (for-label racket/base + racket/file + setup/dirs + "../racket-webview-downloader.rkt")) + +@title{racket-webview-downloader} +@author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] + +@defmodule[racket-webview/racket-webview-downloader] + +Downloader support for the native @tt{racket-webview-qt} runtime. + +This module provides functions for checking whether the native runtime is +already installed, whether it can be resolved and downloaded, and for +downloading and unpacking it into the user's addon directory. + +@section{Overview} + +The module manages one specific downloadable version of the native +@tt{racket-webview-qt} package. The version is fixed in the source code through +three constants: a major, minor, and patch number. + +The download URL is derived from: + +@itemlist[#:style 'compact + @item{the configured download site} + @item{the configured base path} + @item{the version string} + @item{the current operating system} + @item{the current machine architecture}] + +The downloaded archive is installed below the user's addon directory in a +subdirectory named @tt{racket-webview-qt}. + +@section{Installation Layout} + +The installation directory is: + +@racketblock[ +(build-path (find-system-path 'addon-dir) "racket-webview-qt") +] + +Within that directory, the module uses: + +@itemlist[#:style 'compact + @item{@tt{version.txt} to store the installed version} + @item{an OS/architecture-specific subdirectory for the unpacked native files}] + +The OS and architecture components are derived from: + +@racketblock[ +(system-type 'os*) +(system-type 'arch) +] + +@section{Availability and Version Checks} + +@defproc[(racket-webview-qt-is-available?) boolean?]{ + +Returns @racket[#t] if the expected native runtime version is already installed, +and @racket[#f] otherwise. + +The function checks whether @tt{version.txt} exists and can be read as a value. +It then compares the stored major, minor, and patch numbers with the version +hard-coded in this module. + +If reading the version file fails, the result is @racket[#f]. +} + +@defproc[(racket-webview-qt-version) (or/c list? #f)]{ + +Returns the installed version as stored in @tt{version.txt}, or @racket[#f] if +the expected native runtime is not available. + +The returned value is the value read from the version file. In the current +implementation this is a list of three numbers: major, minor, and patch. +} + +@defproc[(racket-webview-qt-directory) (or/c path? #f)]{ + +Returns the directory containing the unpacked native runtime for the current +operating system and architecture, or @racket[#f] if the expected version is not +available. + +The returned path has the form: + +@racketblock[ +(build-path install-path (format "~a-~a" rkt-qt-os rkt-qt-arch)) +] +} + +@section{Downloadability Checks} + +@defproc[(racket-webview-qt-resolves?) boolean?]{ + +Returns @racket[#t] if the configured download host can be resolved through DNS, +and @racket[#f] otherwise. + +If no nameserver can be found, or if DNS resolution fails, the result is +@racket[#f]. +} + +@defproc[(racket-webview-qt-is-downloadable?) boolean?]{ + +Returns @racket[#t] if the configured download URL can be opened, and +@racket[#f] otherwise. + +The function attempts to open an HTTPS input port for the download URL. If that +succeeds, the port is closed immediately and the function returns +@racket[#t]. Any failure is caught and results in @racket[#f]. +} + +@section{Downloading} + +@defproc[(download-racket-webview-qt) boolean?]{ + +Downloads and installs the configured version of @tt{racket-webview-qt}. + +The function performs the following steps: + +@itemlist[#:style 'compact + @item{opens an HTTPS input port for the configured download URL} + @item{creates the installation directory if necessary} + @item{downloads the archive to @tt{archive.zip}} + @item{removes any existing unpacked directory for the current OS and architecture} + @item{unzips the archive into the installation directory} + @item{removes the downloaded zip archive} + @item{writes the installed version to @tt{version.txt}}] + +Progress information is printed to the current output port while downloading and +installing. + +If no download port can be obtained, the function raises an exception. Otherwise, +on successful completion, it returns @racket[#t]. +} + +@section{Notes} + +The module forces HTTPS downloads by temporarily setting the current HTTPS +protocol to @racket['secure] while opening the download port. + +The installed runtime is specific to the current operating system and machine +architecture. The selected archive name has the form: + +@racketblock[ +(format "~a-~a.zip" (system-type 'os*) (system-type 'arch)) +] \ No newline at end of file diff --git a/scrbl/racket-webview-intro.scrbl b/scrbl/racket-webview-intro.scrbl index f1235e2..282f21c 100644 --- a/scrbl/racket-webview-intro.scrbl +++ b/scrbl/racket-webview-intro.scrbl @@ -8,25 +8,27 @@ 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")) + "../wv-context.rkt" + "../wv-window.rkt" + "../wv-element.rkt" + "../wv-input.rkt" + "../wv-dialog.rkt" + "../wv-settings.rkt" + "../rgba.rkt" + "../mimetypes.rkt")) @title{Racket Webview} @author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] +@defmodule{racket-webview} + @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 +of that, @racketmodname[racket-webview/racket-webview] provides a functional API. The class-oriented API described in this manual is built from smaller modules on top of that layer. @@ -46,14 +48,14 @@ content, handles events, and provides access to DOM elements. 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}] + @item{@racketmodname[racket-webview/wv-context] — context creation and settings access} + @item{@racketmodname[racket-webview/wv-window] — window lifecycle, events, navigation, and dialogs} + @item{@racketmodname[racket-webview/wv-element] — DOM element wrapper} + @item{@racketmodname[racket-webview/wv-input] — typed input-element wrappers} + @item{@racketmodname[racket-webview/wv-dialog] — dialog windows} + @item{@racketmodname[racket-webview/wv-settings] — settings wrapper} + @item{@racketmodname[racket-webview/rgba] — RGBA color values} + @item{@racketmodname[racket-webview/mimetypes] — MIME type lookup}] @section{Typical Usage} diff --git a/scrbl/racket-webview-qt.scrbl b/scrbl/racket-webview-qt.scrbl index 9d9fa86..e269f5a 100644 --- a/scrbl/racket-webview-qt.scrbl +++ b/scrbl/racket-webview-qt.scrbl @@ -1,5 +1,7 @@ #lang scribble/manual +@defmodule{racket-webview/racket-webview-qt} + @title{Racket FFI Interface for @tt{rktwebview_qt}} @author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] @@ -10,6 +12,11 @@ native @tt{rktwebview_qt} library. It loads the shared library, initializes the native runtime, and exposes Racket functions for creating and controlling webview windows. +If the Qt backend is available locally, it is loaded directly. Otherwise the +module attempts to resolve and download the backend. If that is not possible, +the module continues in a degraded mode in which a limited subset of the +FFI entry points will only display a warning and perform a no-op. All others will fail. + The wrapper translates the low-level C interface into a Racket-oriented API based on structures, callbacks, and ordinary Racket values. @@ -35,6 +42,45 @@ The shared library @tt{rktwebview_qt} must therefore be built against Qt Earlier Qt versions are not supported. +@section{Backend Availability} + +The module first checks whether the expected @tt{racket-webview-qt} backend is +already installed. + +If it is not installed, the module attempts to resolve the configured download +site. If the site can be resolved and the configured archive is downloadable, +the backend is downloaded automatically. + +If the download site cannot be resolved, if no archive is available for the +current operating system and machine architecture, or if the download fails, the +module does not immediately abort module loading. Instead it switches to a +degraded mode in which native FFI loading is disabled. + +In that degraded mode, a textual reason is stored internally and selected FFI +entry points are replaced by fallback implementations. + +When the backend cannot be loaded, the module defines fallback implementations +for missing FFI entry points through @racket[define-ffi-definer] and +@racket[#:default-make-fail]. + +These fallbacks behave in two different ways. + +For a small set of initialization and shutdown functions, a non-failing fallback +is installed: + +@itemlist[#:style 'compact + @item{@racket[rkt_webview_env] returns @racket[#t]} + @item{@racket[rkt_webview_events_waiting] returns @racket[0]} + @item{@racket[rkt_webview_init] returns @racket[#t]} + @item{@racket[rkt_webview_cleanup] returns @racket[#t]}] + +All other missing FFI functions raise an exception when called. + +Fallback warnings are emitted at most once per function. If native loading was +disabled because the backend was unavailable, the warning message includes the +recorded reason. If native loading was enabled but a specific symbol could not +be loaded from the library, the error names the library file. + @section{Module Initialization} Loading the module performs several initialization steps automatically. @@ -86,9 +132,9 @@ 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]. -} +@;@defproc[(rkt-wv-win [wv rkt-wv?]) exact-integer?]{ +@;Returns the native window handle associated with @racket[wv]. +@;} @section{HTTP(S) Contexts} diff --git a/scrbl/racket-webview.scrbl b/scrbl/racket-webview.scrbl index 6818aa2..d854ded 100644 --- a/scrbl/racket-webview.scrbl +++ b/scrbl/racket-webview.scrbl @@ -6,7 +6,7 @@ @title{racket-webview} @author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] -@defmodule[racket-webview] +@defmodule[racket-webview/racket-webview] Higher-level interface built on top of @racketmodname[racket-webview-qt]. @@ -542,7 +542,7 @@ Represents a file dialog filter entry. @defproc[(make-wv-permitted-exts [name string?] [exts (listof symbol?)]) wv-permitted-exts?]{Creates a filter entry.} -@defproc[(wv-permitted-exts? [v any/c]) boolean?]{Recognizes filter entries.} +@;@defproc[(wv-permitted-exts? [v any/c]) boolean?]{Recognizes filter entries.} @defproc[(wv-list-of-permitted-exts? [v any/c]) boolean?]{ Recognizes lists of filter entries. diff --git a/scrbl/rgba.scrbl b/scrbl/rgba.scrbl index 995629f..f84ef25 100644 --- a/scrbl/rgba.scrbl +++ b/scrbl/rgba.scrbl @@ -9,7 +9,7 @@ @title{rgba} @author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] -@defmodule[rgba] +@defmodule[racket-webview/rgba] RGBA color support used by the webview library. diff --git a/scrbl/rktwebview-api.scrbl b/scrbl/rktwebview-api.scrbl index 3eeb62f..a46e81c 100644 --- a/scrbl/rktwebview-api.scrbl +++ b/scrbl/rktwebview-api.scrbl @@ -1,6 +1,6 @@ #lang scribble/manual -@;@defmodule[racket-webview] +@defmodule[racket-webview/c-api] @author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] diff --git a/scrbl/rktwebviewqt-internals.scrbl b/scrbl/rktwebviewqt-internals.scrbl index dbaf6a1..2bc35aa 100644 --- a/scrbl/rktwebviewqt-internals.scrbl +++ b/scrbl/rktwebviewqt-internals.scrbl @@ -1,6 +1,8 @@ #lang scribble/manual @(require racket/runtime-path) +@defmodule{racket-webview/internals} + @title{Qt WebView Backend Architecture} @author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] diff --git a/scrbl/wv-context.scrbl b/scrbl/wv-context.scrbl index 87d6083..ba9194b 100644 --- a/scrbl/wv-context.scrbl +++ b/scrbl/wv-context.scrbl @@ -6,14 +6,14 @@ (for-label racket/base racket/string racket/class - racket/file)) - -@; "../private/wv-context.rkt") + racket/file + "../wv-context.rkt" + )) @title{wv-context} @author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] -@defmodule[wv-context] +@defmodule[racket-webview/wv-context] @section{Overview} diff --git a/scrbl/wv-dialog.scrbl b/scrbl/wv-dialog.scrbl index d83418d..3298770 100644 --- a/scrbl/wv-dialog.scrbl +++ b/scrbl/wv-dialog.scrbl @@ -5,12 +5,13 @@ scribble/core (for-label racket/base racket/class - "../private/wv-window.rkt")) + "../wv-dialog.rkt" + "../wv-window.rkt")) @title{wv-dialog} @author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] -@defmodule[wv-dialog] +@defmodule[racket-webview/wv-dialog] Dialog-window wrapper built on top of @racket[wv-window%]. diff --git a/scrbl/wv-element.scrbl b/scrbl/wv-element.scrbl index 146d58a..4e0c65c 100644 --- a/scrbl/wv-element.scrbl +++ b/scrbl/wv-element.scrbl @@ -6,13 +6,14 @@ (for-label racket/base racket/string racket/class - "../private/wv-window.rkt" - "../private/racket-webview.rkt")) + "../wv-window.rkt" + "../racket-webview.rkt" + "../wv-element.rkt")) @title{wv-element} @author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] -@defmodule[wv-element] +@defmodule[racket-webview/wv-element] DOM element wrapper used by the window layer. diff --git a/scrbl/wv-input.scrbl b/scrbl/wv-input.scrbl index 7676ea2..4ea0581 100644 --- a/scrbl/wv-input.scrbl +++ b/scrbl/wv-input.scrbl @@ -5,15 +5,16 @@ scribble/core (for-label racket/base racket/class - "../private/racket-webview.rkt" - "../private/wv-element.rkt" - "../private/wv-window.rkt" - "../private/rgba.rkt")) + "../racket-webview.rkt" + "../wv-element.rkt" + "../wv-window.rkt" + "../wv-input.rkt" + "../rgba.rkt")) @title{wv-input} @author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] -@defmodule[wv-input] +@defmodule[racket-webview/wv-input] Typed input-element wrappers used by the window layer. diff --git a/scrbl/wv-settings.scrbl b/scrbl/wv-settings.scrbl index c61961a..e6cd81b 100644 --- a/scrbl/wv-settings.scrbl +++ b/scrbl/wv-settings.scrbl @@ -6,12 +6,13 @@ (for-label racket/base racket/string racket/class - racket/file)) + racket/file + "../wv-settings.rkt")) @title{wv-settings} @author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] -@defmodule[wv-settings] +@defmodule[racket-webview/wv-settings] Settings wrapper used by the webview library. diff --git a/scrbl/wv-window.scrbl b/scrbl/wv-window.scrbl index 325e48b..ad9950a 100644 --- a/scrbl/wv-window.scrbl +++ b/scrbl/wv-window.scrbl @@ -8,16 +8,17 @@ racket/class racket/file net/url - "../private/wv-context.rkt" - "../private/wv-settings.rkt" - "../private/wv-element.rkt" - "../private/wv-input.rkt" - "../private/rgba.rkt")) + "../wv-context.rkt" + "../wv-settings.rkt" + "../wv-element.rkt" + "../wv-input.rkt" + "../rgba.rkt" + "../wv-window.rkt")) @title{wv-window} @author[@author+email["Hans Dijkema" "hans@dijkewijk.nl"]] -@defmodule[wv-window] +@defmodule[racket-webview/wv-window] Window abstraction built on top of @racketmodname[racket-webview]. diff --git a/private/wv-context.rkt b/wv-context.rkt similarity index 100% rename from private/wv-context.rkt rename to wv-context.rkt diff --git a/private/wv-dialog.rkt b/wv-dialog.rkt similarity index 100% rename from private/wv-dialog.rkt rename to wv-dialog.rkt diff --git a/private/wv-element.rkt b/wv-element.rkt similarity index 100% rename from private/wv-element.rkt rename to wv-element.rkt diff --git a/private/wv-input.rkt b/wv-input.rkt similarity index 100% rename from private/wv-input.rkt rename to wv-input.rkt diff --git a/private/wv-settings.rkt b/wv-settings.rkt similarity index 100% rename from private/wv-settings.rkt rename to wv-settings.rkt diff --git a/private/wv-window.rkt b/wv-window.rkt similarity index 100% rename from private/wv-window.rkt rename to wv-window.rkt