Commit graph

1,792 commits

Author SHA1 Message Date
Admin
3370d15264 box3d: perf round 3 — many_pyramids 1.28x -> 1.06x vs C, now within 5% of rapier-simd
Disassembly-driven (fork agents confirmed the stalls, killed the
bounds-check and recycle-rate hypotheses with instruction-level and
runtime-counter evidence — recycle counts are bit-identical to C):

- Manifolds inline-when-single store: Contact.manifolds Vec<Manifold> ->
  enum { None, One(Manifold), Many(Vec) } with deref-as-slice. Convex
  contacts keep their manifold inline (the Rust equivalent of C's block-
  allocator arena locality — the per-contact heap chase was the main
  stall in collide/prepare/store). Contact is #[repr(C)] with manifolds
  last so hot header fields stay on the leading cache lines. Public
  ContactData API unchanged via Deref; contact_solver.rs needed zero
  changes. Pure storage change: determinism hash identical (0x61E35C31).
- #[inline(never)] on update_contact + the four convex stage functions:
  C compiles these standalone; LLVM had inlined all of them into one
  13.6 KB execute_block paying constant register-spill traffic.

Definitive cold-machine matrix: serial geomean 1.15x -> 1.12x vs C
(many_pyramids 2071 vs 1949 ms, large_pyramid 1501 vs 1392); 8-worker
geomean 1.35x -> 1.30x. vs rapier-simd (adjacent runs): box3d ahead 16%
on large_pyramid and 3% on joint_grid, behind 5% on many_pyramids (was
21%). README grids updated.

179/185/179 tests green, zero warnings, hash unchanged across workers/
arch/task systems.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 15:14:52 +02:00
Admin
630577cb98 rapier: restore simd-stable (vendor wide + safe_arch), retest vs box3d
Re-vendors wide 0.7 + safe_arch, restores the upstream simd-stable
wiring in rapier3d/parry3d manifests and the cfg-simd source, and drops
the added 'stripped build does not support SIMD' guards (upstream's
simd-vs-enhanced-determinism exclusivity guard kept).

Interleaved single-thread retest (min of 4): SIMD buys rapier 1.8-2.2x;
box3d vs rapier-simd is now near parity — large_pyramid 1579 vs 1638 ms,
joint_grid 957 vs 1008 ms (box3d ahead), many_pyramids 2389 vs 1970 ms
(rapier ahead). box3d README grid updated with the honest three-column
table; box3d keeps cross-arch determinism + zero deps at that speed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 14:17:26 +02:00
Admin
470cffcdac box3d: rapier comparison — ~2x faster single-threaded, bench in libs/rapier/crates/bench
Same scenes/geometry/materials/dt, matched solver budget (4 substeps vs
4 solver iterations), interleaved min-of-4 runs: large_pyramid 2.23x,
many_pyramids 1.82x, joint_grid 1.88x (geomean ~1.97x). Table + fairness
notes at the top of the box3d README (vendored rapier has no SIMD;
enhanced-determinism measured free on these scenes).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 13:54:05 +02:00
Admin
35c256a76d box3d: perf round 2 — 8-worker geomean 1.47x -> 1.35x vs C, serial 1.15x
- joint prepare: read BodySim through references (was deref-copying
  220 bytes twice per joint per step; prepare_joint now at C parity)
- FMA contraction extended to joint solvers (32 sites; hash re-baselined
  to 0x61E35C31, still bit-identical across workers/arch/task systems)
- scheduler: workers spin ~tens of us before committing to a kernel
  sleep (semaphore try_acquire spin phase; A/B: large_world w=8
  24 -> 11.5 ms, joint_grid w=8 1.58x -> 1.49x, other scenes neutral;
  intentional deviation from C documented in README)
- tried and reverted: chunks_exact twin-pair edge SAT (won 5% on
  junkyard compounds, cost box-box scenes 4-8%; keeps C 1:1 loop shape)
- README: fresh benchmark matrix, second-round notes, stale external
  task-hook claim fixed

179/185/179 tests green, zero warnings.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 11:09:25 +02:00
Admin
364d65680a box3d: performance pass — serial geomean 1.30x -> 1.13x vs C, 8-worker 1.6x -> 1.47x
Profiling-driven (sample + disasm comparison vs clang -O3). All changes
safe Rust except one debug_assert-guarded extension of the existing
SyncSlice unsafe contract. Determinism preserved: hash bit-identical
across workers 1/2/4, NEON/SSE2/scalar, internal/external task systems
(new baseline 0x9018E2D8 after approved FMA contraction).

- f32/f64::mul_add contraction in hot scalar math (= C's -ffp-contract=on;
  89 sites; wide SIMD ops untouched like C intrinsics). large_pyramid
  now at parity with C (1387 vs 1373 ms serial)
- FloatW::get/set: direct lane load/store instead of vector-through-stack
  round trip; layout asserted at compile time
- gather_bodies by reference (removes 20-register spill storm)
- per-worker capacity-preserving scratch for convex + mesh collide paths
  (C-arena equivalent; mesh path allocated per triangle and serialized
  the parallel collide pass on allocator locks)
- update_contact: borrow shapes instead of cloning (deep compound
  geometry clones + cross-worker Arc traffic; junkyard w=8 -39%)
- scheduler semaphore: two-level atomic fast path (C uses
  dispatch_semaphore_t; old Mutex+Condvar locked every enqueue)
- SyncSlice::get_ref/get_mut unchecked indexing under the existing
  unsafe contract, debug_assert-guarded (-6% serial)
- README/PORTING: new numbers, FMA sync conventions, known remainders

179/185/179 tests green (default/double-precision/disable-simd), zero
warnings.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 09:10:44 +02:00
Admin
995aa23bc1 box3d: recording replay player + test_recording port
Full op-stream player in recording_replay.rs (b3RecPlayer port):
opcode dispatch for ~150 ops, StateHash verification at every step
marker, query replay with bitwise comparison, keyframe ring with
budget-driven interval doubling, seek/restart/scrub, validate_replay.

