# Streambert Single Instance Lock: Managing Multiple Windows in Electron

> Learn how Streambert's single instance lock manages multiple Electron windows, including picture-in-picture support, for a seamless user experience.

- Repository: [true_lock/streambert](https://github.com/truelockmc/streambert)
- Tags: internals
- Published: 2026-05-21

---

**Streambert uses Electron's `app.requestSingleInstanceLock()` API in [`src/index.js`](https://github.com/truelockmc/streambert/blob/main/src/index.js) to enforce a single-instance lock while simultaneously supporting multiple auxiliary windows including picture-in-picture and pop-out player windows.**

Streambert is an Electron-based streaming application developed under the `truelockmc/streambert` repository that requires strict single-instance enforcement despite supporting multiple window types. Understanding how Streambert implements a single instance lock while managing multiple windows is essential for developers working with Electron's process model and shared resource management.

## Implementing the Single-Instance Lock in src/index.js

The core implementation resides in the main entry point at [`src/index.js`](https://github.com/truelockmc/streambert/blob/main/src/index.js), where the application leverages Electron's native API to control instance spawning and prevent duplicate backend processes.

### Acquiring the Lock on Startup

Immediately after defining IPC handlers, the code attempts to acquire the single-instance lock:

```js
const gotTheLock = app.requestSingleInstanceLock();

```

This call returns a boolean indicating whether the current process successfully claimed the lock. According to the Streambert source code, this occurs at lines 82-84 in [`src/index.js`](https://github.com/truelockmc/streambert/blob/main/src/index.js).

### Terminating Duplicate Instances

If another Streambert instance is already running, the lock acquisition fails and the duplicate process exits immediately to prevent database corruption:

```js
if (!gotTheLock) {
  app.quit();
}

```

This logic at lines 85-86 ensures that only one process can access the SQLite storage files and download queues managed by [`src/ipc/downloads.js`](https://github.com/truelockmc/streambert/blob/main/src/ipc/downloads.js) and [`src/ipc/storage.js`](https://github.com/truelockmc/streambert/blob/main/src/ipc/storage.js).

### Handling Second-Instance Events

When the lock succeeds, the primary instance registers a `second-instance` event listener. If a user attempts to launch Streambert again—perhaps by clicking the application icon—the existing window is restored rather than creating a new process:

```js
app.on("second-instance", () => {
  if (mainWindow) {
    if (mainWindow.isMinimized()) mainWindow.restore();
    mainWindow.focus();
  }
});

```

This handler at lines 89-93 ensures that keyboard shortcuts, media controls, and the system tray icon always target the same window hierarchy.

## Supporting Multiple Windows Within the Single Instance

Despite enforcing one process, Streambert creates several auxiliary windows that share the same backend state and Electron `session` objects.

### Window Creation Workflow

The main window initializes through `createWindow()` after the Electron `ready` event fires. This function establishes the primary browser window, while additional windows for picture-in-picture (PIP) and pop-out players are created lazily via IPC handlers such as `open-pip-window` and `open-popout-window` defined later in the same file.

### Shared Backend Resources

All windows access common resources through IPC modules. The single-instance lock prevents **duplicate download queues** and conflicting database connections to the SQLite file that stores user settings, subtitle caches, and persistent storage. Running two instances would create file-level race conditions in these shared modules.

### Session and Memory Management

Electron's `session` objects for video playback—specifically `persist:player` and `persist:trailer`—are created once per process. The lock ensures these sessions aren't duplicated across instances, optimizing memory consumption and maintaining consistent media state across the main window, PIP views, and pop-out players.

## Graceful Shutdown and Lock Release

When the user closes all windows, the `window-all-closed` listener triggers `app.quit()`, releasing the system lock and allowing future launches to acquire it:

```js
app.on("window-all-closed", () => app.quit());

```

This implementation at lines 99-100 completes the application lifecycle, ensuring that the `requestSingleInstanceLock()` can succeed on the next application startup.

## Summary

- **Single-instance enforcement** occurs in [`src/index.js`](https://github.com/truelockmc/streambert/blob/main/src/index.js) using `app.requestSingleInstanceLock()`, with duplicate processes immediately calling `app.quit()` at lines 85-86.
- **Window restoration** happens via the `second-instance` event, which focuses the existing `mainWindow` using `mainWindow.restore()` and `mainWindow.focus()` rather than spawning new applications.
- **Multiple auxiliary windows** (PIP, pop-out) operate within the single process, sharing SQLite databases via [`src/ipc/storage.js`](https://github.com/truelockmc/streambert/blob/main/src/ipc/storage.js) and IPC handlers without resource conflicts.
- **Graceful shutdown** through `window-all-closed` at lines 99-100 ensures the lock releases properly when all windows close.

## Frequently Asked Questions

### How does Streambert prevent multiple instances from running?

Streambert calls `app.requestSingleInstanceLock()` in [`src/index.js`](https://github.com/truelockmc/streambert/blob/main/src/index.js) immediately during startup. If the return value `gotTheLock` is `false`, the application executes `app.quit()` to terminate the duplicate process before any windows render, preventing conflicts in the SQLite database and download managers.

### What happens when I try to open Streambert while it's already running?

The operating system routes the request to the existing instance, triggering the `second-instance` event. The handler checks if `mainWindow` exists, restores it if minimized using `mainWindow.restore()`, and brings it to focus with `mainWindow.focus()`, ensuring users always interact with the single running instance.

### Can Streambert open multiple windows simultaneously?

Yes. While only one application instance runs, Streambert supports multiple window types including the main browser window, picture-in-picture views, and pop-out players. These share the same Electron process and backend resources through IPC handlers defined in [`src/index.js`](https://github.com/truelockmc/streambert/blob/main/src/index.js) and preload scripts like [`src/preload.js`](https://github.com/truelockmc/streambert/blob/main/src/preload.js) and [`src/popout-preload.js`](https://github.com/truelockmc/streambert/blob/main/src/popout-preload.js).

### Where is the single-instance logic located in the codebase?

The primary implementation resides in [`src/index.js`](https://github.com/truelockmc/streambert/blob/main/src/index.js) at lines 82-93, containing the lock acquisition, duplicate instance termination, and second-instance event handling. Supporting IPC modules for shared resources are located in [`src/ipc/downloads.js`](https://github.com/truelockmc/streambert/blob/main/src/ipc/downloads.js) and [`src/ipc/storage.js`](https://github.com/truelockmc/streambert/blob/main/src/ipc/storage.js), while window titlebar UI components are defined in [`src/components/WindowTitlebar.jsx`](https://github.com/truelockmc/streambert/blob/main/src/components/WindowTitlebar.jsx).