Wuss picklepuss - #12
Merged
Merged
Conversation
dpt
commented
Sep 9, 2026
Owner
A single global wuss->hover_icon meant moving the pointer from a parent menu row into its submenu window switched the highlight to the submenu row and dropped it from the parent, unlike the RISC OS feel where every ancestor row on the open-submenu path stays lit. wuss__icon_set_hover now consults a new wuss__menu_row_pinned() before dropping the previous hover icon's highlight: a row that is some open chain level's open_index with a live child keeps its highlight. When a re-entering move closes a submenu, menu.c clears the ex-parent row's highlight explicitly unless the pointer landed on that row. Covers arbitrary nesting (walks the whole chain) and borrowed-window submenus (keyed off open_index/child). WUSS_ICONS can build without WUSS_MENUS, so the call site is #ifdef WUSS_MENUS guarded. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Drop the Test submenu (Menu / Menu-desc exercisers) and its static menu tree, the hidden Details window and the print-only fallback from the demo task launcher. The launcher menu is now just Launch / Quit Wuss. The descriptor-built menu (wuss_menu_create_from_desc) moves to the image task, opened on a MENU-button click, rebuilt on each open and freed at QUIT. image_task_t gains wuss / delegate / menu fields for it. tasks_teardown is gone with the last thing it freed; its call in main.c and declaration in tasks.h go too, along with the now-unused stdio.h, geom/box.h and wuss/menu-desc.h includes in tasks.c. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Move the result_t rc/err/crc local to the top of its declaration block, ahead of the other locals, keeping column alignment. Affects 45 functions across wuss core, menu/icon/component/helpers, the wuss test tasks, bmfont and the cache test. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The 2/3-height size was a temporary scroll-testing tweak; show the whole image.
wuss_proginfo is a shared WUSS_COMPONENTS helper modelled on the RISC OS Toolbox ProgInfo / "Info" dialogue: a small fixed window of Name / Purpose / Author / Version rows a task fills in once from a wuss_proginfo_desc_t, then hangs off its Menu-button pop-up as a wuss_menu_item_t.window. The dialogue window is created hidden, wuss_WINDOW_NO_CLOSE, on a task the caller passes in; it lays out from the task's font metrics with one right-justified label and one value per non-NULL field. wuss_proginfo_destroy closes the window and frees the handle. The owning task must not be an autoclose task (the hidden window would keep its window list non-empty) and must outlive the handle; as with any borrowed menu window, close any menu chain referencing it first. The image test task grows an "Info" row wired to a wuss_proginfo, and drops autoclose accordingly (QUIT now arrives via wuss_destroy). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The proginfo dialogue shares the image task, so image_handle receives REDRAW for it too and was blitting the bitmap behind its labels. Bail from the REDRAW case unless the event is for the task's own image window.
A window with this flag gets no wuss_EVENT_REDRAW: wuss fills its backdrop and draws its icons, and for a window whose appearance is entirely backdrop and/or icons that is the lot. Saves such a task a no-op redraw handler. wuss_proginfo sets it -- the dialogue is labels on white -- which also removes the need for the image test task to filter REDRAW by window handle now that the dialogue shares its task.
wuss_icon_spec_t gains `border` (wuss_icon_border_t: NONE / RIDGE / GROOVE), honoured by wuss_ICON_TYPE_LABEL and ignored by every other type. RIDGE is a 1px raised bevel, GROOVE a 1px sunken one -- a RISC OS-style read-only display field -- both in the window manager's bevel shades. Zero stays the current borderless look, so zero-initialised specs are unaffected. An out-of-range border on a label spec is result_WUSS_BAD_ICON.
Each value label now carries wuss_ICON_BORDER_GROOVE and is centred in its box, with a few pixels of padding added each side, matching the RISC OS ProgInfo look.
wuss_destroy closed doomed->menu_chain first, freeing the chain node, then delivered wuss_EVENT_QUIT. A QUIT handler that closes its own menu chain (via a wuss_menu_handle_t it still holds) then dereferenced the freed node before wuss_menu_close's stale-handle guard could fire -- a heap use-after-free at shutdown. Deliver QUIT to every registered task first, so a handler tears down its own windows and menu chain against live objects; the manager's own leftover-chain close and the z_order sweep then just find less to do. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Two more nearest-palette named colours for the conventional body fills: WINDOW is a light grey, MENU is white. Resolved the same way as the other wuss_COLOUR_* names, via the symbolic_rgb table in rebuild-palettecache. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
wuss_COLOUR_WINDOW / wuss_COLOUR_MENU move from the named-colour block (fixed RGB, nearest-palette) into the chrome-roles block, echoing two new wuss_config_t::body fields: body.window and body.menu. When config is NULL they default to wuss_COLOUR_GREY (light grey) and wuss_COLOUR_WHITE. Resolved and range-checked at wuss_create like backdrop, and always honoured regardless of WUSS_FURNITURE / WUSS_ICONS / WUSS_MENUS. BREAKING CHANGE: the numeric values of wuss_COLOUR_WINDOW and wuss_COLOUR_MENU changed (SYMBOLIC+9/+10 to SYMBOLIC+23/+24), and they no longer resolve to a fixed light-grey / white -- a caller wanting those must set wuss_config_t::body. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Menu windows now use wuss_COLOUR_MENU for their backdrop; the proginfo dialogue and the flat-fill demo windows (text, swatches) use wuss_COLOUR_WINDOW. Demos that draw their own backgrounds (wuss_NO_BACKGROUND) or pick a colour on purpose are left alone. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
fill_chrome_config left the new wuss_config_t::body sub-struct uninitialised on its stack config, so wuss_COLOUR_MENU / wuss_COLOUR_WINDOW resolved from garbage -- menu backdrops came out black. Extend g_chrome to carry body.window and body.menu per palette (PICO-8: light grey / white; WIMP16: 75% grey / white) and assign them. Cover both roles in the symbolic-colour test. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
wuss__icon_draw_label measured the label with target_width set to the box interior less 2px. A label whose text filled its box (the widest of a right-justified set) made bmfont_measure break early and return a short width, so pos.x = b->x1 - 1 - width placed it too far left; bmfont_draw then drew the full string and its right edge overhung the narrower labels. The proginfo dialogue's name column showed this as a ragged right edge. Measure the whole string (INT_MAX, no split) so every label's right edge lands at b->x1 - 1. Drop the now-unused interior_w/split_point locals. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
wuss__menu_click_outside and wuss_menu_open's replace-branch freed the whole menu chain without notifying the task that holds the wuss_menu_handle_t from wuss_menu_open. The task's stored handle then dangled, and its next wuss_menu_close (e.g. image.c on QUIT) was a heap-use-after-free. Add a wuss_EVENT_MENU_CLOSED task event, delivered to the chain's owner before the nodes are freed whenever wuss tears the chain down itself -- not for a pick (wuss_EVENT_MENU_SELECT covers that) nor for a wuss_menu_close the task made. Tasks drop their handle on it. A new wuss__menu_abandon helper is the single chokepoint for both internal close paths; it unlinks wuss->menu_chain before delivering so a re-entrant wuss_menu_close is a no-op. image.c also dropped its handle on a SELECT pick (same latent UAF). The wuss menu-move test now stores handles and asserts MENU_CLOSED fires on both the replace and the click-outside path, then calls wuss_menu_close on the now-NULL handle. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Two teardown paths left a menu chain's owner holding a freed wuss_menu_handle_t, so a QUIT handler that called wuss_menu_close on it faulted: - wuss_task_destroy closed the owner's chain with a bare wuss_menu_close, then delivered QUIT. A close_chain_on_quit-style handler then double-freed the chain. It now calls wuss__menu_abandon, which delivers wuss_EVENT_MENU_CLOSED first so the handle is dropped before QUIT. - wuss_destroy freed the internal wuss__menu_task in the same task sweep that fires client QUITs. A client QUIT handler closing a chain it still held then walked the freed menu task's window list (ASan heap-use-after-free in list_remove via wuss_window_close). The sweep now skips wuss__menu_task and tears it down last, after every client QUIT and the leftover-chain close. Retires the matching ponytail TODO. wuss__menu_abandon is de-static'd and declared in core impl.h. New two-phase wuss-test regression covers both paths; each phase reproduces its UAF when its fix is reverted. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
proginfo: tighten margins, add PROGINFO_ROW_LEADING so the label/value fields no longer abut -- rowh is the pitch, the field box is rowh minus the leading. icon draw: replace the four screen_draw_line calls for a LABEL icon's GROOVE/RIDGE border with two screen_draw_lines polylines (top+left, bottom+right). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
icon draw: widen the LABEL GROOVE/RIDGE border to two pixels by drawing the L-shaped hi/lo polyline pair twice, the second inset by one. proginfo: subtract one PROGINFO_ROW_LEADING from the window height so the bottom margin matches the top -- rowh is the pitch and the final row needs no trailing leading. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
New wuss_info component (component/info.h, component/info.c): builds a fixed label:value grid window from a wuss_info_row_t array -- measures the two columns, sizes the window from the task font, lays out two LABEL icons per row. This is the layout half that proginfo carried inline. proginfo is now a thin cap: wuss_proginfo_create maps the non-NULL desc fields to rows and calls wuss_info_create; wuss_proginfo_t is wuss_info_t and wuss_proginfo_destroy / _window are #define aliases. Public API and behaviour unchanged; the image test task still drives it as before. First consumer of a planned app-support component set; a second label:value dialogue will reuse wuss_info directly. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- info_widen helper folds the per-row strlen-guard + bmfont_measure pair into one call site each for label and value. - spec array moves to the stack (INFO_MAX_ROWS = 16 rows); drops the malloc, its OOM branch, the memset-with-cast and the matching free. nrows outside 1..INFO_MAX_ROWS is now result_BAD_ARG. - index specs[i*2] / [i*2+1] directly through named label/value pointers; nspecs, the alloc-copy alias and the llen/vlen locals go. Behaviour unchanged: wuss_icon_create deep-copies each spec and its text, and the font-absent path still yields rowh from MAX(0 + PAD, 12). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
New "Borders" group in the icons task: a framed pair of LABEL icons, one wuss_ICON_BORDER_GROOVE (sunken display field) above one wuss_ICON_BORDER_RIDGE (raised). ICONS_N_BORDERS keeps the spec-count enum in step. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The icons task hard-coded 0xBB/0xDD greys for its icon backgrounds and the crosshatch backdrop. Swap them for the wuss_COLOUR_WINDOW / wuss_COLOUR_GREY chrome roles so the demo tracks the configured colour scheme; keep the crosshatch texture by hatching GREY over WINDOW. task->paper stays a literal -- no public call resolves a symbolic wuss_colour_t to a concrete colour_t for the ruler glyph blend. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
lay.black is exactly black, so the wuss_COLOUR_BLACK symbol serves. lay.red stays on wuss_nearest_colour -- 0xCC3333 is an off-primary demo tone with no matching wuss_COLOUR_* symbol. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
New label border style: a 6px-per-edge "action" surround -- a 2px raised outset, a 2px moat in wuss_COLOUR_ACCENT_BG (the default-action-button fill), then a 2px raised inset -- for a RISC OS default-action look. wuss__icon_from_spec accepts it; the icons demo grows an "Action" example alongside Groove and Ridge. Factor the shared edge draw into screen_draw_bevel_edge(scr, box, a, b): one 2px bevel ring inside an inclusive-exclusive box, colour a top/left, b bottom/right, the bottom edge owning both corners so the ring closes cleanly. GROOVE/RIDGE draw one ring; ACTION nests three on boxes inset 0/2/4. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The two g_chrome rows were wrapped four-per-line, so matching a colour to its config field (fill_chrome_config assigns c[0]..c[16] in order) meant counting across. One constant per line, a blank between the palettes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
image_click now calls wuss_window_resize before wuss_window_set_doc so the visible frame tracks the new bitmap; set_doc alone only changed the scroll extent. Add an 8px solid PICO-8 pink band inset inside the ninepatch frame (IMAGE_BORDERSZ / IMAGE_MARGINSZ).
Add span_p1 (fill + blendconst, MSB-first bit packing) and register it, so bitmap_init hands out a valid span for pixelfmt_p1. Add a p1 case to screen_copy_bitmap: blit a 32bpp RGBA source onto a 1bpp screen, quantising to the 2-entry screen palette via the existing deep->paletted pixelmap fast path (pixelmap already handled p1). Alpha-tested transfer, both indices opaque. Cover both with tests: rgba8888->p1 in pixelmap-test, screen_copy_bitmap to a p1 screen (packing, spill, odd-x) in screen-test.
Add p1 plot paths to the screen primitives so the wuss demo can run on a monochrome framebuffer: - screen_set_pixel / screen_blend_pixel / screen_fill_pattern gain a p1 case, packed MSB-first to match PNG and the existing pattern bit order. - New pixelfmt_paletted_nentries() replaces the (scr->format == pixelfmt_p4) ? 16 : 0 hack at every colour_to_pixel call site, which passed nentries=0 (broken) for any non-p4 paletted screen. - bitmap_convert grows a p1 -> bgrx8888 path, used by the SDL frontend's per-frame display conversion. - apps/wuss: --depth 1 selects pixelfmt_p1 (stride (width + 7) / 8). - screen_copy_rect returns result_NOT_SUPPORTED for p1; callers fall back to redraw. Fix a latent bug in spanregistry_get(): its one-slot cache started with lastformat zero-initialised, which equals pixelfmt_p1 (the first enum member), so the first p1 lookup short-circuited to a NULL span and tripped the assert in screen_fill_hline. Seed lastformat with pixelfmt_unknown and guard the fast path on a non-NULL span. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Add p1 drawchar variants and a pixelfmt_p1 case to bmfont_draw's dispatch. A single bmfont_p1_plot_row helper does the per-pixel MSB-first bit write for both 1- and 2-byte glyph rows and both opaque and transparent backgrounds; the LUT-driven width unrolling the p4 path uses buys nothing for a plain bit write. The rest of bmfont_draw (log2bpp, shift, screen pointer math, native fg/bg via 1 << (1 << log2bpp)) already handles log2bpp == 0. Add pixelfmt_p1 to bmfont_test's format table. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Andrew's monotone chain over the active control points, drawn as a closed light-grey polyline before the curve and blobs. Also fixes the curve-type label origin: it used the per-redraw dirty piece (event->data.redraw.content) instead of the full content box (bounds), so a partial redraw drew the label at the wrong place. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Mirror the recent p1 work for pixelfmt_p2 (four palette entries, packed MSB-first: bits 7..6 of a byte are the leftmost pixel). - span/p2.c + span-p2.h: span_p2_fill and span_p2_blendconst, registered in the span registry. - screen-draw.c: screen_set_pixel_p2, screen_blend_pixel_p2 and screen_copy_bitmap_p2, wired into the three pixelfmt_log2bpp switches. - screen-fill-pattern.c: screen_fill_pattern_p2. - bitmap.c: bmconv_p2_to_bgrx8888 for bitmap_convert. - pixelmap and pixelfmt_paletted_nentries already handle p2 generically. - Tests: p2 cases in pixelmap-test.c and screen-test.c. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The SDL demo now accepts -d/--depth 2, selecting a pixelfmt_p2 framebuffer (stride (width + 3) / 4) alongside the existing 1, 4 and 32. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Add bmfont_p2_plot_row and the four bmfont_drawchar_p2_{1w,2w}_{o,t}
wrappers, dispatched from bmfont_draw's pixelfmt_p2 case. Two bits per
pixel, MSB-first, matching the screen p2 plot helpers. bmfont-test.c
exercises an 800x600 p2 screen.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Match the _p1/_p2/_p4 naming of the other paletted set-pixel helpers. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
SELECT and ADJUST clicks step the ordered-dither matrix forward and backward through 2x2, 4x4 and 8x8. Each matrix cell is mapped to a fixed -8..+8 offset regardless of matrix size, so a larger matrix gives a finer pattern rather than a noisier one (the 4x4 output is unchanged from before). The current size is drawn as a label in the content area's top-left corner. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds three small paletted bitmap faces under resources/bmfonts -- 04b_03, 04b_25 and Nokia -- plus tools/ttf2bmfont.py, which renders a TTF into the bmfont PNG format the loader expects. Registers the three new leafnames in bmfont_enumerate_test (bmfonts_enum_extra[], MAXFONTS_ENUM bumped to 12) so the fixture-directory walk still matches. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The NO_RESIZE_BLIT branch of wuss_window_resize invalidated the dirty region but never dropped the cached furniture layout, so wuss__furniture_draw kept painting titlebar/carve/outline rects at the previous frame's width. The blit branch gets this via wuss__chrome_repaint; add the equivalent wuss__chrome_invalidate_layout call here. Surfaced by the sample-text task (libraries/wuss/test/tasks/text.c), which resizes such a window every idle frame and drew its furniture inconsistently. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
box_intersection returns non-zero when the intersection is empty, but the guard negated it, so any non-NULL area that overlapped the bitmap returned early and painted nothing. Only area==NULL worked. Drop the negation to match screen_fill_pattern. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The decoder ran a bare for(;;) that only stopped on an EOL opcode, so a truncated or corrupt RLE blob (short data_len, missing EOL, bit-rot) read opcodes past the allocation. Every other row walker already threads an `end` limit; the decoder did not. Add the `end` parameter, stop at it, and have a reserved opcode bail to `end` (release builds previously did a bare `break`, desynchronising the caller's row cursor) so a bad blob decodes to nothing rather than garbage. bitmap_decompress now reads data_len from the blob header to form `end`; the two screen RLE blitters and the row round-trip test already had it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
bmfont_draw formed gid = c - ' ' from a raw signed char and used it to index adw[] and glyphs + gid*glyphbytes with no bounds check, so a tab, a DEL or any byte >= 0x80 (UTF-8/Latin-1) produced a negative or oversized index and an out-of-bounds read/write. bmfont_measure already filters c < ' ' and gid >= totalchars; apply the same guard in both of bmfont_draw's loops. Also give the fully-vertically-clipped case (clippedcharheight <= 0) a release-build bail: it was caught only by assert(), so an NDEBUG build would enter drawfn with a negative height and loop ~INT_MAX times. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…task wuss_destroy's task sweep delivered wuss_EVENT_QUIT and then wuss__free'd each task node without first setting wuss_TASK__REAPING. A QUIT handler that closed its last autoclose window hit wuss_window_close's self-destruct path (AUTOCLOSE set, REAPING clear, windows empty), which delivered a second QUIT and freed the node -- which the sweep then freed again. A handler calling wuss_task_destroy(self) hit the same double free via that function's own unlink-and-free. Set wuss_TASK__REAPING before QUIT in the sweep, matching wuss_task_destroy, and make wuss_task_destroy a no-op when the task is already being reaped. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The worst-case row estimate assumed one control byte per 128 pixels, but the encoder emits a 1-byte literal control for every isolated non-repeatable pixel. A legal y8 image of the form singleton, pair, singleton, pair, ... needs ~1.33*w bytes/row (literal-of-1 + repeat-of-2 per three pixels), overflowing the allocation and returning result_BUFFER_OVERFLOW on valid input. bpp >= 4 formats were hidden by the dominant w*bpp literal-data term. Budget w*(bpp+1) plus the literal-long split control and an EOL. Adds a y8 round-trip test on the pathological pattern. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The close furniture now routes through wuss_window_try_close, which fires PRE_CLOSE (vetoable) then CLOSE then frees the window. A task carried over from the pre-PRE_CLOSE contract may still treat CLOSE as "decide whether to keep the window" and hold its wuss_window_t past the handler -- now a use-after-free. Document the contract at the enum: drop the handle in CLOSE, put keep-open logic in PRE_CLOSE. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The loop ran x < src->size.w / 8 and expanded 8 pixels per iteration, so the final w % 8 pixels of each row were never written -- the output had uninitialised garbage columns for any width not a multiple of 8. It also walked src->base continuously, ignoring row padding in src->rowbytes. Switch to a per-pixel loop honouring both width and rowbytes, matching the p1 and p2 converters. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
wuss_window_set_hidden marked a window hidden but left wuss->furniture.dragging, wuss->pressed_icon and wuss->hover_icon pointing into it. Hiding a window mid-drag (from an event handler) meant the next wuss_mouse_move still took the dragging branch and drove wuss_window_move on an off-screen window every pointer report. Clear the same pointer state wuss_window_close does. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
scroll_strip always reserved size + WUSS_DIVIDER_PX at the far end for the resize corner, but scroll_strip_hit only reserves it when something owns that corner (a resize icon, or -- for the horizontal strip -- a vertical scrollbar). With a horizontal scrollbar and NO_VSCROLL and NO_RESIZE the drawn strip stopped short while the hit box ran to the visible edge: the rightmost size + 1 px band showed stale pixels yet hit-tested as HSCROLL_WELL and started a scrollbar drag over empty chrome. Give scroll_strip the same far-end rule. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The fallback claimed wuss_FURNITURE_RESIZE for a whole bottom or right carve band whenever a resize icon was present, and a scroll well for an edge with no scrollbar strip. A click on the bare carve band left of the corner icon (NO_TITLEBAR, NO_VSCROLL, NO_HSCROLL, !NO_RESIZE) then started a resize far from the visible handle. Only hand off to a scroll well when that scrollbar's strip runs the full edge; the resize corner already has its own hit box, so every other edge pixel is frame -> TITLE or CONTENT. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The comment promises a release build no-ops rather than dereferencing NULL, but the guard tested only scr->span and then called scr->span->fill(...). A span registered without a fill entry would pass the check and call through a NULL pointer. Test scr->span->fill too, matching the assert. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Covers every commit since the last CHANGELOG touch (0ba5456): the 1bpp/2bpp paletted format work across bitmap/span/screen/bmfont and the wuss demo, the curve-task convex hull, the ttf2bmfont generator, the gradient-task dither cycling, the screen_set_pixel_8 -> _p8 rename, and the run of correctness fixes from the wuss-picklepuss review (RLE bounds, bmfont glyph range check, task double-free, fill-pattern clip test, p4 conversion, hidden-window pointer state, scroll strip / hit-region mismatch). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.