feat(ports): add hint scan messages and internal capture ids
- commit
- 7f28d9ce0a9c4949ed5a31f5ed0225dd1b042e96
- author
- brice · · 2026-10-19 09:43 UTC
- parent
- e8a5ba6
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
3 files · +56 -1
M .hexcheck.yaml +1 -1
| @@ -25,7 +25,7 @@ allow: | |||
| 25 | 25 | ruleSettings: | |
| 26 | 26 | missing-generated-mock-for-port: | |
| 27 | 27 | # Sealed message unions are channel data, not ports; tested by sending messages (ADR 005). | |
| 28 | - | excludePaths: [internal/ports/client_events.go, internal/ports/client_commands.go, internal/ports/input_events.go, internal/ports/output_events.go, internal/ports/lease.go, internal/ports/session_lock_messages.go, internal/ports/screencast_messages.go, internal/ports/session_backend.go] | |
| 28 | + | excludePaths: [internal/ports/client_events.go, internal/ports/client_commands.go, internal/ports/input_events.go, internal/ports/output_events.go, internal/ports/lease.go, internal/ports/session_lock_messages.go, internal/ports/screencast_messages.go, internal/ports/session_backend.go, internal/ports/hint_messages.go] | |
| 29 | 29 | suspicious-business-logic-in-adapter: | |
| 30 | 30 | # app is the composition root; starting core and wiring channels is its job. | |
| 31 | 31 | excludePaths: [internal/app/app.go, internal/app/session.go] | |
| @@ -25,7 +25,7 @@ allow: | |||||
| 25 | ruleSettings: | 25 | ruleSettings: | ||
| 26 | missing-generated-mock-for-port: | 26 | missing-generated-mock-for-port: | ||
| 27 | # Sealed message unions are channel data, not ports; tested by sending messages (ADR 005). | 27 | # Sealed message unions are channel data, not ports; tested by sending messages (ADR 005). | ||
| 28 | - | excludePaths: [internal/ports/client_events.go, internal/ports/client_commands.go, internal/ports/input_events.go, internal/ports/output_events.go, internal/ports/lease.go, internal/ports/session_lock_messages.go, internal/ports/screencast_messages.go, internal/ports/session_backend.go] | 28 | + | excludePaths: [internal/ports/client_events.go, internal/ports/client_commands.go, internal/ports/input_events.go, internal/ports/output_events.go, internal/ports/lease.go, internal/ports/session_lock_messages.go, internal/ports/screencast_messages.go, internal/ports/session_backend.go, internal/ports/hint_messages.go] |
| 29 | suspicious-business-logic-in-adapter: | 29 | suspicious-business-logic-in-adapter: | ||
| 30 | # app is the composition root; starting core and wiring channels is its job. | 30 | # app is the composition root; starting core and wiring channels is its job. | ||
| 31 | excludePaths: [internal/app/app.go, internal/app/session.go] | 31 | excludePaths: [internal/app/app.go, internal/app/session.go] | ||
M internal/ports/capture_messages.go +6 -0
| @@ -65,3 +65,9 @@ type CaptureDone struct { | |||
| 65 | 65 | Err error | |
| 66 | 66 | Time time.Time | |
| 67 | 67 | } | |
| 68 | + | ||
| 69 | + | // CaptureIDInternal is the bit set in the ID of captures requested by the | |
| 70 | + | // compositor itself (hint scanning) rather than by a Wayland client. Wayland | |
| 71 | + | // IDs start at 1 and increment, so they never set it. Replies carrying it are | |
| 72 | + | // demultiplexed away from the Wayland consumer. | |
| 73 | + | const CaptureIDInternal uint64 = 1 << 63 | |
| @@ -65,3 +65,9 @@ type CaptureDone struct { | |||||
| 65 | Err error | 65 | Err error | ||
| 66 | Time time.Time | 66 | Time time.Time | ||
| 67 | } | 67 | } | ||
| 68 | + | ||||
| 69 | + | // CaptureIDInternal is the bit set in the ID of captures requested by the | |||
| 70 | + | // compositor itself (hint scanning) rather than by a Wayland client. Wayland | |||
| 71 | + | // IDs start at 1 and increment, so they never set it. Replies carrying it are | |||
| 72 | + | // demultiplexed away from the Wayland consumer. | |||
| 73 | + | const CaptureIDInternal uint64 = 1 << 63 | |||
A internal/ports/hint_messages.go +49 -0
| @@ -0,0 +1,49 @@ | |||
| 1 | + | package ports | |
| 2 | + | ||
| 3 | + | // HintKind is the kind of a clickable hint target. | |
| 4 | + | type HintKind uint8 | |
| 5 | + | ||
| 6 | + | const ( | |
| 7 | + | // HintLink is a link or URL. | |
| 8 | + | HintLink HintKind = iota | |
| 9 | + | // HintButton is a button or control. | |
| 10 | + | HintButton | |
| 11 | + | ) | |
| 12 | + | ||
| 13 | + | // HintScanRequest asks the hint scanner to find clickable targets in the last | |
| 14 | + | // frame of Output. Core sends it and expects one HintScanResult echoing Seq. | |
| 15 | + | type HintScanRequest struct { | |
| 16 | + | Seq uint64 // core-chosen, echoed back | |
| 17 | + | Output string | |
| 18 | + | // Width and Height are the output buffer size in physical pixels | |
| 19 | + | // (OutputInfo.Width/Height). | |
| 20 | + | Width, Height int | |
| 21 | + | Scale float64 // screen scale | |
| 22 | + | LinksOnly bool | |
| 23 | + | } | |
| 24 | + | ||
| 25 | + | // HintTarget is a clickable region found in a frame. | |
| 26 | + | type HintTarget struct { | |
| 27 | + | Rect Rect // logical, output-local | |
| 28 | + | Kind HintKind | |
| 29 | + | } | |
| 30 | + | ||
| 31 | + | // HintScanResult answers a HintScanRequest. Core owns Targets. | |
| 32 | + | type HintScanResult struct { | |
| 33 | + | Seq uint64 | |
| 34 | + | Output string | |
| 35 | + | Targets []HintTarget | |
| 36 | + | Err error | |
| 37 | + | } | |
| 38 | + | ||
| 39 | + | // HintLabel is a label drawn over a hint target. | |
| 40 | + | type HintLabel struct { | |
| 41 | + | // Rect is the label box in logical output-local coordinates, placed at | |
| 42 | + | // the target's top-left. W and H may be 0: the renderer sizes the box | |
| 43 | + | // from Text. | |
| 44 | + | Rect Rect | |
| 45 | + | // Text is the full label, lowercase a–z. | |
| 46 | + | Text string | |
| 47 | + | // Typed is the number of leading characters already typed (drawn dimmed). | |
| 48 | + | Typed int | |
| 49 | + | } | |
| @@ -0,0 +1,49 @@ | |||||
| 1 | + | package ports | |||
| 2 | + | ||||
| 3 | + | // HintKind is the kind of a clickable hint target. | |||
| 4 | + | type HintKind uint8 | |||
| 5 | + | ||||
| 6 | + | const ( | |||
| 7 | + | // HintLink is a link or URL. | |||
| 8 | + | HintLink HintKind = iota | |||
| 9 | + | // HintButton is a button or control. | |||
| 10 | + | HintButton | |||
| 11 | + | ) | |||
| 12 | + | ||||
| 13 | + | // HintScanRequest asks the hint scanner to find clickable targets in the last | |||
| 14 | + | // frame of Output. Core sends it and expects one HintScanResult echoing Seq. | |||
| 15 | + | type HintScanRequest struct { | |||
| 16 | + | Seq uint64 // core-chosen, echoed back | |||
| 17 | + | Output string | |||
| 18 | + | // Width and Height are the output buffer size in physical pixels | |||
| 19 | + | // (OutputInfo.Width/Height). | |||
| 20 | + | Width, Height int | |||
| 21 | + | Scale float64 // screen scale | |||
| 22 | + | LinksOnly bool | |||
| 23 | + | } | |||
| 24 | + | ||||
| 25 | + | // HintTarget is a clickable region found in a frame. | |||
| 26 | + | type HintTarget struct { | |||
| 27 | + | Rect Rect // logical, output-local | |||
| 28 | + | Kind HintKind | |||
| 29 | + | } | |||
| 30 | + | ||||
| 31 | + | // HintScanResult answers a HintScanRequest. Core owns Targets. | |||
| 32 | + | type HintScanResult struct { | |||
| 33 | + | Seq uint64 | |||
| 34 | + | Output string | |||
| 35 | + | Targets []HintTarget | |||
| 36 | + | Err error | |||
| 37 | + | } | |||
| 38 | + | ||||
| 39 | + | // HintLabel is a label drawn over a hint target. | |||
| 40 | + | type HintLabel struct { | |||
| 41 | + | // Rect is the label box in logical output-local coordinates, placed at | |||
| 42 | + | // the target's top-left. W and H may be 0: the renderer sizes the box | |||
| 43 | + | // from Text. | |||
| 44 | + | Rect Rect | |||
| 45 | + | // Text is the full label, lowercase a–z. | |||
| 46 | + | Text string | |||
| 47 | + | // Typed is the number of leading characters already typed (drawn dimmed). | |||
| 48 | + | Typed int | |||
| 49 | + | } | |||