From 01ca2c55248d35b58ce5e5ebfc8e6c4794e09050 Mon Sep 17 00:00:00 2001 From: ymote <151983+ymote@users.noreply.github.com> Date: Fri, 2 Oct 2026 10:23:26 -0700 Subject: [PATCH] Repin the runtime to makepad 39a9de88 (OpenHarmony idle and input, GL GPU timing, terminal shortcuts) Makepad main 39a9de88 adds a hidden map's idle frame loop fix (#79), Android HTTP without redirects (#75), the sheets font by crate (#80), Linux GL remote grabs (#93), Android Vulkan without a debug messenger (#92), the touch-down power hint (#83), GL GPU timing (#81), atlas text on phones (#82), the DrawText current-list fix (#89), terminal keyboard shortcuts (#76) and the terminal on OpenHarmony (#91), and OpenHarmony's keyboard, Studio, GL lifetimes and idle frames (#84, #85, #88, #87), through Octoscript-Makepad 62760863 (#70). makepad #90 is not in it. - root Cargo.toml: makepad and octoscript-makepad revisions together; native-apps.json (Sheets, Terminal), regenerated pins unchanged otherwise - both native-runtime.lock.json files - runtime-patches.lock.json: the settings patch is rebased onto 39a9de88 with the same added and removed lines; its touch-down line in MakepadActivity.java now sits next to #83's hint, and draw_text.rs context follows #87's cfg. The system-back, IME and two Windows patches reapply unchanged. The map, OpenHarmony GL-lifetime and DrawText patches are dropped: they are makepad #79, #88 and #89, now upstream. New tree 976bf55b. - Cargo.lock: unchanged - the pinned-hash docs under phone/docs; rom/docs/home-build.md follows in its own change, so this one does not trigger rom.yml (whose jobs local CI cannot run) Co-Authored-By: Claude Opus 5.5 --- Cargo.toml | 34 +- apps/appcard/native-runtime.lock.json | 2 +- native-apps.json | 4 +- native-runtime.lock.json | 2 +- phone/docs/build-tool.md | 4 +- phone/docs/makepad-fork.md | 12 +- runtime-patches.lock.json | 23 +- ...makepad-drawtext-current-list-redraw.patch | 56 --- .../makepad-map-hidden-no-frame-loop.patch | 80 ---- .../makepad-ohos-gl-lifetimes.patch | 361 ------------------ tools/runtime-patches/makepad-settings.patch | 144 +++---- 11 files changed, 108 insertions(+), 614 deletions(-) delete mode 100644 tools/runtime-patches/makepad-drawtext-current-list-redraw.patch delete mode 100644 tools/runtime-patches/makepad-map-hidden-no-frame-loop.patch delete mode 100644 tools/runtime-patches/makepad-ohos-gl-lifetimes.patch diff --git a/Cargo.toml b/Cargo.toml index 78c83828..8653183d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -66,36 +66,36 @@ authors = ["octos-app contributors"] # BEGIN native-apps: pins (generated by tools/native_apps.py from native-apps.json; do not edit) rinx = { git = "https://github.com/hagency-org/Rinx.git", tag = "v1.1.0", default-features = false, features = ["octosense-module"] } octosense-reference = { path = "apps/reference" } -makepad-sheets = { git = "https://github.com/OctoSense-org/makepad.git", rev = "e29a0eaa68781231eb9ec582e5f02648c6dad7e9", default-features = false } -makepad-terminal = { git = "https://github.com/OctoSense-org/makepad.git", rev = "e29a0eaa68781231eb9ec582e5f02648c6dad7e9" } +makepad-sheets = { git = "https://github.com/OctoSense-org/makepad.git", rev = "39a9de88e1af14a9d660887c453fc3102c610411", default-features = false } +makepad-terminal = { git = "https://github.com/OctoSense-org/makepad.git", rev = "39a9de88e1af14a9d660887c453fc3102c610411" } octosense-appcard = { path = "apps/appcard/module" } octosense-app-hub-app = { git = "https://github.com/OctoSense-org/OctoSense-App-Hub", rev = "58c3c8aed8fc811a16d67c5f784a8a44214ff876" } # END native-apps: pins # --- Makepad (OctoSense-org/makepad), the revision Octoscript-Makepad's # runtime.json pins (native-runtime.lock.json); resolved to .sources/makepad. -makepad-widgets = { git = "https://github.com/OctoSense-org/makepad.git", rev = "e29a0eaa68781231eb9ec582e5f02648c6dad7e9" } +makepad-widgets = { git = "https://github.com/OctoSense-org/makepad.git", rev = "39a9de88e1af14a9d660887c453fc3102c610411" } # The script VM alone: system apps' script tests (News's main.splash). -makepad-script = { git = "https://github.com/OctoSense-org/makepad.git", rev = "e29a0eaa68781231eb9ec582e5f02648c6dad7e9" } -makepad-code-editor = { git = "https://github.com/OctoSense-org/makepad.git", rev = "e29a0eaa68781231eb9ec582e5f02648c6dad7e9" } -makepad-ai = { git = "https://github.com/OctoSense-org/makepad.git", rev = "e29a0eaa68781231eb9ec582e5f02648c6dad7e9" } -makepad-studio-protocol = { git = "https://github.com/OctoSense-org/makepad.git", rev = "e29a0eaa68781231eb9ec582e5f02648c6dad7e9" } -makepad-network = { git = "https://github.com/OctoSense-org/makepad.git", rev = "e29a0eaa68781231eb9ec582e5f02648c6dad7e9" } -makepad-wm-api = { git = "https://github.com/OctoSense-org/makepad.git", rev = "e29a0eaa68781231eb9ec582e5f02648c6dad7e9" } -makepad-ai-services = { git = "https://github.com/OctoSense-org/makepad.git", rev = "e29a0eaa68781231eb9ec582e5f02648c6dad7e9" } -makepad-strict-json = { git = "https://github.com/OctoSense-org/makepad.git", rev = "e29a0eaa68781231eb9ec582e5f02648c6dad7e9" } -makepad-app-module = { git = "https://github.com/OctoSense-org/makepad.git", rev = "e29a0eaa68781231eb9ec582e5f02648c6dad7e9" } -makepad-wm-theme = { git = "https://github.com/OctoSense-org/makepad.git", rev = "e29a0eaa68781231eb9ec582e5f02648c6dad7e9" } -makepad-aichat = { git = "https://github.com/OctoSense-org/makepad.git", rev = "e29a0eaa68781231eb9ec582e5f02648c6dad7e9", default-features = false } +makepad-script = { git = "https://github.com/OctoSense-org/makepad.git", rev = "39a9de88e1af14a9d660887c453fc3102c610411" } +makepad-code-editor = { git = "https://github.com/OctoSense-org/makepad.git", rev = "39a9de88e1af14a9d660887c453fc3102c610411" } +makepad-ai = { git = "https://github.com/OctoSense-org/makepad.git", rev = "39a9de88e1af14a9d660887c453fc3102c610411" } +makepad-studio-protocol = { git = "https://github.com/OctoSense-org/makepad.git", rev = "39a9de88e1af14a9d660887c453fc3102c610411" } +makepad-network = { git = "https://github.com/OctoSense-org/makepad.git", rev = "39a9de88e1af14a9d660887c453fc3102c610411" } +makepad-wm-api = { git = "https://github.com/OctoSense-org/makepad.git", rev = "39a9de88e1af14a9d660887c453fc3102c610411" } +makepad-ai-services = { git = "https://github.com/OctoSense-org/makepad.git", rev = "39a9de88e1af14a9d660887c453fc3102c610411" } +makepad-strict-json = { git = "https://github.com/OctoSense-org/makepad.git", rev = "39a9de88e1af14a9d660887c453fc3102c610411" } +makepad-app-module = { git = "https://github.com/OctoSense-org/makepad.git", rev = "39a9de88e1af14a9d660887c453fc3102c610411" } +makepad-wm-theme = { git = "https://github.com/OctoSense-org/makepad.git", rev = "39a9de88e1af14a9d660887c453fc3102c610411" } +makepad-aichat = { git = "https://github.com/OctoSense-org/makepad.git", rev = "39a9de88e1af14a9d660887c453fc3102c610411", default-features = false } # --- OctoScript (Octoscript 5991dfae) and its Makepad runtime -# (Octoscript-Makepad 8f103d0c, native-runtime.lock.json). +# (Octoscript-Makepad 62760863, native-runtime.lock.json). octoscript-ui-l0 = { git = "https://github.com/OctoSense-org/Octoscript.git", rev = "5991dfae9344589e732b2605b530f788e8bbcd11" } # The bounded VM, capability-leased host modules and executable JSON schemas # (the system toolbox's workflow templates, crates/toolbox). octoscript-core = { git = "https://github.com/OctoSense-org/Octoscript.git", rev = "5991dfae9344589e732b2605b530f788e8bbcd11" } octoscript-capabilities = { git = "https://github.com/OctoSense-org/Octoscript.git", rev = "5991dfae9344589e732b2605b530f788e8bbcd11" } octoscript-schema = { git = "https://github.com/OctoSense-org/Octoscript.git", rev = "5991dfae9344589e732b2605b530f788e8bbcd11" } -octoscript-makepad = { git = "https://github.com/OctoSense-org/Octoscript-Makepad.git", rev = "8f103d0c650196d455cbcaa55b13911475121224" } -octoscript-node = { git = "https://github.com/OctoSense-org/Octoscript-Makepad.git", rev = "8f103d0c650196d455cbcaa55b13911475121224" } +octoscript-makepad = { git = "https://github.com/OctoSense-org/Octoscript-Makepad.git", rev = "62760863bc992aeb7b43692b10d479417b4d3d93" } +octoscript-node = { git = "https://github.com/OctoSense-org/Octoscript-Makepad.git", rev = "62760863bc992aeb7b43692b10d479417b4d3d93" } # --- App Hub's host service registry the Mail and llm services register # into; the same revision as App Hub's app crate (a native app, above). octosense-appstore = { git = "https://github.com/OctoSense-org/OctoSense-App-Hub", rev = "58c3c8aed8fc811a16d67c5f784a8a44214ff876" } diff --git a/apps/appcard/native-runtime.lock.json b/apps/appcard/native-runtime.lock.json index eaf65bcc..e2e2c440 100644 --- a/apps/appcard/native-runtime.lock.json +++ b/apps/appcard/native-runtime.lock.json @@ -1,5 +1,5 @@ { "schema_version": 1, "url": "https://github.com/OctoSense-org/Octoscript-Makepad.git", - "revision": "8f103d0c650196d455cbcaa55b13911475121224" + "revision": "62760863bc992aeb7b43692b10d479417b4d3d93" } diff --git a/native-apps.json b/native-apps.json index 1041d592..ba7d40ef 100644 --- a/native-apps.json +++ b/native-apps.json @@ -41,7 +41,7 @@ { "id": "sheets", "crate": "makepad-sheets", - "source": { "git": "https://github.com/OctoSense-org/makepad.git", "rev": "e29a0eaa68781231eb9ec582e5f02648c6dad7e9", "local": ".sources/makepad/apps/sheets" }, + "source": { "git": "https://github.com/OctoSense-org/makepad.git", "rev": "39a9de88e1af14a9d660887c453fc3102c610411", "local": ".sources/makepad/apps/sheets" }, "module": "makepad_sheets::SHEETS_MODULE", "bin": "sheets", "bin_features": ["standalone"], @@ -58,7 +58,7 @@ { "id": "terminal", "crate": "makepad-terminal", - "source": { "git": "https://github.com/OctoSense-org/makepad.git", "rev": "e29a0eaa68781231eb9ec582e5f02648c6dad7e9", "local": ".sources/makepad/apps/terminal" }, + "source": { "git": "https://github.com/OctoSense-org/makepad.git", "rev": "39a9de88e1af14a9d660887c453fc3102c610411", "local": ".sources/makepad/apps/terminal" }, "module": "makepad_terminal::TERMINAL_MODULE", "bin": "terminal", "default_features": true, diff --git a/native-runtime.lock.json b/native-runtime.lock.json index eaf65bcc..e2e2c440 100644 --- a/native-runtime.lock.json +++ b/native-runtime.lock.json @@ -1,5 +1,5 @@ { "schema_version": 1, "url": "https://github.com/OctoSense-org/Octoscript-Makepad.git", - "revision": "8f103d0c650196d455cbcaa55b13911475121224" + "revision": "62760863bc992aeb7b43692b10d479417b4d3d93" } diff --git a/phone/docs/build-tool.md b/phone/docs/build-tool.md index 2a43758b..a56a49a2 100644 --- a/phone/docs/build-tool.md +++ b/phone/docs/build-tool.md @@ -73,9 +73,9 @@ move that touches `tools/cargo_makepad` is the usual trigger): cargo install --path .sources/makepad/tools/cargo_makepad --force ``` -The shared release selects Makepad main `e29a0eaa`, which includes App Hub's +The shared release selects Makepad main `39a9de88`, which includes App Hub's isolate containment (#22), contained script apps (#30), the QR scanner -(#31), Splash `reapply_text` (#35) self-confirmed assistant tools (#36) and the one-call-site Slug, cursor and glass shaders (#37, #39), the terminal's confirmed runs (#41), trackpad scrolling (#42), gestures (#46), Chinese text (#48), tabs and installed fonts (#47), and every app's system-font fallback (#49, #51), WebReader's close ending the page (#43), the OpenHarmony packager's workspace target dir (#52), the `sys.dataset` and `sys.news_digest` helpers (#53) the peer-link client (#54), the Linux Vulkan build (#45), the map's hosted-archive source (#55) HTTPS on OpenHarmony (#56) the keyboard's hide after a cancelled search (#57, #59) and the terminal's tab titles, wide-character reflow, non-blocking PTY writes, control-request timeout and running-job close confirmation (#61–#65), and its grapheme clusters, Kitty keyboard and synchronized output, close handshake and rendering polish (#66–#69), text shaping and drag-select (#70–#72), and clickable links and scrollback search (#73, #74); the consumer lock +(#31), Splash `reapply_text` (#35) self-confirmed assistant tools (#36) and the one-call-site Slug, cursor and glass shaders (#37, #39), the terminal's confirmed runs (#41), trackpad scrolling (#42), gestures (#46), Chinese text (#48), tabs and installed fonts (#47), and every app's system-font fallback (#49, #51), WebReader's close ending the page (#43), the OpenHarmony packager's workspace target dir (#52), the `sys.dataset` and `sys.news_digest` helpers (#53) the peer-link client (#54), the Linux Vulkan build (#45), the map's hosted-archive source (#55) HTTPS on OpenHarmony (#56) the keyboard's hide after a cancelled search (#57, #59) and the terminal's tab titles, wide-character reflow, non-blocking PTY writes, control-request timeout and running-job close confirmation (#61–#65), and its grapheme clusters, Kitty keyboard and synchronized output, close handshake and rendering polish (#66–#69), text shaping and drag-select (#70–#72), clickable links and scrollback search (#73, #74), keyboard shortcuts (#76) and OpenHarmony run (#91), GL GPU timing (#81), atlas text on phones (#82), the Android touch-down power hint (#83) and Vulkan without a debug messenger (#92), Linux GL remote grabs (#93), a hidden map's idle frame loop (#79), and OpenHarmony's keyboard, Studio, GL lifetimes and idle frames (#84, #85, #87–#89); the consumer lock needs no `makepad_override`. To see which checkout an installed tool reads its Java from: diff --git a/phone/docs/makepad-fork.md b/phone/docs/makepad-fork.md index d5e0c1c0..cc003f8d 100644 --- a/phone/docs/makepad-fork.md +++ b/phone/docs/makepad-fork.md @@ -20,9 +20,9 @@ Makepad and that no fork is required do not. The revision is pinned as a chain, not in one place: 1. `native-runtime.lock.json` here names one revision of - `OctoSense-org/Octoscript-Makepad` (`8f103d0c`, its main). + `OctoSense-org/Octoscript-Makepad` (`62760863`, its main). 2. That repo's `runtime.json` names the Makepad fork revision - (`e29a0eaa`, Makepad main: the enforced isolate policy of PR #22, module + (`39a9de88`, Makepad main: the enforced isolate policy of PR #22, module windows, the ROM's Splash fixes, the contained script apps and host services of PR #30, the QR scanner of PR #31, Splash `reapply_text` of PR #35, the self-confirmed assistant tools of PR #36, the one-call-site @@ -37,7 +37,13 @@ The revision is pinned as a chain, not in one place: PRs #57 and #59 and the terminal fixes and close veto of PRs #61–#65 and the terminal's grapheme clusters, Kitty keyboard, close handshake and rendering polish of PRs #66–#69, its text shaping and drag-select of PRs #70–#72, and - its clickable links and scrollback search of PRs #73 and #74) and the + its clickable links and scrollback search of PRs #73 and #74, the + terminal's keyboard shortcuts of PR #76 and its OpenHarmony run of PR #91, + GL GPU timing of PR #81, atlas text on phones of PR #82, the Android + touch-down power hint of PR #83 and Vulkan without a debug messenger of + PR #92, Linux GL remote grabs of PR #93, a hidden map's idle frame loop of + PR #79, and OpenHarmony's keyboard, Studio, GL lifetimes and idle frames + of PRs #84, #85 and #87–#89) and the Octoscript revision (`5991dfa`). OctoSense, AppCard, Rinx and the ROM lock the same release. 3. The manifests repeat the Makepad revision as `rev = "…"`: here in diff --git a/runtime-patches.lock.json b/runtime-patches.lock.json index e05cad89..647a0f8d 100644 --- a/runtime-patches.lock.json +++ b/runtime-patches.lock.json @@ -1,20 +1,17 @@ { "schema_version": 1, "makepad": { - "base_revision": "e29a0eaa68781231eb9ec582e5f02648c6dad7e9", + "base_revision": "39a9de88e1af14a9d660887c453fc3102c610411", "patch": "tools/runtime-patches/makepad-settings.patch", - "sha256": "1bf3c9d5367bb35a0e2ab0eb92b614507817066d31d8030404cbb0655c758268", - "tree": "46c5e8a22592382620c3edf9ffb2dccf789c5c8a", + "sha256": "b17352ebf59e50ab3db6ff1cb825c4e006bcdff47d83522e372b8fe585e57570", + "tree": "976bf55b6b94ae145f941f9aa39ca2b1036352ec", "product_fixes": [ "Settings integration: Android IME synchronization, accessibility and reduced motion, GLES program-cache validation, obscured-gesture cancellation and scroll-position observation.", "Contained-app isolation and secret-input restrictions come from the pinned upstream runtime; the Settings overlay preserves those gates.", "System Back callback owners suppress compatibility Back keys to avoid duplicate navigation on Android 13+.", "A cancelled search's keyboard hides once: an editor session going inactive retires its input connection without restarting input, which brought the keyboard back empty while it was hiding (Android 11).", "Windows remote grabs send raw RGBA pixels to the bounded PNG worker before presenting, keeping full-size encoding off the UI thread and scaling before encoding.", - "Windows frame completion: backport Makepad work c508ab0c8 GPU completion polls around native and hosted repaint so upload buffers can retire.", - "A map that is not drawn (Maps sent to the background) no longer asks for a frame and a full redraw every frame, nor ticks its tile fades every 16 ms, while it waits to draw (OctoSense-org/makepad#79).", - "OpenHarmony GL frees retired GPU allocations through completion fences and serves that retirement on idle vsync beats, as on Android; before, the debt never settled and an idle app repainted at display rate (OctoSense-org/makepad#88).", - "A DrawText no longer redraws a draw list from inside that list's own redraw; one DrawText drawing the big clock as SLUG and labels as raster kept an idle OpenHarmony Home re-recording its scene every frame (OctoSense-org/makepad#89)." + "Windows frame completion: backport Makepad work c508ab0c8 GPU completion polls around native and hosted repaint so upload buffers can retire." ], "stacked": [ { @@ -32,18 +29,6 @@ { "patch": "tools/runtime-patches/makepad-windows-frame-completion.patch", "sha256": "8d58e16bc12aae5f4313fdc5c9d3f6944b96ee20e609fe5ff069fe2403954595" - }, - { - "patch": "tools/runtime-patches/makepad-map-hidden-no-frame-loop.patch", - "sha256": "e89a4776c617d48242c4a33495972e1566036016584c81f58f8cb4affc535d8f" - }, - { - "patch": "tools/runtime-patches/makepad-ohos-gl-lifetimes.patch", - "sha256": "997cca9b560a0ea8fa38a209613752a5430467bcac99a5d90069dc280721a0c7" - }, - { - "patch": "tools/runtime-patches/makepad-drawtext-current-list-redraw.patch", - "sha256": "a64d6b6db40a6ac7c5518d2b9ba6675abd8b8ad04c917e27a674bd41d4904ee4" } ] } diff --git a/tools/runtime-patches/makepad-drawtext-current-list-redraw.patch b/tools/runtime-patches/makepad-drawtext-current-list-redraw.patch deleted file mode 100644 index 6b8d246d..00000000 --- a/tools/runtime-patches/makepad-drawtext-current-list-redraw.patch +++ /dev/null @@ -1,56 +0,0 @@ -diff --git a/draw/src/shader/draw_text.rs b/draw/src/shader/draw_text.rs -index 2d33d6a5c..0b66b891c 100644 ---- a/draw/src/shader/draw_text.rs -+++ b/draw/src/shader/draw_text.rs -@@ -1462,7 +1462,7 @@ struct SlugHelperPrewarmState { - /// *previous* redraw (`instance_count > 0` and a stale `redraw_id`). - /// - /// The slug/raster text paths use this to decide whether a draw item must be redrawn to --/// clear stale glyphs when a run switches rendering path. It must reject two cases that -+/// clear stale glyphs when a run switches rendering path. It must reject three cases that - /// would otherwise cause a per-frame `redraw_area_in_draw` — i.e. a permanent ~100% CPU - /// continuous-repaint loop: - /// - count == 0: an empty batch (e.g. a whitespace-only run, whose glyphs have no -@@ -1470,10 +1470,22 @@ struct SlugHelperPrewarmState { - /// - a *valid* (current-redraw) area: the area was already drawn this frame, either by - /// this run or by another `draw_text` call sharing the same instance (text is drawn - /// in resumable chunks), so its draw item is up to date. -+/// - an area in a draw list that is being redrawn right now (on the draw-list stack): -+/// that redraw already replaced its instances, and redrawing the list from inside its -+/// own draw only schedules the next frame's redraw, which does the same. One DrawText -+/// drawing a big clock as SLUG and small labels as raster into the same list kept an -+/// idle OpenHarmony home redrawing that list at display rate. - /// `Area::is_valid` returns false for count == 0, so the explicit count check is required. - #[cfg(any(target_os = "linux", target_os = "windows"))] --fn area_holds_stale_content(area: &Area, cx: &Cx) -> bool { -- matches!(area, Area::Instance(inst) if inst.instance_count > 0) && !area.is_valid(cx) -+fn area_holds_stale_content(area: &Area, cx: &Cx2d) -> bool { -+ match area { -+ Area::Instance(inst) => { -+ inst.instance_count > 0 -+ && !area.is_valid(cx.cx) -+ && !cx.draw_list_stack.contains(&inst.draw_list_id) -+ } -+ _ => false, -+ } - } - - #[cfg(any(target_os = "linux", target_os = "windows"))] -@@ -3032,7 +3044,7 @@ fn draw_text(&mut self, cx: &mut Cx2d, origin_in_lpxs: Point, text: &Laidou - } - if !drew_slug_this_frame { - let old_area = slug_draw.draw_vars.area; -- if area_holds_stale_content(&old_area, cx.cx) { -+ if area_holds_stale_content(&old_area, cx) { - cx.cx.redraw_area_in_draw(old_area); - slug_draw.draw_vars.area = cx.update_area_refs(old_area, Area::Empty); - } -@@ -3042,7 +3054,7 @@ fn draw_text(&mut self, cx: &mut Cx2d, origin_in_lpxs: Point, text: &Laidou - // Don't clobber the outer batch's area if we've handed it back. - if !drew_raster_this_frame && self.many_instances.is_none() { - let old_area = self.draw_vars.area; -- if area_holds_stale_content(&old_area, cx.cx) { -+ if area_holds_stale_content(&old_area, cx) { - cx.cx.redraw_area_in_draw(old_area); - self.draw_vars.area = cx.update_area_refs(old_area, Area::Empty); - } diff --git a/tools/runtime-patches/makepad-map-hidden-no-frame-loop.patch b/tools/runtime-patches/makepad-map-hidden-no-frame-loop.patch deleted file mode 100644 index 48ff43ef..00000000 --- a/tools/runtime-patches/makepad-map-hidden-no-frame-loop.patch +++ /dev/null @@ -1,80 +0,0 @@ -diff --git a/widgets/src/map/view.rs b/widgets/src/map/view.rs -index 366ccca08..566940e86 100644 ---- a/widgets/src/map/view.rs -+++ b/widgets/src/map/view.rs -@@ -4796,6 +4796,14 @@ pub struct MapView { - pending_ready_tiles: Vec<(TileKey, TileBuffers)>, - #[rust] - last_tile_upload_frame: u64, -+ /// The drawn frame the upload continuation last asked for a frame on. -+ #[rust] -+ continued_at_frame: u64, -+ /// The tile fade timer is running, and the map drew since its last tick. -+ #[rust] -+ fade_armed: bool, -+ #[rust] -+ fade_drawn: bool, - /// Web-only bounded degradation/retry state. Kept on every target so - /// native unit tests can exercise the policy without cfg-shaped APIs. - #[rust] -@@ -5146,7 +5154,14 @@ fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) { - self.handle_archive_watch(cx, event); - if self.tile_fade_timer.is_event(event).is_some() { - self.redraw(cx); -- if self.tiles.values().any(|entry| entry.fade.is_some()) { -+ // Fades end in the draw (`ensure_visible_tiles`): tick again only -+ // if the map drew since the last tick. A map that is not drawn -+ // (Maps in the background) would otherwise redraw every 16 ms -+ // forever; its next draw restarts the ticks (`draw_walk`). -+ self.fade_armed = self.fade_drawn -+ && self.tiles.values().any(|entry| entry.fade.is_some()); -+ self.fade_drawn = false; -+ if self.fade_armed { - self.tile_fade_timer = cx.start_timeout(0.016); - } - } -@@ -5435,6 +5450,17 @@ fn draw_walk(&mut self, cx: &mut Cx2d, _scope: &mut Scope, walk: Walk) -> DrawSt - } - } - self.perf_last_frame = Some(perf_start); -+ // Ready tiles left over while the map was not drawn: continue the -+ // upload now that it is (see the continuation in handle_event). -+ if !self.pending_ready_tiles.is_empty() { -+ cx.new_next_frame(); -+ } -+ // Tile fades left waiting while the map was not drawn: tick again. -+ self.fade_drawn = true; -+ if !self.fade_armed && self.tiles.values().any(|entry| entry.fade.is_some()) { -+ self.fade_armed = true; -+ self.tile_fade_timer = cx.start_timeout(0.016); -+ } - - // The map's own draw list carries the clip: hosted as a pane beside - // other content, every tile/terrain/label draw clamps against -@@ -6932,6 +6958,7 @@ fn insert_ready_tile(&mut self, cx: &mut Cx, tile_key: TileKey, mut buffers: Til - } - cx.stop_timer(self.tile_fade_timer); - self.tile_fade_timer = cx.start_timeout(0.016); -+ self.fade_armed = true; - - self.tiles.insert( - tile_key, -@@ -7488,10 +7515,17 @@ fn handle_tile_worker_messages(&mut self, cx: &mut Cx) { - } - redraw = true; - } -- if !self.pending_ready_tiles.is_empty() { -+ if !self.pending_ready_tiles.is_empty() -+ && self.continued_at_frame != self.frame_counter -+ { - // A pass runs once per frame, and a draw alone never re-enters - // handle_event: the continuation has to be an event that arrives - // after the next frame, or the queue waits for an unrelated timer. -+ // Only while the map draws: uploads wait for a drawn frame, so a -+ // map that is not drawn (a hosted app sent to the background) -+ // would otherwise ask for a frame and a full redraw every frame -+ // forever. Its draw re-arms the continuation (`draw_walk`). -+ self.continued_at_frame = self.frame_counter; - cx.new_next_frame(); - cx.redraw_all(); - redraw = true; diff --git a/tools/runtime-patches/makepad-ohos-gl-lifetimes.patch b/tools/runtime-patches/makepad-ohos-gl-lifetimes.patch deleted file mode 100644 index 5fd92514..00000000 --- a/tools/runtime-patches/makepad-ohos-gl-lifetimes.patch +++ /dev/null @@ -1,361 +0,0 @@ -diff --git a/platform/src/draw_list.rs b/platform/src/draw_list.rs -index e30c3bb73..fa22f5ac3 100644 ---- a/platform/src/draw_list.rs -+++ b/platform/src/draw_list.rs -@@ -1057,18 +1057,18 @@ pub fn retire_free_items_with_ids( - // that empty envelope still occurs here on the worker. - let _ = returned.try_send(batch); - counter.fetch_sub(1, Ordering::AcqRel); -- #[cfg(not(target_os = "android"))] -+ #[cfg(not(any(target_os = "android", target_env = "ohos")))] - crate::thread::SignalToUI::set_ui_signal(); - }; -- // Android serves the rest of the debt on its idle vsync beat -+ // Android and OpenHarmony serve the rest of the debt on the idle vsync beat - // (`opengl_maintain_instance_retirements`) and on every painted - // frame, so a finished batch needs no wake. The signal it used to - // raise (twice, with the pool's completion signal) arrived once per - // animation frame as an `Event::Signal` through the whole app, - // hosted modules included, and as an extra trip round the loop. -- #[cfg(target_os = "android")] -+ #[cfg(any(target_os = "android", target_env = "ohos"))] - slot.submit_detached_silent("retained draw storage retirement", job); -- #[cfg(not(target_os = "android"))] -+ #[cfg(not(any(target_os = "android", target_env = "ohos")))] - slot.submit_named("retained draw storage retirement", job).detach(); - } - // Settlement includes rotating scans and completion/metadata debt, -diff --git a/platform/src/os/linux/open_harmony/open_harmony.rs b/platform/src/os/linux/open_harmony/open_harmony.rs -index a5168ffa2..5c8d79c83 100644 ---- a/platform/src/os/linux/open_harmony/open_harmony.rs -+++ b/platform/src/os/linux/open_harmony/open_harmony.rs -@@ -163,6 +163,13 @@ fn handle_drawing(&mut self) { - } - - self.handle_repaint(); -+ } else { -+ // Nothing to paint: retained-upload retirement debt (released GPU -+ // allocations waiting on their completion fence, freed draw -+ // storage) is served here, on the vsync beat, without a present, -+ // as on Android. Repainting for it recorded new debt every frame: -+ // an idle Home drew at display rate. -+ let _ = self.opengl_maintain_instance_retirements(); - } - } - -diff --git a/platform/src/os/linux/opengl.rs b/platform/src/os/linux/opengl.rs -index 8e4e483c6..3178c44e8 100644 ---- a/platform/src/os/linux/opengl.rs -+++ b/platform/src/os/linux/opengl.rs -@@ -471,11 +471,11 @@ pub(crate) fn render_view( - std::mem::take(&mut os.inst_vb) - }) - { -- // Retirement debt is maintenance, not ink. Android services it on -- // idle vsync beats (`opengl_maintain_instance_retirements`) without -- // painting; the desktop GL loops only wake for a repaint, so they -- // keep the repaint as their wake until the debt settles. -- #[cfg(not(target_os = "android"))] -+ // Retirement debt is maintenance, not ink. Android and OpenHarmony -+ // service it on idle vsync beats (`opengl_maintain_instance_retirements`) -+ // without painting; the desktop GL loops only wake for a repaint, so -+ // they keep the repaint as their wake until the debt settles. -+ #[cfg(not(any(target_os = "android", target_env = "ohos")))] - { - self.demo_time_repaint = true; - } -@@ -486,11 +486,11 @@ pub(crate) fn render_view( - } - - fn retained_adapter_bytes(&self) -> u64 { -- #[cfg(not(any(use_vulkan, linux_direct, target_env = "ohos")))] -+ #[cfg(not(any(use_vulkan, linux_direct)))] - { -- #[cfg(target_os = "linux")] -+ #[cfg(all(target_os = "linux", not(target_env = "ohos")))] - let display = self.os.opengl_cx.as_ref(); -- #[cfg(target_os = "android")] -+ #[cfg(any(target_os = "android", target_env = "ohos"))] - let display = self.os.display.as_ref(); - let Some(display) = display else { - return 0; -@@ -1360,7 +1360,7 @@ pub fn draw_pass_to_texture( - (self.os.gl().glBindFramebuffer)(gl_sys::FRAMEBUFFER, 0); - //(gl.glFinish)(); - } -- #[cfg(not(any(use_vulkan, linux_direct, target_env = "ohos")))] -+ #[cfg(not(any(use_vulkan, linux_direct)))] - if !self.textures.1.readbacks.slots.is_empty() { - self.gl_capture_texture_readbacks(Some(draw_pass_id)); - } -@@ -4000,7 +4000,7 @@ pub fn egl_context(&self) -> *mut std::ffi::c_void { - - // Resolved only for clients using the lifetime API; LibGl's ordinary draw path - // gains no queries, scans, or fence calls. A zero timeout never waits for GPU work. --#[cfg(not(any(use_vulkan, linux_direct, target_env = "ohos")))] -+#[cfg(not(any(use_vulkan, linux_direct)))] - #[derive(Default)] - pub(crate) struct GlReadbacks { - functions: Option, -@@ -4009,7 +4009,7 @@ pub(crate) struct GlReadbacks { - device_lost: bool, - } - --#[cfg(not(any(use_vulkan, linux_direct, target_env = "ohos")))] -+#[cfg(not(any(use_vulkan, linux_direct)))] - struct GlReadback { - work: crate::texture::ReadbackWork, - framebuffer: u32, -@@ -4020,7 +4020,7 @@ struct GlReadback { - receive: Option>>, - } - --#[cfg(not(any(use_vulkan, linux_direct, target_env = "ohos")))] -+#[cfg(not(any(use_vulkan, linux_direct)))] - #[derive(Clone, Copy)] - struct GlReadbackFunctions { - framebuffer_status: unsafe extern "C" fn(u32) -> u32, -@@ -4033,19 +4033,19 @@ struct GlReadbackFunctions { - unmap: unsafe extern "C" fn(u32) -> u8, - } - --#[cfg(not(any(use_vulkan, linux_direct, target_env = "ohos")))] -+#[cfg(not(any(use_vulkan, linux_direct)))] - impl Cx { - fn gl_readback_functions( - &mut self, - ) -> Result { - use crate::texture::ReadbackError; -- #[cfg(target_os = "linux")] -+ #[cfg(all(target_os = "linux", not(target_env = "ohos")))] - let display = self - .os - .opengl_cx - .as_ref() - .ok_or(ReadbackError::DeviceLost)?; -- #[cfg(target_os = "android")] -+ #[cfg(any(target_os = "android", target_env = "ohos"))] - let display = self.os.display.as_ref().ok_or(ReadbackError::DeviceLost)?; - let get_proc = display - .libegl -@@ -4382,35 +4382,35 @@ fn gl_finish_lost_readback_leases(&mut self) { - } - } - --#[cfg(not(any(use_vulkan, linux_direct, target_env = "ohos")))] -+#[cfg(not(any(use_vulkan, linux_direct)))] - type GlSync = *mut std::ffi::c_void; --#[cfg(not(any(use_vulkan, linux_direct, target_env = "ohos")))] -+#[cfg(not(any(use_vulkan, linux_direct)))] - #[derive(Default)] - pub(crate) struct TextureFence { - functions: Option, - pending: Option<(u64, GlSync)>, - /// Idle maintenance beats served (`opengl_maintain_instance_retirements`); - /// their ledger frame keys count down from `u64::MAX`, apart from paints. -- #[cfg(target_os = "android")] -+ #[cfg(any(target_os = "android", target_env = "ohos"))] - maintenance_beats: u64, - framebuffers: Vec, - } --#[cfg(not(any(use_vulkan, linux_direct, target_env = "ohos")))] -+#[cfg(not(any(use_vulkan, linux_direct)))] - struct TextureFenceFunctions { - create: unsafe extern "C" fn(u32, u32) -> GlSync, - poll: unsafe extern "C" fn(GlSync, u32, u64) -> u32, - delete: unsafe extern "C" fn(GlSync), - current: unsafe extern "C" fn() -> GlSync, - } --#[cfg(not(any(use_vulkan, linux_direct, target_env = "ohos")))] -+#[cfg(not(any(use_vulkan, linux_direct)))] - impl CxOsTexture { - pub(crate) fn allocated_bytes(&self, cx: &Cx) -> Option { - if self.gl_texture.is_none() && self.gl_renderbuffer.is_none() { - return None; - } -- #[cfg(target_os = "linux")] -+ #[cfg(all(target_os = "linux", not(target_env = "ohos")))] - let display = cx.os.opengl_cx.as_ref()?; -- #[cfg(target_os = "android")] -+ #[cfg(any(target_os = "android", target_env = "ohos"))] - let display = cx.os.display.as_ref()?; - let get_proc = display.libegl.eglGetProcAddress?; - let gl = &display.libgl; -@@ -4525,7 +4525,7 @@ fn destroy_released(&mut self, gl: &LibGl) { - } - } - } --#[cfg(not(any(use_vulkan, linux_direct, target_env = "ohos")))] -+#[cfg(not(any(use_vulkan, linux_direct)))] - impl Cx { - pub(crate) fn detach_released_texture(&mut self, id: crate::texture::TextureId) { - for slot in &mut self.passes.0.pool { -@@ -4551,7 +4551,7 @@ pub(crate) fn detach_released_texture(&mut self, id: crate::texture::TextureId) - /// hand freed draw storage to the workers. Returns whether debt remains. - /// Call with this renderer's context current. The macOS backend has the - /// same beat (`maintain_instance_retirements`); a paint used to carry it. -- #[cfg(target_os = "android")] -+ #[cfg(any(target_os = "android", target_env = "ohos"))] - pub(crate) fn opengl_maintain_instance_retirements(&mut self) -> bool { - let fence_pending = self.textures.1.gl.pending.is_some() || !self.textures.1.retired.is_empty(); - if !fence_pending && !self.draw_lists.has_pending_instance_retirements() { -@@ -4580,11 +4580,11 @@ pub(crate) fn poll_texture_lifetimes(&mut self) { - // The adapter draws attached blocks here (no per-publication - // backing): dropped blocks release from this poll, contract §3.3. - self.publications.retire_without_backing(); -- #[cfg(target_os = "linux")] -+ #[cfg(all(target_os = "linux", not(target_env = "ohos")))] - let Some(display) = self.os.opengl_cx.as_ref() else { - return; - }; -- #[cfg(target_os = "android")] -+ #[cfg(any(target_os = "android", target_env = "ohos"))] - let Some(display) = self.os.display.as_ref() else { - return; - }; -diff --git a/platform/src/texture.rs b/platform/src/texture.rs -index 80aacff5d..74640497b 100644 ---- a/platform/src/texture.rs -+++ b/platform/src/texture.rs -@@ -172,12 +172,12 @@ pub(crate) struct TextureReadbacks { - /// A one-shot completion sender. Capacity is reserved per ticket; unrelated - /// completions can never fill it. A dropped sender becomes an explicit error - /// when the owning renderer polls the receiver. --#[cfg(any(gpusim, not(any(use_vulkan, linux_direct, target_env = "ohos"))))] -+#[cfg(any(gpusim, not(any(use_vulkan, linux_direct))))] - pub(crate) struct ReadbackCompletion( - pub std::sync::mpsc::SyncSender, ReadbackError>>, - ); - --#[cfg(any(gpusim, not(any(use_vulkan, linux_direct, target_env = "ohos"))))] -+#[cfg(any(gpusim, not(any(use_vulkan, linux_direct))))] - impl ReadbackCompletion { - pub fn finish(self, result: Result, ReadbackError>) { - // There is exactly one producer and one message in this channel. The -@@ -187,7 +187,7 @@ pub fn finish(self, result: Result, ReadbackError>) { - } - } - --#[cfg(any(gpusim, not(any(use_vulkan, linux_direct, target_env = "ohos"))))] -+#[cfg(any(gpusim, not(any(use_vulkan, linux_direct))))] - pub(crate) struct ReadbackWork { - pub ticket: ReadbackTicket, - pub texture_id: TextureId, -@@ -231,7 +231,7 @@ pub(crate) fn readback_pass_submitted(&mut self, pass: crate::draw_pass::DrawPas - } - } - -- #[cfg(any(gpusim, not(any(use_vulkan, linux_direct, target_env = "ohos"))))] -+ #[cfg(any(gpusim, not(any(use_vulkan, linux_direct))))] - pub(crate) fn take_readback_work(&mut self, pass: Option, order: ReadbackChannelOrder, origin: ReadbackOrigin) -> Vec { - let mut work = Vec::new(); - for index in 0..self.textures.1.readbacks.slots.len() { -@@ -273,25 +273,25 @@ pub(crate) fn fail_pending_readbacks(&mut self, error: ReadbackError) { - } - } - --#[cfg(all(not(gpusim), any(use_vulkan, linux_direct, target_env = "ohos")))] -+#[cfg(all(not(gpusim), any(use_vulkan, linux_direct)))] - impl Cx { - pub(crate) fn poll_texture_readbacks(&mut self) { - self.fail_pending_readbacks(ReadbackError::UnsupportedBackend); - } - } - --#[cfg(all(not(gpusim), not(any(use_vulkan, linux_direct, target_env = "ohos")), any(target_os = "linux", target_os = "android", target_os = "windows")))] -+#[cfg(all(not(gpusim), not(any(use_vulkan, linux_direct)), any(target_os = "linux", target_os = "android", target_os = "windows")))] - pub(crate) type ReadbackCopyJob = Box; - - /// One lazy, long-lived worker per renderer. It copies mapped leases and - /// wakes the renderer to poll GPU fences, but never calls a graphics API. --#[cfg(all(not(gpusim), not(any(use_vulkan, linux_direct, target_env = "ohos")), any(target_os = "linux", target_os = "android", target_os = "windows")))] -+#[cfg(all(not(gpusim), not(any(use_vulkan, linux_direct)), any(target_os = "linux", target_os = "android", target_os = "windows")))] - pub(crate) struct ReadbackWorker { - send: std::sync::mpsc::SyncSender>, - active: Arc, - } - --#[cfg(all(not(gpusim), not(any(use_vulkan, linux_direct, target_env = "ohos")), any(target_os = "linux", target_os = "android", target_os = "windows")))] -+#[cfg(all(not(gpusim), not(any(use_vulkan, linux_direct)), any(target_os = "linux", target_os = "android", target_os = "windows")))] - impl ReadbackWorker { - pub fn new(cx: &Cx) -> Result { - use std::sync::{atomic::AtomicBool, mpsc}; -@@ -340,7 +340,7 @@ pub fn try_copy(&self, job: ReadbackCopyJob) -> Result<(), (ReadbackCopyJob, boo - } - - /// Only called by a copy worker while its backend retains the mapped resource. --#[cfg(all(not(gpusim), not(any(use_vulkan, linux_direct, target_env = "ohos")), any(target_os = "linux", target_os = "android", target_os = "windows")))] -+#[cfg(all(not(gpusim), not(any(use_vulkan, linux_direct)), any(target_os = "linux", target_os = "android", target_os = "windows")))] - pub(crate) unsafe fn copy_readback_rows(address: usize, pitch: usize, width: usize, height: usize) -> Arc<[u8]> { - let mut bytes = Arc::<[u8]>::new_uninit_slice(width * height * 4); - let dst = Arc::get_mut(&mut bytes).unwrap().as_mut_ptr().cast::(); -@@ -480,7 +480,7 @@ pub(crate) fn submit(&self) -> u64 { - serial - } - -- #[cfg(any(test, gpusim, use_vulkan, not(any(linux_direct, target_env = "ohos"))))] -+ #[cfg(any(test, gpusim, use_vulkan, not(linux_direct)))] - pub(crate) fn complete(&self, serial: u64) { - self.completed.fetch_max( - serial.min(self.submitted.load(Ordering::Acquire)), -@@ -496,13 +496,13 @@ pub(crate) struct TextureLifetime { - pub(crate) readbacks: TextureReadbacks, - #[cfg(all(not(gpusim), any(target_os = "macos", target_os = "ios", target_os = "tvos")))] - pub(crate) metal_readbacks: crate::os::apple::metal::MetalReadbacks, -- #[cfg(all(not(gpusim), not(any(use_vulkan, linux_direct, target_env = "ohos")), any(target_os = "linux", target_os = "android")))] -+ #[cfg(all(not(gpusim), not(any(use_vulkan, linux_direct)), any(target_os = "linux", target_os = "android")))] - pub(crate) gl_readbacks: crate::os::linux::opengl::GlReadbacks, - #[cfg(all(not(gpusim), target_os = "windows"))] - pub(crate) d3d_readbacks: crate::os::windows::d3d11::D3dReadbacks, - #[cfg(all( - not(gpusim), -- not(any(use_vulkan, linux_direct, target_env = "ohos")), -+ not(any(use_vulkan, linux_direct)), - any(target_os = "linux", target_os = "android") - ))] - pub(crate) gl: crate::os::linux::opengl::TextureFence, -@@ -511,7 +511,7 @@ pub(crate) struct TextureLifetime { - } - - pub(crate) struct RetiredTexture { -- #[cfg(any(gpusim, not(any(use_vulkan, linux_direct, target_env = "ohos"))))] -+ #[cfg(any(gpusim, not(any(use_vulkan, linux_direct))))] - pub(crate) serial: u64, - pub(crate) bytes: u64, - pub(crate) os: CxOsTexture, -@@ -967,7 +967,7 @@ pub(crate) enum TexturePixel { - } - - impl CxTexture { -- #[cfg(any(gpusim, not(any(use_vulkan, linux_direct, target_env = "ohos"))))] -+ #[cfg(any(gpusim, not(any(use_vulkan, linux_direct))))] - pub(crate) fn reset_allocation(&mut self) { - self.allocation_generation = self.allocation_generation.saturating_add(1); - self.producer_serial = 0; -@@ -1664,7 +1664,7 @@ fn mip_format_reports_wrap() { - #[cfg(all( - not(gpusim), - not(target_arch = "wasm32"), -- not(any(use_vulkan, linux_direct, target_env = "ohos")), -+ not(any(use_vulkan, linux_direct)), - any( - target_os = "macos", - target_os = "ios", -@@ -1717,7 +1717,7 @@ pub(crate) fn release_texture_allocation(&mut self, id: TextureId) { - } - - // Renderer backends outside the supported lifetime matrix fail closed. --#[cfg(all(not(gpusim), any(use_vulkan, linux_direct, target_env = "ohos")))] -+#[cfg(all(not(gpusim), any(use_vulkan, linux_direct)))] - impl Cx { - pub(crate) fn poll_texture_lifetimes(&mut self) {} - pub(crate) fn release_texture_allocation(&mut self, _id: TextureId) {} -@@ -1725,7 +1725,7 @@ pub(crate) fn texture_allocation_bytes(&self, _id: TextureId) -> Option { - None - } - } --#[cfg(all(not(gpusim), any(use_vulkan, linux_direct, target_env = "ohos")))] -+#[cfg(all(not(gpusim), any(use_vulkan, linux_direct)))] - impl CxOsTexture { - pub(crate) fn allocated_bytes(&self, _cx: &Cx) -> Option { - None diff --git a/tools/runtime-patches/makepad-settings.patch b/tools/runtime-patches/makepad-settings.patch index 97562e67..ae783ed9 100644 --- a/tools/runtime-patches/makepad-settings.patch +++ b/tools/runtime-patches/makepad-settings.patch @@ -1,5 +1,5 @@ diff --git a/draw/src/shader/draw_text.rs b/draw/src/shader/draw_text.rs -index d4f8c2927..a3ae3a090 100644 +index b9c38073e..86fdd5429 100644 --- a/draw/src/shader/draw_text.rs +++ b/draw/src/shader/draw_text.rs @@ -573,6 +573,20 @@ fn register_draw_text_slug(vm: &mut ScriptVm) { @@ -83,7 +83,7 @@ index d4f8c2927..a3ae3a090 100644 } } -@@ -728,6 +750,20 @@ fn register_draw_text_slug(vm: &mut ScriptVm) { +@@ -731,6 +753,20 @@ fn register_draw_text_slug(vm: &mut ScriptVm) { radius: uniform(float) cutoff: uniform(float) @@ -104,7 +104,7 @@ index d4f8c2927..a3ae3a090 100644 aa_pad_px: uniform(float(1.0)) slug_matrix_0: uniform(vec4(1.0, 0.0, 0.0, 0.0)) slug_matrix_1: uniform(vec4(0.0, 1.0, 0.0, 0.0)) -@@ -821,6 +857,9 @@ fn register_draw_text_slug(vm: &mut ScriptVm) { +@@ -824,6 +860,9 @@ fn register_draw_text_slug(vm: &mut ScriptVm) { } sdf: fn(scale, p, color) { @@ -114,7 +114,7 @@ index d4f8c2927..a3ae3a090 100644 let sampled = self.grayscale_texture.sample_as_bgra(p); let s = if self.atlas_plane < 0.5 { sampled.r -@@ -835,7 +874,7 @@ fn register_draw_text_slug(vm: &mut ScriptVm) { +@@ -838,7 +877,7 @@ fn register_draw_text_slug(vm: &mut ScriptVm) { let safe_scale = max(scale, 0.0001); let luma = dot(color.rgb, vec3(0.299, 0.587, 0.114)); var a = clamp( @@ -123,7 +123,7 @@ index d4f8c2927..a3ae3a090 100644 0.0, 1.0, ); -@@ -848,13 +887,16 @@ fn register_draw_text_slug(vm: &mut ScriptVm) { +@@ -851,13 +890,16 @@ fn register_draw_text_slug(vm: &mut ScriptVm) { } msdf: fn(scale, p, color) { @@ -141,7 +141,7 @@ index d4f8c2927..a3ae3a090 100644 0.0, 1.0, ); -@@ -1212,8 +1254,9 @@ fn register_draw_text_slug(vm: &mut ScriptVm) { +@@ -1215,8 +1257,9 @@ fn register_draw_text_slug(vm: &mut ScriptVm) { let tex_size = self.grayscale_texture.size() let half_texel = vec2(0.5 / tex_size.x, 0.5 / tex_size.y) let p = clamp(self.t.xy, self.t_min + half_texel, self.t_max - half_texel) @@ -153,7 +153,7 @@ index d4f8c2927..a3ae3a090 100644 } else if self.texture_index < 1.5 { let tex_size = self.color_texture.size() let half_texel = vec2(0.5 / tex_size.x, 0.5 / tex_size.y) -@@ -1228,8 +1271,9 @@ fn register_draw_text_slug(vm: &mut ScriptVm) { +@@ -1231,8 +1274,9 @@ fn register_draw_text_slug(vm: &mut ScriptVm) { let tex_size = self.msdf_texture.size() let half_texel = vec2(0.5 / tex_size.x, 0.5 / tex_size.y) let p = clamp(self.t.xy, self.t_min + half_texel, self.t_max - half_texel) @@ -165,8 +165,8 @@ index d4f8c2927..a3ae3a090 100644 } else { return self.sample_slug_pixel() } -@@ -1664,6 +1708,8 @@ enum PrewarmAction { - #[cfg(any(target_os = "linux", target_os = "windows"))] +@@ -1679,6 +1723,8 @@ enum PrewarmAction { + #[cfg(any(all(target_os = "linux", not(target_env = "ohos")), target_os = "windows"))] impl DrawText { fn slug_run_is_ready(&mut self, cx: &mut Cx2d, text: &LaidoutText) -> bool { + let prefs = cx.accessibility_preferences(); @@ -174,7 +174,7 @@ index d4f8c2927..a3ae3a090 100644 let dpi_factor = cx.current_dpi_factor() as f32; let redraw_id = cx.cx.redraw_id; let mut has_slug_candidates = false; -@@ -3035,6 +3081,13 @@ fn finish_many_instances(&mut self, cx: &mut Cx2d, instances: ManyInstances) { +@@ -3139,6 +3185,13 @@ fn finish_many_instances(&mut self, cx: &mut Cx2d, instances: ManyInstances) { pub(crate) fn update_draw_vars(&mut self, cx: &mut Cx2d) { self.draw_vars.append_group_id = cx.draw_call_group_content().0; @@ -188,7 +188,7 @@ index d4f8c2927..a3ae3a090 100644 let fonts = cx.fonts.borrow(); let rasterizer = fonts.rasterizer().borrow(); let sdfer_settings = rasterizer.sdfer().settings(); -@@ -3144,7 +3197,11 @@ fn resolve_glyph(&mut self, cx: &mut Cx2d, glyph: &LaidoutGlyph) -> Option Option 35, Self::TextCopy(_) => 36, diff --git a/platform/src/lib.rs b/platform/src/lib.rs -index a310cd1f6..a16cc32dc 100644 +index 815732636..2b1f2ffb6 100644 --- a/platform/src/lib.rs +++ b/platform/src/lib.rs @@ -111,6 +111,7 @@ @@ -335,10 +335,10 @@ index a310cd1f6..a16cc32dc 100644 #[macro_use] mod app_main; diff --git a/platform/src/os/linux/android/android.rs b/platform/src/os/linux/android/android.rs -index 0c8630f66..6fb38bd68 100644 +index c0bf8571a..de787641c 100644 --- a/platform/src/os/linux/android/android.rs +++ b/platform/src/os/linux/android/android.rs -@@ -235,6 +235,21 @@ pub(crate) fn boost_render_thread() { +@@ -240,6 +240,21 @@ pub(crate) fn boost_render_thread() { } impl Cx { @@ -360,7 +360,7 @@ index 0c8630f66..6fb38bd68 100644 pub(crate) fn current_android_xr_options(&self) -> CxOpenXrOptions { CxOpenXrOptions { buffer_scale: self.os.xr_buffer_scale_requested, -@@ -368,6 +383,12 @@ pub fn main_loop(&mut self, from_java_rx: mpsc::Receiver) { +@@ -373,6 +388,12 @@ pub fn main_loop(&mut self, from_java_rx: mpsc::Receiver) { self.display_context.safe_area_insets = insets; self.update_safe_inset_script_values(insets); self.call_event_handler(&Event::Startup); @@ -373,7 +373,7 @@ index 0c8630f66..6fb38bd68 100644 // After Startup: `warm_task_pool` sets this thread `UserInteractive`, // which is nice 0 on Linux, and would undo an earlier boost. boost_render_thread(); -@@ -404,8 +425,8 @@ pub fn main_loop(&mut self, from_java_rx: mpsc::Receiver) { +@@ -409,8 +430,8 @@ pub fn main_loop(&mut self, from_java_rx: mpsc::Receiver) { FromJavaMessage::Wake => continue, _ => {} } @@ -384,7 +384,7 @@ index 0c8630f66..6fb38bd68 100644 .iter() .all(|t| t.state == crate::event::finger::TouchState::Move) { -@@ -419,12 +440,17 @@ pub fn main_loop(&mut self, from_java_rx: mpsc::Receiver) { +@@ -424,12 +445,17 @@ pub fn main_loop(&mut self, from_java_rx: mpsc::Receiver) { // Flush the deferred move first (if any) so ordering is preserved. if let Some(deferred) = pending_touch_move.take() { self.handle_message(deferred); @@ -402,7 +402,7 @@ index 0c8630f66..6fb38bd68 100644 } self.handle_other_events(); if self.os.in_xr_mode && self.os.openxr.session.is_none() { -@@ -581,8 +607,54 @@ fn copy_or_cut_to_clipboard(&mut self, cut: bool) { +@@ -586,8 +612,54 @@ fn copy_or_cut_to_clipboard(&mut self, cut: bool) { } } @@ -457,7 +457,7 @@ index 0c8630f66..6fb38bd68 100644 FromJavaMessage::SwitchedActivity(activity_handle, activity_thread_id) => { self.os.activity_thread_id = Some(activity_thread_id); if self.os.in_xr_mode { -@@ -852,12 +924,17 @@ pub(crate) fn handle_message(&mut self, msg: FromJavaMessage) { +@@ -857,12 +929,17 @@ pub(crate) fn handle_message(&mut self, msg: FromJavaMessage) { }); self.call_event_handler(&e); } @@ -476,7 +476,7 @@ index 0c8630f66..6fb38bd68 100644 } // Check for outside-click popup dismiss on touch start -@@ -888,6 +965,11 @@ pub(crate) fn handle_message(&mut self, msg: FromJavaMessage) { +@@ -893,6 +970,11 @@ pub(crate) fn handle_message(&mut self, msg: FromJavaMessage) { }; // Synthesize internal drag-and-drop events from touch gestures. @@ -488,7 +488,7 @@ index 0c8630f66..6fb38bd68 100644 if self.os.internal_drag_items.is_some() { if let Some(touch) = e .touches -@@ -1371,9 +1453,13 @@ pub(crate) fn handle_message(&mut self, msg: FromJavaMessage) { +@@ -1376,9 +1458,13 @@ pub(crate) fn handle_message(&mut self, msg: FromJavaMessage) { } } FromJavaMessage::Pause => { @@ -502,7 +502,7 @@ index 0c8630f66..6fb38bd68 100644 if self.os.fullscreen { unsafe { let env = attach_jni_env(); -@@ -1458,40 +1544,6 @@ pub(crate) fn handle_message(&mut self, msg: FromJavaMessage) { +@@ -1463,40 +1549,6 @@ pub(crate) fn handle_message(&mut self, msg: FromJavaMessage) { }); self.call_event_handler(&e); } @@ -543,7 +543,7 @@ index 0c8630f66..6fb38bd68 100644 FromJavaMessage::ComposerSubmit { text } => { // The native floating composer submitted text. Deliver it as a // bare action and drain it *this tick* (post_action alone would -@@ -1598,11 +1650,13 @@ pub(crate) fn handle_message(&mut self, msg: FromJavaMessage) { +@@ -1603,11 +1655,13 @@ pub(crate) fn handle_message(&mut self, msg: FromJavaMessage) { self.handle_action_receiver(); } FromJavaMessage::SafeAreaInsets { @@ -557,7 +557,7 @@ index 0c8630f66..6fb38bd68 100644 let new_insets = crate::event::SafeAreaInsets { top, right, -@@ -1628,6 +1682,7 @@ pub(crate) fn handle_message(&mut self, msg: FromJavaMessage) { +@@ -1633,6 +1687,7 @@ pub(crate) fn handle_message(&mut self, msg: FromJavaMessage) { } } } @@ -565,7 +565,7 @@ index 0c8630f66..6fb38bd68 100644 FromJavaMessage::Init(_) => {} } } -@@ -2204,6 +2259,7 @@ pub fn android_entry(activity: *const std::ffi::c_void, startup: F) +@@ -2209,6 +2264,7 @@ pub fn android_entry(activity: *const std::ffi::c_void, startup: F) let mut initial_params: Option = None; let mut initial_surface: Option<(*mut ndk_sys::ANativeWindow, i32, i32)> = None; let mut initial_physical_keyboard: Option = None; @@ -573,7 +573,7 @@ index 0c8630f66..6fb38bd68 100644 let (window, width, height, android_params) = loop { // Here use blocking method `recv` to reduce CPU usage during cold start. -@@ -2211,6 +2267,10 @@ pub fn android_entry(activity: *const std::ffi::c_void, startup: F) +@@ -2216,6 +2272,10 @@ pub fn android_entry(activity: *const std::ffi::c_void, startup: F) Ok(FromJavaMessage::Init(params)) => { initial_params = Some(params); } @@ -584,7 +584,7 @@ index 0c8630f66..6fb38bd68 100644 Ok(FromJavaMessage::SurfaceCreated { window }) => { // Bootstrap off the first SurfaceChanged so we have a // real size. SurfaceCreated still hands us an acquired -@@ -2254,7 +2314,8 @@ pub fn android_entry(activity: *const std::ffi::c_void, startup: F) +@@ -2259,7 +2319,8 @@ pub fn android_entry(activity: *const std::ffi::c_void, startup: F) } if initial_params.is_some() && initial_surface.is_some() { @@ -594,7 +594,7 @@ index 0c8630f66..6fb38bd68 100644 let (window, width, height) = initial_surface.take().unwrap(); break (window, width, height, android_params); } -@@ -2728,6 +2789,21 @@ fn handle_platform_ops(&mut self) -> EventFlow { +@@ -2736,6 +2797,21 @@ fn handle_platform_ops(&mut self) -> EventFlow { self.os.timers.timers.remove(&timer_id); } CxOsOp::ShowTextIME(_area, _pos, config) => unsafe { @@ -616,7 +616,7 @@ index 0c8630f66..6fb38bd68 100644 // A focused `TextInput` re-issues `ShowTextIME` on every // draw. Calling into Java each time thrashes the IME: // `configure_keyboard` can restart the input connection, -@@ -2745,38 +2821,14 @@ fn handle_platform_ops(&mut self) -> EventFlow { +@@ -2753,38 +2829,14 @@ fn handle_platform_ops(&mut self) -> EventFlow { } }, CxOsOp::HideTextIME => unsafe { @@ -657,7 +657,7 @@ index 0c8630f66..6fb38bd68 100644 CxOsOp::ShareText(content) => unsafe { android_jni::to_java_share_text(content); }, -@@ -3703,6 +3755,7 @@ fn default() -> Self { +@@ -3711,6 +3763,7 @@ fn default() -> Self { last_ime_height: 0.0, last_ime_visible: false, last_ime_config: None, @@ -665,7 +665,7 @@ index 0c8630f66..6fb38bd68 100644 media: CxAndroidMedia::default(), display: None, surface_alive: false, -@@ -3848,6 +3901,12 @@ pub struct CxOs { +@@ -3856,6 +3909,12 @@ pub struct CxOs { /// real change. Reset to `None` on `HideTextIME` and when Java reports the /// keyboard closed. pub last_ime_config: Option, @@ -748,7 +748,7 @@ index 000000000..ea66e8075 + } +} diff --git a/platform/src/os/linux/android/android_jni.rs b/platform/src/os/linux/android/android_jni.rs -index 93d15a63e..5179e8e95 100644 +index 1034093bc..1ae0c3e61 100644 --- a/platform/src/os/linux/android/android_jni.rs +++ b/platform/src/os/linux/android/android_jni.rs @@ -90,7 +90,10 @@ pub enum TouchPhase { @@ -807,7 +807,7 @@ index 93d15a63e..5179e8e95 100644 static MESSAGES_TX: Mutex>> = Mutex::new(None); static INTEGRATION_PENDING: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0); -@@ -1029,6 +1027,7 @@ fn init_simple_render_loop(device_refresh_rate: f32) { +@@ -1039,6 +1037,7 @@ fn init_simple_render_loop(device_refresh_rate: f32) { _: *mut jni_sys::JNIEnv, _: jni_sys::jobject, ) { @@ -815,7 +815,7 @@ index 93d15a63e..5179e8e95 100644 send_from_java_message(FromJavaMessage::Resume); } -@@ -1037,6 +1036,7 @@ fn init_simple_render_loop(device_refresh_rate: f32) { +@@ -1047,6 +1046,7 @@ fn init_simple_render_loop(device_refresh_rate: f32) { _: *mut jni_sys::JNIEnv, _: jni_sys::jobject, ) { @@ -823,7 +823,7 @@ index 93d15a63e..5179e8e95 100644 send_from_java_message(FromJavaMessage::Pause); } -@@ -1174,7 +1174,10 @@ pub extern "C" fn Java_dev_makepad_android_MakepadNative_surfaceOnLongClick( +@@ -1184,7 +1184,10 @@ pub extern "C" fn Java_dev_makepad_android_MakepadNative_surfaceOnLongClick( touches.push(TouchPoint { state: { @@ -835,7 +835,7 @@ index 93d15a63e..5179e8e95 100644 match action_masked { 0 | 5 => TouchState::Start, 1 | 6 => TouchState::Stop, -@@ -1195,7 +1198,7 @@ pub extern "C" fn Java_dev_makepad_android_MakepadNative_surfaceOnLongClick( +@@ -1205,7 +1208,7 @@ pub extern "C" fn Java_dev_makepad_android_MakepadNative_surfaceOnLongClick( time: time as f64 / 1000.0, }); } @@ -844,7 +844,7 @@ index 93d15a63e..5179e8e95 100644 } #[no_mangle] -@@ -1269,8 +1272,10 @@ extern "C" fn Java_dev_makepad_android_MakepadNative_surfaceOnSafeAreaInsets( +@@ -1279,8 +1282,10 @@ extern "C" fn Java_dev_makepad_android_MakepadNative_surfaceOnSafeAreaInsets( right: jni_sys::jfloat, bottom: jni_sys::jfloat, left: jni_sys::jfloat, @@ -855,7 +855,7 @@ index 93d15a63e..5179e8e95 100644 top: top as f64, right: right as f64, bottom: bottom as f64, -@@ -1278,6 +1283,15 @@ extern "C" fn Java_dev_makepad_android_MakepadNative_surfaceOnSafeAreaInsets( +@@ -1288,6 +1293,15 @@ extern "C" fn Java_dev_makepad_android_MakepadNative_surfaceOnSafeAreaInsets( }); } @@ -871,7 +871,7 @@ index 93d15a63e..5179e8e95 100644 #[no_mangle] extern "C" fn Java_dev_makepad_android_MakepadNative_onRenderLoop( _: *mut jni_sys::JNIEnv, -@@ -1684,34 +1698,24 @@ extern "C" fn Java_dev_makepad_android_MakepadNative_onWebSocketError( +@@ -1694,34 +1708,24 @@ extern "C" fn Java_dev_makepad_android_MakepadNative_onWebSocketError( } #[no_mangle] @@ -921,7 +921,7 @@ index 93d15a63e..5179e8e95 100644 } unsafe fn jstring_to_string(env: *mut jni_sys::JNIEnv, java_string: jni_sys::jstring) -> String { -@@ -2689,6 +2693,7 @@ pub unsafe fn to_java_configure_keyboard(config: &TextInputConfig) { +@@ -2699,6 +2703,7 @@ pub unsafe fn to_java_configure_keyboard(config: &TextInputConfig) { /// Update IME text state for programmatic changes (Rust→Java) pub unsafe fn to_java_update_ime_text_state( @@ -929,7 +929,7 @@ index 93d15a63e..5179e8e95 100644 full_text: &str, selection_start: i32, selection_end: i32, -@@ -2696,15 +2701,16 @@ pub unsafe fn to_java_update_ime_text_state( +@@ -2706,15 +2711,16 @@ pub unsafe fn to_java_update_ime_text_state( composing_end: i32, ) { let env = attach_jni_env(); @@ -961,10 +961,10 @@ index a4a335dfe..8a4c77000 100644 + +pub mod android_ime; diff --git a/platform/src/os/linux/gl_sys.rs b/platform/src/os/linux/gl_sys.rs -index 2a2afcf71..abb6e1574 100644 +index 1e8933b6f..69296a0a2 100644 --- a/platform/src/os/linux/gl_sys.rs +++ b/platform/src/os/linux/gl_sys.rs -@@ -405,7 +405,16 @@ macro_rules! gl_flush_error { +@@ -416,7 +416,16 @@ macro_rules! gl_flush_error { enabled: GLboolean, ); @@ -981,7 +981,7 @@ index 2a2afcf71..abb6e1574 100644 pub glGenVertexArrays: TglGenVertexArrays, pub glBindVertexArray: TglBindVertexArray, pub glBindBuffer: TglBindBuffer, -@@ -547,6 +556,7 @@ pub fn try_load(mut loadfn: F) -> Result +@@ -566,6 +575,7 @@ pub fn try_load(mut loadfn: F) -> Result F: FnMut(&[&'static str]) -> *const raw::c_void, { Ok(Self { @@ -990,10 +990,10 @@ index 2a2afcf71..abb6e1574 100644 loadfn, TglGenVertexArrays, diff --git a/platform/src/os/linux/opengl.rs b/platform/src/os/linux/opengl.rs -index 8e4e483c6..7ddc0be29 100644 +index efd3e8095..c081aa356 100644 --- a/platform/src/os/linux/opengl.rs +++ b/platform/src/os/linux/opengl.rs -@@ -1669,6 +1669,10 @@ fn read_program_cache( +@@ -1682,6 +1682,10 @@ fn read_program_cache( #[cfg(not(ohos_sim))] fn read_program_cache(gl: &LibGl, vertex: &str, pixel: &str, os_type: &OsType) -> Option { @@ -1004,7 +1004,7 @@ index 8e4e483c6..7ddc0be29 100644 if let Some(cache_dir) = os_type.get_cache_dir() { let shader_hash = live_id!(shader).str_append(&vertex).str_append(&pixel); let mut base_filename = format!("{}/shader_{:08x}", cache_dir, shader_hash.0); -@@ -1688,8 +1692,8 @@ fn read_program_cache(gl: &LibGl, vertex: &str, pixel: &str, os_type: &OsType) - +@@ -1701,8 +1705,8 @@ fn read_program_cache(gl: &LibGl, vertex: &str, pixel: &str, os_type: &OsType) - if let Ok(mut cache_file) = File::open(&filename) { let mut binary = Vec::new(); let mut format_bytes = [0u8; 4]; @@ -1015,7 +1015,7 @@ index 8e4e483c6..7ddc0be29 100644 let binary_format = u32::from_be_bytes(format_bytes); match cache_file.read_to_end(&mut binary) { Ok(_full_bytes) => { -@@ -1731,8 +1735,14 @@ fn read_program_cache(gl: &LibGl, vertex: &str, pixel: &str, os_type: &OsType) - +@@ -1744,8 +1748,14 @@ fn read_program_cache(gl: &LibGl, vertex: &str, pixel: &str, os_type: &OsType) - error ); (gl.glDeleteProgram)(program); @@ -1030,7 +1030,7 @@ index 8e4e483c6..7ddc0be29 100644 return Some(program); } } else { -@@ -1871,12 +1881,16 @@ fn start_pending_program_compile( +@@ -1884,12 +1894,16 @@ fn start_pending_program_compile( #[cfg(not(ohos_sim))] fn write_program_cache(gl: &LibGl, program: u32, vertex: &str, pixel: &str, os_type: &OsType) { @@ -1048,7 +1048,7 @@ index 8e4e483c6..7ddc0be29 100644 binary.resize(binary_len as usize, 0u8); let mut return_size = 0i32; let mut binary_format = 0u32; -@@ -1887,7 +1901,24 @@ fn write_program_cache(gl: &LibGl, program: u32, vertex: &str, pixel: &str, os_t +@@ -1900,7 +1914,24 @@ fn write_program_cache(gl: &LibGl, program: u32, vertex: &str, pixel: &str, os_t &mut binary_format as *mut _, binary.as_mut_ptr() as *mut _, ); @@ -1162,10 +1162,10 @@ index c763d8501..b2b321cd2 100644 fn set_window_dpi_override_converts_every_in_window_metric() { let mut cx = test_cx(); diff --git a/tools/cargo_makepad/src/android/java/dev/makepad/android/MakepadActivity.java b/tools/cargo_makepad/src/android/java/dev/makepad/android/MakepadActivity.java -index c6e70c6fb..274d922b1 100644 +index a7dd7524d..e95620a5d 100644 --- a/tools/cargo_makepad/src/android/java/dev/makepad/android/MakepadActivity.java +++ b/tools/cargo_makepad/src/android/java/dev/makepad/android/MakepadActivity.java -@@ -370,7 +370,7 @@ class MakepadSystemInsets { +@@ -371,7 +371,7 @@ class MakepadSystemInsets { static void report(View view, WindowInsets insets) { float density = view.getResources().getDisplayMetrics().density; MakepadSystemInsets i = MakepadSystemInsets.from(view, insets, density); @@ -1174,7 +1174,7 @@ index c6e70c6fb..274d922b1 100644 } } -@@ -386,6 +386,24 @@ class MakepadSurface +@@ -387,6 +387,24 @@ class MakepadSurface { // IME InputConnection for handling composition text private MakepadInputConnection mInputConnection; @@ -1199,7 +1199,7 @@ index c6e70c6fb..274d922b1 100644 // Shared Editable buffer for IME - this is the source of truth for Java side private SpannableStringBuilder mEditable = new SpannableStringBuilder(); -@@ -427,7 +445,8 @@ class MakepadSurface +@@ -428,7 +446,8 @@ class MakepadSurface private int mAutocapitalize = AUTOCAP_SENTENCES; private int mAutocorrect = AUTOCORRECT_DEFAULT; private int mReturnKeyType = RETURN_KEY_DEFAULT; @@ -1209,15 +1209,15 @@ index c6e70c6fb..274d922b1 100644 private boolean mIsSecure = false; // Package-private getters for MakepadInputConnection to access shared state -@@ -549,6 +568,7 @@ class MakepadSurface - } +@@ -602,6 +621,7 @@ class MakepadSurface } + if (actionMasked == MotionEvent.ACTION_DOWN) hintTouchLoad(); + if (actionMasked==MotionEvent.ACTION_DOWN || actionMasked==MotionEvent.ACTION_UP || actionMasked==MotionEvent.ACTION_CANCEL) MakepadNative.beginInput(); MakepadNative.surfaceOnTouch(event); return retval; } -@@ -614,6 +634,27 @@ class MakepadSurface +@@ -667,6 +687,27 @@ class MakepadSurface @SuppressWarnings("deprecation") @Override public boolean onKey(View v, int keyCode, KeyEvent event) { @@ -1245,7 +1245,7 @@ index c6e70c6fb..274d922b1 100644 if (event.getAction() == KeyEvent.ACTION_DOWN && keyCode != 0) { int metaState = event.getMetaState(); boolean isRepeat = event.getRepeatCount() > 0; -@@ -625,7 +666,11 @@ class MakepadSurface +@@ -678,7 +719,11 @@ class MakepadSurface MakepadNative.surfaceOnKeyUp(keyCode, metaState); } @@ -1258,7 +1258,7 @@ index c6e70c6fb..274d922b1 100644 int character = event.getUnicodeChar(); if (character == 0) { String characters = event.getCharacters(); -@@ -822,23 +867,39 @@ class MakepadSurface +@@ -875,23 +920,39 @@ class MakepadSurface } // Called from Rust to update text state (for programmatic changes, not IME input) @@ -1312,7 +1312,7 @@ index c6e70c6fb..274d922b1 100644 // Clamp selection int textLen = textChanged ? fullText.length() : currentText.length(); selStart = Math.max(0, Math.min(selStart, textLen)); -@@ -861,13 +922,6 @@ class MakepadSurface +@@ -914,13 +975,6 @@ class MakepadSurface mInputConnection.setComposingRegion(composingStart, composingEnd); } @@ -1326,7 +1326,7 @@ index c6e70c6fb..274d922b1 100644 // Notify IME of text change without restarting input // restartInput() destroys composition state and causes IME flicker; // updateExtractedText() + updateSelection() is the lightweight alternative -@@ -906,6 +960,7 @@ class MakepadSurface +@@ -959,6 +1013,7 @@ class MakepadSurface } } } @@ -1334,7 +1334,7 @@ index c6e70c6fb..274d922b1 100644 } public Surface getNativeSurface() { -@@ -1114,6 +1169,7 @@ public class MakepadActivity +@@ -1167,6 +1222,7 @@ public class MakepadActivity private FrameLayout mRootLayout; private FrameLayout mApplicationOverlay; private ApplicationExtension mApplicationExtension; @@ -1342,7 +1342,7 @@ index c6e70c6fb..274d922b1 100644 /** Optional app Java client. Implementations enqueue blocking work on workers. */ public interface ApplicationExtension { -@@ -1124,6 +1180,24 @@ public class MakepadActivity +@@ -1177,6 +1233,24 @@ public class MakepadActivity void onDestroy(); default boolean onActivityResult(int requestCode, int resultCode, Intent data) { return false; } default boolean onBackPressed() { return false; } @@ -1367,7 +1367,7 @@ index c6e70c6fb..274d922b1 100644 } private void createApplicationExtension() { -@@ -1590,6 +1664,26 @@ public class MakepadActivity +@@ -1643,6 +1717,26 @@ public class MakepadActivity MakepadNative.activityOnStart(); } @@ -1394,7 +1394,7 @@ index c6e70c6fb..274d922b1 100644 @Override protected void onResume() { super.onResume(); -@@ -1616,6 +1710,7 @@ public class MakepadActivity +@@ -1669,6 +1763,7 @@ public class MakepadActivity if (mQrScanning) closeQrScanner("interrupted"); prepareSurfaceSnapshotOverlayForPause(); super.onPause(); @@ -1402,7 +1402,7 @@ index c6e70c6fb..274d922b1 100644 MakepadNative.activityOnPause(); if (mApplicationExtension != null) mApplicationExtension.onPause(); stopGpsLocationUpdates(); -@@ -2603,6 +2698,7 @@ public class MakepadActivity +@@ -2656,6 +2751,7 @@ public class MakepadActivity runOnUiThread(new Runnable() { @Override public void run() { @@ -1410,7 +1410,7 @@ index c6e70c6fb..274d922b1 100644 if (show) { if (view == null || view.getInputMode() == MakepadSurface.INPUT_MODE_NONE) { return; -@@ -2647,17 +2743,16 @@ public class MakepadActivity +@@ -2700,17 +2796,16 @@ public class MakepadActivity }); } @@ -1432,7 +1432,7 @@ index c6e70c6fb..274d922b1 100644 selStart, selEnd, composingStart, -@@ -3021,16 +3116,19 @@ public class MakepadActivity +@@ -3074,16 +3169,19 @@ public class MakepadActivity if (action == MotionEvent.ACTION_DOWN) { setSelectionHandlePosition(v, absX, absY); @@ -1848,10 +1848,10 @@ index 10f380316..4df279052 100644 } } diff --git a/tools/cargo_makepad/src/android/java/dev/makepad/android/MakepadNative.java b/tools/cargo_makepad/src/android/java/dev/makepad/android/MakepadNative.java -index a63e3864a..daecd8509 100644 +index 866ef68dc..9f27bf02c 100644 --- a/tools/cargo_makepad/src/android/java/dev/makepad/android/MakepadNative.java +++ b/tools/cargo_makepad/src/android/java/dev/makepad/android/MakepadNative.java -@@ -32,7 +32,8 @@ public class MakepadNative { +@@ -34,7 +34,8 @@ public class MakepadNative { public native static void surfaceOnCharacter(int character); public native static void surfaceOnResizeTextIME(int keyboard_height, boolean is_open); public native static void surfaceOnPhysicalKeyboardChanged(boolean connected); @@ -1861,7 +1861,7 @@ index a63e3864a..daecd8509 100644 // networking public native static void onHttpResponse(long id, long metadata_id, int status_code, String headers, byte[] body); -@@ -48,19 +49,16 @@ public class MakepadNative { +@@ -50,19 +51,16 @@ public class MakepadNative { // selection handles public native static void onSelectionHandleDrag(int handle, int phase, float x, float y, long timeMillis);