CHANGELOG 0.4.1.md — Notepad

Added

  • Native processes can have threads. SXN_SYS_THREAD_CREATE, SXN_SYS_THREAD_EXIT and SXN_SYS_THREAD_EXIT_CODE (sxn_thread_create, sxn_thread_exit, sxn_thread_exit_code): a waitable handle per thread, and the last thread's exit ends the process. Threads of one process run on several cores at once: unmapping a view other cores may hold sends them a TLB shootdown IPI, and its pages are freed only once they have flushed. See docs/kernel/THREADS_ROADMAP.md.

  • Each native thread has its own %fs and %gs. SXN_SYS_SET_THREAD_BASE (sxn_set_thread_base, SXN_THREAD_BASE_FS/_GS) sets the calling thread's segment base, the anchor of thread-local storage and of a future Win64 TEB. See docs/kernel/KERNEL_NATIVE_API.md.

  • Native threads can sleep on a word of memory. SXN_SYS_WAIT_ADDRESS and SXN_SYS_WAKE_ADDRESS (sxn_wait_address, sxn_wake_address): a futex / WaitOnAddress for building locks, keyed by process and address. See docs/kernel/KERNEL_NATIVE_API.md.

  • POSIX programs can use threads. pthread.h (create/join/detach, mutexes, condition variables, once, keys), sched.h and __thread variables; errno is per thread, the heap and stdio lock, exec ends the other threads. pthread-test smoke. See docs/kernel/THREADS_ROADMAP.md.

  • AHCI (SATA) disk driver with DMA. kernel/ahci.cpp registers SATA disks as ahciN, and QEMU now attaches disk.img to the q35 AHCI controller by default (SAVANXP_DISK_BUS=ide or run_qemu.py --disk-bus ide keeps legacy IDE). Up to 256 sectors per command: a 390 KB copy moves in 0.33 s instead of 1.99 s. See docs/kernel/AHCI.md.

  • The Command Prompt, the first SUN application. /bin/console (Start menu or Ctrl+Alt+T) runs /bin/sh --console 3 as a separate process over pipes: an 80x300 buffer with a scroll bar, doskey line editing and history, and Ctrl+C that ends the foreground job. In that mode sh prints <cwd>>, separates commands with ; and has start. See docs/desktop/CONSOLE.md.

  • SUN windows choose their size, title and icon, and present rectangles. sxnwm_submit_rects, sxnwm_request_size, sxnwm_check_resize, sxnwm_close_requested, sxnwm_set_title; a native program's .sxres is compiled in as <name>.sunres.h (gen_sxe_resources.py --native-program).

  • SUN gets CreatePipe and CreateProcess with chosen handles. SXN_SYS_PIPE_CREATE (sxn_pipe_create) and SXN_SYS_SPAWN_EX (sxn_spawn_ex: stdio plus up to four handles at 3..6, nothing else), and SXN_SYS_TERMINATE now ends any descendant. See docs/userland/SUN.md.

  • The Start menu shows ▲/▼ arrows when its list does not fit. As in Windows 98, resting the pointer on a strip scrolls the list, and the arrow at an end is greyed. The scroll bar arrow is now shared as sxchrome_draw_arrow.

  • Native programs have a heap. system/runtime/sxn_runtime.c, linked into every native target (CMake NATIVE and build-user.sh --native), maps malloc's arenas through SXN, so malloc works past the 256 KiB bootstrap arena. See docs/userland/NATIVE_HEAP.md.

  • SXN_SYS_SPAWN_STDIO and SXN_SYS_SET_NONBLOCKING. A native process can start a child that gets only stdio, and make a pipe or device stop blocking (sxn_spawn_stdio, sxn_set_nonblocking); sessiond spawns that way.

  • SXN_SYS_PROCESS_QUERY tells a native process about any other. Parent, whether it is running or ended (with its exit code), handle count and name (sxn_process_query).

  • SXN_SYS_WAIT_MANY, and pipes and devices can be waited on. A native process waits for any of up to 16 handles (sxn_wait_many); a stream opened for reading counts as signaled while a read would not block, for native and POSIX waits alike. See docs/kernel/KERNEL_NATIVE_API.md.

  • sessiond, the session manager. A native process init now starts instead of windowd: it starts windowd, then the desktop and Program Manager, restarts the desktop, and restarts the whole session when windowd dies; session-smoke kills both and checks they come back. See docs/desktop/DESKTOP_ARCHITECTURE.md#the-session-manager-sessiond.

  • SXN_SYS_TERMINATE ends a child. A native process can end a process it spawned, with the exit status its waitpid will report (sxn_terminate); any other pid is refused. See docs/kernel/KERNEL_NATIVE_API.md.

  • Ports, and POSIX on the native floor. SXN_SYS_PORT_CREATE, _CONNECT and _ACCEPT let a process find a service by name (two pipes per connection), SXN_SYS_PIPE_SEND/RECEIVE_HANDLE pass handles natively, and POSIX processes can make the native object calls. See docs/kernel/KERNEL_NATIVE_API.md.

  • Native calls for handles, devices and time. SXN_SYS_CLOSE, _DUPLICATE, _READ and _WRITE (pipes and devices), _OPEN_DEVICE and _DEVICE_CONTROL (a device by bare name, the same control codes as ioctl) and _CLOCK, with sxn.h wrappers; native-test covers them.

  • Window roles and global hotkeys for the shell. gfx_window_open_role opens a panel (a reserved screen edge) or a popup (dismissable on an outside press); SAVANXP_WM_SHELL_REGISTER_HOTKEY (shell protocol v4) routes a key to the shell. See docs/desktop/DESKTOP_ARCHITECTURE.md.

  • Web Viewer (/bin/webview), a local HTML viewer in the spirit of IE 1.1. Opens .html/.htm files from disk, renders headings, paragraphs, lists, rules and entities in vertical flow, and ships with /disk/welcome.html as its sample page.

  • Web Viewer gains its browser chrome. An address bar with Go (file paths, file:// included), Back/Forward buttons with a history of visited paths on the buttons, the Go menu and Alt+Left/Right, plus /disk/about.html as a second sample page.

  • Web Viewer fetches http:// pages from numeric IPs, follows links and redirects, and shows source. Clickable blue underlined links, View Source on Ctrl+U, 3xx following for same-scheme locations, and honest errors where DNS or TLS would be needed.

  • Web Viewer paints a first CSS. Tag rules from <style> plus style="", over colour, background, alignment, bold (double-strike), underline and a two-face size; body rules and <body> attributes set the page colours, <font color> works.

  • Web Viewer resolves names through DNS. A minimal A-record client over UDP (numeric IPv4 stays a local fast path), with CNAME chasing, NXDOMAIN told apart, and dns:// plus --dns overrides pointing it at a test server.

  • The taskbar shows a W2K-style clock that opens a calendar. A sunken HH:MM readout (RTC in UTC, uptime fallback) whose click toggles a popup with the month grid (today highlighted) and a live HH:MM:SS, closed by toggle or outside click.

  • Manual date/time setting (/bin/date, SET_REALTIME). A new syscall writes the CMOS RTC (UTC, years 2000..2099, leap-aware validation); date prints it bare and sets it as date YYYY MM DD HH MM SS, and date-smoke covers set, reject and restore.

  • Automatic time sync (/bin/ntpsync, ntp-smoke). A one-shot SNTP client over UDP (numeric IPs, transmit + rtt/2, sane-range validation) that sets the RTC from the server, with a host fixture and a closed-port failure path in the smoke.

  • Paint (/bin/paint), in the Accessories group. A drawing sketchbook with the toolbox on the left, the colors on top and the canvas over a status bar; pencil, line, rectangle and ellipse tools, 16 color swatches and 24-bit BI_RGB BMP open/save. ./build.sh smoke paint-smoke covers the geometry plus a bit-exact save/load round-trip through --selftest.

  • Paint gains brush, eraser, picker and undo. The brush stamps ellipses along the drag (+/- size it), the eraser paints the background, the picker reads the pixel under the cursor, and every stroke pushes one of 8 document snapshots for Edit > Undo and Ctrl+Z. tools/shoot.sh --scenario paint drives tool switching by keyboard and asserts the status bar on screen.

  • Paint gains a flood-fill bucket. Clicking pours the current color into the exact-match 4-connected region under the cursor (iterative, with a visited set, so it always fits and always terminates); like every stroke it pushes undo first. Covered in --selftest (frame intact, no leaks) and in the paint visual scenario.

  • libsximg.so.0.4, a PNG decoder the tree builds and installs in /disk/lib. Reference implementation (no third-party code): inflate written from RFC 1951 plus the 8-bit truecolor/RGBA non-interlaced subset with all five filters, zlib-checked, alpha composited over white. savanxp-sximg-test proves the engine on the host (stored, fixed and dynamic blocks, RGB/RGBA, rejections); Paint maps it and opens .png through the same load path as BMP, with /disk/paint-test.png as its guest fixture.

  • --gui external applications link the window-chrome module. tools/build-user.sh was missing sxchrome.c, which the toolkit needs since the system 3D edges moved out of it, so no --gui binary outside the tree could link.

  • GitHub Actions CI (.github/workflows/ci.yml) on every push and pull request. In an archlinux:latest container it runs ./build.sh build, ./build.sh test, the Doom persistence check and the smoke, native-test, windowd-smoke and sxgui-smoke QEMU scenarios.

  • <dlfcn.h>: dlopen, dlsym, dlclose, dlerror and dladdr for PIE programs. Per-handle scopes with RTLD_LOCAL/RTLD_GLOBAL/RTLD_NOLOAD, dlsym through the handle's DT_NEEDED tree, constructors run, and a failed dlopen rolls back with the reason in dlerror(); dlclose never unmaps. New dltest scenario, also run by smoke. Step 1 of the Xash3D FWGS plan.

Changed

  • Every house icon is redrawn in a Windows 2000 look, each size drawn on its own: the system catalog, Shut Down, the media player, the Doom and Celeste ports and the tray speaker. The Tango file-type icons are unchanged. icon_file= now takes one PNG per size (icon_file=icon.png,icon-32.png). See docs/desktop/ICON_STYLE.md.

  • The Start menu draws each program's own 16x16 icon (progman_item_icon_small) instead of shrinking its 32x32 one; a binary with only a large icon is still shrunk.

  • Static programs map their ELF headers. linker.ld puts them at 0x400000 with the text right after, so sx_image_base is the header for every program; editing the script now relinks every static program.

  • The kernel schedules threads, not processes. process::Thread owns the saved context, kernel stack, FPU state and every wait; a process is the container. Each process has exactly one thread, so nothing visible changes yet: phase 0 of docs/kernel/THREADS_ROADMAP.md.

  • Disk writes are written back in the background. Physical disks queue writes in the block layer (block::write_cached, ordering points via block::flush) and the idle task drains them one bounded step at a time, so a write syscall no longer freezes the system for the device's duration (Doom's quit: 8–13 ms in write syscalls, was 247–293). Writes are durable once drained; sync, shutdown and reboot wait for it (block::sync_all). See docs/kernel/BLOCK_WRITEBACK.md.

  • Disk writes are ordered by explicit flushes. block::write_cached and block::flush join block::write; an SxFS commit flushes at its four ordering points instead of after every write, and file writes reach SxFS in pieces of up to 64 KiB instead of 256 bytes. Doom's quit spends 247 ms inside SxFS on virtio-blk instead of 522 ms. See docs/fs/SXFS_JOURNAL.md.

  • The libc FILE buffer is 4 KiB, allocated on first use instead of embedded in the stream pool, so fopen("w") plus fprintf grows a file in fewer, larger writes.

  • SxFS commits write only the metadata sectors that changed. The journal logs a sparse set (SXFS_JOURNAL_KIND_SPARSE) instead of a full metadata copy, so fscheck's bytes_per_commit drops from 1575424 to about 3872 and saving a file no longer freezes the system for seconds (Doom's in-game quit: 70.7 s → 0.53 s on IDE). Format stays v2; old full journals still replay, and mount validates home metadata after the replay. See docs/fs/SXFS_JOURNAL.md.

  • The taskbar's Start label uses the caption font. "Start" is drawn in SX_FONT_UI_TITLE, the title-bar face, standing in for the bold label of Win9x.

  • The visual harness opens programs through the Command Prompt. Session.run() and taskbar-smoke type start <program>; exit instead of walking Start menu > Program Manager; shoot.sh --scenario console replaces shell.

  • AltGr never triggers a hotkey. On layouts where it is Ctrl+Alt, AltGr plus a letter stays a character.

  • Program Manager no longer opens with the session. sessiond starts only compositord, windowd and desktop; Program Manager is opened from the Start menu (System), and session-smoke asserts it is not started.

  • The desktop's text is Wine's MS Sans Serif, crisp and 1-bit. SX_FONT_UI is its hand-drawn 13px bitmap strike instead of antialiased Noto Sans, so lines are 13px tall and layouts tighten; genfont.py sfd bakes it. Noto now only draws the boot wordmark. See docs/desktop/UI_FONTS.md.

  • malloc's page source is a replaceable hook. The arenas past the bootstrap one come from sx_heap_pages_map/sx_heap_pages_unmap (weak, savanxp/libc.h), so a native runtime can supply them; native-test asserts a native program gets the bootstrap arena only. See docs/userland/NATIVE_HEAP.md.

  • The platform services live in system/. compositord, windowd and sessiond moved out of subsystems/posix/userland/ into system/<service>/, built by savanxp_system_service (cmake/SystemServices.cmake); compositor_protocol.h moved to system/include/.

  • Application frames go straight to compositord. The submit event in the WM welcome is compositord's; requests get windowd's own event, asked for with SAVANXP_WM_HELLO_REQUEST_EVENT (older clients still work, their requests seen on windowd's tick). compositord-stats replaces windowd-stats. A pipe's handle queue holds eight handles instead of four.

  • compositord composes the desktop. windowd paints only its own surface (frames, the Alt+Tab switcher, the fallback background) and commits the scene; compositord maps the client surfaces, composes, presents and draws the cursor (compositor_protocol.h v5: ATTACH, DETACH, COMMIT). Frames now pace on the GPU's present event: shoot.sh --scenario spin on virtio-gpu went from ~61 to ~970 fps. See docs/desktop/DESKTOP_ARCHITECTURE.md#composition-in-compositord.

  • compositord is a session service. sessiond starts it before windowd; it allocates the display memory and opens the port compositord, which windowd connects to (compositor_protocol.h v4). Either one ending restarts the whole session; windowd no longer respawns compositord. See docs/desktop/DESKTOP_ARCHITECTURE.md, phase 4.

  • windowd is a native process. It speaks only the SXN API: windowd_sys.h maps the POSIX calls of its sources onto it (windowd_sys.c), text goes to /dev/serial. See docs/desktop/DESKTOP_ARCHITECTURE.md, phase 3.

  • compositord connects to windowd through a private port. windowd names the port on compositord's command line and hands over the display section as a handle, instead of a fork with descriptors 3, 4 and 5 (compositor_protocol.h v3).

  • Closing a window asks the program; a hung one gets an End Program dialog. The X and Alt+F4 request the close and the runtime ends a program that does not handle it (gfx_handle_close to answer yourself); windowd never kills. A program still running 5 s later shows "(Not Responding)" and the desktop offers End Now / Wait. See docs/desktop/DESKTOP_ARCHITECTURE.md#closing-a-window.

  • The shell role goes to a process the session started. The desktop asks for it with gfx_open_shell (SAVANXP_WM_HELLO_SHELL); windowd grants it only when the client's parent is its own parent or itself, one at a time. A client whose WM went away is asked to close.

  • Programs connect to windowd for a window (WM protocol v5). A client opens the port windowd, sends a hello with the launch flags its own .sxe declares, and gets its handles with the welcome; gfx_desktop_launch* now spawns the program in the caller, and windowd no longer forks clients, keeps a launch queue or uses fixed descriptors (surface header v5). Native clients use sxnwm_connect. External programs must be rebuilt. See docs/desktop/WM_SUBSYSTEM.md#descriptor-budget.

  • Each window publishes its own title, icon, accent and style. The runtime reads the program's .sxe at gfx_open (savanxp_wm_presentation in the surface header); windowd reads no binary for it and its per-path table is gone. External programs built earlier show their file name until rebuilt.

  • compositord is a native process. It speaks only the SXN API -- the GPU as a device with control codes, its pipes through native read/write -- and no POSIX. In-tree programs can be built native with NATIVE in cmake/UserPrograms.cmake (tools/stamp_osabi.py).

  • Ctrl+Esc opens the Start menu, Ctrl+Shift+Esc opens Task Manager, and Alt+Tab shows its own switcher. The keys are hotkeys the desktop registers (a fullscreen app leaves fullscreen first); the switcher is a box with the icon and title of the next window.

  • The shell is one /bin/desktop process. Wallpaper, taskbar, Start menu and the volume, clock and keyboard-layout popups are windows of it instead of six processes, so a popup opens without a launch; windowd no longer knows any of them, its fallback background is a solid colour, and it restarts a desktop that exits. The Start button stays sunken while the menu is open.

  • New app-paint and app-webview icons. Paint shows a palette with a brush and pencil in a cup, after the classic Windows Paint icon; Web Viewer is now a shaded globe.

  • The system edition is centralized as SAVANXP_EDITION. System Properties reads it from include/shared/version.h instead of a hardcoded string, and the boot splash and the desktop stamp now show it alongside the system name.

  • The native syscall dispatcher is a separate kernel unit. It now compiles as kernel/native_dispatch.cpp against the public process boundary instead of sharing process.cpp internals; syscalls and the POSIX fallback behave as before.

  • The kernel has an sx:: native surface. User-memory copy, current-process identity and errors live once in kernel/sx.cpp (include/kernel/sx.hpp); the native dispatcher speaks sx:: and the process:: wrappers keep drivers compiling untouched.

  • The POSIX dispatcher is a separate translation unit. It now compiles as subsystems/posix/kernel/posix_dispatch.cpp against the published process:: translation boundary instead of sharing process.cpp internals; numbers, errors and the blocking protocol behave as before.

  • The native ABI is standalone, with its first guest test. SXN_SYS_EXIT gives native processes their own minimal lifecycle via sx::exit_current, the < 0x1000 POSIX fallback is cut (any non-SXN number is ENOSYS), and sdk/nativetest proves it from the guest over raw syscalls (./build.sh smoke native-test, built with tools/build-user.sh --native).

  • Neutral sx:: sync primitives. Event, timer and semaphore constructors and signals live in kernel/sx.cpp; the process:: translation keeps flag parsing, access masks and handle allocation with identical errors and wakes.

  • Native spawn/wait (SXN_SYS_SPAWN, SXN_SYS_WAITPID). Backed by the published process:: machinery with waitpid_child as the shared core behind both WAITPID paths; sdk/nativetest self-spawns and checks ECHILD, reaped pid and child status.

  • Native event/section/wait syscalls plus the sxn.h userland surface. SXN_SYS_EVENT_CREATE/SET/RESET, SXN_SYS_WAIT_ONE and SXN_SYS_SECTION_CREATE/MAP_VIEW/UNMAP_VIEW ride the published cores over the shared handle table; header-only typed wrappers in include/sxn/sxn.h need no tool or link change, and sdk/nativetest proves cross-process sync plus shared memory through them. Native spawn clones the caller's handle table, so inherited handles arrive (POSIX spawn still takes stdio only).

  • First native window, proven inside real windowd. sdk/nativedemo paints a v4 client surface using SXN syscalls only (output-only: the input pipe stays unread) and a new windowd selftest launches it through the unchanged fork/dup2/exec path, composes it and samples the marker from the framebuffer (./build.sh smoke windowd-smoke).

  • Native input ring plus the sxnwm.h toolkit seed. windowd sniffs EI_OSABI at launch and routes input records to a shared ring on fd 7 for native clients (same 32-byte records, drop-when-full, wake signaled); header-only attach/submit/composed-wait/drain over a context struct, used by a demo that answers a key with green, proven end to end through the real router.

  • Native widgets with scripted interaction. Label, Button and Field over sxnwm.h with a hand 5x7 font in include/sxn/sxnwidgets.h; sdk/nativewidgets counts button clicks and typed text into state squares, and the selftest clicks, types and sends Esc through the real router, sampling the squares from the framebuffer.

  • Real PS/2 keys into a native form, native apps in the launcher. windowd --hw-native-test (scenario native-hw-smoke) drains /dev/input0 through the production path into nativewidgets while the host taps h, i, Esc over QMP, asserting the typed square from the framebuffer; both native demos ship .sxres with a menu category and progman --selftest asserts the scan lists them.

  • POSIX translation out of the kernel. The 33 POSIX-only process bodies (fds, fs, sockets, pipes, timers, semaphores, fork/kill, poll) move to subsystems/posix/kernel/posix_translation.cpp, sharing kernel machinery through the internal kernel/process_detail.hpp; lifecycle, scheduler and shared cores stay in kernel/process.cpp. docs/userland/NATIVE_APPS.md guides native programs with examples.

  • The kernel stops including the POSIX SDK. The shared wire contract moves to include/abi/savanxp_abi.h; the SDK keeps the POSIX vocabulary and includes it. kernel/ and include/kernel/ now depend on no userland header, and a layout guard keeps it that way.

  • The current directory leaves the process state. Each subsystem now declares its per-process private state and the kernel reserves it without reading it, so Process no longer carries a POSIX cwd; a native process declares zero bytes. New cwdtest asserts chdir/getcwd, relative resolution, fork inheritance and exec preservation.

  • The kernel no longer parks processes for poll(). The timer tick walked the process table re-evaluating POSIX poll requests; now a subsystem hook receives any process parked with a deadline and decides what it was waiting for. The request and its evaluation move to the POSIX subsystem's private state, taking 32 KiB of unconditional kernel memory with them.

  • POSIX signals leave the process state. The kernel's pending-signal flags were written and never read — this kernel has no signal delivery — so they existed only to name POSIX signals. The signal vocabulary moves to the POSIX subsystem; kill and waitpid behaviour is unchanged.

  • The smoke runner no longer leaves a QEMU behind when it is killed. Its cleanup runs in a finally, which does not run if the process is killed, so an aborted scenario used to leave a TCG machine spinning on a core indefinitely. QEMU now gets PR_SET_PDEATHSIG. Verified A/B: killing the runner mid-scenario leaves zero orphans with the fix and one without it.

  • A wedged disk is reset instead of failing the operation. A long write (390 KB, ~16,000 sectors, five minutes) used to die on a single exhausted status poll, with nothing in the whole chain retrying. Each command is now re-issued whole up to three times, and if those all fail the controller is reset by software and the command is retried again. Intermittent progman-smoke copy failures on a loaded host should stop with it.

  • The error space belongs to the kernel. Errors returned by the kernel are now sx_status/SX_E* rather than savanxp_error_code/SAVANXP_E*, with the POSIX names kept as aliases so existing programs are unaffected. The values are unchanged, so no userland-visible behaviour moves with this.

  • Native IPC proven over sections plus events. sdk/nativetest runs a 50-round ping-pong ring between parent and child with strict alternation (same shape as a WM submit/retire channel, no new syscalls); the windowed-client design is rendezvous by inheritance, with windowd native attach as slice 9 (see docs/kernel/KERNEL_NATIVE_API.md).

  • Neutral sx:: sections, views and waits. Section constructors, view map/unmap with the W^X and mask policy, and wait satisfaction/consumption live in kernel/sx.cpp; the process:: translation keeps flag parsing, file checks, handle allocation and clock/parking orchestration. One shared integer handle table per process, enforced by granted access, is the decided handle model (see docs/kernel/KERNEL_NATIVE_API.md).

Removed

  • The icon generators are no longer in the repository (tools/gen_desktop_source_art.py, the player's gen_icons.py): the checked-in PNGs are the source of the art, and the savanxp_desktop_source_art target exists only where a local copy of the generator does.

  • Eight redundant test programs. spawnloop, pipestress, waittest, errtest, demo, seektest, renametest and truncatetest are gone: sh, init, mv, truncate and the smoke suite already exercise the same paths. An existing build/disk.img keeps the stale copies.

  • SDK examples that duplicated in-tree programs. sdk/errdemo (same as sdk/hello), sdk/udptest and sdk/tcpget are gone; the in-tree udptest and tcpget remain.

  • shellapp, the old terminal window. The Command Prompt (/bin/console) replaces it in the Start menu and Program Manager, and the legacy icon=shell alias now points at it. An existing build/disk.img keeps its stale /disk/bin/shellapp until it is removed by hand.

  • The BusyBox port. vendor/busybox, vendor/busybox-port and /bin/busybox are gone; ls, cat, echo, mkdir [-p], rm [-rf], mv, cp [-r], ps, true, false and sleep are small in-tree programs (subsystems/posix/userland/coreutils).

  • The Task List. The taskbar, Alt+Tab and Task Manager cover switching, restoring and ending tasks (see docs/desktop/DESKTOP_ARCHITECTURE.md).

  • /bin/shellui, /bin/taskbar, /bin/startmenu, /bin/volumepopup, /bin/clockpopup and /bin/kbdlayoutpopup, now part of /bin/desktop, and the four shell launch flags (SAVANXP_DESKTOP_LAUNCH_FLAG_TASKBAR_POPUP, _START_MENU, _VOLUME_POPUP, _CLOCK_POPUP).

  • The Haxe native experiment is removed. subsystems/native (builder, SDK, apps, smoke scenarios) is gone and userland is C on the POSIX SDK only. The neutral savanxp_native_abi.h routing stays reserved for the future NT-style kernel API (see docs/userland/SYSTEM_LAYERING.md).

Fixed

  • clear in the Command Prompt no longer loses the prompt. The clear now travels in band (ESC [ 2 J) on the output pipe instead of the control channel; the cls control line is gone. The prompt lands on the top row, with no blank line before it, as after cls in cmd.

  • A process ended by SXN_SYS_TERMINATE no longer reads as running. When it was running on another core, SXN_SYS_PROCESS_QUERY reported it running until that core tore it down; it now reports it ended, with its status, as soon as TERMINATE returns.

  • Windows opened during a fullscreen app get the desktop's size. A taskbar, Start menu or window created while the screen ran in the 640x400 fullscreen mode kept that geometry after the restore, or was refused; windowd now lays every window out on the native mode (layout_display).

  • Paint no longer overwrites PNG files or resizes what it opens. Save on a PNG asks for a .bmp name instead of writing BMP bytes into the .png; opened images keep their own size; top-down BMPs load; a failed Save As keeps the old name; no-op strokes push no undo step.

  • IDE flushes reach the drive. FLUSH CACHE was written while the drive was still busy with the write before it, and dropped; it is now issued once BSY clears, so a commit is on the medium when it returns.

  • waitpid returns to the parent that is waiting, not to whoever waits first. A process in waitpid(-1) (init and sessiond always are) took any process's exiting child, so a shell waiting for its command in the graphical session waited forever.

  • Window titles are sharp. RetroSans was baked at 18px, off its 17px pixel grid, so over a third of every caption's pixels came out grey.

  • windowd-stats lines are back. Since windowd became native its clock read was a POSIX call that failed, so every frame was discarded as unmeasured.

  • A POSIX program started by a native one has its POSIX state. Spawning kept the parent's subsystem state even when the child's image is of another subsystem, so poll failed in it.

  • The kernel's text console no longer stalls the machine when it scrolls. It repainted the whole framebuffer for every line; it now writes only the glyph pixels that changed, which matters when it takes the screen back from the desktop.

  • Leaving fullscreen right after compositord died left the screen in the low mode. A mode change is now the first to notice a dead daemon and recovers it, as present does; and windowd kills a compositord that does not confirm its shutdown instead of waiting forever.

  • Minimizing a window from the taskbar left the next window's caption inactive. The window below became active but kept its gray caption until something else repainted it; taskbar-smoke now asserts it.

  • A clean checkout builds again. tools/check_shared_libs.py (run by every ./build.sh build), tools/glyphs.py (sxgui-smoke) and tools/qmp_native_hw.py (native-hw-smoke) were caught by the tools/* rule in .gitignore and had never been committed.

  • tools/verify_doom_persistence.sh runs on any host. Its scratch directory was created under a machine-specific /tmp/opencode; it now uses $TMPDIR (default /tmp).

  • ./build.sh test builds and passes again. The gfx2d, audio and ccleste-wav host tests find abi/savanxp_abi.h, the removed native-port-layout-test is no longer registered, and smoke-runner-layout-test reads docs/kernel/KERNEL_NATIVE_API.md.

  • The loader no longer holds a descriptor per library, nor leaks a failed load's segments. The handle of each executable segment stayed open for the life of the process, and a load that failed after mapping left its views in place.

Version 0.4.12026-10-23104 changes