tests/test_recording.rs ports test_recording.c (17 tests incl.
record-at-4-workers/replay-at-1-and-4 hash equality). 179/185/179
tests green across default/double-precision/disable-simd, zero
warnings, determinism hash unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 16:06:18 +02:00
Admin
dfa0b07753 box3d: recording op stream (capture side)
All ~140 opcodes from recording_ops.inl with exact C values, capture hooks
in every mutator and query (~137 sites across body/shape/joint/world),
48-byte header with registry locator backpatch, snapshot seed, query tag
interning, state-hash anchors per step. Recording is observer-only
(bit-identical world state with and without a recording attached).
Replay/player side lands separately.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 16:06:18 +02:00
Admin
ec3378b060 box3d: external task-system hooks + makepad 3D example
- WorldDef enqueue_task/finish_task/user_task_context (C contract incl.
  null-return-means-inline); TaskSystem dispatch (Serial/Internal/External)
  replaces the bare scheduler; determinism hash bit-identical through an
  external thread-per-task system.
- examples/box3d: makepad app rendering the live simulation (offscreen 3D
  pass with depth, orbit/zoom camera, instanced lit boxes/spheres, 204-box
  pyramid + spheres, 4-worker solver, Space to reset).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 16:06:18 +02:00
Admin
66b42fc9dd box3d: multithreading — scheduler, parallel_for, atomic solver stages
Port of the C threading design: worker threads with a fixed task ring and
help-while-waiting finish (scheduler.rs), atomic block-claiming parallel_for,
and the solver's stage machinery (per-block syncIndex CAS, sync-bits stage
advancement, mainClaimed race). Parallel narrow phase, broad-phase pairs,
sensors, finalize. Shared access goes through documented disjointness
primitives (sync.rs: SyncPtr/SyncSlice/AtomicIndex); worker_count 1 keeps the
serial path bit-identically. Results are bit-identical at any worker count
(determinism hash 0x7A796F4F asserted at 1/2/4 workers). 8 workers: 3.4-5.7x
over serial on heavy scenes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 16:06:18 +02:00
Admin
88f7d7a2c6 box3d: reuse per-step solver and broad-phase scratch allocations
Persist solver constraint arrays/spans/stage blocks and broad-phase pair
query buffers across steps instead of reallocating each world_step.
Bit-identical results (determinism hash unchanged); washer -7.6%, small
wins on trees/rain, pairs stage -6% on junkyard. A contact-manifold
reuse attempt regressed pyramid scenes and was dropped.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 16:06:18 +02:00
Admin
60ec705ab2 box3d: SIMD (SSE2/NEON), double-precision large world, snapshots, benchmarks
- contact solver wide ops + V32 now have real SSE2 and NEON paths selected
  by target arch; scalar fallback behind the disable-simd feature. All three
  paths are bit-identical (cross-arch determinism verified: same ragdoll
  hash on NEON, SSE2 under Rosetta, and scalar).
- double-precision feature (C BOX3D_DOUBLE_PRECISION): f64 world positions
  with the exact C boundary-function semantics; enables the far-from-origin
  test halves (157 tests in DP mode, 151 default).
- world snapshots: recording substrate subset (buffer/writers/geometry
  registry/readers) + world_snapshot.c port; bit-identical continuation
  after restore, corrupt-image rejection.
- examples/benchmark.rs: all 10 C benchmark scenarios; serial Rust runs
  1.05-1.55x slower than C -O2 at one worker (geomean ~1.3x with fat LTO).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 16:06:18 +02:00
Admin
848e715c6c box3d: pure Rust port of Box3D (erincatto/box3d @ 29bf523)
Full engine port in libs/box3d: math, geometry, GJK/TOI, hull builder,
dynamic tree, manifolds, constraint graph, solver (serial, scalar SIMD
path), all 8 joint types, sensors, mover, world API. 147 ported C unit
tests green in debug and release. See libs/box3d/README.md for the
upstream revision and sync notes, PORTING.md for conventions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 16:06:18 +02:00
Kevin Boos
30eeae75ca
View: add fn for toggling optimize and force texture caching (#1136)
* TextInput: expose the location of the caret/cursor

in absolute window-relative coordinates.

THis allows, for ex, a widget to be placed relative to the
current location of the text being inputted by the user.

* View: add fn for toggling `optimize` and force texture caching

Add CachedView fns that make it easier to control its parameters:
* set_optimize(cx, ViewOptimize): switch optimize mode at runtime and
  allocate the draw_list on demand. Previously `optimize` was set once from
  `texture_caching` and never reset, so a view couldn't toggle between direct
  and texture-cached rendering per frame.
* set_texture_max_height(Option<f64>): cap the Texture-mode render turtle's
  height so a tall Fit-height cached view can't allocate a render target past
  the GPU's max texture size (was a hard MTLTextureDescriptor abort once
  content exceeded 16384px). None (default) leaves it uncapped; content past
  the cap is clipped. Only affects Texture mode.
* redraw_texture_cache() / force_texture_redraw: force one offscreen
  re-render after a content repopulate or an optimize-mode flip. The
  rect-based will_redraw check can't see a content change on a recycled or
  toggled view, so without this it would composite a stale texture.
* view_size is now updated in every optimize mode, not just draw-list modes.
  The None (direct-render) path previously left it stale, so a view toggled
  None<->Texture sized its next offscreen turtle from an old height and
  clipped/mis-positioned its content.
