Did you know ... Search Documentation:
Title for pldoc(default)
Branch: development (switch to stable),
version to version

SWI-Prolog Changelog from version 10.1.18 to 10.1.19

[Oct 20 2026]

  • 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 <name>-<version>.dll for an import library lib<name>.dll.a, as ffmpeg's Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

[Oct 19 2026]

  • 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.

[Oct 18 2026]

  • 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 file_search_path/2 and 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.

[Oct 17 2026]

  • 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).

[Oct 16 2026]

  • 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.

[Oct 15 2026]

  • 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.

[Oct 16 2026]

  • 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.

[Oct 14 2026]

  • 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%.

[Oct 16 2026]

  • 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().

[Oct 13 2026]

  • 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.

[Oct 16 2026]

  • 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().

[Oct 15 2026]

  • 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.

[Oct 16 2026]

  • 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>

[Oct 14 2026]

  • 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.

[Oct 13 2026]

  • 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.

[Oct 9 2026]

  • 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

[Oct 13 2026]

  • 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.

[Oct 12 2026]

  • 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

[Oct 18 2026]

  • 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

[Oct 18 2026]

  • 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

[Oct 18 2026]

  • 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

[Oct 18 2026]

  • 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

[Oct 18 2026]

  • 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

[Oct 18 2026]

  • 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

[Oct 18 2026]

  • 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

[Oct 18 2026]

  • 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

[Oct 18 2026]

  • 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

[Oct 18 2026]

Package protobufs

[Oct 18 2026]

  • 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

[Oct 18 2026]

  • 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

[Oct 18 2026]

  • 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

[Oct 21 2026]

  • 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.

[Oct 20 2026]

  • 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>

[Oct 19 2026]

  • 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.

[Oct 18 2026]

  • 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 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.

[Oct 17 2026]

  • 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.

[Oct 16 2026]

  • 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>

[Oct 15 2026]

  • 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: <tt> shows code in xpce's fixed-width font on a faint background <tt> and font_family use xpce's font families, so <tt> 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 <b>%s</b>", 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++.

[Oct 14 2026]

  • 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.

[Oct 13 2026]

  • 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.

[Oct 12 2026]

  • 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 <b>bold</b> and <span foreground='red'>red</span> 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.

[Oct 13 2026]

  • 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.

[Oct 12 2026]

  • 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 <class> 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 <CamelCase> and <x> 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

[Oct 18 2026]

  • 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

[Oct 18 2026]

  • 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.