# Window Lifecycle Management in OpenWhispr: Architecture and Implementation Guide

> Discover how OpenWhispr manages its dual-window Electron app. Explore the windowManager js module for centralized creation, visibility, resizing, and state tracking.

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

---

**The [`src/helpers/windowManager.js`](https://github.com/OpenWhispr/openwhispr/blob/main/src/helpers/windowManager.js) module handles all window lifecycle management in OpenWhispr, centralizing creation, visibility toggling, resizing, and state tracking for the application's dual-window Electron architecture.**

OpenWhispr is an Electron-based dictation application that relies on sophisticated window lifecycle management to coordinate its always-on-top overlay and control panel interfaces. Understanding how the application manages window creation, visibility transitions, and interactivity states is essential for contributors working with the codebase. The [`windowManager.js`](https://github.com/OpenWhispr/openwhispr/blob/main/windowManager.js) helper serves as the single source of truth for these operations throughout the main process.

## Core Window Lifecycle Management Module

According to the OpenWhispr source code, all window lifecycle logic lives in **[`src/helpers/windowManager.js`](https://github.com/OpenWhispr/openwhispr/blob/main/src/helpers/windowManager.js)**. This module acts as a centralized manager responsible for creating the two primary Electron windows: the always-on-top dictation overlay and the full-size control panel. It maintains references to these window instances and exposes a rich API used across the application to manipulate window state without scattering Electron-specific code throughout the codebase.

The manager tracks critical state flags including **`isQuitting`**, **`isOnboardingDemoActive`**, and **`notificationPrefs`** to guide shutdown handling, onboarding flows, and user notification preferences. These flags ensure that window operations respect the current application context, preventing inappropriate window manipulation during critical transitions.

## Window Creation and Initialization

The [`windowManager.js`](https://github.com/OpenWhispr/openwhispr/blob/main/windowManager.js) module exposes explicit factory methods for instantiating the dual-window architecture:

- **`createMainWindow()`** – Initializes the dictation overlay window that remains always-on-top during transcription sessions.
- **`createControlPanelWindow()`** – Spawns the full-size settings and configuration interface.

Both methods configure window properties using static dimensions defined in [`src/helpers/windowConfig.js`](https://github.com/OpenWhispr/openwhispr/blob/main/src/helpers/windowConfig.js), ensuring consistent sizing across the application. Once created, the manager retains references to these windows, preventing garbage collection and enabling subsequent lifecycle operations.

## Window Visibility and Dimension Control

The module provides granular control over window presentation through dedicated visibility methods:

**Visibility Toggles:**
- `showDictationPanel({ focus, reposition })` – Displays the dictation overlay with optional focus and positioning parameters.
- `hideDictationPanel()` – Conceals the overlay while preserving the window instance.
- `showControlPanel()` – Reveals the full control panel interface.
- `hideControlPanelToTray()` – Minimizes the control panel to the system tray rather than closing it.

**Dynamic Resizing:**
- `resizeMainWindow()` – adjusts the primary dictation window dimensions.
- `resizeAssistantWindowToContent()` – resizes the assistant interface to fit dynamic content.
- `resizeDictationErrorWindowToContent()` – accommodates error message displays without truncation.

**Interactivity Management:**
- `setMainWindowInteractive(boolean)` – toggles whether the main window accepts mouse and keyboard input.
- `setNotificationInteractivity(boolean)` – controls input handling during active transcription or meeting notifications.

These methods allow other components to manipulate window state without direct access to Electron's `BrowserWindow` APIs, maintaining a clean abstraction layer.

## Integration with Application Components

OpenWhispr employs a dependency injection pattern to share the window manager across modules. The **`setWindowManager`** method injects the manager instance into core components that require window manipulation capabilities.

In **[`src/helpers/ipcHandlers.js`](https://github.com/OpenWhispr/openwhispr/blob/main/src/helpers/ipcHandlers.js)**, the manager attaches via `this.windowManager = managers.windowManager` and subsequently delegates IPC calls to show panels, hide interfaces, and resize windows based on renderer process requests.

The **[`src/helpers/tray.js`](https://github.com/OpenWhispr/openwhispr/blob/main/src/helpers/tray.js)** module queries the manager to synchronize window visibility with system tray interactions. When users click the tray icon, the tray component invokes manager methods to toggle panel visibility rather than managing window references directly.

In **[`src/updater.js`](https://github.com/OpenWhispr/openwhispr/blob/main/src/updater.js)**, the auto-updater checks `windowManager.notificationPrefs` before presenting update alerts, ensuring that critical update notifications respect user preferences managed by the window lifecycle system.

## Configuration and Static Definitions

While [`windowManager.js`](https://github.com/OpenWhispr/openwhispr/blob/main/windowManager.js) handles dynamic lifecycle operations, static window configuration resides in **[`src/helpers/windowConfig.js`](https://github.com/OpenWhispr/openwhispr/blob/main/src/helpers/windowConfig.js)**. This separation of concerns allows the manager to focus on runtime state manipulation while the configuration file maintains constant dimensions, frame preferences, and web preferences used during window instantiation.

## Practical Implementation Examples

Initialize the window manager and create primary windows in your main process entry point:

```javascript
const WindowManager = require("./src/helpers/windowManager");

// Instantiate the lifecycle manager
const windowManager = new WindowManager();

// Create both application windows
windowManager.createMainWindow();        // dictation overlay
windowManager.createControlPanelWindow(); // settings panel

```

Expose window controls through IPC handlers:

```javascript
// Show the dictation overlay with focus and repositioning
ipcMain.handle("show-dictation-panel", async () => {
  await windowManager.showDictationPanel({ focus: true, reposition: true });
});

// Hide control panel and move to tray instead of closing
ipcMain.handle("hide-control-panel-to-tray", async () => {
  await windowManager.hideControlPanelToTray();
});

```

Inject the manager into dependent modules:

```javascript
// In ipcHandlers.js, tray.js, or updater.js
const managers = { windowManager: new WindowManager() };
someComponent.setWindowManager(managers);

```

## Summary

- **[`src/helpers/windowManager.js`](https://github.com/OpenWhispr/openwhispr/blob/main/src/helpers/windowManager.js)** serves as the exclusive module for window lifecycle management in OpenWhispr, eliminating scattered window manipulation code.
- The manager maintains references to two distinct windows (dictation overlay and control panel) and tracks state flags including `isQuitting` and `isOnboardingDemoActive`.
- A rich API provides methods for visibility control (`showDictationPanel`, `hideControlPanelToTray`), dynamic resizing, and interactivity toggling.
- Components receive the manager via `setWindowManager` injection, enabling delegation of window operations from [`ipcHandlers.js`](https://github.com/OpenWhispr/openwhispr/blob/main/ipcHandlers.js), [`tray.js`](https://github.com/OpenWhispr/openwhispr/blob/main/tray.js), and [`updater.js`](https://github.com/OpenWhispr/openwhispr/blob/main/updater.js).
- Static configuration in [`src/helpers/windowConfig.js`](https://github.com/OpenWhispr/openwhispr/blob/main/src/helpers/windowConfig.js) supports the manager's runtime operations while maintaining separation of concerns.

## Frequently Asked Questions

### Which module handles window lifecycle management in OpenWhispr?

The **[`src/helpers/windowManager.js`](https://github.com/OpenWhispr/openwhispr/blob/main/src/helpers/windowManager.js)** module exclusively handles window lifecycle management. This helper creates and tracks both the always-on-top dictation overlay and the full-size control panel, exposing methods for visibility, resizing, and interactivity control that other components consume through dependency injection.

### How does OpenWhispr toggle visibility between the dictation panel and control panel?

OpenWhispr uses dedicated manager methods including **`showDictationPanel`**, **`hideDictationPanel`**, **`showControlPanel`**, and **`hideControlPanelToTray`**. These methods abstract Electron's window APIs and handle positioning, focus states, and tray integration without requiring direct `BrowserWindow` manipulation in consumer code.

### What pattern does OpenWhispr use to share window management across modules?

OpenWhispr implements a **setter injection pattern** via the `setWindowManager` method. Core components like [`ipcHandlers.js`](https://github.com/OpenWhispr/openwhispr/blob/main/ipcHandlers.js), [`tray.js`](https://github.com/OpenWhispr/openwhispr/blob/main/tray.js), and [`updater.js`](https://github.com/OpenWhispr/openwhispr/blob/main/updater.js) receive the manager instance through this setter, then delegate window operations to the centralized API rather than instantiating or managing window references independently.

### How does window lifecycle management affect update notifications in OpenWhispr?

The updater module checks **`windowManager.notificationPrefs`** before displaying update alerts, as implemented in [`src/updater.js`](https://github.com/OpenWhispr/openwhispr/blob/main/src/updater.js). This integration ensures that auto-update notifications respect the window manager's state tracking and user preference configuration, preventing disruptive notifications during active transcription or onboarding flows.