2026-07-02 08:34:19 +02:00
Kevin Boos
c65b72efad
TextInput: expose the location of the caret/cursor (#1132)
in absolute window-relative coordinates.

THis allows, for ex, a widget to be placed relative to the
current location of the text being inputted by the user.
2026-07-02 08:34:04 +02:00
Admin
3a82d26045 hypothetical heap access fix 2026-07-01 14:04:23 +02:00
Kevin Boos
cb93fa9822
android: don't make the surface invisible, that destroys it (#1134)
Setting MakepadSurface to be `INVISIBLE` in the pause path will
destroy that surface and cause system overlays to flash/flicker for a moment.
2026-06-30 09:42:03 +02:00
Admin
82abd655b9 history 2026-06-26 16:47:13 +02:00
Admin
a4c87a64dd animating buttons 2026-06-26 16:46:24 +02:00
Admin
e7939c8f14 animating bg 2026-06-26 15:49:25 +02:00
Admin
6c3c3252bf animating bg 2026-06-26 15:34:54 +02:00
Admin
c50a74b3b7 glass style 2026-06-26 14:06:57 +02:00
Admin
5cb5219d23 parse {}{} as {},{} 2026-06-26 13:37:17 +02:00
Admin
a6c7a22ba8 glass centering 2026-06-26 13:07:21 +02:00
Admin
283ef5553a cargo 2026-06-26 10:29:06 +02:00
Admin
02592599ec aichat 2026-06-25 18:52:10 +02:00
Admin
837da0d7bd aichat: track glass splash.md doc & fix runtime path
- Rename splash2.md -> splash.md so the tracked doc matches what aichat
  references via include_str!/read_to_string (a clean clone now builds).
- Fix the live-read path (CARGO_MANIFEST_DIR was ../../../ = one dir above
  the repo, loading a stale doc); now ../../splash.md -> repo-root glass doc.
- Full repaint (cx.redraw_all) on Clear/remove so self-managed glass overlay
  draw lists aren't left composited stale.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 16:41:49 +02:00
Admin
7861ecb10e splash: replace splash2.md with updated Splash DSL guide
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 16:13:11 +02:00
Admin
cba6d6ff7e aichat 2026-06-25 16:11:42 +02:00
Admin
ac10a82c34 aichat otw 2026-06-25 16:11:42 +02:00
Admin
3ad65e8bd3 glass kit more 2026-06-25 16:11:42 +02:00
Admin
725a726e3d glass kit more 2026-06-25 16:11:42 +02:00
Admin
374fa0c285 gloop glass radio 2026-06-25 16:11:42 +02:00
Admin
f91b0fa0bd gloop glass radio 2026-06-25 16:11:42 +02:00
Admin
70062ed86b gloop glass radio 2026-06-25 16:11:42 +02:00
Admin
ba0306d4ee Add glass_panel widget example; restore rustfmt guard
- New GlassPanel widget (widgets/src/glass_panel.rs) + lib export
- gauss_view: honor surface_alpha for translucent glass surfaces
- examples/glass: standalone demo (wired into Cargo workspace + makepad.splash)
- rustfmt.toml: re-enable disable_all_formatting to stop rustfmt from
  reformatting the whole tree on save

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 16:11:42 +02:00
Kevin Boos
82db45a00c
parse and use orientation info for all supported image formats (#1130) 2026-06-23 09:08:45 +02:00
Kevin Boos
a13b8876a5
code editor: support proper Fit size bound with max height value (#1128) 2026-06-22 19:54:30 +02:00
Admin
d37a34f24e move after draw demo 2026-06-16 17:45:59 +02:00
damien
7aae8d6ffe
fix: hot reload broken when file contains script_apply_eval! calls (#1124)
script_apply_eval! expands to a ScriptMod{file, line, column, ...} with
its code field prefixed by __script_source__. This adds a runtime body
to the VM just like script_mod! does, so collect_compiled_sites_for_file
counts it toward the compiled-site total for that file.

The file extractor (extract_script_mods_from_rust_file) only scans for
the script_mod! macro pattern, so any file with N script_apply_eval!
calls and M script_mod! calls causes:

  hot reload could not match script_mod! blocks for <file>:
  runtime has N+M, file has M

Skip __script_source__ bodies in collect_compiled_sites_for_file. These
are Rust-driven runtime evals, not static DSL blocks, so the extractor
cannot match them and hot reload cannot update them anyway.

Fixes hot reload for files that mix script_mod! with script_apply_eval!.
2026-06-16 09:09:08 +02:00
Kevin Boos
e4e1585b05
TextInput: infer soft-keyboard input_mode from content_type if its unset (#1125)
* Support standard keyboard navg shortcuts/keys in TextInput

Implement platform-standard TextInput navigation and deletion behavior,
including Home, End, PageUp, PageDown, word movement, line/document
boundaries, and Shift-based selection.

* Use Apple Option/Cmd conventions on Apple targets
* Use Ctrl conventions on non-Apple targets
* Web accepts both shortcut styles for now, since we don't have a way
  to query the host OS from within a makepad web env.

Also, be extremely careful to ensure that we respect Unicode grapheme boundaries
when doing all the selection/navigation logic.

Fix `Delete`, which was erroneously handled before.

Add lots of missing keys in Linux X11 & Wayland backends, e.g.,
Home, End, Delete, Insert, PageUp/PageDown, and arrow keys

* Add `CropToFill` image fit variant, improve ImageFit docs

This allows you to easily achieve the "centered cropped fit" that most apps
want for things like avatars or small thubmnails that get masked.

* Detect and support hardware keyboards, distinguish from soft/virtual kbd

Mimic desktop behavior on mobile systems as much as possible.
This is esp important for tablets like iPad OS where you're more likely
to have a real physical keyboard attached.

For iOS:
* Arrow keys and Home/End/PageUp/PageDown navigate and auto-repeat
  at the system-defined rate (connected via `UIKeyCommand`)
* Cmd+Enter to submit a `TextInput` and Cmd+C/X/V clipboard shortcuts now work.
* Ensure the pop-up diacritic/accent menu is properly placed using a hidden
  `UITextInput` native widget, which acts as a sort of "proxy"
* Proactively drain `ShowTextIME` after each draw so the IME position will be
  properly updated after each keystroke.
* Importnatly, don't mark the IME dismissed when a hardware keyboard is attached.

For both iOS & Android:
* Add a `has_physical_keyboard()` detection mechanism across both backends,
  and fix platform-specific key repeat behavior

For Android:
* Ensure clipboard cut/copy works using the same Ctrl shortcuts (API 26+)

Soft/virtual keyboard/IME changes:
* For multiline TExtInputs, a soft keyboard Enter/Return key will always just
  insert a new line, to avoid complexity with keyboard shortcut cfgs.
* CJK keyboard character selection should also be properly positioned now

* minor optimization to avoid re-setting IME pos if it didn't change

* Ensure inline composition is still shown in TextInput on all platforms

This is mostly relevant when using CJK and other similar IMEs.
Previously Makepad didn't shown any "echoes" of the single latin chars
that the user would type, but it would correctly input the selected CJK
glyph. So if you typed `nihao` and then selected `你哈`, then you would
see the proper chinese characters but not the latin "nihao".
Tha't s a bit confusing while typing.

Summary of the fixes per platform:

macOS:
- `set_marked_text` now forwards the marked (composition) text to the
  focused TextInput with `replace_last = true`; previously it only stored
  it in an ivar. `unmark_text` clears the preview, and both it and
  `insert_text` share a new `clear_marked_text_ivar` helper so a commit
  doesn't emit a second, destructive text-input event.

Windows:
- Add `WM_IME_COMPOSITION` handling: commit `GCS_RESULTSTR`
  (`replace_last = false`) and show `GCS_COMPSTR` inline
  (`replace_last = true`), and clear on `WM_IME_ENDCOMPOSITION`. The
  message is consumed so DefWindowProc neither draws its own composition
  window nor synthesizes a duplicate WM_CHAR for the result.
- Extend the vendored `windows` binding with `ImmGetCompositionStringW`,
  `GCS_COMPSTR`/`GCS_RESULTSTR`, and `WM_IME_COMPOSITION`/
  `WM_IME_ENDCOMPOSITION`, which it didn't previously generate.

Linux (Wayland):
- Handle the `zwp_text_input_v3` `PreeditString` event (previously empty)
  and apply the double-buffered preedit/commit state on `Done`, in the
  protocol-mandated order (commit, then preedit), clearing the preview
  when a cycle carries no preedit.

Linux (X11):
- Create the input context with XIM on-the-spot (`XIMPreeditCallbacks`)
  and forward the preedit string from the draw/start/done callbacks,
  falling back to `XIMPreeditNothing` if the IM server doesn't support
  callbacks. Callbacks run inside `XFilterEvent`, so they only mutate a
  thread-local that the event loop drains into the widget afterward,
  avoiding re-entrant access to the app.

Android:
- Don't mark the IME dismissed when a physical keyboard is attached
  (mirrors the iOS guard). Android was unconditionally calling
  `text_ime_was_dismissed()` on soft-keyboard hide, which tore down the
  IME connection that hardware-key composition relies on.

* iOS: replace custom `UITextInput` with a native `UITextView`

`UITextView` is a full system-native keyboard client, so we get all the
major features for free: language HUD pill and the complete globe/Ctrl+Space
shortcut to cycle between IMEs/languages.

Makepad basically just mirrors the state of the system native text view,
via the `full_state_sync`, but the actual native text view is kept invisible
so it doesn't interfere with what we render in Makepad's TextInput.
Notably, the Full Keyboard Accessibility setting now does work properly,
whereas it did not before with our UITextInput-based approach.

We also make sure that arrow keys, nav keys, auto-repeat, and modifiers
are properly hanlded so we can retain the expected kbd shortcuts,
like other desktop platforms.

* iOS: remove the old `UITextInput` connection with the Makepad TextInput

We've now switched to the native UITextview, so we don't need this any more.

* iOS: fix desync during fast typing

Ensure there's no race between the native UITextView and
Makepad's TextInput, as the Enter/REturn key needs special handling
w.r.t. how `pressesBegan` gets it (From a real hardware kbd).

* TextInput: more iOS integration, and text input types

more native integration for things like username/password,
new password fields, email, address, URLs, etc.
These tell iOS to change the keyboard layout/type for the text input.

* iOS: don't let Full Keyboard Access focus on our hidden native cursor

* cleanup

* iOS/TextInput: fix perf issues

* iOS TextInput: more fixes for read-only efficiency, and filtered input

Also port some of these fixes to Android's IME integration layer

* iOS/TextInput: hide the native caret iOS draws during autocorrect

but still allow the "decline autocorrect" bubble to popup where that
hidden caret is located (and the CJK candidate window in the same spot)

* Avoid script VM re-entrant panic: defer animator_cut/play if script VM is held

`animator_cut` / `animator_play` call `cx.with_vm`, which panics
(*"Script VM swapped off"*) when invoked during an apply walk — e.g. a
widget's `on_after_apply` on `ScriptReapply` / `Reload` — because the VM
is already taken for the duration of that walk's enclosing `cx.with_vm`.

- The derive macro's `animator_cut_scoped` / `animator_play_scoped` now
  check `cx.is_script_vm_held()`; when held, they queue the op
  (`defer_cut` / `defer_play`) and return instead of re-entering the VM.
- `animator_handle_event_scoped` replays the queue via `flush_deferred`
  on the next frame, once the VM is free.

The defer path runs **only** in the formerly-panicking case, so VM-free
animations are byte-for-byte unchanged.

Also adds a re-entrancy-naming panic (`VmHolderGuard`) plus
`Cx::try_with_vm` / `Cx::is_script_vm_held` for diagnosing and handling
this class of bug.

* Better spacing/positioning for IME popups like the CJK candidate menu

applied to all platforms, but primarily an issue on macOS/iOS.

The candidate/conversion window (e.g. CJK pinyin) was covering the line of
text being composed. Carry the caret-line rect (not just a point) through
ShowTextIME and feed each backend its native "keep clear of this line" API,
so the OS places the candidate directly above/below the line with a small gap:

- macOS: firstRectForCharacterRange returns the line rect via AppKit
  convertRect:toView:nil + convertRectToScreen (drops the hand-rolled
  screen-coord math + fudge offsets); invalidate on caret move.
- Windows: ImmSetCandidateWindow with a CFS_EXCLUDE line rect.
- Wayland: set_cursor_rectangle with the real line rect.
- X11: XNSpotLocation/XNArea at the line.
- iOS: return the true composing-line box from firstRectForRange so iOS flips
  around the real edges (consistent at any screen position) instead of a
  degenerate point; only while marked text is active, to avoid an oversized
  autocorrect highlight when typing normally.

* Fix Linux X11 behavior: Ctrl-based kbd shortcuts didn't work in TextInput

also trying to fix X11 behavior for positioning the CJK candidate window,
turns out there was an X11 bug for Ubuntu 22 and older so it's not always
possible, but we can attempt a workaround if errors occur (based on that,
we try to auto-detect the version of X11)

* fix X11 event loop latency by draining only a max of 64 events before redrawing

still working on X11 CJK candidate window positioning...

* add logs to X11 ime to figure out wtf is going on

* more robust fallbacks for X11 CJK candidate window positioning... grr

* maybe try to set the XFontSet attribute? for CJK candidate positioning

* positioning works now but there is a bit of overlap still

* now that X11 CJK candidate positioning works in some cases,
we need to pass the full rectangle containing the current line of text
to the X11 library so that it can position the window both on top
and beneath the current line of text, if needed.

* tweaking X11 CJK candidate positioning

* abandon the screen-positioning heuristic

Instead, we just send the bounding rect of the current text character
and hopefully let the X11 platform libs decide where to put the
CJK candidate popup

* add more spacing to the bounding rect on X11

* tweak for a bit more space between CJK candidate window

* more tweaks, rect height isn't being respected for some reason...

* attempting to add more instrumentation to figure out wtf is going on with X11 CJK positioning

* remove bad instrumentation that was causing freezes. ugh

* different approach for IME placement on X11

* previous positioning attempts for X11 didn't work.

New strategy: let it be positioned, and then try to move it

* still trying to fix X11 CJK candidate window positoining...

* trying to find CJK candidate window with X11 queries (To move it)

* abandon window scanning approach

* better approach, now just tweaking it

* fix one case where the candidate window was flipped but it pointing too low

* tweaking more

* trying to fix above-text line positioning

* still trying to tweak CJK candidates ABOVE the text line

* be more conservative when guessing whether X11 will show the CJK candidate above or below

* improve size heuristic for CJK candidate height

* calling X11 as complete now. jfc. Cleanup, remove debug logs, etc

* TextInput: infer soft-keyboard `input_mode` from `content_type` if its unset

New functon: `effective_input_mode()` will now derive a keyboard layout
from the `content_type`, if one was provided and if it makes sense to infer.

Explicitly setting the `input_mode` will always take precendence.
2026-06-16 09:08:10 +02:00
Kevin Boos
af130e98fd
Limit cache growth for text/script, reclaim memory after gc (#1123)
* Run script-VM gc in the desktop and mobile event loops, not just macOS

Only macOS was calling the script VM's garbage collector.
Now we call it everywhere, based on the original implementation in macOS.

* Limit cache growth for text/script, reclaim memory after gc

This PR includes several misc improvements to reduce memory usage and/or
return unused memory to the OS properly.

- slug atlas: reset the append-only curve buffer past a cap (mirrors the raster
  atlas reset: cleared at the prepare_textures boundary, forcing a rebuild), so
  it no longer accumulates every distinct large glyph ever rendered.
- script heap: in gc(), truncate the String reuse pool and shrink over-allocated
  free-list/slot capacity (never moves a live slot, so all refs stay valid).
- font outline cache: cap per-font distinct-glyph entries (clear-on-exceed).
- image cache: evict Loaded entries past a cap; widgets keep their own texture
  clones so displayed images are unaffected, and in-flight loads are preserved.

The string intern table is intentionally left unbounded: it backs stable
pointer-based FontId/FontFamilyId, and is bounded by the few distinct font names.
2026-06-16 09:07:53 +02:00
Kevin Boos
529f7d7720
Ensure inline composition is still shown in TextInput on all platforms (#1109)
* Support standard keyboard navg shortcuts/keys in TextInput

Implement platform-standard TextInput navigation and deletion behavior,
including Home, End, PageUp, PageDown, word movement, line/document
boundaries, and Shift-based selection.

* Use Apple Option/Cmd conventions on Apple targets
* Use Ctrl conventions on non-Apple targets
* Web accepts both shortcut styles for now, since we don't have a way
  to query the host OS from within a makepad web env.

Also, be extremely careful to ensure that we respect Unicode grapheme boundaries
when doing all the selection/navigation logic.

Fix `Delete`, which was erroneously handled before.

Add lots of missing keys in Linux X11 & Wayland backends, e.g.,
Home, End, Delete, Insert, PageUp/PageDown, and arrow keys

* Add `CropToFill` image fit variant, improve ImageFit docs

This allows you to easily achieve the "centered cropped fit" that most apps
want for things like avatars or small thubmnails that get masked.

* Detect and support hardware keyboards, distinguish from soft/virtual kbd

Mimic desktop behavior on mobile systems as much as possible.
This is esp important for tablets like iPad OS where you're more likely
to have a real physical keyboard attached.

For iOS:
* Arrow keys and Home/End/PageUp/PageDown navigate and auto-repeat
  at the system-defined rate (connected via `UIKeyCommand`)
* Cmd+Enter to submit a `TextInput` and Cmd+C/X/V clipboard shortcuts now work.
* Ensure the pop-up diacritic/accent menu is properly placed using a hidden
  `UITextInput` native widget, which acts as a sort of "proxy"
* Proactively drain `ShowTextIME` after each draw so the IME position will be
  properly updated after each keystroke.
* Importnatly, don't mark the IME dismissed when a hardware keyboard is attached.

For both iOS & Android:
* Add a `has_physical_keyboard()` detection mechanism across both backends,
  and fix platform-specific key repeat behavior

For Android:
* Ensure clipboard cut/copy works using the same Ctrl shortcuts (API 26+)

Soft/virtual keyboard/IME changes:
* For multiline TExtInputs, a soft keyboard Enter/Return key will always just
  insert a new line, to avoid complexity with keyboard shortcut cfgs.
* CJK keyboard character selection should also be properly positioned now

* minor optimization to avoid re-setting IME pos if it didn't change

* Ensure inline composition is still shown in TextInput on all platforms

This is mostly relevant when using CJK and other similar IMEs.
Previously Makepad didn't shown any "echoes" of the single latin chars
that the user would type, but it would correctly input the selected CJK
glyph. So if you typed `nihao` and then selected `你哈`, then you would
see the proper chinese characters but not the latin "nihao".
Tha't s a bit confusing while typing.

Summary of the fixes per platform:

macOS:
- `set_marked_text` now forwards the marked (composition) text to the
  focused TextInput with `replace_last = true`; previously it only stored
  it in an ivar. `unmark_text` clears the preview, and both it and
  `insert_text` share a new `clear_marked_text_ivar` helper so a commit
  doesn't emit a second, destructive text-input event.

Windows:
- Add `WM_IME_COMPOSITION` handling: commit `GCS_RESULTSTR`
  (`replace_last = false`) and show `GCS_COMPSTR` inline
  (`replace_last = true`), and clear on `WM_IME_ENDCOMPOSITION`. The
  message is consumed so DefWindowProc neither draws its own composition
  window nor synthesizes a duplicate WM_CHAR for the result.
- Extend the vendored `windows` binding with `ImmGetCompositionStringW`,
  `GCS_COMPSTR`/`GCS_RESULTSTR`, and `WM_IME_COMPOSITION`/
  `WM_IME_ENDCOMPOSITION`, which it didn't previously generate.

Linux (Wayland):
- Handle the `zwp_text_input_v3` `PreeditString` event (previously empty)
  and apply the double-buffered preedit/commit state on `Done`, in the
  protocol-mandated order (commit, then preedit), clearing the preview
  when a cycle carries no preedit.

Linux (X11):
- Create the input context with XIM on-the-spot (`XIMPreeditCallbacks`)
  and forward the preedit string from the draw/start/done callbacks,
  falling back to `XIMPreeditNothing` if the IM server doesn't support
  callbacks. Callbacks run inside `XFilterEvent`, so they only mutate a
  thread-local that the event loop drains into the widget afterward,
  avoiding re-entrant access to the app.

Android:
- Don't mark the IME dismissed when a physical keyboard is attached
  (mirrors the iOS guard). Android was unconditionally calling
  `text_ime_was_dismissed()` on soft-keyboard hide, which tore down the
  IME connection that hardware-key composition relies on.

* iOS: replace custom `UITextInput` with a native `UITextView`

`UITextView` is a full system-native keyboard client, so we get all the
major features for free: language HUD pill and the complete globe/Ctrl+Space
shortcut to cycle between IMEs/languages.

Makepad basically just mirrors the state of the system native text view,
via the `full_state_sync`, but the actual native text view is kept invisible
so it doesn't interfere with what we render in Makepad's TextInput.
Notably, the Full Keyboard Accessibility setting now does work properly,
whereas it did not before with our UITextInput-based approach.

We also make sure that arrow keys, nav keys, auto-repeat, and modifiers
are properly hanlded so we can retain the expected kbd shortcuts,
like other desktop platforms.

* iOS: remove the old `UITextInput` connection with the Makepad TextInput

We've now switched to the native UITextview, so we don't need this any more.

* iOS: fix desync during fast typing

Ensure there's no race between the native UITextView and
Makepad's TextInput, as the Enter/REturn key needs special handling
w.r.t. how `pressesBegan` gets it (From a real hardware kbd).

* TextInput: more iOS integration, and text input types

more native integration for things like username/password,
new password fields, email, address, URLs, etc.
These tell iOS to change the keyboard layout/type for the text input.

* iOS: don't let Full Keyboard Access focus on our hidden native cursor

* cleanup

* iOS/TextInput: fix perf issues

* iOS TextInput: more fixes for read-only efficiency, and filtered input

Also port some of these fixes to Android's IME integration layer

* iOS/TextInput: hide the native caret iOS draws during autocorrect

but still allow the "decline autocorrect" bubble to popup where that
hidden caret is located (and the CJK candidate window in the same spot)

* Avoid script VM re-entrant panic: defer animator_cut/play if script VM is held

`animator_cut` / `animator_play` call `cx.with_vm`, which panics
(*"Script VM swapped off"*) when invoked during an apply walk — e.g. a
widget's `on_after_apply` on `ScriptReapply` / `Reload` — because the VM
is already taken for the duration of that walk's enclosing `cx.with_vm`.

- The derive macro's `animator_cut_scoped` / `animator_play_scoped` now
  check `cx.is_script_vm_held()`; when held, they queue the op
  (`defer_cut` / `defer_play`) and return instead of re-entering the VM.
- `animator_handle_event_scoped` replays the queue via `flush_deferred`
  on the next frame, once the VM is free.

The defer path runs **only** in the formerly-panicking case, so VM-free
animations are byte-for-byte unchanged.

Also adds a re-entrancy-naming panic (`VmHolderGuard`) plus
`Cx::try_with_vm` / `Cx::is_script_vm_held` for diagnosing and handling
this class of bug.

* Better spacing/positioning for IME popups like the CJK candidate menu

applied to all platforms, but primarily an issue on macOS/iOS.

The candidate/conversion window (e.g. CJK pinyin) was covering the line of
text being composed. Carry the caret-line rect (not just a point) through
ShowTextIME and feed each backend its native "keep clear of this line" API,
so the OS places the candidate directly above/below the line with a small gap:

- macOS: firstRectForCharacterRange returns the line rect via AppKit
  convertRect:toView:nil + convertRectToScreen (drops the hand-rolled
  screen-coord math + fudge offsets); invalidate on caret move.
- Windows: ImmSetCandidateWindow with a CFS_EXCLUDE line rect.
- Wayland: set_cursor_rectangle with the real line rect.
- X11: XNSpotLocation/XNArea at the line.
- iOS: return the true composing-line box from firstRectForRange so iOS flips
  around the real edges (consistent at any screen position) instead of a
  degenerate point; only while marked text is active, to avoid an oversized
  autocorrect highlight when typing normally.

* Fix Linux X11 behavior: Ctrl-based kbd shortcuts didn't work in TextInput

also trying to fix X11 behavior for positioning the CJK candidate window,
turns out there was an X11 bug for Ubuntu 22 and older so it's not always
possible, but we can attempt a workaround if errors occur (based on that,
we try to auto-detect the version of X11)

* fix X11 event loop latency by draining only a max of 64 events before redrawing

still working on X11 CJK candidate window positioning...

* add logs to X11 ime to figure out wtf is going on

* more robust fallbacks for X11 CJK candidate window positioning... grr

* maybe try to set the XFontSet attribute? for CJK candidate positioning

* positioning works now but there is a bit of overlap still

* now that X11 CJK candidate positioning works in some cases,
we need to pass the full rectangle containing the current line of text
to the X11 library so that it can position the window both on top
and beneath the current line of text, if needed.

* tweaking X11 CJK candidate positioning

* abandon the screen-positioning heuristic

Instead, we just send the bounding rect of the current text character
and hopefully let the X11 platform libs decide where to put the
CJK candidate popup

* add more spacing to the bounding rect on X11

* tweak for a bit more space between CJK candidate window

* more tweaks, rect height isn't being respected for some reason...

* attempting to add more instrumentation to figure out wtf is going on with X11 CJK positioning

* remove bad instrumentation that was causing freezes. ugh

* different approach for IME placement on X11

* previous positioning attempts for X11 didn't work.

New strategy: let it be positioned, and then try to move it

* still trying to fix X11 CJK candidate window positoining...

* trying to find CJK candidate window with X11 queries (To move it)

* abandon window scanning approach

* better approach, now just tweaking it

* fix one case where the candidate window was flipped but it pointing too low

* tweaking more

* trying to fix above-text line positioning

* still trying to tweak CJK candidates ABOVE the text line

* be more conservative when guessing whether X11 will show the CJK candidate above or below

* improve size heuristic for CJK candidate height

* calling X11 as complete now. jfc. Cleanup, remove debug logs, etc
2026-06-16 09:07:32 +02:00
Kevin Boos
bc13b891e5
iOS: replace custom UITextInput with a native UITextView (#1121)
* iOS: replace custom `UITextInput` with a native `UITextView`

`UITextView` is a full system-native keyboard client, so we get all the
major features for free: language HUD pill and the complete globe/Ctrl+Space
shortcut to cycle between IMEs/languages.

Makepad basically just mirrors the state of the system native text view,
via the `full_state_sync`, but the actual native text view is kept invisible
so it doesn't interfere with what we render in Makepad's TextInput.
Notably, the Full Keyboard Accessibility setting now does work properly,
whereas it did not before with our UITextInput-based approach.

We also make sure that arrow keys, nav keys, auto-repeat, and modifiers
are properly hanlded so we can retain the expected kbd shortcuts,
like other desktop platforms.

* iOS: remove the old `UITextInput` connection with the Makepad TextInput

We've now switched to the native UITextview, so we don't need this any more.

* iOS: fix desync during fast typing

Ensure there's no race between the native UITextView and
Makepad's TextInput, as the Enter/REturn key needs special handling
w.r.t. how `pressesBegan` gets it (From a real hardware kbd).

* TextInput: more iOS integration, and text input types

more native integration for things like username/password,
new password fields, email, address, URLs, etc.
These tell iOS to change the keyboard layout/type for the text input.

* iOS: don't let Full Keyboard Access focus on our hidden native cursor

* cleanup

* iOS/TextInput: fix perf issues

* iOS TextInput: more fixes for read-only efficiency, and filtered input

Also port some of these fixes to Android's IME integration layer

* iOS/TextInput: hide the native caret iOS draws during autocorrect

but still allow the "decline autocorrect" bubble to popup where that
hidden caret is located (and the CJK candidate window in the same spot)
2026-06-12 09:12:26 +02:00
Kevin Boos
4f1f545ef3
Linux: fix desktop close/terminate lifecycle handling (#1120)
This avoids a strange case where Linux (both X11 and wayland but
in different ways) failed to properly shut down cleanly.

* Fix X11 close handling by removing destroyed windows from the map,
  which helps avoid delivering duplicate window closed events.
* Restructure how close handling happens on Wayland too, and allow
  the app to respond to a close request just like other platforms.
* Add a Linux second-signal hard exit so that repeated Ctrl+C
  or `kill` comands can actually terminate a failed/hung shutdown.
* Also a tiny fix to windows too: clear Win32 `GWLP_USERDATA` during
  `WM_DESTROY` to avoid accessing an old window pointer.
2026-06-11 22:12:28 +02:00
Kevin Boos
585475d02a
Fix modal behavior: prevent scroll behind it, make Fit{max} scrollable (#1117)
* Ensure that a view that specifies Fit with a max value can be scrolled.
* Turtle: include a view's outer maring in the size calc for a `Fit{max}` bound.
* Modal: dismiss on Escape KeyUp (not KeyDown) so the release can't leak to a
  background widget behind the modal.
* Modal: allow scrolling, and reset the scroll to the top when showing it.
* Touch-baased dragging for views (ScrollBar) and PortalList now respect
  the blocked scrolling areas, not just the mouse wheel / trackpad scroll.
* Forward the `set_scroll_pos()` through the widget derive traits so that
  we don't have to hook it up for each specific widget.
2026-06-11 22:12:09 +02:00
Kevin Boos
bb1474003c
SVG: allow replacing and re-loading the SVG "doc" (#1116)
Without this, once you load an SVG for the first time,
you can never change it. This meant that you couldn't change
a buttton's icon, for example, at runtime, even using a script apply.

Now that works, at no cost too, since we track which SVG body/"doc"
has been loaded to ensure we're not re-loading it on every draw
(which was already there, it was just too strict).
2026-06-09 21:04:52 +02:00
Kevin Boos
8b2e7e3eb0
iOS: fix hardware kbd behavior with "Full Keyboard Access" enabled (#1113)
* Support standard keyboard navg shortcuts/keys in TextInput

Implement platform-standard TextInput navigation and deletion behavior,
including Home, End, PageUp, PageDown, word movement, line/document
boundaries, and Shift-based selection.

* Use Apple Option/Cmd conventions on Apple targets
* Use Ctrl conventions on non-Apple targets
* Web accepts both shortcut styles for now, since we don't have a way
  to query the host OS from within a makepad web env.

Also, be extremely careful to ensure that we respect Unicode grapheme boundaries
when doing all the selection/navigation logic.

Fix `Delete`, which was erroneously handled before.

Add lots of missing keys in Linux X11 & Wayland backends, e.g.,
Home, End, Delete, Insert, PageUp/PageDown, and arrow keys

* Add `CropToFill` image fit variant, improve ImageFit docs

This allows you to easily achieve the "centered cropped fit" that most apps
want for things like avatars or small thubmnails that get masked.

* Detect and support hardware keyboards, distinguish from soft/virtual kbd

Mimic desktop behavior on mobile systems as much as possible.
This is esp important for tablets like iPad OS where you're more likely
to have a real physical keyboard attached.

For iOS:
* Arrow keys and Home/End/PageUp/PageDown navigate and auto-repeat
  at the system-defined rate (connected via `UIKeyCommand`)
* Cmd+Enter to submit a `TextInput` and Cmd+C/X/V clipboard shortcuts now work.
* Ensure the pop-up diacritic/accent menu is properly placed using a hidden
  `UITextInput` native widget, which acts as a sort of "proxy"
* Proactively drain `ShowTextIME` after each draw so the IME position will be
  properly updated after each keystroke.
* Importnatly, don't mark the IME dismissed when a hardware keyboard is attached.

For both iOS & Android:
* Add a `has_physical_keyboard()` detection mechanism across both backends,
  and fix platform-specific key repeat behavior

For Android:
* Ensure clipboard cut/copy works using the same Ctrl shortcuts (API 26+)

Soft/virtual keyboard/IME changes:
* For multiline TExtInputs, a soft keyboard Enter/Return key will always just
  insert a new line, to avoid complexity with keyboard shortcut cfgs.
* CJK keyboard character selection should also be properly positioned now

* minor optimization to avoid re-setting IME pos if it didn't change

* Image support: add bmp/qoi,ico, webp, SVG in `Image` widget, 16-bit png

Generally, this commit makes improvements to image decoding and rendering.

Added a bunch of functions for image discovery / metadata gathering:
`decode_image_from_data()`, `image_size_by_data()`, `looks_like_svg()`

Added more `Image[Ref]` functions for other image formats:
`ImageRef::load_{bmp,qoi,ico,gif,webp,svg}_from_data()`, plus a nice
convenience fn for auto-detec+load: `load_image_from_data()`.

Added cheap, lazily-init'd support for SVGs within the `Image` widget.

Fixed some issues with aspect ratio being clobbered during image rotation.

* iOS: fix hardware kbd behavior with "Full Keyboard Access" enabled

That accessibility setting messed with our previous version, but now
we've made it play nicely with FKA.

It's not *quite* perfect yet, we still don't get the nice little
system-native "pill" pop-up that allows you to easily switch between
the languages/IMEs you've enabled. But it sort of works.
2026-06-09 10:01:57 +02:00
Kevin Boos
8b03b0b2ad
Audit and harden image decoding stuff against huge inputs (DoS) (#1110)
* Image support: add bmp/qoi,ico, webp, SVG in `Image` widget, 16-bit png

Generally, this commit makes improvements to image decoding and rendering.

Added a bunch of functions for image discovery / metadata gathering:
`decode_image_from_data()`, `image_size_by_data()`, `looks_like_svg()`

Added more `Image[Ref]` functions for other image formats:
`ImageRef::load_{bmp,qoi,ico,gif,webp,svg}_from_data()`, plus a nice
convenience fn for auto-detec+load: `load_image_from_data()`.

Added cheap, lazily-init'd support for SVGs within the `Image` widget.

Fixed some issues with aspect ratio being clobbered during image rotation.

* Audit and harden image decoding stuff against huge inputs (DoS)

Bound the size of the decoded image, pixel count, frame counts (for animated),
range of SVG sniffing, and encoded file size.
Only once we run those checks do we actually alloc a buffer for the decoded image. before allocating decode buffers. Validate

Add various other checks within the vendored image decoding libraries too.
2026-06-09 00:31:36 +02:00
Kevin Boos
f5df1eb4d1
Layout/turtle fixes: right-wrap flows could cut off the right side of widgets (#1114)
Especially in right-aligned view rows (`Align: {x: 1.0}`), the turtle logic
wasn't accounting for spacing nor alignment when deciding to wrap.
Now those are taken into account, so we don't get weird cut-off views.
2026-06-09 00:10:47 +02:00
Kevin Boos
850edc8ca6
Image support: add bmp/qoi,ico, webp, SVG in Image widget, 16-bit png (#1108)
Generally, this commit makes improvements to image decoding and rendering.

Added a bunch of functions for image discovery / metadata gathering:
`decode_image_from_data()`, `image_size_by_data()`, `looks_like_svg()`

Added more `Image[Ref]` functions for other image formats:
`ImageRef::load_{bmp,qoi,ico,gif,webp,svg}_from_data()`, plus a nice
convenience fn for auto-detec+load: `load_image_from_data()`.

Added cheap, lazily-init'd support for SVGs within the `Image` widget.

Fixed some issues with aspect ratio being clobbered during image rotation.
2026-06-09 00:09:29 +02:00