Windows shell - #19
Draft
neriousy wants to merge 59 commits into
Draft
Conversation
Checkpoint of the Windows port work plus this session: the decluttered speech-model browser (flat list, pinned active model, uninstall, single-select filter), Cohere Transcribe recommendation coverage, windowless curl downloads, and the start of the shared ui component layer over gpui-component (Fluent theme bridge, embedded Lucide icons, first Select migration) with the main window hosted in Root.
src/ is now common/ (paths, audio, dictation, history), desktop/ (shared
shell layer), speech/ (models and engines), platform/{windows,linux,macos}/
(one shell per OS, prefixes dropped), and ui/ (shared components). The old
flat module names stay valid through crate-root re-exports so call sites
migrate folder by folder; meeting_live/meeting_tests ride along via their
existing #[path] declarations. Verified by full check+tests on Windows and
module-tree parse checks against the linux and macos targets.
32/64px taskbar/caption icons now derive from app/AppIcon.icon/Assets/ Image.png (squared on a transparent canvas, Lanczos downscale).
The four hand-rolled Windows dropdowns (transcription model, dictation language, microphone, interface language) now share ui::combobox — a stateless, controlled DropdownButton+PopupMenu wrapper whose items are rebuilt on every open (microphones re-enumerate then; enumeration errors show as an inline note). Deletes the per-dropdown open flags, canvas bounds tracking, backdrop/panel/flip-up layout machinery and its two tests, and the Windows fork of disclosure_button.
The split DropdownButton read as a bare label with a boxed caret and only dropped the menu from the chevron. The trigger is now a single 220px secondary Button with an inline caret via the DropdownMenu trait, so the whole control opens the menu and carries the standard Fluent border.
The component library's styling pipeline fought the Fluent look (trigger refinements silently moved onto popover wrappers), so the dependency, theme bridge, Root wrapper, embedded icon assets, and both migrations (catalogue Select, settings comboboxes) are gone; the hand-rolled dropdown stack and disclosure buttons are back. Kept from the detour: dropdown panels can now be wider than their trigger (growing leftward) so long microphone names fit, and height clamps quantize to whole rows.
desktop/ui.rs now has a single token palette (the Windows Fluent 2 dark values) and a single body per widget — header_button, compact_button, disclosure_button, toggle (position-interpolating Fluent pill), keycaps, navigation_item, section labels, settings copy, segmented controls — with only the icon primitives (Segoe glyph / SF Symbol / heroicon) per-platform. The dropdown stack (backdrop, anchored flyout panel with whole-row height clamping and leftward width growth, item rows) moves from the Windows shell into the shared layer, as do selection_pill and the control-fill constants; windows_ui re-exports its historical names. A tr() shim translates on Windows and passes through elsewhere. macOS and Linux now inherit the Windows look for every shared widget.
The Linux shell gains the listener hero card (status dot, device and shortcut hint, in-window Start/Stop via the host actions) and a Problem section that finally surfaces operation errors with a Dismiss control — previously they were computed but never rendered. Section labels move to the shared title-case style, and the content column widens to the shared PANE_CONTENT_WIDTH via pane_content(). SUCCESS/CRITICAL join the shared token set. Verified by Windows build+tests and a linux-target resolution check (no name or field errors; only absent-crate noise).
macOS-parity hints, but real end to end: the local transcriber now passes trimmed hints to Whisper as its initial decoder prompt via transcribe-cpp's run extension (previously the field existed only in settings and was never consumed by the GGUF runtime, on any platform). The Windows settings pane gains the Recognition hints multiline row, shown only while the active model supports hints; edits persist immediately and a running listener restarts through the existing "Applying settings" path after a 1.2s debounce. Hints survive model switches — models that cannot use them load a stripped selection so validation never rejects them.
macOS parity: with the new toggle on (shown under Double-tap to lock), holding the shortcut no longer records — the first complete tap arms the double-tap window silently and the second tap starts hands-free capture, ended by the next press. Implemented in the CaptureState machine with a recording flag so armed taps emit nothing, persisted in WindowsSettings, exposed through the snapshot, and applied via the usual listener restart. Covered by two new state-machine tests.
The tray glyph was a hand-rasterized white "H"; it now ships the actual app icon, pre-rendered from app/AppIcon.icon/Assets/Image.png to a 32×32 raw-RGBA blob embedded at compile time. Full color works on both taskbar themes, so the light-theme probe and the capsule rasterizer are gone.
tray-icon defaults menu_on_left_click to true, so the context menu swallowed the left click that should surface HEX. The menu is now right-click only.
macOS parity for the "While dictating" behavior with three choices in a segmented settings row: Mute silences every other process's WASAPI render session (remembering exactly which ones it muted), Pause media pauses currently-playing system media-transport sessions and resumes them afterwards, Do nothing stays out of the way (default). Suppression engages when recording starts and restores on finish or cancel, runs on a dedicated COM/WinRT worker thread so the dictation loop never blocks, restores on shutdown, and treats every failure as log-and-continue. Adds scoped windows/windows-future dependencies for the WASAPI session and GlobalSystemMediaTransportControls APIs.
macOS-parity toggle: with it on, the listener starts with the capture device closed and opens it on demand when the shortcut is pressed — recording begins at the first chunk, trading pre-roll and first-capture latency for not holding the microphone (and its in-use indicator) open all day. Release/cancel before the device finishes opening discards cleanly, on-demand open failures report through the event log instead of killing the listener, and the device label survives closed periods for status lines. Recording finish/cancel closes the device again.
First slice of macOS Modes parity: a mode names case-insensitive application substrings (matched against the focused process's executable stem) and carries corrections that run after the global text replacements, scoped to the app the dictation lands in. History entries now record that application too. Modes persist in settings, hot-reload through the same Arc<RwLock> path as replacements, and get an editor in the Modes pane: add/remove modes, name and application fields, and per-mode correction rows. Matching is covered by unit tests.
The Application section gains a Software updates row whose button reflects the updater state: Checking while a query runs, an accent-colored "Update to X" that opens the release page when one is available, and "Check now" otherwise — backed by a new request_check() that wakes the background worker immediately instead of waiting out the six-hour interval.
Hold Ctrl+Alt+I (toggle in Settings, off by default), speak an instruction, release: the transcription plus the focused application's selected text go to the local OpenCode service and its reply pastes at the cursor. Pieces: a third hold-to-talk binding in the keyboard hook with its own capture state (Escape cancels, modifier release finishes, mutual exclusion with dictation); clipboard-preserving Ctrl+C selection capture in the paster; a minimal Windows client for the same opencode2 api CLI the macOS processor drives (deadline-bounded, hidden console, identical prompt protocol); voice jobs flowing through the existing output worker with the reply stored as the last dictation for re-paste. The settings row warns inline when OpenCode is not installed. Works with release-microphone-while-idle via the pending-start path.
Voice Action moves out of the Settings pane into a dedicated nav tab (between Modes and History, matching the macOS order) with the same structure: an explainer paragraph, a Capture section holding the shortcut toggle and keycaps, and a Processing section that reports whether OpenCode is installed.
The voice-action arms now engage the While-dictating suppression on start and restore it on finish/cancel, and play the start/stop/cancel feedback tones symmetrically with ordinary dictation.
The duplicated OpenCode CLI client in the macOS dictation processor moves to common/opencode.rs; both platforms now share discovery, the api transport with deadlines and cancellation, the model catalog, prompts, and generation. Windows discovery prefers the real opencode2.exe over npm cmd shims (which shred JSON argv) and strips verbatim \?\ paths from the x-opencode-directory header. The Windows Voice Action pane gains a model picker fed by the catalog: the OpenCode default is adopted automatically (also at startup when a hotkey is configured), the choice persists in settings, and the running listener picks it up per job. Without a chosen model the request omits the model field so OpenCode's own default answers. run_command now kills the whole process tree on deadline, cancel, and exit - a process group on unix, a kill-on-close job object on Windows - so pipe reader joins cannot hang on orphaned descendants. Install detection only counts spawnable .exe files, and dictation failures now surface in the settings hero instead of dying in the event log.
Modes with corrections, Voice Action with in-app model selection, recognition hints, release-microphone-while-idle, while-dictating audio control, and background update checks all shipped; the matrix and the next-slices summary now say so instead of listing them as missing.
…model catalog The Linux settings pane now matches Windows: separate Model (Browse + dropdown), Language, and Microphone rows on the shared dropdown stack instead of the combined picker row. The speech-model browser is one shared dialog (desktop/model_catalog.rs) driven through a delegate trait; Windows renders it with its caption inset and Fluent glyphs, Linux with text controls, and both keep the language filter, install/uninstall, progress, and the pinned active model. Microphone choice persists in Linux settings and opens by exact name at listener start, with automatic fallback when the device is gone; the CLI --device override keeps its substring semantics. Devices re-enumerate on every dropdown open, and changing the microphone, model, or language requires a stopped listener - the controls dim and refuse while running. The tray icon is rendered from the branded app icon instead of the hand-drawn H. Also fixes a pre-existing bare eyre! macro in the Linux dispatch arm that failed to resolve, which broke every Linux build. The whole tree now compiles and passes its suite (72 tests) on a real Linux toolchain under WSL, replacing the old parse-only gate.
The shared search engine already matched text, application, and profile; the Windows pane now has the search field in its header, filtering the list live and keeping the selection when it survives the query.
A new Windows context adapter reads the foreground browser's page URL from its UIA Document element value pattern - locale-independent and working across the Chromium family and Firefox. The read starts when a dictation is submitted so the accessibility walk overlaps inference, is single-flight so a hung provider cannot pile up blocked threads, skips DevTools and sidebar documents by requiring a web URL, and degrades to application-only context after 300ms with a logged warning. Modes gain website rules: exact hosts that beat application substrings, mirroring the macOS selector ordering. Entries accept bare hosts, pasted URLs, host:port forms, and IDN text, all reduced to their comparable host. Voice Action prompts now carry the real browser host too.
The ed25519 trust core moves to common/self_update.rs - feed verification, per-target content-addressed manifest validation, bounded HTTPS-pinned downloads - and the Linux updater consumes it unchanged in behavior. Windows managed installs (running from the user profile's support versions layout, the ACL analog of Linux's ownership checks) now verify, stage, and activate updates with an atomic current-version pointer, repoint Launch at login, and restart through a watcher that only starts the new version once the old process is gone; the Settings row offers a one-shot 'Restart into X'. Source builds keep the GitHub release link. scripts/release-windows.sh mirrors the Linux prepare/publish discipline with the same signing key, an MZ and --version artifact check, and a stale-safe release lock.
The translation table, tr/tr_fill, and the language setting machinery move from the Windows shell to desktop/i18n.rs; the Windows path stays as an alias. System-locale resolution is per platform - the Windows user locale as before, POSIX LC_ALL/LC_MESSAGES/LANG on Linux. The Linux shell gains the persisted Interface language row with the same choices, applies it at startup, and its remaining raw literals now translate, including the statuses, dropdown labels, and the shared model catalog.
install-windows.ps1 creates the self-updating layout the updater activates on - a checksum-verified, version-probed hex.exe under the support versions directory, the current-version pointer, and a managed Start Menu shortcut - and uninstalls cleanly while preserving settings. Updates retarget the managed shortcut alongside the Launch-at-login entry, so every launch path follows the active version. The release script publishes the installer next to the signed feed. Bootstrap trust is TLS plus the feed's content address; every subsequent update is signature-verified by the app.
…ions A fresh install (no persisted settings) gets a welcome dialog on both port shells: pick a dictation language, download its recommended model with live progress, and start dictating - or set up later. The microphone stays cold until the dialog closes. recommended_selection moves to the shared model catalog and now recommends per language instead of falling back to English for everything but Polish, which also upgrades Windows first-run defaults for other locales. Per review: finishing persists the dialog's pending selection only when its model is installed and verified (dropping any stale prepared transcriber), every action is gated while any preparation is in flight, progress rows name the model actually preparing, and re-picking the current language no longer cancels a download.
Both shells gain the macOS Activity surface as one shared read-only pane: live session state and age, the capture device, the recent transcripts the shared activity reader already collected, the last failure, and the observations path. Linux gets its first multi-pane navigation for it. The sidebar now matches macOS ordering with Activity last, and both port shells render the same bundled vector icons drawn to match the macOS SF Symbols, replacing the Windows Fluent glyphs. This commit also carries the shells' onboarding wiring (first-run detection, delegate impls, deferred listener start) alongside the pane plumbing they share files with.
Keep commands and HUD Lab developer-only until Linux ships its native command assets and completes physical X11 validation.
Share the rich foreground-context vocabulary while keeping macOS capture and monitoring native.
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.
No description provided.