Ann: SWI-Prolog 10.1.19

Dear SWI-Prolog user,

SWI-Prolog 10.1.19 is ready for download. The core has a faster virtual
machine and much faster tabling. XPCE can now handle sound, cameras,
video, gamepads, pens and touch screens, draw using the GPU and draw
vector graphics. Highlights:

Core

  • The virtual machine instructions can be compiled as functions that
    continue using guaranteed tail calls. This is now the default for
    GCC >= 15 and Apple Clang. Together with keeping the hot code
    together and avoiding several stalls, this makes the VM faster.
  • Tabling is much faster: cheaper creation, completion and resumption
    of tables, a compact trie representation, lazily compiled answer
    tries (Prolog flag table_compile_threshold) and the experimental
    flag table_drop_intermediate to drop tables that are no longer
    needed. Monotonic tabling and trie_gen/2,3 index better.
  • Fixed monotonic tabling not propagating to calls answered from
    subsumptive or abstract tables and several trie bugs: trie_gen/2,3
    crashing on an emptied trie or missing attributed variables and
    trie_update/3 corrupting stored compound values.
  • Fixed JIT indexing dropping a single remaining candidate argument,
    deleted clauses of a static predicate remaining visible after
    reloading, #1552 (crash on a stack overflow in debug mode) and
    term_minimal/2 and friends copying attributed variables.
  • profile_data/1 counts the self ticks of recursive predicates
    correctly.
  • check_installation/0 reports the image, sound and video formats xpce
    supports.
  • The macOS release is a universal binary built using Apple Clang and
    there is a Windows installer for ARM64.

XPCE (GUI)

  • Input devices: pens, touch screens, trackpad pinch and smooth
    scrolling, gamepads (including rumble and LED), keyboard polling and
    key_up events. Events have a device and device specific details.
  • Media: classes sound, audio_recorder and audio_stream play and record
    sound (MP3, Ogg, FLAC, … using SDL3_sound), camera delivers video
    from a camera and video and video_writer play, record and stream
    video with sound. display->bell can play a sound.
  • Images: class animation plays and saves animated PNG, GIF and WebP,
    image->save writes many formats, animated cursors, copy and paste
    of images and graphicals and a tray_icon in the system tray.
  • GPU drawing: classes sdl_texture, sdl_layer, sdl_window, sdl_mesh
    and sdl_canvas draw sprites, video and particles using the SDL
    renderer.
  • Vector graphics: class canvas, path with Bezier curves, arcs and SVG
    path data, line styles, image fills, nested clipping, blend modes
    and saving graphicals and windows as SVG.
  • Pango markup: classes markup and markup_text and markup in labels,
    menu items and list_browser items.
  • Font aliases are theme fonts that can be edited in the preferences
    editor.
  • IDE: a key bindings browser, keyboard control of panes and tabs,
    PceEmacs grep results in a filterable hit list. MODIFIED: PceEmacs
    loads its init file from user_app_config(‘xpce/emacs/init’).
  • New demos, including the games Asteroids and Pong and demos for
    sound, the camera, video, particles, animations and graphics.
  • The XPCE User Guide is updated for version 9, with new chapters on
    input devices and media and on paths, paint and text.
  • Many fixes, notably crashes and hangs after a process terminated,
    the profiler call graph and several Epilog terminal issues.

Platform notes

  • MacOS: Compiling the VM to tail-call functions causes AppleClang
    to produce faster code than GCC15. This simplifies a lot, expecially
    for those using Macports, Homebrew or build from source.
  • Windows: Building using MSVC or MSYS2 has not been tested. Only
    the cross-compiled release build has been tested. Claude enabled
    the VM tail-call functions for MSVC. If this works it might -as for
    Clang- close the performance gap.
  • WASM: Unfortunately enabling VM tail-call functions makes things
    worse using Emscripten’s Clang compiler. This is related to how WASM
    optimizes as well as the address validation when jumping to a function
    pointer.

Build dependencies

  • Unfortunately the release only works with SDL >= 3.4.0. Users of
    older SDL versions should use the GIT sources for building :frowning:

  • Add SDL3_sound as dependency if you want sound with anything but
    .wav files.

  • Add ffmpeg as dependency if you want video on Linux and streaming
    video on MacOS or Windows. On these systems basic video decoding
    falls back to the native API. The MacOS and Windows binaries include
    a stripped down version of ffmpeg. The default install for Macports
    or Homebrew is big. Building withput ffmpeg uses the native video
    API of the OS. This does not support most streaming options.

    Enjoy — Jan

