Add the cooperative geometry port (WHERE), the escape hatch for layout.gadget children - #78
Merged
Merged
Conversation
…t.gadget children (#49) layout.gadget children are permanently invisible to structural walking on classic AmigaOS 3.x, so no plain manifest entry could ever address them. This adds manifest format v2 (WHEREPORT/WHEREGADGET), a new WHERE verb, and routes CLICK/TYPE @name through an app's own cooperative ARexx port for geometry while still acting with real input.device input -- verified end to end against a new CAAPP.WHERE port on fixtures/classact-app, whose three gadgets previously had no manifest entry at all. Along the way, found and fixed a real gap: a hand-built RexxMsg (CreateRexxMsg/FillRexxMsg/PutMsg, the same recipe MUIREXX already uses) arrives with ln_Type left at NT_MESSAGE, causing rexxsyslib.library's own IsRexxMsg() to reject it even though the message is otherwise correct -- invisible in the existing MUIREXX check only because MUI-Demo never calls IsRexxMsg() on what it receives. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018CbPo4nMpnM5JQX3LKE5JP
…RexxMsg send Investigated whether the WHERE port's own receiver could stay a fully standard, unmodified ARexx port (IsRexxMsg()-gated, no special knowledge required) by fixing the sender instead -- tried both the commonly-cited ln_Type = NT_REPLYMSG pre-marking and a genuine CreateArgstring()-backed rm_Args[0] in AmipWhereQuery(). Neither changed the outcome: PutMsg() itself resets the node type regardless of what's set beforehand, so a message built via CreateRexxMsg()/ FillRexxMsg()/PutMsg() from ordinary C code cannot be made indistinguishable from a live ARexx interpreter's own send by any public API tried. No functional change (where.c is back to its prior form) -- just recording the investigation so this isn't re-attempted, and being explicit that any third-party WHERE implementation (e.g. AmiAuth) needs a receive loop that doesn't call IsRexxMsg(), the same as CAAPP.WHERE's own. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018CbPo4nMpnM5JQX3LKE5JP
… not IsRexxMsg() The previous commit's "trust every message on a dedicated port" workaround was correct in that it made the tests pass, but not in its diagnosis. IsRexxMsg() checks ln_Type == NT_REPLYMSG, which ReplyMsg() sets -- the right question for a sender inspecting its own reply, not a receiver validating an incoming, not-yet-answered command (which is legitimately still NT_MESSAGE regardless of how carefully the sender is built, confirmed by ruling out two separate sender-side fixes live: pre-marking ln_Type before sending, and using a genuine CreateArgstring()-backed rm_Args[0]). RXCOMM is the field that actually means "this is a command invocation" -- CAAPP.WHERE now checks rm_Action & RXCOMM instead, a completely ordinary, one-condition receive-loop check any third-party ARexx port (including AmiAuth's) can use, not a dedicated-port special case. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018CbPo4nMpnM5JQX3LKE5JP
This was referenced Aug 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
layout.gadgetchildren are permanently invisible to structural walking on classic AmigaOS 3.x (the project's own documented "Confirmed limit"), so no plainGADGETmanifest entry — or quirk profile — could ever address them.WHEREPORT <port-name>andWHEREGADGET <name> <window>: a gadget resolved not byGA_IDbut by querying a small, optional ARexx port the application itself exposes, reporting its own liveGetAttr(GA_Left/GA_Top/GA_Width/GA_Height)geometry.CLICK @name/TYPE @nameroute through that query automatically and then act with a genuineinput.deviceclick (AmipClickWindowRelative()) — discovery is cooperative, but actuation stays real input, unlikeMUIREXX, where the target's own port does the acting too. A new standaloneWHERE @name [TIMEOUT=<n>]verb is the diagnostic/test probe.GETTEXT/DRAGhave noWHERE-based path — an honestRC 10"geometry only" limit, not a silent fallback.fixtures/classact-appnow implements a realCAAPP.WHEREport; its manifest (previously naming zero gadgets, as the honest example of this exact limit) now addresses all three of its gadgets viaWHEREGADGET.CAApp.goldenis unchanged, confirming the walker's own view of the window genuinely didn't change.RexxMsg(CreateRexxMsg/FillRexxMsg/PutMsg, the same recipeMUIREXX's ownAmipMuiRexxSend()already uses) arrives at the receiver with its node type left atNT_MESSAGE, notNT_REPLYMSG—rexxsyslib.library's ownIsRexxMsg()rejects it despite every other field being correct. Root cause:IsRexxMsg()checksln_Type == NT_REPLYMSG, whichReplyMsg()sets — the right question for a sender inspecting its own reply, not a receiver validating an incoming, not-yet-answered command (confirmed by ruling out two sender-side fixes live: pre-markingln_Typebefore sending, and a genuineCreateArgstring()-backedrm_Args[0]).RXCOMMis the field that actually means "command invocation," and every sender here already sets it correctly.CAAPP.WHEREnow validates incoming messages withrm_Action & RXCOMMinstead — a completely ordinary, one-condition receive-loop check, not a dedicated-port special case, so any third-party ARexx port (including AmiAuth's own) can implementWHEREwith the same one-line change. Full account inserver/README.md's WHERE section andtests/copperline/README.md.Test plan
make amiga fixtures server— clean build under-Wall -Wextra -Werror(viamake docker)make test-host— 234 host tests pass (the sole unrelated failure, missingpytestmodule, is a pre-existing local-environment gap, not a regression)tests/copperline/run.sh's newrun_where_check— verified live against real Copperline:WHEREgeometry sanity, unknown-name/GETTEXT-limit rejections,TYPE @host_fieldlanding text in a layout child (confirmed via the fixture's own log line, sinceGETTEXTcan't read it back), andCLICK @connect_buttongenuinely closing the windowrun_click_check/run_type_check/run_manifest_check/run_wire_check(the shared manifest-resolution code path this PR touches) — all still passCAApp.goldenbyte-identical (run_golden_check) — confirms the walker's own view is unaffected🤖 Generated with Claude Code
https://claude.ai/code/session_018CbPo4nMpnM5JQX3LKE5JP