Ann: SWI-Prolog 10.1.15

Dear SWI-Prolog user,

SWI-Prolog 10.1.15 is ready for download. This version comes with a lot of
enhancements. Highlights:

Core

  • Make library(persistency) recover from an incomplete last term if it
    crashes hard while writing or the device was full. Attaching used to
    fail. Now it truncates the file to the last correct term and issues a
    warning.
  • More reliable detection that a .qlf file is out of date. We now do a
    quick filter on time. If that is not decisive we compare a content hash.
  • Cyclic term handling. @kuniaki.mukai contributed bisimulation of Prolog
    terms. This provides several new features and fixes several issues:
    • Added term_minimal/2, term_automaton/2 and automaton_minimal/2,3.
      term_minimal/2 allows creates a canonical form of a term with maximal
      sharing (smallest number of compound terms).
    • These primitives are used for a new implementation of term_factorized/3,
      which is about 6 times faster and reliably handles arbitrary cyclic terms.
    • These primitives are also used for creating cycle-safe versions of
      variant_hash/2 and variant_sha1/2. This provides support for cyclic terms in e.g., library(nb_set), used by distinct/1,2

SSL

  • Support OpenSSL 4. A bug in our BIO handling caused timeouts to fail with
    OpenSSL 4.
  • MacOS: By default get certificates from /etc/ssl/cert.pem. This avoids a
    possible hang getting them from the system key chains. By setting the Prolog
    flag system_cacert_filename to keychain, the old behaviour is restored.

XPCE (GUI)

Notably thanks to @mike.elston for his daily reports on issues!

  • Complete overhaul of the development tools. Rather than every tool creating
    a toplevel window, there is now a generic tool container window that holds a
    menu, one or more tabs and an optional status area. A tab can hold one or more
    pane. The panes are tiled. There are some generic rules that determine
    how a new tool appears. You can rearrange panes (tools) arbitrarily: put them
    in a new window, put them in a tab on their pwn, drag them to split an existing
    pane in this or another window, etc. The system learns from what what you do and
    you can use Settings/Remember how this window is arranged to explicitly prefer
    a combination of panes. With this comes horizontal and vertical splitting of
    PceEmacs editor windows as GNU Emacs does (^X2, ^X3).
  • MacOS: Use Apple central menu rather than per-window menu. This effectively
    copies the content of the native window to the MacOS Cocoa menu and forwards
    selected options back. The per-window menu is hidden.
  • Several terminal (Epilog) enhancements:
    • Avoid deadlocks if the input queue fills completely.
    • Several fixes to escape sequences
    • Drawing enhancements: deal with block elements and scale glyphs to their
      cell size (either single or double if wcwidth() says so).
    • Fixed reporting initial size to clients.
    • Safe command injection: validates the terminal is reading a command. If
      a partial command is typed, wipe it, inject and restore the partial command.
      Injection is now also used by PceEmacs Compile commands.
  • Faster partial window redraw. Old versions used to refresh the whole window
    on any change. We now only refresh the damaged area, keeping track of maximal
    8 damage areas.
  • Life resizing of windows. Used to work on Linux only, now also works on MacOS
    and Windows.
  • Fixed SDL native message box API to stop freezing other windows on Wayland.
  • Several memory management changes provide better performance and more eager
    reclaiming of objects. Several leaks are fixed.
  • Many more small improvements :slight_smile:

MacOS

  • Updated dependencies for binary bundle. Changed BDB dependency from 6.1 to
    5.3 due to license issues. This upgrade might also fix binary portabiluty
    issues. If all is right, it should run on 10.15 or later for Intel macs and
    11.0 for later for Apple Silicon (M*).

    Enjoy — Jan

