# How OpenWhispr Coordinates Window Visibility During Recording Sessions

> OpenWhispr coordinates window visibility using a Window Manager to sync overlays and panels, automatically hiding the main panel to the system tray when recording starts.

- Repository: [OpenWhispr/openwhispr](https://github.com/OpenWhispr/openwhispr)
- Tags: internals
- Published: 2026-09-06

---

**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`](https://github.com/OpenWhispr/openwhispr/blob/main/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.

```javascript
// 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`](https://github.com/OpenWhispr/openwhispr/blob/main/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`](https://github.com/OpenWhispr/openwhispr/blob/main/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.

```javascript
// 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`](https://github.com/OpenWhispr/openwhispr/blob/main/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`](https://github.com/OpenWhispr/openwhispr/blob/main/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`](https://github.com/OpenWhispr/openwhispr/blob/main/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.js`](https://github.com/OpenWhispr/openwhispr/blob/main/src/helpers/windowManager.js) module 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, triggering `hideControlPanelToTray()` automatically when recording begins.
- **Tray Integration**: The [`src/helpers/tray.js`](https://github.com/OpenWhispr/openwhispr/blob/main/src/helpers/tray.js) helper synchronizes manual user actions with automatic recording-state management.
- **Fixed Recording Footprint**: `WINDOW_SIZES.RECORDING` defines 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`](https://github.com/OpenWhispr/openwhispr/blob/main/test/helpers/windowSizeLadder.test.js). This ensures the "recording pill" maintains consistent compact dimensions across different screen resolutions and DPI settings.