SWI-Prolog Changelog since version 10.1.18

  • FIXED: waiting on a queue or thread_wait/2 spun with a pending signal
    in sig_atomic/1 Inside sig_atomic/1 or a cleanup handler, signals
    cannot be handled. cv_timedwait() nevertheless reported a pending
    signal as an interrupt, PL_handle_signals() did nothing and the wait
    was retried immediately. As a result, e.g., thread_get_message/3 with
    timeout(0) never returned. Waits now only stop for signals that can
    be handled and time out normally otherwise.

  • BUILD: scripts/configure: add `deps’ to build against ~/deps for macOS
    10.15 build.deps builds what scripts/make-distribution builds for the
    bundle, using the dependencies from scripts/macos-deps.sh, but for
    this machine’s CPU and without the bundle. MACOS_DEPS overrides ~/deps.

  • BUILD: macOS deps: add a small LGPL ffmpeg and, with WITH_SRT=yes,
    libsrt ffmpeg 8.1.3 with only libavformat, libavcodec and libavutil,
    encoding through VideoToolbox/AudioToolbox and using the bundled
    OpenSSL for TLS. xpce uses it if SWI-Prolog is configured with
    -DXPCE_VIDEO=ffmpeg. Not yet built on a Mac.

  • BUILD: MinGW: also copy DLLs named -.dll for an import
    library lib.dll.a, as ffmpeg’s Co-Authored-By: Claude Opus
    5.5 noreply@anthropic.com

  • ENHANCED: check_installation/0 reports the video codecs xpce can play
    and write Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com

  • FIXED: macOS: only use dependencies from one of Macports,
    Homebrew or a directory Macports builds picked up packages from
    Homebrew, e.g., SDL3_sound, which then loads Homebrew’s libSDL3
    next to the one from Macports. find_package() derives prefixes
    from $PATH, which CMAKE_IGNORE_PATH does not stop. Now also use
    CMAKE_IGNORE_PREFIX_PATH and ignore the other package managers in
    all modes. If MACOSX_DEPENDENCIES_FROM is a directory, add it to
    CMAKE_PREFIX_PATH and limit pkg-config to its .pc files.

  • FIXED: profile_data/1: ticks_self ignored nested calls of the same
    predicate If a predicate is called (indirectly) recursively, only
    the self ticks of its outermost nodes in the call tree were counted.
    The ticks of the nested nodes are now added to the self ticks and
    removed from the sibling ticks, such that the self ticks of all
    predicates plus the accounting ticks add up to the total ticks.

  • ENHANCED: check_installation/0 reports the image formats xpce can
    save and the sound files it can load Both depend on how SDL_image
    and SDL3_sound were built. Nothing is reported if xpce cannot tell,
    e.g., without a display or with an older xpce.

  • FIXED: macOS: allow the app to use the camera and microphone
    swipl-win was killed by TCC when XPCE opened the camera because
    Info.plist lacked NSCameraUsageDescription. The sound recorder
    needs NSMicrophoneUsageDescription for the same reason. Also add
    the camera and audio-input entitlements: under the hardened runtime,
    access is silently denied without them.

  • BUILD: macOS deps: add SDL3_sound, use libpng for SDL3_image, update
    versions SDL3_sound 3.2.0 (icculus/SDL_sound) is a CMake project
    built universal next to SDL3 and SDL3_image. All its decoders are
    built in; MIDI stays off as it needs patch files. 3.2.0 never sets
    SDLSOUND_VERSION, which sdl3-sound.pc.in uses, so we pass it.

  • TEST: cleanup of tests only removes what the test added retractall/1
    on user:file_search_path/2 and user:message_property/2 also removed
    the clauses with a variable head, destroying the library search path.
    The settings test removed all settings and loaded settings files.
    Erase the asserted clauses by reference and restrict the settings
    reset to the test module.

  • TEST: removed search path setup for the library alias Co-Authored-By:
    Claude Opus 5.5 noreply@anthropic.com

  • BUILD: Build the MacOS release using Apple Clang in a single pass The
    MacOS release is now a universal (arm64 + x86_64) Release build using
    Apple Clang with CMAKE_OSX_ARCHITECTURES, on both Apple Silicon and
    Intel hosts. This replaces the two GCC PGO builds that were merged
    using lipo. build --no-sign creates an unsigned .pkg.

  • WASM: default to the switch-based VM again The 19% gain of tail-calling
    VMI functions measured with Node 22 was an artifact of V8’s tiering:
    wasm functions start in the baseline compiler and V8 has no on-stack
    replacement for wasm, so the single large PL_next_solution() may
    run as baseline code for an entire benchmark while the small VMI
    functions are optimized quickly. With all code optimized, bench/
    takes for tail calls relative to the switch:

  • DOC: src/wasm/README.md describes tiered compilation and the VM
    variants, and fixes the commands to create a self-contained .qlf
    of bench/.

  • WASM: use tail-calling VMI functions by default Clang reports
    musttail for WebAssembly, but the backend can only emit tail calls
    with the tail-call feature (-mtail-call). VMI_TAILCALL now requires
    wasm_tail_call on WebAssembly.

  • PORT: Enable VMI functions by default when using AppleClang

  • TEST: only test AGC reclaiming trie atoms if
    SWIPL_TEST_FAIL_ON_UNLIKELY=y Atom-GC may find stale references to
    the atoms on the stacks, making the test fail depending on the build
    (e.g., VMI_FUNCTIONS).

  • FIXED: term_minimal/2 and friends copied attributed variables
    term_minimal/2, term_factorized/3,4, term_automaton/2 and
    automaton_minimal/2,3 copied the cell of an attributed variable in
    the input into the answer rather than referencing it. That made a
    second attributed variable that is not on the attvar chain: binding the
    original did not show in the answer, and GC could corrupt the stacks.
    In the WASM version this showed as test_bisim failing and crashing.

  • TEST: tabling tests failed without threads (WASM) Co-Authored-By:
    Claude Opus 5.5 noreply@anthropic.com

  • BUILD: GCC PGO -Wstringop-overflow false positive in trie_gen_raw()
    trie_gen() passed a NULL trie when retrying. With profile data, GCC
    (MinGW 16) cloned trie_gen_raw() for that constant and warned about
    the first-call branch that dereferences it, though a retry never
    takes that branch.

  • BUILD: compile without O_PROFILE (WASM) Co-Authored-By: Claude Opus
    5.5 noreply@anthropic.com

  • BUILD: GCC PGO build failed on inconsistent profiles of the VMI
    functions With VMI_FUNCTIONS using musttail, GCC finds the profile
    of most VMI functions not flow-consistent and refuses to use it.
    Add -fprofile-correction. The resulting build is 2-4% faster on bench/
    than a PGO build using computed goto.

  • FIXED: Windows (MinGW GCC): crash compiling the boot file with VMI
    tail calls MinGW GCC accepts preserve_none for the VMI functions,
    but the result enters a VMI with LD == NULL. Do not use preserve_none
    for MinGW GCC.

  • ENHANCED: HOT and hot VMI functions for tabling Mark trie_insert_flat(),
    trie_lookup_flat() and push_continuation_list() HOT and add S_TABLED
    to src/pl-vmi-hot.h.

  • ENHANCED: tabling: cheaper insertion of variant answers
    trie_insert_flat() dereferences the arguments once and looks up children
    inline; TRIE_STAT_INC() is a relaxed non-atomic increment. Variant
    answers are added without a foreign frame: tbl_reset_add_answer()
    calls trie_insert_flat() itself and only for a new or conditional
    answer continues in tbl_add_answer_found(). 500pDoubleFirst about 72%.

  • ENHANCED: tabling: resume suspended goals cheaply I_RESET pushes
    all environments of a continuation at once instead of meta-calling
    call_continuation/1 (which remains for reset/3), the answer is unified
    directly into the skeleton of the suspension, ‘$tbl_reset’/6 prunes
    and fails on an answer that completes the table and is no longer
    a meta-predicate.

  • ENHANCED: compiled tries: save the trie VM state only at choice
    points The trie VM trails its frame slots at most once per choice
    point; T_TRY_* saves TrieOffset in the CHP_JUMP choice point instead
    of trailing it (setJumpChoice()). accManyComp 78%, accOneComp 63%,
    accManyAtom 88%.

  • ENHANCED: tabling: add answers on exit of the worker Answers are added
    by I_EXITRESET when the worker of ‘$tbl_reset’/6 exits rather than by a
    Prolog call. Unconditional answers without delay information are added
    inline and tries no longer keep reference counts for built-in atoms.

  • ENHANCED: tabling: cheaper creation and completion of tables Call
    internal deterministic foreign setup and cleanup goals directly, cheaper
    creation of a private table, run the leader using ‘$tbl_leader’/5
    with a C cleanup and in fewer steps, return zero or one answer of a
    leader directly and reuse freed components, worklists and clusters.

  • ADDED: Prolog flag table_drop_intermediate (experimental) If non-zero,
    abolish tables of completed child components that merely served the
    outermost tabled goal when this goal completes. Tables are kept
    if they are small, called again after completion or expensive to
    recompute (in inferences, including the dropped tables below them).
    Trie node chunks count their live nodes and empty chunks are freed,
    so pruning many variants releases memory. Deleting a node in a full
    chunk only locks if atom-GC may register the chunk.

  • ENHANCED: tries: allocate nodes from chunks and avoid atomic counters
    Trie nodes are allocated from chunks. Atom-GC marks the atom keys
    of the chunks and registers the keys of full chunks.

  • ENHANCED: tabling: compile answer tries lazily and discard their
    nodes Answer tries are compiled when called often enough (Prolog flag
    table_compile_threshold, default 32) and their nodes are discarded.
    trie_gen/2,3 use a compact path for deep tries. table_statistics/0
    handles answer tries with discarded nodes.

  • ENHANCED: tries: compact children representation with optional striped
    write locks Trie node children are now a tagged word: no children, a
    single child or a block of {key,child} entries. Blocks up to 8 entries
    are searched linearly; larger blocks have an open addressing index.
    This replaces the lock-free hash tables, making a hashed child lookup
    about 3 times cheaper and reducing memory usage of tries.

  • ENHANCED: tabling: add flat answers to the answer trie without the
    generic term walk trie_insert_flat() adds an atom or a compound whose
    arguments are atomic or plain variables, creating the same keys as
    trie_lookup_abstract(). ‘$tbl_wkl_add_answer’/4 uses it first and
    falls back to trie_lookup_abstract() for other answers. This reduces
    the cost of an answer insertion (mostly duplicate checks) by about 25%.

  • ENHANCED: tabling: S_TABLED supervisor calls complete tables directly
    The S_TABLED supervisor looks up the variant of a call directly from the
    frame arguments (flat calls, cached start node of the predicate in the
    variant table) and calls a complete table without going through Prolog.
    S_INCR_DYNAMIC uses put_supervisor_goal().

  • FIXED: ‘$tbl_variant_table’/6 crashed if the first argument is
    not a closure start_tabling/3 documents that the closure may be
    passed as 0, in which case the predicate is found from the wrapper.
    ‘$tbl_variant_table’/6 then used a NULL predicate. Resolve the
    predicate from the variant if there is no closure.

  • FIXED: calling a complete shared moded table raised a type error For
    a shared table, ‘$tbl_variant_table’/6 returned the compiled answer
    trie clause if the table is complete. start_moded_tabling/5 passes
    this to trie_gen/2, which requires the trie. Moded tabling does not
    use the compiled answer trie, so do not request it.

  • MODIFIED: GCC defaults to VMI_FUNCTIONS if it supports musttail With
    musttail (GCC >= 15) the VMI functions use guaranteed tail calls,
    which is faster than the single function using computed goto (GCC 16:
    bench/ 97%, tabling 91-101%). Older GCC keeps computed goto.

  • ENHANCED: keep the hot VMI and C functions of the VM together
    src/pl-vmi-hot.h lists the 80 VMI/VMH functions with the most cycles
    on bench/ and the tabling benchmarks (doc/tabling/tools/vmi-hot.sh).
    pl-wam.c redeclares these with attribute((hot)) when using
    tail-calling VMI functions, which groups them in .text.hot (33.5Kb
    contiguous instead of spread over 94Kb). HOT marks the hottest C
    functions of the VM (clause selection, unify, tries, continuations,
    fastheap terms), so they are placed next to these: the instruction
    cache behaviour of the hot code then no longer depends on the placement
    of unrelated code.

  • ENHANCED: tail-calling VMI functions With VMI_FUNCTIONS and a compiler
    supporting musttail (GCC >= 15, Clang >= 13), VMI and VMH functions
    continue with a guaranteed tail call of the next instruction instead
    of returning to the dispatch loop. Helper arguments are passed
    in the register file so all functions have the same signature.
    With preserve_none the hot registers LD, PC, FR, the register file
    (r15) and ARGP are arguments. VMI functions are noinline (GCC 16 drops
    musttail in inlined VMIs). VMCODE_IS_ADDRESS is used for Clang too.
    VMI_TAILCALL=0 and VMI_CC= select the fallbacks.

  • ENHANCED: mark slow-path functions COLD Add COLD (attribute((cold)))
    and apply it to functions that are only called on slow paths: stack
    overflows and growing the stacks, errors, the debugger, tracing,
    coverage, profiling, etc. GCC moves the blocks calling these
    into the .cold part of the caller, which shrinks the hot part of
    PL_next_solution() from 92.9Kb to 74.2Kb.

  • ENHANCED: put_fastheap(): relocate by tag in a single pass Drop the
    relocation array from fastheap records: the term part holds only tagged
    cells, so a cell is relocated iff it has STG_GLOBAL storage and is
    not a functor (mask table). Restoring is a single branch-free pass
    with post-passes for attvars and atoms only if needed. Records are
    about 40% smaller.

  • ENHANCED: avoid store-to-load forwarding stalls in arithmetic and clause
    choice points A struct copy or memcpy() of data just written by narrower
    stores compiles to wide loads that cannot be store-forwarded and stall
    until the stores retired. moveNumber() copies small integers and floats
    by field; clause choices and moved choice points are copied using scalar
    moves (copyWordsScalarUp()/copyWordsScalarDown(), copyClauseChoice()).

  • ENHANCED: use non-atomic updates for the flags of local frames set()
    and clear() use atomic operations. Local frames are only accessed by
    their own thread, so the VM can update their flags with plain stores.
    The locked instructions were paid on every non-deterministic exit,
    SSU commit, cut, etc. Adds setLocal() and clearLocal().

  • ENHANCED: per-thread cache for looking up modules by name Meta calls
    look up the module of M:Goal by name. Each thread now caches the
    most recent lookups in a direct-mapped cache of 8 entries, which is
    flushed when a module is destroyed. Calling a qualified goal takes
    10% fewer instructions.

  • ENHANCED: do not validate term_t for internal PL_get_blob() and
    PL_get_pointer_ex() As for the other PL_*() functions, the exported
    functions validate their arguments and internal callers use the ___LD
    version without validation. These two are used by the tabling and
    trie predicates for each table.

  • ENHANCED: dark theme: colours for the CPU gauges of the thread monitor
    and the code ranges of the symbol picker Co-Authored-By: Claude Opus
    5.5 noreply@anthropic.com

  • ENHANCED: dark theme: colours for error and warning reports, the failing
    part of an incremental search and code in running text Co-Authored-By:
    Claude Opus 5.5 noreply@anthropic.com

  • ENHANCED: dark theme: colour for filter matches in PceEmacs hit lists
    Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com Claude-Session:
    https://claude.ai/code/session_01UgGX2Hqkp4kavsXYTKX8Sf

  • FIXED: #1552 crash when unwinding a stack overflow in debug mode If
    there is no space to start the tracer, b_throw_unwind_debug retries
    while unwinding using dbg_except_start_tracer(). This runs GC, trims
    the stacks and prints the message, which may move the local stack.
    The VM registers were not saved and reloaded around this call,
    leaving FR pointing at the old stack.

  • FIXED: JIT indexing: a single remaining candidate argument was dropped
    candidate_indexes() only merged the remaining single-argument candidates
    inside the block that builds two-argument combinations, which requires
    at least two assessments. If exactly one poor but useful argument
    remained (e.g., the parent argument of bintree(Parent,Child) with the
    child argument as good index), it was silently discarded. As static
    predicates have fixed candidate indexes, calls on that argument then
    scanned all clauses. This made the bintree18 tabling benchmark about
    60 times slower.

  • BUILD: macOS deps: build libpng so that cairo has the SVG surface
    cairo builds its SVG surface only along with the PNG functions,
    so XPCE’s ->svg was unavailable in the bundle.

  • TEST: monotonic propagation to reused tables and trie value/delete cases
    test_mono_reuse.pl covers several binding patterns on one subsumptive
    table, a subsumed call on a recursive table, a dependency created
    during propagation, incremental+monotonic subsumptive tables, indirect
    keys in abstracted calls and reevaluation of an invalidated incremental
    abstract table. test_trie.pl adds an emptied root that held a variable
    key and balanced atom references over repeated trie_update/3 calls.

  • DOC: trie_gen/3: do not claim the cost only depends on matching paths
    A variable in Key still visits every stored subterm at its place.
    Also state that the enumeration order is undefined and that a choice
    point may be left after the last answer.

  • FIXED: monotonic dependency index left a foreign frame open on errors
    mono_index_find(), mono_index_insert() and mono_index_build() returned
    on an error without closing the foreign frame they opened. Close it,
    keeping the exception. Also update the comment on cluster.sindex,
    which now indexes on several key paths.

  • ENHANCED: trie_gen/2,3 keep pruning on bound arguments after a variable
    trie_gen/2,3 followed the bound arguments of Key only up to the
    first variable, in Key or in a stored key. From there it enumerated
    the whole subtrie and left it to unification to reject the paths,
    so looking up p(a, 25000) in a trie of p(_, I) keys walked every I.
    dyn_affected/2 in boot/tabling.pl makes such a lookup on the variant
    table of an incremental predicate for every fact the predicate gains
    or loses.

  • ENHANCED: tabling: index suspensions on key paths during completion
    During completion ‘$tbl_wkl_work’/6 offers every answer of an answer
    cluster to every suspension of the suspension cluster it is paired with.
    A suspension of a call answered from a more general table carries the
    call as an instance. The scan rejects it cheaply only when a key of
    an argument of that instance differs from the answer’s, and otherwise
    copies the instance from the fastheap and unifies it with the answer.

  • ENHANCED: monotonic tabling: index a table’s dependencies by skeleton
    Calls answered from an abstract or more general table each record
    a monotonic dependency on that table with their own skeleton.
    The dependencies of one (source, consumer) edge form a chain:
    find_dep() walks it to find a duplicate of each new dependency, and
    propagating an answer copies and unifies every dependency of the source.
    One consumer making N bound calls to one abstracted table cost 2.1 s
    to evaluate for N = 32000, against 0.40 s through N variant tables,
    and each later answer 6.6 ms to propagate, against 8 us.

  • FIXED: monotonic tabling: propagate to calls answered from subsumptive
    and abstract tables A call to a monotonic tabled predicate that is
    answered from a table other than a new variant table of its own did
    not record its dependency on that table: a subsumed call reading a
    more general table, a call reusing an existing variant table of a
    subsumptive predicate, and a call abstracted by subgoal_abstract(N).
    Answers that monotonic propagation later added to that table never
    reached the caller. For example, with

  • FIXED: trie_gen/2,3 crashed on a trie emptied by trie_delete/3
    When trie_delete/3 removes the last key below a root whose children
    are hashed, prune_node() stops at the root and leaves it the empty
    table. add_choice() enumerated that table without testing whether
    advanceTableEnum() produced a child and used the undefined key
    and child:

  • FIXED: trie_gen/2,3 missed a stored attvar in a hashed trie node
    When the children of a trie node are hashed and the query is bound at
    that position, add_choice() looks up the query’s own key and then the
    variable keys recorded in the node’s var_mask. update_var_mask() only
    records plain variables (TAG_VAR), so the key of a stored attributed
    variable, (N<<LMASK_BITS)|TAG_ATTVAR|STG_STATIC, was never tried and
    the answer was lost. With a single child (TN_KEY) the attributed
    variable was found:

  • FIXED: trie_update/3 and trie_insert/3 corrupted a stored compound
    value variantRecords(), which equal_value() uses to compare the value
    stored at a trie node with a new one, called memcpy() where memcmp()
    was meant. For two records of the same size it copied the new record
    over the old one and, as memcpy() returns its destination, reported
    them as different.

  • FIXED: clause_info/4 failed on optimised clauses using dicts in
    maplist/N or debug/3 library(apply_macros) reorders the arguments
    of maplist/N, which changes the order of the ‘.’/3 calls that
    evaluate dicts. Decompiled ‘.’/3 goals may now match any goal in a
    run of ‘.’/3 calls. Also skip the ‘.’/3 calls of a goal removed by
    optimisation such as debug/3.

  • FIXED: clause_info/4 failed on clauses with Var is Int + Var The
    compiler turns this into A_ADD_FC, which decompiles as `Var is Var

    • Int`. The clause body unification now handles this argument swap.
  • FIXED: reloading a file that deletes clauses from an indexed
    static predicate left the deleted clauses reachable through the
    index reconsultFinalizePredicate() only updated the clause indexes
    for dynamic predicates. Since the static code fast path skips the
    visibility check, the erased clauses remained visible through the
    JIT indexes after make/0.

  • FIXED: with optimise, var/1 and nonvar/1 on a fresh variable did
    not mark the variable as initialised. As 7dba157ea, this could
    leave the variable uninitialised after + inside a branch of ;/2.
    Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com

  • ADDED: Build the ARM64 Windows installer in the release workflow Turn
    the single x64 job into a matrix over {x64, arm64}. The ARM64 leg runs
    on a native aarch64 runner (ubuntu-24.04-arm), as the ARM64 host tools
    execute under Wine and need a 4K-page aarch64 kernel. It uses the
    swipl-mingw-build-arm64 image and --winarm64-from-git. fail-fast is
    disabled so a failure on one architecture does not cancel the other.

Package RDF

  • TEST: removed search path setup for the library and foreign aliases
    src/swipl in the build tree already finds the libraries and foreign
    modules of all packages.

Package chr

  • TEST: removed search path setup for the library and foreign aliases
    src/swipl in the build tree already finds the libraries and foreign
    modules of all packages.

Package clib

  • TEST: removed search path setup for the library and foreign aliases
    src/swipl in the build tree already finds the libraries and foreign
    modules of all packages.

Package cpp

  • TEST: removed search path setup for the library and foreign aliases
    src/swipl in the build tree already finds the libraries and foreign
    modules of all packages.

Package http

  • TEST: removed search path setup for the library and foreign aliases
    src/swipl in the build tree already finds the libraries and foreign
    modules of all packages.

Package inclpr

  • TEST: removed search path setup for the library and foreign aliases
    src/swipl in the build tree already finds the libraries and foreign
    modules of all packages.

Package jpl

  • TEST: removed search path setup for the library and foreign aliases
    src/swipl in the build tree already finds the libraries and foreign
    modules of all packages.

Package odbc

  • TEST: removed search path setup for the library and foreign aliases
    src/swipl in the build tree already finds the libraries and foreign
    modules of all packages.

Package pengines

  • TEST: removed search path setup for the library and foreign aliases
    src/swipl in the build tree already finds the libraries and foreign
    modules of all packages.

Package pldoc

  • CLEANUP: declare latex//1 and print_latex/3 public They are called
    by xpce’s gen_refman.pl.

Package protobufs

  • TEST: removed search path setup for the library and foreign aliases
    src/swipl in the build tree already finds the libraries and foreign
    modules of all packages.

Package semweb

  • TEST: removed search path setup for the library and foreign aliases
    src/swipl in the build tree already finds the libraries and foreign
    modules of all packages.

Package ssl

  • TEST: removed search path setup for the library and foreign aliases
    src/swipl in the build tree already finds the libraries and foreign
    modules of all packages.

Package xpce

  • MODIFIED: xdot demo only lists the installed graphviz layout engines
    Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com

  • FIXED: clicking a menu bar moved the keyboard focus of the frame If
    the window holding the menu bar wants the keyboard, e.g., a dialog
    with a text_item, a click on the menu bar made it the keyboard focus
    of the frame. After the menu, or a dialog opened from it, such as
    PceEmacs Edit/Replace, closed, the keys no longer went to the window
    the user was working in. A click on a menu bar now leaves the focus
    alone. Keyboard operation of the menu is not affected: while open,
    the menu bar grabs the keyboard.

  • FIXED: closing a transient frame could leave its owner without the
    keyboard Window managers are supposed to give the keyboard back to the
    window a dialog is transient for when the dialog closes. GNOME with
    focus-follows-mouse does not always do so, leaving the owner visible but
    without a caret or keys. If the transient had the keyboard and nothing
    took it over, raise the transient_for frame ourselves, on all platforms.

  • DOC: Versioned userguide upload

  • BUILD: take the xpce version from the VERSION file CMake, the C kernel
    (via config.h) and the User Guide’s version.tex now all get PCE_VERSION
    from VERSION. Removed the stale fallback definition from h/interface.h.

  • DOC: User Guide: SDL’s PipeWire camera driver does not work
    Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com

  • FIXED: demo video player: loading a file raised `@nil <-duration’ ->open
    reports the status synchronously for a local file, so ->video_status
    ran ->prepare before ->load had set the video slot.

  • FIXED: SDL timer: a tick queued before ->stop still ran the message
    Closing the Asteroids or Pong window stops its timer in ->unlink,
    but a tick that was already in the event queue then sent ->tick to
    the freed window.

  • DOC: User Guide section “Drawing with the GPU” with mesh and canvas
    examples; refman links to sdl_mesh and sdl_canvas The User Guide
    documents pce_sdl_mesh_set/3. The anchors of the sdl_mesh and
    sdl_canvas pages used hyphens, which broke links to them.

  • ADDED: demo Particles; demos Asteroids, Pong and Camera use the new
    GPU drawing Particles draws thousands of glowing particles using a
    single sdl_mesh. Asteroids has glowing sparks, drifting tiled dust
    and an exhaust trail drawn into an sdl_canvas, Pong glowing sparks
    and a net of one tiled layer and Camera ripple and fisheye effects
    that warp the video using an sdl_mesh.

  • ADDED: class sdl_canvas draws sdl_layer objects into a texture that a
    layer shows Moves many sprites as one, shows the same layers again,
    e.g., as a minimap, and leaves trails with sdl_canvas<->clear @off.
    The renderer draws a canvas before the frame and only after it changed.

  • MODIFIED: sdl_layer<-window is now sdl_layer<-device, as
    graphical<-device This prepares for layers shown on an off-screen
    sdl_canvas.

  • ADDED: class sdl_mesh: triangles with coloured corners that an sdl_layer
    draws, mapping its texture onto them sdl_layer<->mesh makes a layer
    draw the triangles of a mesh using SDL_RenderGeometry(). This draws
    gradients, warps a texture and draws many particles in one layer.
    pce_sdl_mesh_set/3 replaces all triangles of a mesh in one call.

  • FIXED: translucent sdl_layer textures drawn with a shear replaced
    what is below on the software renderer SDL’s software renderer draws
    triangles without the premultiplied blend modes. It now gets textures
    with straight alpha.

  • ADDED: sdl_layer blend modes, tint, scale mode, tiling and 9-slice
    scaling sdl_layer<->blend selects SDL’s blend modes (blend, add,
    mod, mul, none), <->tint multiplies the colours of the texture
    and <->scale_mode selects linear, nearest or pixelart sampling.
    Scale tile repeats the texture over <-area, shifted by <->offset,
    and <->slices scales it as nine parts that keep the size of the corners.

  • FIXED: sdl_layer<-alpha was too bright for images and ignored for
    camera and video frames SDL does not scale the RGB of premultiplied
    textures by the alpha mod, and textures without an alpha channel were
    drawn without blending.

  • DOC: xpce refman: fix links to classes whose name contains an
    underscore Several newer class pages used hyphens in their anchor
    (e.g. {#class-sdl-layer}), giving the label sec:class-sdl-layer,
    while \class{sdl_layer} links to sec:class-sdllayer (PlDoc strips the
    _). Links to these classes were therefore missing.

  • DOC: User Guide: video backends, sprite stacking, cursor none and
    class summary entries for SDL and video classes Co-Authored-By:
    Claude Opus 5.5 noreply@anthropic.com

  • ADDED: demo Pong: the good old game for one or two players Play against
    the computer or with two players using the keyboard or gamepads.
    Like the Asteroids demo, the paddles, ball, trail, sparks and net
    are GPU sprites driven by a timer, the controls are polled and the
    beeps are generated sound. Before the first game the computer plays
    against itself.

  • ENHANCED: demos Camera and Sound: tidier controls with tooltips,
    split buttons and a REC/LIVE/PLAY indicator Start/Stop, Record/Stop
    and Play/Stop are single buttons whose label changes. Snapshot,
    Record and Open are split buttons whose menu holds the other actions,
    e.g., saving a snapshot, streaming to a URL or recording to a WAV file.

  • ADDED: classes video and video_writer play, record and stream encoded
    video with sound A video plays a file, a URL (http, HLS, RTSP,
    UDP, …) or encoded data written to it, e.g., using pce_open/3.
    Its frames go into an sdl_texture, so an sdl_layer shows them in an
    sdl_window without Cairo, and its sound sets the time. It can play,
    pause, seek and loop, gives thumbnails and keeps up with live streams.
    A video_writer encodes images, textures, frames, windows, cameras
    and the microphone into a file, streams them to a URL (RTMP, SRT,
    UDP, TCP, RTP, HLS) or gives the data to code. The backends are
    ffmpeg (Linux, and Windows and macOS with -DXPCE_VIDEO=ffmpeg), Media
    Foundation (Windows) and AVFoundation (macOS); streaming needs ffmpeg.
    library(pce_video) writes video to a Prolog stream. Demos: Video
    player, Camera records and streams.

  • FIXED: A slider without label or values was too high and its bar was
    not aligned with the items in its row Without a label, the reference
    point of a slider is the baseline of its values or, without these,
    such that its bar is at the middle of the text of the other items.
    The height only includes the label and the values if they are shown.

  • FIXED: Compile with SDL < 3.4.16, where pen proximity events have no
    pen_state Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com

  • FIXED: Crash decoding data SDL_sound does not recognise on macOS
    SDL3_sound’s CoreAudio decoder crashes if no file extension is given,
    which happens for an audio_stream with encoded data and when loading a
    file whose name has no extension. Pass “” instead, which also makes
    SDL_sound try all decoders.

  • TEST: sdl_keyboard:text_input only checks the key events Dispatching
    events for 0.2 seconds also delivers the events of the real pointer,
    e.g., area_enter and loc_move on Windows if the pointer is over the
    new window.

  • ENHANCED: Asteroids demo draws its objects as GPU sprites, has buttons
    to play, edit the settings and show the controls, and hides the pointer
    while playing The field is an sdl_window and the ship, rocks, bullets,
    particles and stars are sdl_layer subclasses with a texture drawn
    once from a figure. The buttons appear on start-up, after the game
    is over and while it is paused. Settings opens the class variable
    editor on the preferences of the game. F1 shows the controls.

  • ADDED: predefined cursor none hides the pointer Co-Authored-By:
    Claude Opus 5.5 noreply@anthropic.com

  • ADDED: classes sdl_texture, sdl_layer and sdl_window draw pixels with
    the SDL renderer instead of Cairo An sdl_texture keeps its pixels in
    their own format. An sdl_layer places it in an sdl_window, scaled
    to an area or as a sprite that is moved, rotated and scaled using a
    transform around the texture’s hot spot. The layers are drawn below
    the graphicals of the window, so these can annotate, e.g., video.
    camera->texture delivers frames to a texture without converting them,
    which the Camera demo uses. Textures are made from an image or a
    graphical, image->copy converts them back and sdl_texture->draw_in
    draws on them.

  • ENHANCED: The class variable editor serves applications: Control-comma
    opens it and it shows the class variables of application classes
    Control-comma (Command-comma on MacOS) opens the class variable editor
    on the object below the pointer in any xpce window, or shows that object
    in the editor that is open. Without a preferences specification,
    the editor shows the class variables the manual classifies as basic.
    The manual does not know the classes of an application, so all class
    variables of these classes are now basic.

  • ENHANCED: Asteroids demo: game objects are graphicals that hold their
    own state The ship, asteroids, bullets, particles, stars and scoreboard
    texts are now classes that keep their position, velocity and timers
    in slots and update themselves in a ->tick method. The window holds
    the state of the game as a whole and ticks everything using

  • ADDED: display_manager<-audio_output tells whether there is a device to
    play sound on The first request starts the audio subsystem. From then
    on the value follows the playback devices that are added and removed.
    This allows an application to make sound optional: playing a sound
    or audio_stream without an audio device prints an error.

  • ENHANCED: The event viewer shows the button, click, rotation, device
    and event<-detail of an event; event_node<->summary describes each event
    type All types of @event_tree have a summary, including those of pens,
    touch screens, pinches, gamepads, devices, drag-and-drop and key_up.
    The event viewer shows it; a key that types a character shows the
    summary of its kind. Fixed the description of cursor_down and the
    function keys.

  • ADDED: key_up event for releasing a key and event<-repeat for
    auto-repeated key-downs A key_up is not a keyboard event, so key
    bindings and text editing do not see it. It goes to the keyboard focus
    and its event<-key is that of the key-down it releases. Both carry
    a new event_detail, key_data. frame->sdl_test_event accepts text_input.

  • FIXED: A window without text input did not get the keys of plain
    characters Without text input, as in a plain window without a focused
    text_item or editor, SDL sends no text input event. The key-down now
    gives the character, shifted as the keymap says, without waiting
    for text. Dead keys and input methods still need text input.
    frame->sdl_test_event accepts key_down and key_up.

  • FIXED: A read-only text_item that has the keyboard focus showed an
    active caret A read-only item still takes the focus when clicked,
    so text can be selected with Shift-cursor and copied with C-c, but
    it shows no caret.

  • ENHANCED: file_item has a browse icon; library(find_file) uses the
    file dialog of the desktop unless display.native_file_dialog is @off
    text_item<->icon and <->icon_message show a clickable image right
    of the field. file_item uses it to run ->browse (class variable
    browse_image), replacing the separate “Browse …” buttons of the
    PceEmacs prompter and the class variable editor. file_item<->filter
    sets the extensions offered. @finder uses frame<-open_file, <-save_file
    and the new <-open_directory if display.native_file_dialog is @on and
    a frame is shown. The sound demo uses a file_item for the location
    it streams.

  • ADDED: class audio_stream plays audio while it is written;
    audio_recorder->record(to=[source_sink]) writes while recording An
    audio_stream is a source_sink that plays raw samples or encoded data
    (WAV, MP3, FLAC, …; not Ogg Vorbis) while Prolog writes it using
    pce_open/3 or ->append. <-low_water_message asks for more data,
    closing the stream ends the data and <-message runs when everything
    is played. audio_recorder->record(to=File) writes a WAV file while
    recording; any other source_sink gets the raw samples.

  • ENHANCED: pce_open/3: binary streams on a source_sink with encoding
    octet; ->close_as_file pce_open/3 opens a binary stream on a source_sink
    whose encoding is octet, so ->write_as_file gets the bytes unchanged.
    Closing a stream opened for writing sends ->close_as_file to the
    object, a new virtual method of source_sink.

  • ADDED: variable<-types, as method<-types The argument types of the send
    method: <-type if the variable can be set, none if it can only be read.
    Fails if the variable is not accessible. Fixes M-x comment-column
    in PceEmacs language modes, where comment_column is a slot.

  • FIXED: PceEmacs grep: report a failing command in PceEmacs and show
    the outcome of the next grep A failing grep reported its exit status
    on the console, and its error message stayed on the PceEmacs status
    bar, hiding the outcome of later greps.

  • ENHANCED: Theme preferences edit display.bell_sound The bell sound
    is edited using a file_item with a Browse button that starts in the
    desktop’s sound directory. Bell pitch and duration are inactive if
    a bell sound file is set.

  • ENHANCED: display->bell plays a sound: display.bell_sound or a tone
    made by the new sound->tone display<-bell_sound returns the sound ->bell
    plays. The class variable display.bell_sound names a sound file to play
    instead of the tone of display.bell_pitch and display.bell_duration.
    The tone now fades in and out, so it no longer clicks.

  • FIXED: PlDoc warning on ->goto_history in pce_html_manual.pl xpce
    member comments take a bare header; the signature is derived from
    the method definition.

  • TEST: frame->sdl_test_event lost negative device ids on ARM64 (macOS)
    It converted the float field value directly to the unsigned id type,
    which is undefined for negative values: ARM64 gives 0 instead of,
    e.g., SDL_PEN_MOUSEID. The tests sdl_emulation:pen_mouse_ignored
    and touch_mouse_ignored failed on macOS.

  • DOC: no “PlDoc: unknown tag @cursors” warning when building the
    reference manual @see @cursors makes PlDoc read @cursors as a tag.
    Added it, and the other globals that follow an @see (@completer,
    @errors and @key_bindings), to the globals for which pldoc_xpce
    suppresses this warning.

  • ENHANCED: demos ImageViewer and Juggler use class animation ImageViewer
    plays animated PNG, GIF, WebP and AVIF files and shows WebP, AVIF,
    BMP, ICO, CUR and ANI files. Juggler plays an animation made from
    its SVG images; its speed sets the delays of the frames. Also fixed
    the spelling of the Juggler’s description in the demo browser.

  • FIXED: image->copy painted the copy over the old pixels, losing
    transparency As a result, animation->append also made the transparent
    parts of a frame, e.g., of an SVG image, opaque white.

  • FIXED: semi-transparent pixels were too dark when saved, copied or
    used in a cursor, and image->pixel ignored premultiplied alpha Images
    are Cairo surfaces with premultiplied alpha. Converting them for SDL
    (saving, the clipboard, cursors) now unpremultiplies, and image->pixel
    and image<-pixel convert between the straight alpha of colours and
    the premultiplied pixels.

  • ADDED: animated cursors: cursor(Name, Animation), e.g., from a
    Windows .ani file Images keep the hot spot of CUR and ANI files in
    image<-hot_spot and save it, so cursor/2 uses the hot spot of the
    file by default.

  • ADDED: animation->append, ->record and ->save: make and save animated
    PNG, GIF and WebP files, with their loop count and metadata An
    animation can now be made from images (->append) or by recording a
    frame or window (->record, ->stop), and saved as an animated image file
    (->save). ->save writes <->loop_count and the new <->title, <->author,
    <->description and <->copyright, as far as the format can hold them.
    Loading finds the format from the data rather than the file name.

  • ENHANCED: image->save writes JPEG, WebP, AVIF, GIF, BMP, TGA, ICO
    and CUR The format defaults to the one the file extension selects,
    PNG if the extension is not one of these. A new third argument sets
    the quality of JPEG, WebP and AVIF. display<-image_save_formats lists
    the formats SDL_image can write.

  • MODIFIED: PceEmacs loads its init file from
    user_app_config(‘xpce/emacs/init’) On all platforms, PceEmacs now
    loads xpce/emacs/init.pl from the user’s configuration directory
    (e.g., ~/.config/swi-prolog) instead of ~/.pceemacsrc or, on Windows,
    pceemacs.ini. If only the old file exists, PceEmacs prints a warning
    asking to move it.

  • ADDED: demo Animated images: play animated PNG, GIF and WebP files
    Plays an animation in a bitmap, with controls to play, stop, step
    and select a frame, and a film strip of all frames. The default
    animation is the public domain bouncing beach ball APNG by Holger
    Will from Wikimedia Commons.

  • ADDED: class animation holds the frames of animated PNG, GIF,
    WebP and AVIF files; a bitmap plays it animation(File) decodes all
    frames using SDL_image, with <-delays per frame and <-loop_count.
    bitmap(Animation) shows its first frame; bitmap->play, ->stop and
    ->frame play it or show a frame, and <-playing tells whether it plays.

  • FIXED: Windows: class sound only loaded WAV files although SDL3_sound
    was found Windows did not use the config.h that CMake generates, but the
    hand-written src/md/md-win64.h, so HAVE_SDL3_SOUND was never defined.
    All platforms now use config.h. src/md/md-windows.h is reduced to
    what CMake cannot know about Windows or finds although it does not
    work for xpce on Windows, such as select() and mkstemp().

  • FIXED: Windows: the drop shadow of popups was black SDL’s transparent
    windows show black where they should be transparent, both on Windows
    11 and on Wine. Popups on Windows are now opaque and drawn without
    a shadow, as on X11 without a compositor. Windows 11 rounds their
    corners.

  • ENHANCED: Epilog: a pane whose shell waits for a command closes
    without asking An interactive shell is the foreground process group
    of its terminal while it waits for input, so closing the pane asked
    for confirmation because “a program is running”. Epilog now remembers
    the pid of the shell it starts and only asks if another process group,
    i.e., a command run by the shell, holds the terminal.

  • ENHANCED: demo browser shows the demos in groups with headings The
    demos are grouped as Applications and tools, Dialogs and windows,
    Graphics, Media and devices and Games and animation, followed by the
    contributions. Demos that are not in a group appear under Other demos.

  • ADDED: demo Asteroids: a game using keyboard polling, gamepads and
    sound Fly a ship through an asteroid field and shoot the asteroids,
    which break up into smaller ones. The game polls the keyboard
    (keyboard<-key_down) and a gamepad on each tick of a timer, moves
    and rotates figures using figure->transform and plays sound effects
    that it generates as WAV data. The asteroids are shaded using radial
    gradients and glow, and explosions fade out using opacity.

  • ADDED: class keyboard; @keyboard_device<-key_down polls whether a
    key is held @keyboard_device is now an instance of class keyboard, a
    subclass of input_device, like class gamepad. There are no events for
    releasing a key, so applications such as games can poll the keyboard,
    e.g., get(@keyboard_device, key_down, cursor_left, @on).

  • ADDED: demo Sound: record, replay, load and save sound Records from
    the microphone while showing the input level and the growing waveform,
    plays the sound back, loads sound files (MP3, Ogg, FLAC, … if xpce
    has SDL3_sound) and saves the sound as WAV.

  • ENHANCED: class sound loads MP3, Ogg Vorbis, FLAC, … using SDL3_sound
    If SDL3_sound is available, sound->load decodes WAV, MP3, Ogg Vorbis,
    FLAC, AIFF, AU, VOC and module files. @pce then has the feature
    sound_decoders. display<-sound_file_extensions lists the extensions
    that can be loaded. Added sound<-peaks to draw a waveform.

  • ENHANCED: camera decodes Motion JPEG frames; camera->open accepts a
    size Most webcams deliver Motion JPEG frames without Huffman tables,
    which SDL cannot convert. The frames are now decoded using SDL_image.
    camera->open(Size) uses the supported frame size that is closest, with
    the highest frame rate, and camera<-sizes lists the supported sizes.
    The Camera demo lets the user choose the size.

  • ADDED: demo Camera: show the video of a camera and take snapshots The
    demo shows the video of the camera selected in a menu, the status of
    the camera, the frame size and the frame rate. Snapshot copies the
    current frame, which can be saved as PNG or copied to the clipboard.

  • DOC: User Guide chapter “Input devices and media” Describes
    event<-device and event<-detail, sub-pixel positions and smooth
    scrolling, pens, touch screens and pinch gestures, gamepads, sound,
    cameras, images on the clipboard, the system tray, power and locale
    and how to test input without the devices. The examples are in
    examples/devices.pl. Other chapters refer to it.

  • ADDED: class tray_icon shows an icon with a menu in the system tray
    tray_icon(Image, Tooltip, Popup) shows Image in the system tray
    (notification area). Its menu is built from the popup: selecting an
    entry executes the popup with the tray_icon as context. Sub-popups
    become submenus. On Linux this requires libayatana-appindicator.

  • ADDED: display<-power_state, <-battery_percent,
    <-battery_seconds and <-preferred_locales Co-Authored-By:
    Claude Opus 5.5 noreply@anthropic.com Claude-Session:
    https://claude.ai/code/session_01R86ZKx3ZMkfQcXM87545Tt

  • ADDED: copy and paste images and graphicals using the clipboard
    display->copy and display->selection accept an image (offered as
    PNG) or a graphical (offered as SVG and PNG). display<-selection
    with target image returns an image from PNG, JPEG or another
    image format on the clipboard and with target svg the SVG text.
    display<-selection_targets lists the MIME types on the clipboard.

  • ADDED: class camera delivers video from a camera as an image
    camera->open starts the camera. Each frame is copied into the same
    camera<-image, so a bitmap showing this image shows the video, and
    camera<-message is executed. <-status tells whether the user gave
    permission (waiting, open, denied); <-status_message reports changes.
    display<-cameras lists the available cameras.

  • ADDED: class sound to play WAV files and class audio_recorder
    sound(File) loads a WAV file. ->play plays it, possibly several
    times at once, ->stop stops it and <-message is executed when a play
    is finished. ->save writes a WAV file. An audio_recorder records
    from the default input (->record, ->stop) into its <-sound and executes
    its <-level_message with the input level while recording.

  • ADDED: gamepads: events, hot-plug, polling, rumble and LED
    display<-gamepads enables gamepads and returns the connected ones.
    Their buttons and axes generate gamepad_button_down, gamepad_button_up
    and gamepad_axis events for the window with the keyboard focus,
    whose <-detail is a gamepad_input (event<-control, event<-value).
    Controls are named by position (south, east, dpad_up, left_x, …).
    A gamepad can be polled (<-button, <-axis) and may ->rumble and show a
    colour (->led). When a device is added or removed, the keyboard-focus
    window of each frame receives a device_added or device_removed event.

  • ADDED: pen, touch screen and trackpad pinch input A pen and the
    first finger on a touch screen act as the mouse, so mouse-only
    applications work. Their events carry the device and its data:
    event<-pressure, <-xtilt, <-eraser, … (class pen_state) and
    event<-finger (class touch_point). Other fingers generate touch_*
    events. A trackpad zoom gesture generates pinch_begin, pinch_update
    and pinch_end with event<-scale; library(pan_zoom) zooms on a pinch.
    frame->sdl_test_event allows testing this input without the devices.

  • ADDED: precise and smooth scrolling for trackpads Wheel events
    report the precise scroll distance of trackpads and high resolution
    wheels as event<-dx and <-dy (class wheel_data). In a window with
    window<->smooth_scroll @on, every scroll step generates a wheel event
    whose <-rotation may be a fraction of a notch. The built-in handlers
    add up the fractions: a window scrolls by whole pixels, an editor or
    list_browser by whole lines.

  • ENHANCED: each input device has its own event state The defaults
    for a new event, the multiclick detection, the implicit grab from a
    button-down to its up and the window holding the pointer are kept
    per input_device. Interleaved events from the mouse and a pen or
    touch screen thus no longer disturb each other. Keyboard events use
    the state of the last pointer device, as before.

  • MODIFIED: drop events answer <-path and <-text instead of attributes
    The detail of a drop_* event is a drop_data, and class event delegates
    to its <-detail. So the dropped file and text are now available as
    event<-path and event<-text, and event<-source gives the application
    that sent the drop. Use get(Ev, path, Path) instead of get(Ev,
    attribute, path, Path).

  • ADDED: event<-device and event<-detail, classes input_device and
    event_detail Each event refers to the input_device that generated
    it: @mouse_device, @keyboard_device or, later, a pen, touch
    screen or gamepad. display<-input_devices lists the known devices.
    event<-detail will hold device specific data such as pen pressure; it
    is @nil for now. event->initialise accepts the device as an optional
    7th argument. If omitted, keyboard events use @keyboard_device and
    other events use the device of the last pointer event.

  • ADDED: window<->subpixel_events: events keep the fractional position
    Events now store the position the window system reports, including
    the fraction. The position getters (event<-x, <-y, <-position, …)
    return it for a window with subpixel_events @on. Otherwise they
    return whole pixels, rounded down, as before. This prepares for pen
    and touch input.

  • FIXED: terminal: an erase to the end of the line that starts beyond
    the text of the line used the default background Whiptail dialogs
    (e.g., raspi-config) draw the shadow of their window this way, so
    the shadow was missing. Cells that are added to a line to reach the
    caret now also keep the colour of an earlier erase.

  • TEST: test cleanup only removes the search paths the test added
    retractall/1 on user:file_search_path/2 also removed the clauses
    with a variable head, destroying the library search path. Erase the
    asserted clauses by reference. The tracer configuration sandbox
    moved to xpce_test_sandbox.pl and is removed after the tests.

  • ENHANCED: font alias label for the labels of the user interface The
    label_font of dialog items, dialog groups, list browsers, editors,
    window decorations and the display defaults to the new alias label
    rather than bold. It is bold, so nothing changes by default, but
    labels can now use a normal font without affecting bold text, e.g.,
    using font.system_fonts: [label := font(sans, normal, 12)].

  • ENHANCED: menu items and dialog labels can be markup The label of a
    menu_item, dialog item, dialog group or tab may be a markup object,
    which is displayed with its fonts, colours, etc. The mnemonic is
    chosen from the text without the markup and underlined. A cycle menu
    that is too narrow ellipsizes the markup.

  • ENHANCED: font_item offers the installed Pango families The family
    menu lists the generic families sans, serif and mono, followed by the
    installed families, shown in their own font. Items for a mono_font
    and the monospaced font aliases only offer the monospaced families.
    The list that opens from the family menu shows 15 lines.

  • FIXED: the list of a cycle menu did not show the selection The list
    was scrolled before its frame had its final size, so it always opened
    at the top.

  • ENHANCED: menu->max_value_width ellipsizes the value of a cycle menu
    A cycle menu with many long values, such as font families, no longer
    needs to be as wide as its longest value. A selection that does not
    fit ends in an ellipsis and menu<-ellipsized_label provides the full
    label, which library(help_message) shows as tooltip. The list that
    opens from the menu is as wide as its labels.

  • FIXED: class variable help window could not be resized The help window
    is ->transient_for the editor, which makes it a frame of kind transient
    that cannot be resized.

  • MODIFIED: font alias fixed is now an old name for tt fixed and tt
    were two aliases for the same font. fixed is no longer an alias
    of its own: converting it to a font yields the theme font tt, and
    fixed := Font in font.system_fonts defines tt. As a result,
    @font_aliases no longer has an entry fixed. All code now uses tt.

  • FIXED: class variable editor: help window failed without the IDE
    The help window uses class tool_bar, which was only available if
    library(toolbar) was already loaded, e.g., by the IDE.

  • ENHANCED: preferences editor: edit the font aliases in the Text
    tab The Text tab of the GUI preferences editor shows a family,
    style and size per font alias, followed by a sample text in the
    font and a tooltip that describes the role of the alias. If “Same
    size for related fonts” is on, changing the size of an alias also
    changes the aliases that only differ by style. Class font_item has
    a Theme… button to select a theme font. Documented font.scale,
    font.system_fonts and font.pango_families for users and added the
    manual page of class theme_font.

  • FIXED: tab labels were not laid out again after fonts_changed If
    a font changed in place, e.g., after changing font.scale or a font
    alias, the tab labels kept their old size and overlapped.

  • ENHANCED: font aliases are theme fonts that can be changed in place
    Font aliases such as normal and bold are now instances of the
    new class theme_font, a font whose properties are copied from the
    font it is derived from. Changing that font using ->derived_from
    or by changing font.system_fonts changes the theme font in place,
    so all users follow after display_manager ->fonts_changed.

  • TEST: key_binding_browser: expect macOS key symbols on macOS
    Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com

  • FIXED: thread monitor failed to open if the font descent is fractional
    On Windows, font<-descent is a float, making the icon size a float
    and between/3 in thread_browser->icon_styles raise a type error.

  • BUILD: avoid clang -Wabsolute-value warning in failing isearch report
    Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com

  • FIXED: profiler: call graph and browser issues reported on Discourse
    Sorted on the time of the children, the browser showed ticks. In the
    call graph, recursive calls are summed over all cycles and shown for
    every node, edges into a cycle no longer show inflated times but the
    number of calls, tooltips show the fail count if ports were recorded
    and the graph is redrawn when its preferences change.

  • ENHANCED: thread monitor, theme colour chooser and symbol picker
    follow the theme; icons of list browsers use the icon gap The CPU
    gauges of the thread monitor use the theme colours thread_cpu_idle and
    thread_cpu_busy and are drawn again if the theme or the font changes.
    All thread status icons have the size of the gauge, so the names
    line up. The swatches of the theme colour chooser follow a change
    of theme. The code ranges of the symbol picker use the theme colours
    symbol_picker_user and symbol_picker_prolog.

  • ENHANCED: markup in list_browser items and the labels of list_browser,
    editor and decorated windows A dict_item whose label is a markup shows
    its text using the fonts, colours and underlining of the markup on
    top of the item’s style; selection and search feedback stay on top.
    Searching and sorting a dict ignore the markup. The labels of
    list_browser, editor and window_decorator are displayed by a
    markup_text, so they accept a markup:

  • TEST: terminal rows: use the whole-pixel cell metrics of the terminal
    The terminal truncates the metrics of its font, which are fractional
    on Windows.

  • TEST: emacs grep: only run grep if it is installed Co-Authored-By:
    Claude Opus 5.5 noreply@anthropic.com

  • ENHANCED: key bindings browser: summaries next to the keys, choose
    functions from a list of commands, moved to the Settings menu The
    list of keys shows the summary of the function, which is the tooltip
    of the row. Changing the function of a key shows the commands with
    their summaries, a filter and a menu of classes; selecting one shows
    its documentation. Only commands are offered: built-in methods
    in a group of commands, such as caret or search, and methods
    defined in Prolog that are bound to a key or refine such a method.
    The browser moved from the Help to the Settings menu of the IDE.

  • ENHANCED: Pango markup: shows code in xpce’s fixed-width font
    on a faint background and font_family use xpce’s font families,
    so uses the same font as fixed-width text elsewhere in xpce.
    The background is the new theme colour ui_code_background.

  • FIXED: markup in a clipped label read past the end of its text A clipped
    label draws a one-line copy of its text that is not 0-terminated,
    while the markup code assumed it was. This showed as a failing
    isearch in PceEmacs that printed the raw markup and a Pango warning
    about invalid UTF-8.

  • ENHANCED: a failing incremental search shows which part of the target
    was found The warning shows the part of the search string that was
    found on the background of the isearch hit, ui_isearch_background,
    and the part that cannot be found on the new theme colour
    ui_isearch_failed_background.

  • FIXED: xpce format: incomplete and unknown %-sequences and *
    widths An incomplete or unknown conversion is copied verbatim.
    A % at the end of the format was written as \, a format ending
    in a flag or width, such as “%-” or “%5”, read past the end of the
    format and wrote a NUL character, and an unknown conversion such as
    “-5z" lost its flags and width. A `*` width, as in "*d” and “%-*s”,
    consumed its argument but printed the directive literally.

  • ENHANCED: reporter shows errors and warnings in the theme
    colours ui_error and ui_warning Co-Authored-By: Claude Opus 5.5
    noreply@anthropic.com

  • ADDED: class markup, a string holding Pango markup; formatting it
    escapes the arguments, and a label renders it, also for ->report
    messages send(Window, report, warning,
    markup(“Cannot open %s”, File))

  • MODIFIED: keyboard control of the panes and tabs of IDE windows;
    panes agree to be closed using ->can_close. Control-Page-Down/Up
    show the next or previous tab, F6, Shift-F6 and Control-X o move
    between the panes of a tab, Control-X 1 closes the other panes of
    the tab and Control-X 0 the current one. These work from any pane,
    including tools. Control-X 1 moves panes that do not agree to be
    closed, such as a terminal running a query or the console showing
    the messages of Prolog, to a new tab. <-can_close: bool is now
    ->can_close(Ask:[bool]).

  • FIXED: a window of the IDE that was not open kept its dropped status
    bar in its layout. Laying out the window then sent ->geometry to
    the freed bar, e.g., when an editor was moved to the tab beside it.
    frame->delete keeps the tile of a window if the frame is not created,
    as tab_frame relies on that.

  • FIXED: a key after a prefix that no table binds ran the default
    function. For example, Control-X 1 in Epilog inserted “1”. Such a
    sequence is now reported as undefined.

  • ENHANCED: key bindings browser for PceEmacs (Ctrl-H b) and any window
    of the IDE (Help/Key bindings). The browser is a tool pane that
    lists the keys per table, with a filter that works as you type and
    the manual entry of the method a key invokes. Keys can be bound to
    another function or key, unbound, and added to a table by selecting
    its header. Changes apply at once; Save writes them to the Defaults
    file as key_binding.<table>: [Key := Function, ...], one binding
    per line. Functions are completed from the commands of the target,
    which PceEmacs modes declare with Name = command; M-x completes
    the same commands.

  • FIXED: Preferences editor saved values with a backslash so they did
    not read back Prolog writes the atom \C-x as ‘\C-x’, which xpce reads
    with two backslashes: xpce reads quoted text as is. Such atoms are
    now written as xpce reads them.

  • FIXED: goal stack of xpce warnings lost the arguments of Prolog methods
    The arguments of a goal handled by Prolog were written to the current
    output instead of user_output, where xpce writes the rest of the line.
    In swipl-win they were missing from the warning and appeared on the
    terminal when the program halted.

  • CLEANUP: Delete PceEmacs C++ support for defining xpce classes in C++.

  • TEST: terminal: the first attribute shot painted on the input background
    out/2 writes to the terminal directly, bypassing the line editor, whose
    input decoration is still on at the prompt. Start each shot with SGR 0.

  • FIXED: Epilog windows were one row short of the rows asked for Since
    the terminal leaves room below the last row for the caret, a window
    sized as rows times the font height fits one row less, so the default
    Epilog window had 24 rows rather than 25. Added terminal_image
    <-cells_size, the inverse of how the terminal derives its rows and
    columns from its size, and size Epilog windows with it.

  • FIXED: Epilog on Windows: libedit assumed 80 columns until the window
    was resized Discourse 9090/232: editing a wrapped input line in a fresh
    window climbed up the screen, deleting characters from the rows above.

  • FIXED: terminal: italic fonts ignored after changing the font size
    If the user changed terminal_image.font (and bold_font), the italic
    variants still named the default size and were dropped with a “pitch
    differs” warning. A variant that does not fit is now derived from
    <-font.

  • FIXED: frame <-open_file and <-save_file: Cancel returned ‘’ SDL 3.2’s
    zenity file dialog reports a cancel as a single empty file name.
    Treat that as a cancel. Reported for File/Edit in swipl-win on
    Debian Trixie.

  • ENHANCED: PceEmacs hit list: filter as you type The bookmark pane used
    for grep, git grep and find-references has a filter field. It shows
    only the hits whose line or file name matches the (case insensitive)
    regular expression and highlights what the filter matches using the
    new theme colour emacs_bookmark_filter.

  • FIXED: terminal: the caret on the last row could be truncated The
    rows of the terminal now leave room below the last row for the part
    of the caret that reaches below its cell, such as the triangle of
    the default xpce caret style.

  • ENHANCED: PceEmacs grep and git grep show their hits in a hit list
    The hits appear in the same reusable pane as find-references instead
    of a compilation buffer. The commands run with --color=always, so
    the colour tells where the match is, which is highlighted in the hit
    list and the editor. Output that is not a hit is reported when the
    command is done.

  • TEST: check the reference manual card signatures against the classes
    xpce:refman_signatures compares the signature line of each card
    in man/refmanual/md with the live behaviour. Updated the cards it
    found stale, removed cards for figure->shadow, figure<-shadow and
    figure->convert_old_slot, and fixed the argument declarations of
    frame->y (named x) and pen->initialise.

  • ENHANCED: regex<->newline_sensitive; PceEmacs search/replace do
    not match newlines with . or [^…] Class regex compiles with
    REG_NLANCH only, so . and [^...] match a newline and .* in
    PceEmacs query-replace-regex ran to the end of the buffer. The new
    option adds REG_NLSTOP. It defaults to @off, as library patterns
    rely on spanning lines. PceEmacs query-replace-regex and the find
    dialog switch it on for the pattern typed by the user.

  • ENHANCED: manual browsers adapt the name column to the window width
    The name column of the class, module, group and search browsers is
    as wide as the widest name, but at most half the window, and follows
    the window when it is resized. Longer names are truncated with an
    ellipsis and show the full name as tooltip.

  • ADDED: @pce has the feature svg if ->svg can write SVG images Cairo
    may be built without the SVG surface, as by MacPorts. Test using
    send(@pce, has_feature, svg). The demo galleries only offer to save
    as SVG if it is supported.

  • FIXED: graphical->graphics_state used a freed stroke_style A
    stroke_style created for the texture argument is not referenced, so
    it was freed when the send returned while the drawing context still
    used it. ->restore_graphics_state then crashed on macOS.

  • ADDED: graphics demos and the XPCE userguide chapter “Paths, paint
    and text” Demos Path gallery, Paint gallery, Text gallery and Canvas
    show paths, gradients, line styles, markup text, clipping, blending
    and the canvas.

  • ADDED: class canvas for Cairo-style vector drawing; graphical->svg
    and window->svg A canvas is drawn on using paths, stroke, fill,
    clip, transformations, text and images, recorded as vectors.
    graphical->draw_path draws a path object from a ‘_redraw_area’ method.
    graphical->svg and window->svg write the graphical or window contents
    as an SVG image.

  • ENHANCED: clipping regions nest; added figure->clip_path and
    figure->blend ->clip intersects with the enclosing region and ->unclip
    restores it. figure->clip_path clips the contents of a figure to
    a path and figure->blend composites a figure onto what is below it
    using a blend mode such as multiply, screen or difference.

  • FIXED: colour(‘#RRGGBB’) created through new/2 or as a term argument
    was not parsed as hexadecimal Only conversion of a name such as
    ‘#RRGGBB’ parsed the hexadecimal notation; creating the colour
    explicitly, e.g. send(Box, fill, colour(‘#ff8000’)), produced an
    unknown named colour. The parsing is now shared by both.

  • FIXED: a colour with an unknown name was black instead of the grey50
    the warning announces The fallback stored the RGBA value untagged.

  • FIXED: a rounded box with an elevation lifted the clip of its window,
    painting outside the area being redrawn r_3d_box() reset the clip after
    drawing each half of the box rather than restoring the enclosing one.

  • ADDED: class markup_text displays text formatted using Pango markup,
    with Pango wrapping, alignment, justification, ellipsizing and line
    spacing; graphical->draw_markup draws markup from a ‘_redraw_area’
    method Markup can mix fonts, sizes, styles and colours, e.g.
    “Some bold and red text”.
    Unlike class text, a markup_text is read-only. It uses a layout
    of its own from the same Pango context as the fonts, so its metrics
    match those of plain text.

  • ADDED: line styles, image fills and gradient extend and units Class
    stroke_style provides line caps, joins, miter limit, arbitrary dash
    patterns and gradient lines, usable as graphical ->texture. Graphicals
    can be filled with a repeated image. gradient<-extend selects what
    is painted beyond the stops and gradient<-units: bounding_box makes
    a gradient relative to the shape it fills.

  • FIXED: the arrows of a path were never drawn The arrow heads of a
    path were positioned but not marked as displayed, so RedrawArea()
    skipped them. Line, arc and bezier_curve already did this.

  • ADDED: class path supports Bezier curves, elliptical arcs, sub-paths, a
    fill rule, rounded corners and SVG path data Curves, arcs and sub-paths
    use the new point subclasses curve_point, arc_point and move_point.
    path->svg_data and path<-svg_data set and get the points as SVG
    path data.

  • FIXED: graphical->draw_poly filled after stroking, painting the
    fill over the inner half of the outline Also removes a transparent
    cairo_paint() from r_fill_polygon() that had no effect.

  • FIXED: r_pixel() and r_get_pixel() accepted x == width and y == height
    The callers in image.c check bounds with inImage(), so this could not be
    reached from Prolog; there is therefore no regression test. The bounds
    check and address computation are now shared in target_pixel().

  • FIXED: ->draw_fill drew nothing unless the fill was @default, and
    r_fill() rejected gradients graphical->draw_fill now fills with any
    colour or gradient, and a figure with a gradient background draws it.

  • FIXED: gradient colour stops were scaled by 1/256, so no stop reached
    its full colour A red stop rendered as ffff0101 instead of ffff0000.
    Adds tests/test_cairo_render.pl, which checks drawn pixels via
    image->draw_in.

  • FIXED: graphical ->graphics_state used a freed colour A colour converted
    from a name is not referenced, so it was freed when the send returned
    while the drawing context still used it. Depending on the reuse
    of the memory, lines were drawn in a random colour or not at all.
    This made the graphics_state test fail on Windows.

  • FIXED: a process was reported to exit with status 0 at the end of its
    output End of file on the output of a process was taken as ->exited 0,
    losing the real exit status or signal and leaving the child unreaped.
    On Unix the termination is now only reported when the child is reaped,
    after handling the output it wrote. process->wait also waits for
    the process to terminate, such that <-status and <-code are known.
    On Windows the end of the output still means normal termination.

  • FIXED: crashes and hangs after a process (e.g., PceEmacs grep)
    terminated The SIGCHLD handler reaped the children and sent ->exited
    or ->killed, running the terminate message (Prolog, frame labels, the
    window system) inside the signal handler, interrupting whatever the
    main thread was doing. This crashed in GTK (libdecor on Wayland),
    corrupted the Prolog VM or crashed on halt. The handler now only
    writes to a pipe that is watched by the fd watcher thread, so the
    children are reaped from the main thread’s event loop.

  • FIXED: X11 with SDL 3.2: clicking a menu_bar did not keep the popup
    open With SDL 3.2 under a window manager such as xfwm4, the up-event of
    the click that opens a popup is reported for the popup window as that
    takes the focus. It is redirected to the window of the down-event,
    but the translation used SDL_GetWindowPosition(), which is relative to
    the parent for a popup. The menu_bar saw the up far from the down, so
    it did not keep the popup open and the popup closed without a selection.
    Compute screen positions through the parents of popup windows.

  • FIXED: possible crash on pressing Alt when a freed popup frame is
    still listed by the display acceleratorCuesFrame() walks the popup
    frames of the display to update their accelerator underlines. A freed
    frame keeps its <-kind (names are not reset) while its <-members is
    @nil, which crashed. Skip freed frames there and in wsid_to_frame().
    Reported on Debian/Xfce with 10.1.18.

  • TEST: theme:colour_trace failed on systems without a GNOME or KDE
    desktop There, sys_window_background uses xpce’s default, so the
    trace source is default rather than desktop.

  • FIXED: various issues found while updating the userguide - Interface:
    new(X, 3.5) crashed on an assertion. A float is not an
    object and now raises a type error, as for integers. - Interface:
    prolog(Float) did not pass the float. - Interface: calling Prolog
    from xpce while a Prolog exception is pending,
    e.g., reporting the type error after an unknown @Ref, printed
    “did not clear exception” and lost the exception. The pending
    exception is now saved and restored around the call. - Arithmetic
    objects truncated float arguments: 3+2.5 evaluated to 5. - Class
    compiler: unquoted range types such as Vol:[0..130] did not
    expand. - A frame larger than its display, e.g., from view ->size in
    characters, could crash the graphics driver. Frames are now limited
    to the size of their display. - program_object <-dflags is an
    alien slot. It held raw flag bits in
    an int slot, which showed as a garbage float. - bezier_curve term
    names were those of box. - <-man_summary warned about ->has_help if
    the manual is not loaded. - toc_tree ->selection selected a graphical
    used as node identifier
    rather than the node. - Visual hierarchy: show anonymous object
    arguments as rather
    than their long and varying reference.

  • DOC: XPCE userguide: recreate the screenshots Added
    screenshots/screenshots.pl to create the screenshots in figs from the
    code in the guide, using make screenshots. screenshots/shoot.sh
    runs it against a private headless mutter display at scale 2, or
    Xvfb if mutter is not available. A logical pixel is printed as 0.6
    point, such that the text has about the size of the running text.
    Recreated all screenshots of the guide and removed the explicit widths
    that scaled them.

  • DOC: XPCE userguide: update the content for version 9 Revised all
    chapters for the SDL/Cairo/Pango based version. Removed material
    on features and systems that no longer exist (X11 resources,
    PostScript, ProWindows, other Prolog systems, old Windows versions,
    removed classes and methods), described themes, the flat dialog look,
    keyboard operation, OS drag and drop, image formats and the IDE tools
    as panes, and fixed code examples that no longer work. The class
    summary has entries for new classes such as bool_item, theme_colour,
    gradient and shadow.

  • DOC: XPCE userguide: automatic version, title page and build fixes -
    The Makefile creates version.tex with \productversion from PCE_VERSION
    in CMakeLists.txt and \productdate and \productyear from the date.

    • Updated the title page and the overview of changes since version 6.
    • Class summaries listed all classes as name(). The header is now
      created from the class <-term_names. - Removed the httpd section. -
      Added a section on printing and exporting PDF, replacing the PostScript
      section that was removed before. - doc2tex: did not terminate if
      the input ends with a code block and
      did not translate and meta names and ->_name.
  • FIXED: graphical ->restore_graphics_state raised “Unknown texture”
    g_save() no longer recorded the pen, texture and colours because
    graphstate.c was included in sdldraw.c before the drawing context
    was declared. The initial dash of a context is now none rather than
    NULL, so it can be restored. Also fixed g_level(), which tested the
    inverse condition.

Package yaml

  • TEST: removed search path setup for the library and foreign aliases
    src/swipl in the build tree already finds the libraries and foreign
    modules of all packages.

Package zlib

  • TEST: removed search path setup for the library and foreign aliases
    src/swipl in the build tree already finds the libraries and foreign
    modules of all packages.

No longer builds on Debian with the OS-provided SDL packages, but builds OK with locally built versions,

Prior to the version release, it didn’t build for me on Debian, but now it does with gcc (with a few, probably incorrect, warnings about possibly initialized variables). I had to do a clean build.

However, I get some errors from the XPCE tests (I’ve sent the output separately).