SWI-Prolog Changelog since version 10.1.14

  • BUILD: macOS deps: use Berkeley DB 5.3.28 instead of 6.1.26 Berkeley
    DB 6.x is AGPL, which would conflict with distributing the bundle,
    e.g. as a Homebrew cask. 5.3 is under the Sleepycat licence and,
    unlike 6.x, is still freely downloadable from Oracle. Pin it with
    a comment so it is not “updated” back.

  • BUILD: macOS: derive LSMinimumSystemVersion from the deployment target
    The app and framework Info.plist claimed 10.14 while the binaries are
    built for 10.15. Both templates now use CMAKE_OSX_DEPLOYMENT_TARGET.

  • FIXED: #1526 Windows: tmp_free(NULL) corrupted the heap tmp_free() has
    two implementations. The MMAP_STACK one, used wherever <sys/mman.h>
    exists, accepts NULL like free() does. The fallback, which is what
    Windows builds get, walked back over the size header and called free()
    on NULL-sizeof(word). On Windows that is reported as heap corruption,
    exit code 0xC0000374.

  • FIXED: #1525 ~:f ignored the locale decimal point in a non-C environment
    localizeDecimalPoint() assumed the number in the buffer was printed with
    the decimal point of the default' PL_locale, and skipped the rewrite when that matched the requested one. Since PL_initialise() no longer sets the process LC_NUMERIC (issue #1093) that assumption is wrong: the C library prints "." while default’ carries the environment’s
    “,”. In a German locale format(‘~2:f’, [123456.7]) therefore produced
    ‘123.456.70’ instead of ‘123.456,70’.

  • FIXED: #1524 Windows: undefined behaviour scanning UNC path host names

  • FIXED: macOS release build: take system
    libs from the Xcode SDK make-distribution put
    /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr on
    CMAKE_PREFIX_PATH, while cmake uses the Xcode SDK as CMAKE_OSX_SYSROOT.
    The Command Line Tools 27.0 update made that symlink point at
    MacOSX27.0.sdk, whose .tbd stubs name an arm64e.x1 target the
    Xcode 26.5 linker rejects with “tapi error: malformed file”.
    As libcurses.tbd/libform.tbd end up in CMAKE_REQUIRED_LIBRARIES,
    every check_function_exists() link failed and the configure reported
    signal(), signbit(), access(), fork(), … as missing.

  • FIXED: Single threaded: record the module a file is loaded from
    source_file_property(File, load_context(Module, Location, Options))
    had no solutions at all in a single threaded system: recording the
    context was done by the loader of the multi-threaded system only.
    make/0 could therefore not reload a file the way it was loaded, and
    a .qlf file did not depend on the files whose term or goal expansion
    went into it, nor on the file an XPCE class template was copied from.

  • BUILD: macOS deps: update versions, build both arches on one machine
    Update the bundle dependencies to current releases: OpenSSL 3.6.4, zlib
    1.3.2, libarchive 3.8.9, unixODBC 2.3.14, pcre2 10.48, libffi 3.8.0,
    SDL3 3.4.16 (3.4.14 is broken), SDL3_image 3.4.6, pango 1.58.2.
    Berkeley DB and OSSP uuid stay where they are, being no longer
    downloadable. libjpeg is dropped: nothing references it any more, and
    with the CoreText font map neither do FreeType, fontconfig or libpng.

  • BUILD: Keep the C and the C++ compiler flags apart The flags of
    a build type used the optimization flags of C for C++ as well,
    and those were $CFLAGS entire: every option meant for the C
    compiler reached the C++ compiler too, so a $CFLAGS carrying, e.g.,
    -Werror=implicit-function-declaration warned on every C++ file it
    compiled. Fixes #1518.

  • FIXED: atom GC scanned 8 times too far above the local stack top
    markAtomsOnLocalStack() added LOCAL_MARGIN, which is in bytes, to a
    Word pointer and thus scanned about 67Kb above lTop instead of the
    frame header plus MAXARITY arguments a call may be building there.
    Atoms, and notably blobs, left in that area by deeper calls that had
    long returned were kept alive. This could also form a pointer beyond
    the local stack.

  • BUILD: install customize/ into the build home tree The user init
    file template customize/init.pl was installed, but not linked into
    the build tree home directory, so swi('customize/init.pl') did not
    resolve when running from a build directory. Move it from a plain
    install() to the SWIPL_DATA_DIRS machinery, which does both.

  • FIXED: tmp_dir flag held an OS path rather than a Prolog one On Windows
    the flag was the raw value of TEMP, which uses "" as the separator.
    Every other path Prolog hands out uses “/”, so a file built from the
    flag with directory_file_path/3 did not compare equal to the same file
    named any other way: .qlf files recorded a source under one name and
    looked it up under the other, and a buffer opened on such a file was
    not recognised as being open.

  • ADDED: term_automaton/2 and automaton_minimal/2,3 term_automaton/2
    converts between a term and its term graph written out as an explicit
    automaton, and automaton_minimal/2,3 minimises such an automaton under
    bisimulation, collapsing bisimilar states and dropping the ones the
    start state cannot reach. Composed, the two are term_minimal/2.

  • FIXED: Windows build of pl-bisim.c The bs_graph field grp2 clashes with
    a macro from the Windows header dlgs.h, which defines the common dialog
    control ids grp1..grp4 as plain numbers. Renamed the field to grp_next.

  • ADDED: variant_hash/2 and variant_sha1/2 accept cyclic terms Both
    refused a cyclic term with type_error(acyclic_term, T). The manual
    said why: “Cyclic terms are not supported because this would require
    establishing a canonical cycle. That is, given A=[a|A] and B=[a,a|B],
    A and B should produce the same hash. This is not (yet) implemented.”

  • FIXED: term_factorized/3: looping and under-factoring on cyclic terms
    term_factorized/3,4 are now built in, computed from the term graph
    quotient. The library(terms) implementation kept an rbtree of the
    subterms it had seen, keyed on the standard order, and the standard
    order is not antisymmetric on rational trees – for A = s(A,0), B =
    s(C,1), C = s(B,0), compare/3 answers (>) in both directions. The tree
    could therefore lose a key that was present, and term_factorized/3
    either looped forever or, less visibly, counted a subterm reached
    twice as reached once and did not factor it out at all. Over 4000
    random cyclic terms the old implementation diverged or under-factored
    on 11 of them.

  • ADDED: term_minimal/2 and term_factorized/3,4 A term in the store is a
    graph, and a cyclic term is a finite graph denoting an infinite tree.
    Two terms denote the same tree exactly when their graphs are bisimilar,
    which is the equivalence ==/2 already decides. What was missing is a
    canonical representative: the smallest graph denoting the same tree.
    pl-bisim.c computes it, and the new predicates hand it to Prolog.

  • FIXED: =@=/2 and =@=/2: use after free, and errors reported as answers
    isomorphic() held a node pointer across the second term_id() call.
    That call can grow the node buffer, and growing it moves it, so
    the pointer was read and written after the block it points into had
    been freed. It takes a term with enough sharing to enter isomorphic()
    and enough cells to grow the buffer; f(D,D) nested four deep against
    the same term written out in full was enough to crash. Number both
    cells before looking either of them up.

  • FIXED: term_factorized/2, term_subsumer/3: deal with zero-arity terms.

  • FIXED: term_factorized/2: handle zero-arity compounds.

  • ENHANCED: decide whether a .qlf file is out of date by content, not
    by time A .qlf file now records a hash of the content of every source
    that went into it, and a source is recompiled only when that hash
    says it really changed. Modification times cannot say: a tree that
    arrives by checkout, copy, unpack or install carries times of its own,
    in either direction and at the resolution of the file system it landed
    on, and a file edited in the second its .qlf file was written has the
    very time of that file. Touching all 707 sources of the system library
    now recompiles none of them, and hashing them to find that out takes
    97ms – against minutes for one file wrongly kept or wrongly rebuilt.

  • FIXED: Make toplevel stop on thread_exit/1.

  • DOC: WindowsInstaller.md: document the SignPath signing step Describe
    how signing fits into the release-windows workflow, which artifact to
    download, how to verify the signature, the one-time SignPath setup and
    how to dispatch the workflow from a branch when testing changes to it.

  • FIXED: library(persistency): CRLF handling of the database file on
    Windows The database file is now read and written using newline(posix).
    On Windows the file was written using CRLF, while the reader deletes
    all carriage returns. As a result the byte counts used to repair
    a truncated database were off and a file ending in a lone CR was
    considered to end in layout, causing a new term to be glued to the
    . of the previous one.

  • ENHANCED: library(persistency): recover from an incomplete last term
    If a persistent database file ends in a partially written term, e.g.,
    because the disk was full or the process was killed while writing,
    db_attach/2 now prints a warning and truncates the file to just after
    the last complete term instead of raising a syntax error.

Package json

  • CMAKE: always install json_rpc_common.pl It was installed only
    if the pcre package is available, while json_rpc_client.pl, which
    needs it, is installed for any multi-threaded build. Without pcre
    this breaks loading library(json_rpc_client) with “source_sink
    `library(json_rpc_common)’ does not exist”. The module has no
    conditional dependencies of its own, so there is no reason to gate it.

Package libedit

  • FIXED: link the threading library into the binding libedit4pl.c uses
    a pthread mutex to serialise painting the input line, but the plugin
    never linked a threading library. On platforms where pthreads are
    not part of the C library, notably MSYS2 and MinGW, that leaves
    pthread_mutex_init() and friends undefined at link time.

Package nlp

  • FIXED: isub/4 goal expansion to not raise an error Compiling a call to
    isub/4 that passes a constant as Normalize, or that passes options
    that are only known at runtime, raised an error while expanding the
    goal. The error dropped the clause that held the call from the program.
    This affected, e.g., apropos/1, whose isub/4 call sits in library(help).

Package pldoc

  • TEST: man_links: skip the test if the documentation is not installed
    The test renders manual pages and resolves the links in them.
    Both library(help) and the manual index it reads only exist if the
    documentation is built, so without them there is nothing to test.

  • FIXED: #9803 help/1 on a manual section that embeds a figure Rendering
    such a section raised http_handler_id manual_file does not exist.
    The handler id used for images in the main manual has never existed;
    it is pldoc_refman. That handler now serves the images, and without
    a PlDoc server (help/1) images become a file:// URI.

Package ssl

  • FIXED: macOS HTTPS hang in system_root_certificates/1
    On macOS the system root certificates were obtained using
    SecTrustCopyAnchorCertificates(). This talks to securityd over Mach
    IPC and can block forever if the keychain is not accessible, e.g.,
    in an ssh session while the login keychain is locked. Such a block
    cannot be interrupted using e.g. call_with_time_limit/2. We now read
    the PEM file provided by the OS as on other Unix systems.

  • FIXED: #176 SSL streams became unusable after a read timeout with
    OpenSSL 4 Our BIO read and write callbacks returned -1 on a stream
    timeout without setting the BIO retry flags, so OpenSSL considered
    the failure fatal. Up to OpenSSL 3 this surfaced as SSL_ERROR_SYSCALL
    and left the SSL object usable, but since openssl/openssl@ebb188f0d0
    (OpenSSL 4.0) a fatal record layer read latches the state machine in
    MSG_FLOW_ERROR and every further SSL_read() fails with SSL_ERROR_SSL
    and an empty error queue, reported as “SSL(00000000) : reason(0)”.

  • FIXED: SWI-Prolog/packages-ssl#176

Package xpce

  • FIXED: SDL: Windows live resize painted only the window backgrounds
    display_manager<-test_queue defaults to @on on Windows, which makes
    redrawDisplayManager() stop as soon as events are queued. Inside the
    modal resize loop the queue cannot drain, so the resize watch aborted
    every redraw and only the freshly cleared backing surfaces were shown.
    The watch now disables the queue test while it redraws.

  • FIXED: SDL: ws_draw_frame() crashed on a frame that is not created
    The guard lacked its return, so a frame without an SDL window fell
    through and dereferenced a NULL WsFrame instead of failing.

  • FIXED: SDL: redraw windows while the user is dragging a border On
    MacOS and Windows the window system runs a modal event loop for the
    duration of a resize, leaving our main loop blocked in SDL_WaitEvent().
    The resulting RESIZED and EXPOSED events were queued but only handled
    after the drag, so MacOS stretched the last drawable and Windows
    padded the window with black. We now relayout and repaint from an
    SDL_AddEventWatch() callback, which SDL calls from inside that modal
    loop, giving the immediate resize of X11 and Wayland on all platforms.

  • FIXED: bitmap->image left a dangling <-bitmap reference in the old
    image tab_frame ->drop took anything dragged over a pane for a pane,
    warping the pointer to a nested window used the wrong offset, and
    epilog/0 was non-deterministic. The display_manager obtains its class
    variables early, getting the windows of panes and tiles is simpler,
    and a C method can be edited directly where addr2line is available.

  • FIXED: terminal: Home and End with a modifier were not passed to
    the client Only the plain keys have a binding. With a modifier
    they now send the xterm sequence, e.g. Ctrl-End sends `CSI 1;5F’.
    The wheel events of the test set the rotation slot, which replaced
    the attribute in 37170e65.

  • FIXED: two memory errors AddressSanitizer found Each font name lookup
    leaked the string it formatted the name with, and @pce<-unresolved_types
    read beyond a name object: a type for a class that does not yet exist
    has the class name as its context.

  • FIXED: pane_frame: rebuilding the menu bar leaked the old menus
    Taking a popup off the bar does not free it: its items refer to it.
    Everything that fills the bar makes its popups anew on every rebuild,
    so the old ones are freed now.

  • FIXED: xpce: free objects when their last reference disappears Since
    b1dec9a9 delRefObject() only did so for objects being inspected, so
    everything else that lost its last reference leaked, e.g. the argument
    vector of every message with two or more arguments. Objects with code
    references, as well as locked, protected and answer objects are left
    alone. Code that used an object after dropping the last reference
    to it now holds a code reference while it does: cleanTile(), the
    receiver of a running method, ->erase and the recompute of a device,
    and the cycle between a menu_item and its pull-right.

  • ADDED: tools to find what leaks: class<-no_reachable and
    object->_check(silent := @on) say which instances a check reaches,
    object->_find_holders which objects refer to a set of objects, and
    pce_lost_objects/1, pce_lost_instances/2 and pcerefer/1 turn that into
    the classes that leak, their lost instances and the chain of holders
    of one of them. These report Prolog references, and take care neither
    to pin what they report nor to hold on to what they collect.

  • ENHANCED: Epilog: only terminals and unsaved editors keep the
    application alive Added frame<->keep_alive (class variable, default
    @off) and an optional keep_alive argument to ->has_visible_frames.
    pane_frame asks its panes: Epilog terminals and PceEmacs views with
    unsaved file changes say @on. ep_main/0 now halts when no such frame
    is visible, so tools, demos and user windows no longer block exit.
    Closing the main console halts immediately unless keep-alive frames
    remain.

  • ENHANCED: Profiler GUI opens showing the most interesting predicate
    For a cumulative profile this is the first predicate using less than
    90% of the time; otherwise it is the first in the list.

  • FIXED: PceEmacs: error from the history buttons after closing a pane
    The tool bar of a pane_frame kept the client it was created with,
    the pane in view at that time. After closing that pane, updating the
    history buttons raised an existence error. pane_menu_dialog ->client
    now also updates the client of the tool bar.

  • ENHANCED: terminal_image scrolls while the selection is dragged past
    its edge Dragging a selection above or below the terminal scrolls
    the scroll-back and extends the selection over what comes into view,
    faster the further out the pointer is. Not on the alternate screen
    or while the application tracks the mouse.

  • FIXED: freeing a terminal_image without a scroll_bar sent ->destroy to
    @nil Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com
    Claude-Session: https://claude.ai/code/session_018urSFBQAQZtC1sjsbkrdwm

  • FIXED: MacOS: Option held while the focus moved to a new window
    was lost SDL forgets the modifiers when a window loses the focus.
    Holding Option from M-x into PceEmacs’ command prompt made M-p type π
    rather than walk the history. Take Option from Cocoa if SDL misses it.

  • FIXED: SDL keyboard debug message printed garbage for the timestamp
    Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com
    Claude-Session: https://claude.ai/code/session_018urSFBQAQZtC1sjsbkrdwm

  • MODIFIED: meta (Alt) is a modifier in event <-buttons, not an offset on
    <-id A key typed with meta held now has the plain character as <-id and
    BUTTON_meta in <-buttons, like shift, control and gui. META_OFFSET and
    Meta() are gone, char no longer accepts M-x or \ex, and ->typed
    methods that must see the meta key take event|event_id. User code
    that compares <-id against offset values, or declares Id:event_id on
    a method that forwards keys, must be updated.

  • ENHANCED: store wheel rotation in event <-rotation instead of an
    attribute Wheel events are frequent and attaching an attribute to
    each event object is expensive. Class event now has a rotation
    slot (int*), @nil for all other events. Code using get(Ev, attribute,
    rotation, R) must use get(Ev, rotation, R).

  • FIXED: editing a tab label left the pane’s focus active and lost it
    afterwards A double click on a tab label opened the label editor while
    the window of the tab kept an active cursor, and after the edit that
    window looked focused without receiving keys. The editor now takes
    the frame’s focus, the tabbed window no longer passes it on to its
    tab while a label is edited, and the focus goes back to the window
    the user was typing in.

  • FIXED: PceEmacs: tabs of the editor had no popup menu The editor
    keeps its source tabs in an emacs_pane, which never got the label
    popup the window puts on its own tabs. It now has one with Close
    tab, Close other tabs and Move to new window. Closing other tabs
    goes through ->close_tab so modified buffers are still asked about.

  • ENHANCED: PceEmacs Prolog mode: inject consult buffer and make/0 If
    there is a current Epilog terminal, inject the command there.

  • ADDED: @prolog_ide<-current_epilog Find the current Epilog terminal.

  • CLEANUP: Removed swi_console. Outdated.

  • ENHANCED: Epilog: safely inject commands. Handles preserving partial
    input and signalling if the console is not waiting.

  • FIXED: Wayland: native message boxes froze all xpce windows On Wayland,
    SDL_ShowMessageBox() runs zenity and blocks the calling thread until
    the box is closed. When called from the SDL main thread this stopped
    event dispatching, so windows were not redrawn. The box is now shown
    from a helper thread while the main thread keeps dispatching events.
    User input is discarded during the wait, except for mouse button
    releases, which are re-queued afterwards.

  • ADDED: prolog_terminal->inject Check that the terminal can be used now,
    i.e., that it is at the prompt or reading while we can save/restore
    the already typed input.

  • FIXED: swipl-win: capture messages. The terminal is created in
    frame->create, which runs asynchronously. This means we must
    drive the event loop until the terminal is ready before we can enable
    capturing.

  • ENHANCED: Answer stack: constant time delete; reclaim leftovers at the
    host boundary Deleting an object from the answer stack no longer scans
    the stack. Objects left on the answer stack when control returns to
    Prolog are reclaimed, so code that creates objects outside a mark/rewind
    pair no longer leaks them. Use debugpce(gc) to list such objects.

  • FIXED: SDL events were never reclaimed The SDL backend created events
    as answer objects before marking the answer stack, so the rewind
    after dispatching did not reach them and freeableObj() refused them
    while they carried the answer flag. Every event leaked, keeping the
    windows and frames it referred to allocated after they were freed.

  • ENHANCED: checkpce/0: show reference counts and freed state along
    the path Each object in the “Path from checked object” listing,
    as well as object keys of hash tables, now prints its reference
    and code reference counts and the freed, freeing, creating, locked,
    protected and answer flags.

  • ENHANCED: A new tab opens beside the current one, not at the end
    of the row Command-T and Control-Shift-T in Epilog put the terminal
    they make at the far end of the tab row, which in a window with a few
    tabs is nowhere near where the user is looking. A tab made on purpose
    now goes straight after the tab it was made from. The new-tab button
    keeps appending at the end: the button is at the end of the label row,
    which is where the tab it makes belongs.

  • FIXED: Epilog windows claimed a keyboard focus they did not have An
    Epilog window went on drawing an active caret after the window system
    gave the keyboard to another window, kept the platform text input
    enabled, and never sent its client the focus-out report (CSI ? 1004).
    The mirror image was true of a new window: it showed a pane, but the
    first keystroke went nowhere until the pointer entered that pane.
    Moving the focus between the panes of one window always worked,
    which is what made both hard to place.

  • FIXED: Epilog terminal: a character’s column width must not depend on
    the font The terminal promoted a character to two columns when the
    font drew its glyph more than 1.5 cells wide. The column grid is a
    contract with whatever writes to the pty though: that program lays
    its output out with its own wcwidth() and cannot see our font, so a
    character we make a column wider puts us ahead of it for the rest of
    the line, and the frame it redraws over that lands on the wrong rows.
    On macOS the heuristic caught U+23BF LEFT PARENTHESIS LOWER HOOK,
    resolved from a symbol face that draws it at ~1.6 cells – and U+23BF
    opens every tool-result line Claude Code prints, so its display came
    apart into overwritten and interleaved rows.

  • ADDED: Chart gallery demo covering library(plot) One window with a cell
    per feature of the two libraries that draw charts: plot_graph’s poly,
    smooth and points_only curves, plot_axis grid lines, formats, labels
    and log scale, an axis that prints its own tick labels, plot_mark,
    and bar charts in both orientations with stacks, groups, ->sort, bars
    that can be dragged and bars with a bar_button_group of their own.
    Listed in the demo browser as “Chart gallery”, or run ?- charts_demo.

  • DOC: bitmap: transparency comes from the image, not from the bitmap
    Class bitmap documented a <-transparent and a bug about bitmaps not
    being partly transparent. Both went away with bitmap<->transparent
    (cb34992c): a bitmap is transparent where its image’s alpha channel
    says so, which is also what clears its solid flag.

  • MODIFIED: image ->save: PNG is the only format, and only to a file The
    format' argument was typed {xbm,xpm,pnm,pbm,pgm,ppm,jpeg,gif} and in’ as a source_sink, but the only thing that can be written is a PNG
    to a file. Every value the type accepted was refused by the backend,
    and png – the default – was not in the type. Both are now honest:
    in=[file], format=[{png}].

  • FIXED: barchart: vertical bar charts could not be created at all
    Appending a bar to a vertical bar_chart raised “no implementation for:
    ->transparent” and left the chart empty. Class bar_label is now a
    figure that rotates its text with ->rotate rather than drawing it
    into an image and rotating that, so the label is anti-aliased and
    any angle works, not just multiples of 90.

  • FIXED: PceEmacs: the editor’s reports never reached the bar of its
    window A report climbs from the window that made it to the frame,
    and every pane on the way is asked whether it is the one in view.
    PceEmacs is a group – one pane holding a tab per source – and
    pane_frame <-current_pane' looks inside a group, so the group compared itself against the view it holds, decided it was not the pane in view, and dropped everything its own editors had to say: Mark set’, the
    mode it switched to, and the running feedback of an incremental search.

  • ENHANCED: Navigator: the “Show:” menu sits on the tool bar The menu that
    chooses between the loaded files, the Prolog files and all files moved
    from the filter dialog to the tool bar of the Prolog Navigator, which
    leaves the whole dialog below it to the file filter. That filter now
    says what it is for – “Filter files” – rather than carrying a label.

  • FIXED: PceEmacs: do not load the user’s files if xpce_defaults is
    `none’ The mode extensions in app_config(‘xpce/emacs’) and the init
    file user_profile(‘.pceemacsrc’) are the customisation of whoever
    runs PceEmacs, so the flag that says a program is not to depend on
    their preferences now also says to leave those alone.

  • TEST: test_undefined: help/1 is only there if the documentation
    is built src/CMakeLists.txt only installs library(help) if the
    documentation is built, so emacs_language_mode:help/1, called by the
    mode’s ->prolog_manual, has nothing to autoload from in such a build.

  • FIXED: the alternate screen dropped the text of the line it was started
    on A client that had written to the line without a newline after it
    – a prompt, a progress line – found it empty on coming back from
    a full screen application.

  • FIXED: the folds of a session were lost by running a full screen
    application Coming back from less' or man’ the session had all its
    folds open, because the application had cleared its own screen along
    the way.

  • FIXED: full screen applications scrambled the screen on a session with
    folds Running less', man’ or any other application that takes the
    whole window left it with rows missing and the caret in the middle of
    it, on a terminal that had closed folds on the screen. Clearing the
    terminal was the way out.

  • FIXED: xpce:bookmark_store and xpce:bookmarks failed without a display
    Both were registered with test_libs() but left out of XPCE_EXTRA_TESTS,
    which is the list that gets SDL_VIDEODRIVER=dummy in its environment.
    Without it swipl-rc’s has_display/0 fails on a headless machine,
    xpce is never set up, and library(emacs/bookmark_store) cannot be found.

  • FIXED: checkpce/0: only take pce blobs held by clauses or records as
    roots A pce blob that lives only on a Prolog stack is no longer a root
    for the check. The atom GC scans the stacks conservatively, including
    a margin above the top of the local stack, so a window that was just
    closed leaves blobs for its tiles and chains there. They keep those
    objects alive, and checkpce/0 reported them as holding freed objects.
    Stack garbage can neither be collected nor reliably wiped, so a blob
    now only counts if ‘$atom_references’/2 says a clause, a record or
    foreign code registered it. Calling garbage_collect_atoms/0 first
    is dropped: it cannot change that set.

  • FIXED: bookmark editor: bookmarks lost between instances, notes lost
    when unfocussed The bookmarks were written out as a whole tree when
    a session ended, so the last instance of PceEmacs to leave overwrote
    whatever the others had marked, and one that never got to leave wrote
    nothing at all. They are kept as an append-only log now – the new
    library(emacs/bookmark_store), over library(log_store) – in which a
    bookmark made, annotated or thrown away is written down there and then,
    and which is tidied to one record per bookmark once it has grown long.
    A note is given to its bookmark when the caret leaves it as well as when
    another bookmark is selected, and the note field is inactive while no
    bookmark is selected, there being nowhere to put what is typed into it.

  • ADDED: library(log_store): a file of Prolog terms kept as an append-only
    log The window arrangements the IDE learns are kept this way already,
    so that several instances running at once do not overwrite each
    other’s; the bookmarks of PceEmacs need the same. Moved the file,
    the lock and the terms out of library(pane_layouts), which now says
    only what a record of its own means and when the log has grown long
    enough to summarise.

  • FIXED: Settings/User init file when the init file does not exist
    Answering “yes” to “Preferences file … doesn’t exist. Create
    it?” did not create the file, after which PceEmacs reported “No
    source for …”. The template was looked up as customize/swipl.ini or
    customize/dotswiplrc, names that vanished with the autoconf build; it
    is customize/init.pl. If no template is found at all we now create an
    empty file rather than nothing. Also create the user config directory
    if it is missing: locating the init file used absolute_file_name/3
    with access(write), which fails when /swi-prolog does not
    exist yet, silently failing the whole menu action.

  • FIXED: emacs_prolog_mode <-forward_clause handed itself to a regex
    `regex ->search’ wants a char_array, text_buffer or fragment. A mode
    is none of those: it only delegates to its editor, so the send raised
    a type error, <-forward_clause failed and ->fill_paragraph filled the
    clause as if it were a paragraph of prose rather than indenting it.
    Alt-Q in Prolog code printed the error and did the wrong thing.

  • FIXED: objects that outlived what owned them Three leaks that checkpce/0
    reported by the thousand after using the IDE for a while: cloning an
    event copied the whole user interface, a window left the graphicals
    of its fixed layer behind when it was destroyed, and the manual kept
    freed tools in its tool table.

  • ENHANCED: object->_check tells where the faulty object was found Each
    inconsistency found by object->_check (checkpce/0) is now followed
    by the path from the checked object to the object that holds the
    illegal value. A step of this path is printed as the object and the
    slot we descend in: <-name' for an instance variable, [index]’ for
    an element of a chain or vector and `{key}’ for a key of a hash table.
    Without it a report names an anonymous chain and there is no way to
    tell what put the freed object in it.

  • ENHANCED: The symbol picker is a pane, and shows a range from the top
    It was a frame of its own. It is a `tool_pane’ now, so it docks like
    the navigator or the list of buffers; the arrangements the system
    comes with give it a window of its own, which is where a thing you
    pick from while typing elsewhere belongs.

  • FIXED: A tool given a window of its own could not be learned Two
    things stood in the way of “this tool lives in a window of its own”
    ever becoming what the IDE does.

  • ADDED: Settings/Remember how this window is arranged The IDE learns
    where panes go from how long a window is worked in, which takes a
    while to come round and fades again. This says it outright: the
    window as it stands is where panes of these kinds go.

  • ENHANCED: The event viewer counts a repeated event rather than
    listing it Dragging the mouse across the box filled the history with
    a screenful of `loc_move’ and pushed what came before it out of sight.
    A run of the same event now counts up on the line it is already on –
    “loc_move (5×)” – and that line keeps the last of them, which is
    the one selecting it shows.

  • FIXED: A text_item that cannot be typed in showed its clear button The
    button clears the field, which a field that is not <-editable does
    not allow, and clicking it there did nothing. It is not drawn now,
    and the room kept for it goes to the text: a read-only field has no
    use for a strip down its right. ->editable asks for a recompute,
    as the width the field wants from its dialog changes with it.

  • FIXED: The popup of the buffer list asked for things that are not
    there Three items on it had gone stale:

  • ADDED: editor ->placeholder An editor that holds no text writes its
    <-placeholder where the text would be, in the text colour faded to
    editor.placeholder_opacity' (0.5), so that an empty one can say what it is for. Class text_item has had one for a while; this is the same thing for the classes built on an editor, and class view answers for its editor, so a view ->placeholder’ works as well.

  • ENHANCED: The PceEmacs bookmarks are a pane that can be docked The
    bookmark editor was a frame of its own, holding a tool bar, the tree
    of bookmarks, the note being written and a reporter, so it could only
    float over the window it was asked for. It is a tool_pane' now, like the navigator and the list of buffers, and the arrangements the system comes with put it right of the editor at a third of the width. find_references_editor/2’ makes hit lists of the same class, so
    those dock too, pin and all.

  • ENHANCED: The PceEmacs buffer menu is a pane that can be docked It
    was a frame of its own, holding a tool bar, the list of buffers and
    a reporter, so it could only float over the window it was asked for.
    It is a `tool_pane’ now, like the navigator and the debug monitor,
    and the arrangements the system comes with put it down the left of
    the editor at a fifth of the width. Asking for it again brings the
    one there is into view rather than making a second.

  • FIXED: The menus of the bar ignored where their items belong The File
    menu put “Close window” and “Halt prolog” at the top, and the Settings
    menu showed a tick beside “User init file”, which is a command rather
    than a setting. Both come of a menu of the bar being filled from two
    sides: the application puts its own items on it and the pane in view
    adds what it can do afterwards.

  • FIXED: bookmarks: a bookmark on another drive was silently dropped
    ->bookmark walks the root of the bookmark tree up until it holds
    the file being marked. On Windows the walk runs out of parents
    before it gets there whenever the file is on another drive than the
    one the tree is rooted on, and the bookmark was then thrown away.
    Root the tree at “My Computer” instead: that root holds every drive,
    and ->append already knows how to place a file below it.

  • FIXED: terminal: Block Elements drawn as glyphs when the font lacks
    them A Block Element is drawn as rectangles of the cell rather than
    from the font, but its width was still classified by asking the
    font how wide the glyph is. Where the font has no glyph for it –
    the quadrants are missing from the fixed font on Windows – that
    measures the hex box the shaper substitutes, which is wider than a
    cell, so the character was taken to be double width. A double-width
    cell is a two-cell cluster, which the painter does not draw itself,
    and the hex box went to the screen.

  • FIXED: font copy left the creating' flag set getCopyFont() builds the instance with allocObject() but never called createdClass(), so the copy kept F_CREATING for its entire life. Such an object is reported by Object ->_check’ as

  • FIXED: char type rejected Meta-modified key codes Raising META_OFFSET
    above the Unicode range (b996819) made every Meta-modified key code
    larger than UNICODE_MAX, so the char' type validation started rejecting them. As a result Object ->_check’ (and thus checkpce/0) reported e.g.

  • CLEANUP: epilog: leave fading an inactive terminal to the frame A
    prolog_terminal faded itself on losing the keyboard focus, from an
    inactive_opacity' class variable of its own. A pane_frame already does that for every pane it holds, driven by pane_frame.inactive_opacity’,
    so the terminal was saying twice what the frame says once – and only
    for the terminal image, not for the pane around it.

  • FIXED: window <-opacity had no effect Fading a window is how a
    pane_frame shows which of its panes has the focus, but nothing
    rendered it: <-opacity was applied by pushing a Cairo group around
    what a graphical paints into the surface it shares with the graphicals
    around it, and a window paints nothing there. It has a surface of
    its own that the frame composites, so the group wrapped only the
    selection and inversion of the window rectangle, which the window’s
    own texture then covered. Setting `pane_frame.inactive_opacity’
    in a Defaults file reached <-opacity of the pane and stopped there.

  • DOC: how the panes of a window are managed, and how to configure
    them Defaults.user gains the class variables that govern the layout
    of a window of the IDE, and the User Guide a chapter on panes: how
    a window is put together, what the user can do to it by hand, how
    the system decides where a new pane goes, how library(pane_layouts)
    learns that from the way windows have been arranged, and the class
    variables that change any of it.

  • FIXED: pane_menu_bar <-menu_order taken from a Defaults file The
    order of the pulldown menus is a class variable so that a user
    can name it in their Defaults file, but doing so had no effect:
    the XPCE tokeniser reads a quoted name as a string, and GUI' and ’ have to be quoted there. chain <-index' then matched neither, so <-rank failed for GUI and for every menu that should have taken the place of ', leaving all of them at the end of the bar.

  • FIXED: initial tty size of an Epilog terminal was 0x0 The pty is created
    lazily, when the Prolog thread is connected, and nothing gave it a
    size: TIOCSWINSZ was only issued from a resize, and the terminal is
    created at the size it is laid out at, so the first resize never comes.
    tty_size/2 therefore reported 0,0 until the user resized the window.
    Tell the pty the size the terminal already has when creating it.
    On Windows the same size now reaches CreatePseudoConsole() instead
    of a hardcoded 80x25.

  • ENHANCED: SDL: upload only the part of a window a redraw changed Drawing
    a frame uploaded every window’s full Cairo backing into its texture,
    so the cost of an update was proportional to the total pixel area
    of the frame rather than to what changed. A window that updates by
    itself, such as the thread monitor, therefore got more expensive the
    more windows it shared its frame with. Updating one small text now
    costs 0.16ms instead of 1.73ms in a frame of four 800x600 windows,
    and 0.29ms instead of 2.07ms in one of sixteen 400x300 windows.

  • FIXED: the busy cursor could stay on screen until the mouse moves
    Dropping `display ->busy_cursor’ only forgot the cursor, leaving it
    to the updateCursorWindow() that runs after each event to put the
    normal shape back. That does not happen if the event went to a frame
    rather than to one of its windows, which is the case for a keystroke
    while the pointer is outside the frame: typing a command in the GUI
    debugger left the watch cursor until the pointer moved.

  • ADDED: PceEmacs keeps its tabs to itself: the editor is a pane with
    tabs A source the user asks to see – edit/1, M-. find-definition,
    a location picked in a tool – takes a tab of the editor rather than
    the editor that is there. The tabs of the window are whole layouts,
    so putting a source in one of those would take whatever sits beside
    the editor off the screen; the editor now holds a tab per source of
    its own, and splitting it keeps those tabs with it.

  • FIXED: emacs_view ->pane_term: a buffer restored by its name
    dict <-member' answers the dict_item rather than the object in it, so a window description naming a buffer rather than a file -- editor([buffer(‘scratch’)])’ – restored nothing and reported a
    type error.

  • FIXED: tab_frame <-current: the keyboard focus in a window of a window
    A window on a tab may itself hold windows – a tabbed_window used as
    a pane, as class tool_pane is – and then the frame’s keyboard focus
    is on one of those rather than on a window the tab holds. The tab
    answered whichever window it last made current instead, so clicking
    inside such a pane left the tab, and its frame, believing the user
    was working somewhere else.

  • FIXED: the menu bar could be dragged shut A tile that was given
    a size held on to it and stayed resizable, whether the size came
    from the user’s hand or from the window in it asking for the room
    its content needs. The menu bar of a pane_frame asks for that room
    whenever the strip changes – a second row of menus, a tool bar coming
    or going – and so does the status bar when a prompter does not fit,
    which marks the tiles above it as well. The gap under the menu bar
    then became a handle, and a strip dragged shut cannot be opened again:
    `tile ->rebalance’ leaves a tile with no size alone, and what is left
    to grab lies under the frame’s border.

  • FIXED: Call sites using an outdated signature for ->inform,
    ->confirm and ->report display ->inform' and display ->confirm’ are
    for=[visual], title=[char_array], message=char_array, any ...' and ->report’ is `kind={status,inform,progress,done,warning,error,fatal},
    format=[char_array], argument=any …'. A number of call sites still
    passed the message as the first argument, raising a type error instead
    of showing the message or asking for confirmation.

  • ENHANCED: The debugger opens in the window the traced thread runs in
    A debugger used to take a window of its own, so tracing a thread that
    talks in a terminal of the IDE left the user with a second window to
    watch it in. It is now a tab of the window that thread is talking in:
    `prolog_ide <-thread_frame’ finds that window from the terminal the
    thread runs in, and the arrangements the system comes with put a
    debugger in a tab beside a terminal.

  • FIXED: laying out, drawing and resizing the panes of a window The
    room a window has is divided in pixels, so it has to be there before
    the shares are handed out. A frame that is not open has only been
    fitted – every pane at the least it will take – and dividing that
    gives nothing, so building a window from a term now resizes it first;
    an open window is not laid out again from ->resize, which would put
    the panes back where they were before the menu strip and the status
    bar took theirs. tile ->rebalance' turns the layout as it stands into the wish, so a hand resize of the panes is kept when the window is resized: the resize gesture, the frame's own separator drag and the shares a window_tree’ asks for all end with one.

  • ADDED: library(pane_layouts): the IDE learns where you put your panes
    Where a tool or a source appeared was decided by one setting for all of
    it, prolog_ide.tool_placement', which gives the same answer whatever is already on the screen. library(pane_layouts) reads *arrangements* instead: a window written down with the content left out. Given the kinds of pane a window holds and the kind of the one to add, it answers window’, tab', or split(Kinds, Side, Share)’ – beside the panes of
    those kinds, on that edge, at that share of their room. It answers
    in kinds rather than in panes, so all of it is plain Prolog that is
    read and tested without a window on the screen. The setting gains
    a fourth value, `as_arranged’, and it is the default.

  • MODIFIED: every source the user asks to see opens where they asked A
    window of the IDE offers one setting on its Settings menu for where
    new things go – in a window of its own, in a tab, or beside what is
    there – and a source is now placed by it, as a tool is. The item says
    “New tools and sources open” now that it means both.

  • MODIFIED: the tools of the IDE are panes of the IDE Every tool that was
    a window of its own is a pane now, so it sits in a tab of any window of
    the IDE or beside a terminal or an editor, is dragged around by its grip
    like anything else, and says what it is doing on the status bar of the
    window it is in. Where a tool goes is the “New tools open as” setting.
    Being panes rather than persistent_frames, they no longer remember
    their own geometry: they take the size of the pane they are given.

  • ADDED: class tool_pane and window ->display_fixed: a tool is a pane
    too A tool that shows several windows – the thread monitor is the
    first of them – could only be a tab. Class tool_pane makes it a pane:
    a tabbed_window holding a single tab_frame, which lays its windows out
    with a tile the way class frame does for its members while presenting
    one window to the outside. ->append_window adds a window beside the
    ones it has, <-window finds one by class, and it carries the grip,
    so a tool can sit beside a terminal or an editor in one tab and be
    dragged to another window like anything else.

  • ADDED: library(pane_frame): one main window holding tools in tabs and
    panes A pane_frame carries a menu bar on top, a set of tabs below
    it that each hold one or more panes side by side, and optionally a
    bar at the bottom that reports and prompts. It is the one window
    Epilog, PceEmacs and the IDE tools live in, so that a terminal and an
    editor can sit beside one another. PceEmacs and Epilog run in one,
    and their windows belong to @prolog_ide.

  • ADDED: library(tab_frame): a tab that holds a tiled set of windows A
    tab could show one window. Class tab_frame lays a set of them out
    with a tile hierarchy, the way class frame does for its members,
    so a tab can hold a split window: windows are split, resized and
    dragged from one tab to another. ->split and ->drop put a window
    beside another, a separator is drawn in every gap that can be resized,
    and class split_handle is the grip in the corner of a pane that splits
    or moves it.

  • ENHANCED: xpce: window<-image, beside frame<-image Reads back the
    pixels of one window, on a surface of the window’s own size and with
    the window at its origin. A window decorator and any subwindows come
    along, as they do for the frame.

  • FIXED: epilog: draw the Block Elements as rectangles of the cell A
    font lays its glyphs out in its own em box, which is not the cell:
    the box is placed by the baseline and is shorter than the line height
    a terminal gives a row. Drawn from the font, U+2588 FULL BLOCK left
    a strip of the cell background above it and a quadrant sat below the
    top of its cell, so a picture built out of these characters – Claude
    Code’s logo – came out in stripes, with a dark line where the client
    had set a background colour and a gap between the body and the feet.

  • FIXED: epilog: Shift+Tab is the back-tab, not a tab The key sent a
    plain tab, so a client that walks a form both ways – Claude Code
    cycles its modes with it – could not tell it from Tab. It now sends
    the CBT xterm spells CSI Z', and CSI 1 ; Z’ when another
    modifier is held with it.

  • FIXED: epilog: the CSI parameter prefixes <' and =’ ESC[<u', which Claude Code writes when it exits to pop the kitty keyboard protocol's flags, printed a stray u’ on the screen: <' was not recognised as one of the ECMA-48 parameter prefixes, so the sequence ended there and its final byte was taken for text. For the same reason ESC[>5u’
    was read as the `CSI u’ that restores the caret.

  • TEST: epilog: the copy keys must not reach the client Covers b5dfc657:
    Command-C and Ctrl+Shift-C with nothing selected used to fall through
    to the program on the terminal, as a `c’ and as ^C.

  • FIXED: epilog: Command-C and Ctrl+Shift-C must not reach the client
    A key the terminal has a binding for is now kept by the window even
    when the bound method declines. Copying with nothing selected made
    Command-C insert a `c’ into the program running on the terminal,
    and Ctrl+Shift-C reach it as the ^C the keymap makes of it.

  • FIXED: text_item_combo_width() read <-style of a non-text_item
    The completion browser is shared with class menu: a ->kind:
    cycle menu opens it as its combo box and becomes @completer’s
    <-client. destroyCompleter() asks the client for its combo width,
    so text_item_combo_width() was reached with a menu and read a slot
    that class does not have.

  • FIXED: crash when menu ->initialise' fails A failed ->initialise is still followed by ->unlink, and unlinkMenu() walked <-members, which is still @nil when the argument type check rejects the call before initialiseMenu() ever runs. new(M, menu(test, cycle, ))’ crashed rather than failing.

  • ENHANCED: profile GUI: do not allow scrolling the table off screen.

  • FIXED: terminal_image: drop a selection the line editor left behind
    A selection on the line being edited stayed as it was made while the
    line moved on under it: the cursor keys walk the caret away from it,
    and what a key does to the text can leave the highlight over something
    else entirely. Every key that goes to the program now drops it,
    the way an editor drops the selection as soon as one types on, unless
    the key edits the selection itself – typing replaces it and Delete
    takes it, which ->delete_selection already did.

  • TEST: terminal_input_selection: the selection over the line being
    edited, with the two ends of what is left alone.

  • ENHANCED: Epilog: keep the report bar off the line being worked on
    The bar with the short messages is drawn over a line of the terminal,
    which is a nuisance when that is the line being edited. The new
    epilog_report.placement' class variable says which line it takes: smart’ (the default) takes the last one unless the caret or an end
    of the selection is there, in which case it takes the first, bottom' and top’ pin it and `none’ sends the messages to the normal XPCE
    reporting instead.

  • ADDED: terminal_image <-selection_start, <-selection_end: the ends of
    the selection as point(col, row), in the coordinates <-cursor_position
    uses. `smart’ needs them to see where the hit of a running incremental
    search is, as that hit is the selection.

  • FIXED: colour: the alpha of a #rgba' colour name Expanding the four nibbles of the short form to bytes doubled the blue one into the alpha rather than the alpha itself, so #f008’ came out at an alpha
    of 8 rather than 136.

  • ADDED: edit the selection of the line being typed A left click already
    moves the caret inside the line the program on the terminal is reading.
    This lets the selection be edited as well: Delete and Backspace take
    it, ^X and Command-X cut it, typing replaces it, and so does a paste
    from the clipboard.

  • ADDED: Epilog: Command-Z undoes on MacOS Command-Z is how MacOS
    asks for undo, and terminal_image->typed already offers a Command
    key to the terminal’s own bindings before the program on it.
    Add prolog_terminal->undo, which sends ^_ – the key libedit binds
    undo to – and bind it in the `apple’ epilog table beside the other
    Command keys.

  • FIXED: Control-Shift--' did not reach the client as ^_ SDL reports the unshifted key, so Control-Shift--’ arrived as -' (0x2D). That is below @‘, so the C0 conversion skipped it and the client was sent a
    bare `-’. libedit binds undo to ^_, which could therefore never be
    typed in a terminal.

  • ENHANCED: show keyboard accelerators in the native menu bar An item
    of a natively displayed menu_bar showed no shortcut, because nothing
    turned menu_item<-accelerator into an NSMenuItem key equivalent.
    Doing so needs two things.

  • FIXED: Apple bindings for Command-arrow never fired characterName()
    writes a named key between angle brackets, so Command-Left is
    \s-<cursor_left>', not \s-cursor_left’. The four cursor entries
    of the `apple’ editor bindings used the latter and could therefore
    never match an event, leaving Command-Left/Right/Up/Down without
    the beginning_of_line, end_of_line, point_to_top_of_file and
    point_to_bottom_of_file they were meant to have.

  • ENHANCED: PceEmacs: reach the location history without the tool bar
    The two history buttons in the mode dialog’s tool_bar were the only
    way to walk the location history: no menu item and no key binding.
    With the menu bar displayed natively (MacOS) the menu_bar is not drawn,
    which left those buttons alone in an otherwise empty strip.

  • ADDED: menu_bar<-native

  • FIXED: PceDraw: type error setting an attribute from the editor
    colour->equal declared its argument as `colour’, so comparing a colour
    against anything else raised a type mismatch rather than answering
    false. The attribute editor does exactly that when it checks whether
    the value changed, so setting the colour of a shape raised an error.
    equalColour() already guards both arguments with instanceOfObject(),
    so the declaration is what was wrong.

  • FIXED: drain the terminal pty on the watcher thread The console
    pty was read only by receiveTerminalImage(), which runs on the main
    thread from ws_dispatch(). The main thread is also what writes to it,
    so once the pty filled, a main-thread write could never complete:
    the only thread that could make room was the one stuck in write().
    Any sufficiently large write hung the application – reporting an
    XPCE error with a backtrace was simply the easiest way to get there.

  • MODIFIED: library(dragdrop): use the `move’ cursor Also brings the
    file header up to date.

  • FIXED: let an empty window collapse instead of claiming a strip A dialog
    holding only a menu_bar that is displayed natively (MacOS) has nothing
    to show, but still occupied a visible strip at the top of the frame,
    so the frame appeared to draw a double-height border above its content.

  • BUILD: compile the Objective-C menu bar with Clang, not the C compiler
    Cocoa headers use blocks, nullability and instancetype, which only
    Clang understands, so building XPCE with e.g. MacPorts GCC failed:
    enable_language(OBJC) defaults CMAKE_OBJC_COMPILER to CMAKE_C_COMPILER,
    and gcc-mp-15 cannot parse Foundation.h.

  • ENHANCED: native MacOS menu bar for class menu_bar On MacOS the menus
    of a menu_bar' are now shown in the system menu bar at the top of the screen rather than drawn inside the frame. The XPCE menu_bar’
    object remains the model: its popup' members are mirrored into an NSMenu, and selecting an item is routed back through the normal popup->execute’ path, so applications need no changes. Controlled by
    the new class variable `menu_bar.native’, which defaults to @on on
    MacOS and @off elsewhere.

1 Like