Window Lifecycle Management in OpenWhispr: Architecture and Implementation Guide

The 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 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. 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 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, 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, 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 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, 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 handles dynamic lifecycle operations, static window configuration resides in 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:

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:

// 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:

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

Summary

  • 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, tray.js, and updater.js.
  • Static configuration in 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 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, tray.js, and 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. 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.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →