How OpenWhispr Coordinates Window Visibility During Recording Sessions
OpenWhispr coordinates window visibility during recording sessions through a centralized Window Manager that synchronizes the dictation overlay and Control Panel via lifecycle state transitions, automatically hiding the main panel to the system tray when recording begins.
OpenWhispr is an open-source dictation application built on Electron that manages complex UI state transitions during audio capture. The application relies on a dedicated window management system to coordinate visibility between the minimal recording overlay and the full Control Panel. Understanding how OpenWhispr coordinates window visibility during recording sessions reveals a state-machine-driven architecture that prevents UI collisions and ensures a seamless dictation experience.
The Window Manager Core Architecture
The coordination logic resides in src/helpers/windowManager.js, which acts as the central authority for all window visibility decisions. This module maintains references to both the dictation overlay (the compact "recording pill") and the Control Panel (the full-size configuration interface). By centralizing state management, OpenWhispr ensures that these two windows never compete for screen space during active recording sessions.
Dictation Lifecycle State Management
The primary mechanism for coordinating visibility is the setDictationLifecycleState(state, scope) method. This function accepts a state parameter—either "recording" or "idle"—and a scope parameter that specifies whether the recording targets the plain dictation UI ("dictation") or the assistant panel ("assistant").
When the system transitions to a recording state, the Window Manager immediately invokes hideControlPanelToTray() to relocate the Control Panel to the system tray, preventing it from obscuring the compact recording interface. This behavior is validated in the test suite, where manager.setDictationLifecycleState("recording", "assistant") at line 185 and manager.setDictationLifecycleState("recording", "dictation") at line 186 demonstrate the dual-scope support.
// Transition to recording state for standard dictation
windowManager.setDictationLifecycleState('recording', 'dictation');
// Control Panel automatically hides to tray; recording pill appears
// Transition back to idle state
windowManager.setDictationLifecycleState('idle', 'dictation');
// Control Panel restores (unless user prefers tray-only mode)
Hiding the Control Panel During Recording
The hideControlPanelToTray() method, implemented at line 1672 of src/helpers/windowManager.js, executes the actual window manipulation. When called, this method moves the Control Panel out of the visible window stack and into the system tray area, ensuring it remains accessible via the tray icon without interfering with the recording workflow.
This method is triggered automatically when recording initializes (line 1238) and prevents the Control Panel from appearing in screen captures or overlapping the dictation interface. The logic is reversible; when the recording lifecycle state returns to "idle", the manager restores the panel to its previous visibility state unless the user has explicitly configured tray-only operation.
Tray Integration and Menu Coordination
The tray helper (src/helpers/tray.js) maintains bidirectional communication with the Window Manager. When users interact with the tray icon menu, the tray module forwards hide and show requests directly to the window manager instance, as seen at line 89 where this.windowManager?.hideControlPanelToTray() delegates the action.
This integration ensures that manual user actions via the tray menu remain synchronized with automatic recording-state changes. Whether the user clicks "Hide to Tray" manually or the system hides the panel automatically when recording starts, the underlying hideControlPanelToTray() method ensures consistent behavior.
// Tray menu interaction delegates to Window Manager
trayMenuItem.on('click', () => {
windowManager.hideControlPanelToTray();
});
Recording Footprint and Window Sizing
During recording sessions, OpenWhispr switches to a dedicated recording footprint defined in WINDOW_SIZES.RECORDING. This sizing configuration, verified in test/helpers/windowSizeLadder.test.js at line 6, specifies the compact dimensions required for the recording pill overlay.
By isolating the recording UI to this predefined footprint, the Window Manager guarantees that the overlay never forces the main Control Panel to resize or reposition. This separation ensures that when the Control Panel returns from the tray after recording ends, it retains its original geometry and state.
Busy-State Guards and Race Condition Prevention
To prevent UI race conditions, the Window Manager implements a busy-state flag that blocks visibility changes while recording is active. As documented in test/helpers/windowManagerAssistantPanel.test.js at line 643, any attempt to programmatically show the Control Panel while the busy flag is set (indicating an active recording) is ignored by the state machine.
This guard extends to meeting notifications as well. The test suite in test/helpers/windowManagerMeetingNotification.test.js (line 247) verifies that meeting-related UI elements respect the recording busy state, deferring notifications until the recording lifecycle returns to idle. This ensures that critical dictation sessions remain unobstructed by secondary UI events.
Summary
- Centralized Coordination: The
src/helpers/windowManager.jsmodule acts as the single source of truth for window visibility, managing both the Control Panel and dictation overlay. - Lifecycle-Driven Transitions: The
setDictationLifecycleState()method automates visibility changes, triggeringhideControlPanelToTray()automatically when recording begins. - Tray Integration: The
src/helpers/tray.jshelper synchronizes manual user actions with automatic recording-state management. - Fixed Recording Footprint:
WINDOW_SIZES.RECORDINGdefines a compact overlay size that prevents window geometry conflicts during capture. - Busy-State Protection: A busy flag prevents the Control Panel from interrupting active recordings, ensuring UI stability during critical dictation sessions.
Frequently Asked Questions
What triggers the Control Panel to hide when I start recording?
When you initiate a recording, the application calls setDictationLifecycleState("recording", scope), which automatically invokes hideControlPanelToTray() to move the Control Panel into the system tray. This prevents the larger window from obscuring the compact recording pill interface.
Can I manually show the Control Panel while a recording is in progress?
No. The Window Manager implements a busy-state guard that blocks visibility changes while recording is active. As implemented in the assistant panel tests, any attempt to show the Control Panel during the recording lifecycle is ignored until the state returns to "idle".
How does OpenWhispr distinguish between standard dictation and assistant panel recording modes?
The setDictationLifecycleState() method accepts a scope parameter that differentiates between "dictation" (standard mode) and "assistant" (AI-assisted mode). Both scopes trigger the same Control Panel hiding logic, but the scope determines which overlay UI renders the recording feedback.
Where is the recording window size defined?
The recording overlay dimensions are defined in the WINDOW_SIZES.RECORDING configuration constant, which is validated in test/helpers/windowSizeLadder.test.js. This ensures the "recording pill" maintains consistent compact dimensions across different screen resolutions and DPI settings.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →