Branch: development (switch to
stable),
SWI-Prolog Changelog from version 10.1.8 to 10.1.9
[Jun 15 2026]
- ENHANCED: Windows installer optionally associates .pl with
swipl-win.exe Adds an "Open .pl files with SWI-Prolog" checkbox to
the installer's Install Options page (alongside the desktop icon
option). When ticked, registers the SWIProlog.SourceFile ProgID so
.pl files double-click to open in swipl-win.exe. Uninstall removes
the association only if it still points at our ProgID.
[Jun 14 2026]
- MODIFIED: current_input/1 and current_output/1 diagnostics According
the the ISO standard, these predicates shall raise a domain error
for stream aliases and shall fail if the argument is a closed stream.
- FIXED: Ensure shifting stacks properly resizes the local stack.
Due to a typo, the system could get into a state with many very small
local stacks enlargements, almost grinding to a halt.
[Jun 7 2026]
- ENHANCED: doc2tex --xpce recognises Class->Sel arrow refs Add a CLI
flag that turns on three extra recogniser clauses for
Class->Sel,
Class<-Sel and Class<->Sel in plain prose; they emit
\classsend{C}{S} / \classget{C}{S} / \classboth{C}{S}
respectively. Selectors may start with _ for private slots. The
- (instance variable) and . (class variable) shapes are
left alone because they collide with ordinary hyphenation and
end-of-sentence punctuation in English prose; callers wanting those
links should write the macro explicitly.
[May 30 2026]
- TEST: Disable tcmalloc when using ASAN. Can lead to conflicts
- FIXED: #1497 libbf mpz_import: stack overread when leading bytes
are zero The byte-count for the import loop was captured before
the leading-zero strip, so when OP began with zero bytes the loop
read that many bytes past the end of the input buffer. Triggered by
seed_from_dev() seeding the random state from /dev/urandom in libbf
builds.
[May 29 2026]
- MODIFIED: macOS: name the installer swipl-<version>-1.<arch>.pkg Adds
the `-1' package revision before the architecture suffix so the .pkg
matches the Windows swipl-<version>-1.x64.exe naming convention.
Package cpp
[May 31 2026]
- FIXED: macOS GCC build aborting on std::bad_alloc from over-sized
new On macOS a foreign extension built with GCC links libstdc++,
while the process also loads the system libc++/libc++abi via the
system frameworks. As operator new is a coalesced weak symbol it
resolves to libc++, so
new throws a libc++ std::bad_alloc whose
type_info differs from the libstdc++ one named in PREDICATE_CATCH's
catch(const std::bad_alloc&). That handler misses and, lacking a
catch-all, the exception reaches std::terminate() and aborts the
process (e.g. test_cpp.pl cpp:malloc).
Package http
[May 31 2026]
- TEST: proxy: pick the `unused' port from below the ephemeral range
The previous fix reserved the `unused' port by holding a socket
bound but not listening, so that
connect() attempts are refused
while no concurrent ctest job can grab the port via bind(0). On
Linux/Windows a bound, non-listening socket is refused promptly,
but on macOS connecting to such a socket blocks for several seconds
before failing. As several tests connect to the unused port, the
suite took ~30s on macOS instead of a fraction of a second.
Package ltx2htm
[Jun 10 2026]
- ENHANCED: \classsuffix{Slug}{Display} for case-preserving class-name
refs
- ENHANCED: hyperlink global object refs (@pce, @nil, ...) to
their section The objectname macro now emits an \lref into
sec:object-<safe> mirroring the section anchors doc_latex generates
for the {#object-<name>} headings in objects.md. If no such section
exists, ltx2htm leaves the inner bold @<name> visible unchanged.
- FIXED: inline <-> ref resolves when only send/get methods are defined
\sendmethod and \getmethod now emit a class-C-both-N anchor in addition
to their own class-C-send-N / class-C-get-N anchors, mirroring
the alias \bothmethod already provided. An inline \classboth{C}{N}
reference (the inline
<->protect form) therefore lands on the
first of the send/get method's <dt> when no bothmethod or ivar carrying
that name exists.
- FIXED: keep underscores in member-anchor selectors so _free and
free differ
[Jun 9 2026]
- ENHANCED: add classivar*method commands for xpce ivars Defines
\ivarbothmethod / \ivargetmethod / \ivarsendmethod / \ivarnonemethod
alongside the existing \sendmethod / \getmethod / \bothmethod
/ \classvarmethod. Each variant renders with the documented
side-effect-free access and indexes the member under
xpce(Class, ivar,
Name), so the manindex sees one bucket per ivar regardless of which
arrow notation the source .md picked. \classinstvar inline links are
rerouted to the ivar anchor.
- BUILD: silence \_word + tokenise \date{} arg before translate Two
follow-ups to the previous noise cleanup:
- BUILD: define preamble dummies and \_word escape in latex.cmd /
latex2html A clean build of the xpce manual emitted 5 'Failed to
translate' preamble warnings for \RequirePackage, \newenvironment,
\excludecomment, \date, \today (all general LaTeX, not xpce-specific)
and another 4 for \_method, \_manager, \_check and \_sink (the
C-side tokeniser greedily reads an underscore after \ as part of
the command name, so 'class object->\_check' in the .tex parses as
a single \_check command).
- FIXED: tokenise Args atom before #
var(+Args) in sendmethod et al.
ltx2htm's translate/3 only handles list inputs; sty_xpce passed the
raw Args atom via #var(+Args), so every xpce method whose argument
spec had punctuation other than identifiers (name=name, [int],
\Sbar{}, ...) emitted
- BUILD: drop autoload for delete/3 and friends in sty_xpce A
clean build hit 'Unknown procedure: delete/3' from
clean_anchor_part/2 before library_index/INDEX.pl had been built, so
the autoload couldn't fire. Use use_module/2 for maplist/3, append/3
and delete/3 instead so the imports don't depend on the autoload index.
[Jun 7 2026]
- ENHANCED: \errid renders as anchored link Wrap the
!<id>
bold-code in #lref so prose references to !already_has_parent,
!argument_type, ... navigate to the error's card. The label
matches the sec:error-<id> slug pce_html_manual computes from a
live error instance.
- FIXED: classinstvar/classvar text bold like classsend/get/both
The previous emission wrapped Class+separator+Var in a single
#code, so the whole link rendered in monospace; the rest of the
xpce link macros use bold for the names and only #code for the
arrow / separator. Restructure to match that pattern so all six
member-reference forms style consistently.
- ENHANCED: \classinstvar and \classvar render as anchored links Like
\classsend / \classget / \classboth, the two slot-reference macros now
wrap their bold-code rendering in a #lref so the HTML output points
at the corresponding member's anchor (class-C-both-V for instance
variables, class-C-classvar-V for class variables). Falls back to
plain bold-code when the target isn't indexed -- e.g. for private
slots that have no member card.
- ENHANCED: bothmethod registers send/get anchor aliases Emit two
empty
<a id="class-C-send-N"> / <a id="class-C-get-N">
labels next to the canonical class-C-both-N anchor on
every \bothmethod{C}{N}{...} so cross-references written as
\classsend{C}{N} or \classget{C}{N} (the natural form in
prose) resolve onto the bothmethod entry. Without these aliases the
lref to send-form fell back to plain bold-code because no label by
that name existed.
[Jun 6 2026]
- ENHANCED: add classvarmethod and quote member data-obj attributes *
Add
\classvarmethod{C}{V}{Args} as the HTML counterpart of
xpce.sty's new macro. Emits the same <dt class="pubdef"> +
hidden <a data-obj="xpce(C,classvar,V)"> shape the send /
get / both macros produce so manindex.db's SGML walker captures
the entry. * The member data-obj attribute now writes the class
name and
selector with ~q, so selectors starting with underscore
(object->_check, object<-_arg, ...) round-trip cleanly
through atom_to_object/2 instead of being read as Prolog
variables.
- ENHANCED: emit pubdef + data-obj on xpce method <dt> Change
sendmethod/getmethod/bothmethod to render
<dt class="pubdef"> with
a hidden <a data-obj="xpce(Class,Kind,Selector)"> preceding the
visible #label anchor. The SGML walker in packages/pldoc/man_index.pl
picks up the data-obj on the first nested <a>, so the entries
land in manindex.db keyed by the xpce(C,K,S) compound that PlDoc's
search/page hooks understand.
- ENHANCED: ltx2htm picks up \getmethod's 4th arg and the text-mode
brackets - xpce.cmd: \getmethod takes 4 args (Class, Sel, Args,
RetType), not
- With the prior 3-arg declaration ltx2htm parsed the 4th brace
group as stray content, swallowing successive tokens until EOF.
- sty_xpce.pl: \getmethod{C}{S}{A}{R} -> <dt>C<-S: A -> R</dt>.
- latex.cmd: declare \textless and \textgreater so the C-side
tokeniser knows they take zero args (the Prolog dispatcher rule
landed in Phase 4b; the tokeniser needs its own declaration).
- FIXED: clean_name accepts \textgreater / \textless PlDoc emits operator
names like ->/2 through print_char/2 with the text-mode \textgreater{}
/ \textless{} escapes that ltx2htm's \textgreater handler turns into
> / < entities. clean_name/2 runs on those names when rendering
predicate / infix-operator entries (\infixtermitem etc.); the existing
clauses didn't know about the LaTeX commands, so any predicate using ->
in its operator-form was failing to translate ("Failed to translate
\infixtermitem in mode description"). Two extra clauses fold them
back to the bare > and < chars.
- ADDED: \textless and \textgreater emit < / > entities PlDoc now
escapes < / > as \textless / \textgreater (so they're safe inside
hyperref PDF bookmark strings); teach ltx2htm to translate them to
the matching HTML entities. Without this they showed up as "Failed
to translate" warnings on every chapter that mentioned a class with
angle brackets in its prose (369 in our reference manual corpus).
- ENHANCED: xpce ltx2htm rules for the .md-driven reference manual -
Add cmd declarations and HTML emitters for \classinstvar and
\errid (introduced in TeX/xpce.sty for the .md-driven
reference manual). - Switch the cross-reference anchor scheme for
\class{X} / \classs{X}
from "class:X" to "sec:class-X" so the section labels PlDoc emits
from "# class X {#class-X}" headings resolve as link targets.
Strip underscores from the link target to match PlDoc's
delete_unsafe_label_chars/2 behaviour on the corresponding
\label{...} statement (so "class foo_bar" links to
"sec:class-foobar"). - Switch from
autoload(library(ltx2htm/latex2html)) to
use_module(latex2html) so sty_xpce.pl loads cleanly when invoked
outside an installed environment with the matching library path
alias.
Package pldoc
[Jun 9 2026]
- ENHANCED: accept
xpce(C, ivar, N) in manindex.db Recognise the new
"ivar" kind so xpce class instance variables indexed via sty_xpce's
classivar emission survive the round-trip through atom_to_object/2.
- ENHANCED: swi_man_xpce ->
swi('xpce/man/refmanual') The xpce
refman HTML is now staged and installed under the xpce home
tree (swi('xpce/man/refmanual') = <prefix>/lib/swipl/xpce/man/
refmanual/), alongside the rest of the xpce data files (bitmaps,
prolog/, appl-help/, man/faq/, ...). Update the file_search_path so
save_man_index/0 picks up the .html chunks from the new location and
manual_object/5 returns file paths that actually exist after install.
[Jun 7 2026]
- FIXED: {#anchor} parser accepts `_' as a token The wiki tokenizer
breaks
{#object-_not_returned} into ['{', '#', w(object), -, '_',
w(not_returned), '}'], but the section-label parser's label_cont
rule only accepted - and w(Name) tokens, dropping anchors
that contain a _ immediately after a separator. Add an explicit
clause for the bare _ token so such anchors are recognised.
[Jun 6 2026]
- ENHANCED: index XPCE class-member entries in manindex.db Recognise
xpce(Class,Kind,Name) compounds emitted by the ltx2htm xpce backend
(see sty_xpce.pl) so the new XPCE refman HTML lands in the same
machinery PlDoc uses for the core manual:
- FIXED: escape < > with \textless / \textgreater instead of math mode
print_char/2 used to emit \$<\$ and \$>\$, which break hyperref's
PDF bookmark string generation ("Token not allowed in a PDF string:
removing 'math shift'") and don't survive any subsequent text-mode
context cleanly. Switching to the text-mode commands lets hyperref
embed them in bookmarks unchanged and renders identically in normal
text.
- FIXED: tags environment uses ##1 to escape nested newcommand
parameter \newenvironment{tags}{...}{...} previously had
\newcommand{\tag}[1]{\item[#1]} inside the begin body. Modern LaTeX
interprets the bare #1 as a parameter of the surrounding environment
(which has none), giving "Illegal parameter number in definition
of \tags". Doubling to ##1 lets the inner \newcommand reach its
own parameter.
- FIXED: @tag block no longer swallows following section headers
rest_tag/4 used to read continuation lines for a tag until the next
@tag or end of input, which meant a following ## section heading became
part of the last tag's value. Now also terminates at any section header
(twiki or markdown atx/setext).
Package utf8proc
[May 29 2026]
- FIXED: install additional file in tests folder needed for the runtime
unit tests
Package xpce
[Jun 15 2026]
- ADDED: Epilog key bindings
Shift-ctrl-{V,C} for copy/paste
- ENHANCED: Multi-file drop on PceEmacs opens each file in a new tab
Drop one or more files on a PceEmacs editor to open each as a new tab.
Show a faint centered hint during the drag.
- ENHANCED: Multi-file drop on Epilog with overlay feedback Drop one or
more files on an Epilog terminal to consult all Prolog source files
in a single consult/1 call. Show a faint centered hint during the
drag and briefly flag any non-Prolog files in red.
- ADDED:
library(pce_drop_target) for SDL3 drop overlays A small helper
that turns the SDL3 drop_position / drop_file / drop_complete lifecycle
delivered to an xpce graphical into a single callback receiving the
list of dropped OS paths, with a centred bordered hint overlay shown
on the target's window during the drag. Transient state lives in
xpce object attributes, so consumers need no class variables.
[Jun 14 2026]
- CLEANUP: misc Smaller, independent cleanups that surfaced during the
larger work:
- ADDED: Epilog XPCE menu with the core manpce/0 tools A new "XPCE" popup
before Help in Epilog's menu bar covers the File/Demo programs entry,
all Browsers entries and the first three Tools entries from manpce/0.
All tool entries route through the existing send(@manual, start_tool,
Tool) hook, which creates @manual silently (no expose), so users do
not have to call manpce/0 first. "Inspect GUI hierarchy" moves from
the Tools menu to the new XPCE menu.
- ADDED: OS file/text drag-and-drop events via SDL3 Surface SDL3
file/text drop events as xpce events. src/sdl/sdlevent.c translates
SDL_DROPFILE / SDL_DROPTEXT into a pair of new event names that the
kernel and class event recognise. prolog/demo/dragdrop_file.pl ships
a small drag-and-drop demo and the pce_demo entry registers it in
the demo set.
- CLEANUP: drop image ->invert, ->invert_pixel, ->and, ->or, ->xor Five
send-methods on class image were stubs that did nothing. Remove the
SM entries, the C bodies (invertImage, invertPixelImage, opImage,
orImage, andImage, xorImage), the matching backend stubs r_op_image
and r_complement_pixel in sdldraw, and the unused T_image_atADpointD
type decl. image<-rotate documentation is updated to advertise the
figure + transform idiom (see the markdown sources commit).
- CLEANUP: reduce dialog_item look domain to {xpce,win} The look slot
on class dialog_item used to admit four values: open_look, motif,
win and gtk. open_look and motif are legacy look-and-feels nobody
runs anymore; gtk was the working Unix default and is renamed to xpce
(a neutral name not tied to a host toolkit). The domain narrows to
{xpce,win}, with xpce default on non-Windows and win on Windows.
- REMOVED: class c, class c_pointer and the public C/C++ embedding API
xpce now embeds only via pl2xpce.so; the old C/C++ host classes and
the XPCE_* embedding API are unused and removed.
- CHANGED: manpce/0 modernization for the markdown manual The manpce/0
tool moves from the .doc card database to the markdown-generated HTML
chunks served by
library(pce_html_manual). The main changes:
- ENHANCED: HTML manual viewer (pbox selection, code blocks, scroll
clamp) doc_window grows the affordances needed to host the new
HTML manual:
- REMOVED: legacy .doc reference manual sources Drop man/reference/*.doc
-- the old binary-encoded card database that backed the .doc-format
reference manual. Replaced by the markdown sources under
man/refmanual/md/ that the new pipeline renders into the manpce/0
card viewer and the published HTML/PDF manuals.
- ADDED: markdown reference manual sources Add man/refmanual/md/*.md
as the new home for the xpce reference manual. Each class, group of
error codes and special section gets a PlDoc-flavoured markdown file
with stable {#class-<name>} (and similar) anchors that the new build
pipeline turns into both the LaTeX manual and the HTML chunks served
to the manpce/0 card viewer.
- BUILD: markdown-based reference manual pipeline Introduces a refman
pipeline that renders the xpce reference manual from markdown sources
via PlDoc (with xpce-specific extensions) into the existing TeX/HTML
manual:
[Jun 4 2026]
- ADDED: London tube demo Interactive map of the London tube network:
zoom and pan, search stations, toggle lines on or off, hover to
highlight every line through a station or segment. Demonstrates
figure transforms, recognisers, the report system and connection
routing via handles.
- ADDED:
library(pan_zoom) Reusable recogniser that handles
wheel-zoom-around-cursor and left-drag pan by editing the receiver
figure's transform. A global @pan_zoom_recogniser is provided for
class-wide reuse.
[Jun 2 2026]
- FIXED: terminal_image: initialise <-armed_link to @off The slot has
type bool (not bool*), so the implicit @nil left at construction
tripped the object base check.
- FIXED: font: align C struct field order with vardecl The fontobj
C struct ordered fixed_width before ex/avg_char_width, while the
vardecl ordered ex/avg_char_width before fixed_width. Since slot
indices come from the vardecl but
assign() writes through the C field,
slot values landed at the wrong index, producing object base check
warnings such as `Illegal value in slot ex: off and Illegal value
in slot fixed_width: 11`.
- FIXED: transform: silence maybe-uninitialized warning under -O2
tuple_to_nums() only assigns *first/*second on success and TRY()
returns from initialiseTransform() on failure, so the success path
is well-defined. GCC's -Wmaybe-uninitialized can't see through the
macro and warns at -O2. Initialise the locals to ZERO to silence it
without changing behaviour.
- ENHANCED: demo: interactive opacity demo Adds a pcedemo entry `Opacity'
that opens a frame with six labelled cells and a single slider driving
the opacity of every foreground graphical at once. The cells cover:
- DOC: userguide: document <-opacity on graphical Adds a short Opacity
section to the Simple graphics chapter, explaining the group-composite
semantics on a device or figure and contrasting it with per-pixel
colour alpha. Points at the demo for the visual comparison.
The class-card database under man/reference remains untouched; the
slot's own docstring is reachable via manpce.
- ENHANCED: graphical: composite with alpha when <-opacity < 1.0
RedrawArea now wraps the per-class redraw in a cairo group when the
graphical's opacity is below 1.0, then paints the group onto the parent
surface with that alpha. For a single primitive this is equivalent
to using an alpha-bearing colour; for devices and figures it gives
the correct CSS-style opacity, where overlapping children composite
fully opaque first and the whole group is then blended.
- ENHANCED: sdldraw: add r_push_group / r_pop_group_with_alpha Thin
wrappers around cairo_push_group / cairo_pop_group_to_source +
cairo_paint_with_alpha. Used by the next commit to composite a
graphical's drawing onto its parent with a single alpha modulation,
giving correct CSS-style opacity for overlapping children of a group.
- ENHANCED: graphical: add <-opacity slot (Num, 0.0..1.0, default 1.0)
Per-graphical opacity for compositing. The slot is declared on class
graphical so it applies uniformly to primitives, dialog items, devices
and figures. Values outside [0.0, 1.0] are clamped on assignment.
Rendering itself is wired up in a follow-up commit; this change only
adds the slot, the accessors and request-redraw on change.
- FIXED: Image viewer demo.
- ENHANCED: demo/transform: use figure shortcuts and a single rebuild
Each slider now sends `->rebuild' instead of a per-slider callback;
->rebuild reads all three slider values from the dialog and composes
the scene's transform via the new figure shortcuts (->translate,
->scale, ->rotate, ->shear), starting from a fresh identity.
- FIXED: transform: validate tuple slots in ->initialise
scale :=
tuple(Sx, Sy) and `shear := tuple(Kx, Ky)' previously cast the tuple's
slots straight to Num without checking; passing a non-numeric value
silently produced a garbage matrix. Add a small tuple_to_nums()
helper that runs each slot through TypeNum (so any xpce-convertible
numeric value is accepted) and raises the standard unexpected-type
error otherwise.
- ENHANCED: figure: ->translate / ->scale / ->rotate / ->shear
Composing transform shortcuts on class figure. Each method composes
the corresponding operation into the figure's transform, allocating
an identity transform on demand if the figure currently has none.
The same `self := self * Op' rule as on class transform applies,
so calling these in sequence pre-composes from the inside out.
- ENHANCED: transform: rotate/scale/shear initialise; ->set for
coefficients Replaces the 6-coefficient ->initialise with a high-level
form:
[Jun 1 2026]
- BUILD: install demo/transform.pl with the demo data files
XPCE_DATA_prolog_demo is an explicit list; without this entry
demo/transform.pl is not copied to the install tree and pcedemo fails
with `source_sink
demo(transform) does not exist'.
- ENHANCED: pce_demo: register figure->transform demo Adds the Transform
entry to the XPCE demo browser (pcedemo/0) so the new demo/transform.pl
shows up in the standard demo list.
- FIXED: handle.c: drop unused Int x, y from getXYHandle Leftover
declarations from the pre-transform-aware version; the rewrite uses
hx/hy and gx/gy only.
- FIXED: transformed figure: pass children pre-transform area for
paint RedrawTransformedChildren handed each child the dirty rect
coming from the parent, which after EnterRedrawAreaDevice is in the
figure's POST-transform local coord (where the rotated pixel AABB
lives). But each child's gr->area slot is in PRE-transform local
coord, so the overlap test in RedrawArea mis-clipped: children whose
pre-transform position fell outside the post-transform AABB (e.g. a
text label below the bounding box that rotates to above it at 180°,
or any child past a heavy scale-down) were silently skipped — text
vanished at rotate ±180° and at scales below 50%.
- FIXED: figure->transform: always repaint, even on same object The
setter previously short-circuited when the assigned transform was the
same object as the current one. That broke the common pattern of
mutating a single transform in place (e.g. from a slider callback)
and re-assigning it: the figure kept the cached bounding box and
skipped the repaint.
- ENHANCED: demo/transform.pl: live figure->transform demo Opens a
window with a small scene (yellow box, red diagonal, green circle,
text label) inside a figure that carries an editable transform.
Sliders below the picture drive rotation (-180..180), scale (25..250%),
and horizontal shear (-100..100%) around the scene's centre; a reset
button restores identity.
- ENHANCED: absolute area, handles, flash route through transforms
graphicalToDeviceCoord / graphicalToDeviceAreaAABB compose the affine
that maps a graphical's local coord into any specific ancestor device's
children-coord, taking figure->transforms along the chain into account.
[May 31 2026]
- ENHANCED: damage propagation through transformed figures Adds
deviceLocalAreaToWindowAABB to coords.c (corner-by-corner walk through
the device chain producing an outward-rounded integer AABB).
- ENHANCED: events: route through transform-aware coord mapping
get_xy_event_device and get_xy_event_graphical now consult the new
windowToDeviceLocalCoord / windowToGraphicalCoord helpers whenever
the device chain contains a non-identity figure->transform. An event
delivered to a child of a rotated or scaled figure now arrives in
the child's actual local frame instead of being computed with the
un-transformed integer offset.
- ENHANCED: graphical: transform-aware coord mapping Adds
src/gra/coords.c with a small 2D affine composition that walks the
device chain from a graphical (or device) up to its window, applying
figure->transform at each step. Five C-level entry points are exposed:
- TEST: Add tests/test_figure_transform.pl Plunit-style tests for class
figure's transform slot and bounding box semantics: identity fast-path,
rotation 90/180/270, scale (uniform and non-uniform), translate-only,
empty figure, multiple children, border interaction, and recompute on
transform set/clear/replace. Also verifies that <-local_area stays
in un-transformed children-coords as the transform changes.
- ENHANCED: figure: parent-coord bounding box follows transform A
transformed figure's <-area is now the AABB of the transformed
children, while a new <-local_area slot keeps the un-transformed
children union in figure-local coordinates. computeBoundingBoxFigure
first lets computeBoundingBoxDevice fill area as today, then projects
the local box through f->transform when present and re-rounds the
result to integer.
- ENHANCED: figure: paint children under f->transform Adds
r_push_transform / r_pop_transform to the SDL backend. Pushing absorbs
the current integer pen offset into the cairo transform, then composes
the figure's affine matrix and resets the integer offset to zero so
that r_* primitives feed their coordinates directly into the matrix.
- ENHANCED: figure: add optional transform slot Adds a transform slot to
class figure, default @nil, with a setter that requests recompute and
full repaint when changed. Painting, hit testing and bounding-box
math will start consulting the transform in the following commits;
for now any figure without a transform behaves exactly as before.
- TEST: Add tests/test_transform.pl Plunit-style tests for class
transform covering construction (defaults, explicit coefficients,
set/copy/identity), the basic ops (translate, scale, rotate, shear),
cairo-style composition order, invert/inverse (including singular
detection and round-trip identity), and <-apply on points and areas.
- ENHANCED: Add transform class for 2D affine transformations A
`transform' instance holds a 2x3 affine matrix (xx, xy, yx, yy, tx,
ty) stored as Num slots and provides methods to compose translation,
scale, rotate, shear and matrix multiplication, plus an inverse and
a <-apply that maps a point or the AABB of an area through the matrix.
[Jun 2 2026]
- FIXED: Graphical ->flash: account for window scroll_offset The flash
overlay was rendered in the window's logical (client) coordinate
system, while Cairo draws graphicals translated by sw->scroll_offset
(see
d_window() / Translate()). Windows whose origin is not at (0,0)
-- e.g. a workspace with origin (0, h/2) -- made the flash land at the
wrong screen position. Apply the same scroll_offset before passing
the rect to flashWindow().
[Jun 1 2026]
- FIXED: ws_event_in_subwindow: translate ev->x/ev->y to frame
coordinates When called with a frame argument, the function descended
event_window() using ev->x/ev->y as if they were frame-relative.
They are relative to ev->window though, which during a drag stays
on the original receiver (the mouse_tracking_window). The position
was therefore shifted by the tracking window's offset in the frame,
so dragging out of e.g. the top-left subwindow into the top-right
kept reporting the top-left.
- FIXED: SDL: stale modifier bit could leak into mouse clicks After
a Ctrl-Shift-<key> binding (e.g. Ctrl-Shift-O to split an Epilog
window), the next left click was treated as Shift-click and extended
the selection instead of starting a new one.
- ENHANCED: demo/arc: show three arrowed arcs in the arrows cell
Demonstrates that the wing midpoint lands on the arc across a range
of curvatures and sweep directions.
- ENHANCED: arc: align attached arrow wings with the arc's curvature The
arc's first_arrow/second_arrow used to be aimed along the tangent at
the endpoint, so the wing line — l1 pixels behind the tip — sat on
a straight line that the arc had already curved away from. The visible
offset was about l1^2/(2*radius) (≈1.9px for the demo arc).
- ENHANCED: arrow: accept Num for tip/reference and wing/length
pointsArrow, ->tip_x/y, ->reference_x/y, ->length, ->wing and the
corresponding getters now declare and pass Num rather than Int,
so arrow geometry set programmatically (e.g. from class arc) keeps
sub-pixel precision end-to-end. Round the bounding area set by
->compute with floor/ceil so the area still encloses the triangle
when the points are non-integer.
- ENHANCED: arc: carry sub-pixel precision through geometry and rendering
points_arc, RedrawAreaArc, includeArrowsInAreaArc, computeArc and
the <-start/<-end getters now use double for the computed sx/sy/ex/ey
coordinates and pass them to attached arrows via
toNum() without an
integer round-trip. r_arc takes its bounding rectangle and angles as
double, so drawArcGraphical (->draw_arc) and the arc class no longer
truncate angles to int before handing them to cairo. The bounding
area set on the arc is still rounded — out to floor/ceil with the
existing 1-pixel margin — because Area itself is integer.
- ENHANCED: demo: add an arc gallery demo Shows the main usage patterns
of class arc — angles, close modes, ->points, ->connect_angle,
arrows, elliptic <-size, over-wound sweep, CW vs CCW direction,
and a tiny pie chart.
- ENHANCED: arc: use Num for start_angle and size_angle Class arc
stored its two angle slots as Real. The Num type is a better fit:
it accepts both integers and floats, returns naturally to Prolog as a
number, and avoids the heavier Real object identity. The on-the-wire
behaviour is unchanged.
- FIXED: r_arc: pass arc size_angle correctly to cairo The 2nd integer
argument to r_arc has always been size_angle (relative sweep),
per the X11/xpce convention shared by all callers. The SDL/cairo
backend treated it as an absolute end angle and ignored that cairo's
angle direction is opposite to xpce's (cairo angles go clockwise on
screen because cairo's y axis points down). As a result class arc
and ->draw_arc drew unrelated arcs.
[May 31 2026]
- ENHANCED: terminal: strikethrough support (SGR 9 /
Style->strikethrough) text_char gains a strike bit (from the reserved
word in the bitfield, no struct growth). SGR 9 sets it, SGR 29 clears
it. paint_chunks threads the resolved strike+strike_texture pair to
a new r_strikethrough in sdldraw, drawn through Pango's strikethrough
metrics (pango_font_metrics_get_strikethrough_{position,thickness}
stored on WsFont next to ul_*).
- ENHANCED: terminal: dotted underline by default for hyperlinks
(line-texture) Style->underline now accepts a texture_name
(none/dotted/dashed/dashdot/ dashdotted/longdash) on top of the
existing Bool|Colour, both in the class declaration and in the
initialise argument vector. r_underline gains a `Name texture`
parameter so the dash pattern survives until the line is drawn
(previously hard-coded to none). paint_chunks threads the resolved
texture from effective_style_for through to r_underline.
- ENHANCED: terminal: per-link armed style (link_armed_style) Add a
link_armed_style slot on TerminalImage (default: blue + underline,
same as link_style for now) and wire it into the paint loop. Hover
detection tracks the specific href node the mouse is over on b->
armed_href;
effective_style_for(b, flags, armed) overlays the armed
style only on cells inside that href, falling back to link_style for
other links on screen. The chunk grouper now splits on the armed
boundary, so a partially-hovered link renders correctly when adjacent
to a second link.
- ENHANCED: terminal: drive hyperlink rendering from a link_style object
Add a link_style slot on TerminalImage (default: blue + underline),
set via ->link_style and class variable link_style, parallel to the
existing selection_style and nfd_style. Paint resolves per-cell
fg/bg/underline/ bold through a new
effective_style_for() helper that
overlays link_style on cells whose link bit is set. rlc_put_link no
longer forces SGR 34/4 into b->sgr_flags — the colour and underline
come from the style, so applications can carry their own fg/bg through
the link label.
- TEST: terminal: visual demo of all SGR attributes the
xpce terminal renders demo_terminal/0 walks through styles
(bold/underline/inverse/link), the 16 ANSI colors via fg/bg/hfg/hbg,
the xterm-256 cube and grayscale ramp, 24-bit channel ramps + HSV
rainbow, mixed style+color, and an OSC 8 hyperlink. All output goes
through library(ansi_term) so the same goal also exercises any other
ANSI terminal.
- ENHANCED: terminal: support xterm-256 and 24-bit (truecolor) SGR
sequences CSI 'm' now walks its argument list, consuming 38;5;N /
48;5;N for xterm-256 colors and 38;2;R;G;B / 48;2;R;G;B for 24-bit
truecolor. Colors land in a per-buffer palette[] (slots 0..15 still
alias ti->ansi_colours; 16..4094 are interned via an open-addressed
COLORRGBA hashtable). On overflow (4095 distinct truecolors), new
requests fall back to the nearest existing entry by RGB Euclidean
distance.
- ENHANCED: terminal: repack per-cell metadata to make room for a
color palette Restructure text_flags as a 32-bit tagged union (raw +
bitfield struct): width:2, bold:1, underline:1, inverse:1, link:1,
reserved:2, fg:12, bg:12. The width byte on text_char is gone;
text_char stays 64 bits. fg/bg now hold palette indices (sentinel
PAL_DEFAULT = 4095) instead of 5-bit ANSI codes, opening 4096 slots
per slot for the upcoming 256-color and truecolor support.
[May 29 2026]
- FIXED:
newdir icon (used by Browse in PceEmacs file prompter)
- FIXED: Mixup of port and action toolbutton images (fail) for tracer.