# How FlClash’s Window Manager Supports Multi-Window Functionality on Desktop

> Discover how FlClash's Window Manager enables multi-window functionality by managing native windows, persisting geometry, and validating monitor positioning. Learn about its extensible architecture.

- Repository: [chen08209/FlClash](https://github.com/chen08209/FlClash)
- Tags: internals
- Published: 2026-05-31

---

**FlClash orchestrates desktop UI through a singleton `WindowManager` that leverages the `window_manager` and `window_ext` plugins to control a single native window, persist geometry across sessions, and validate positioning against multiple monitors, while maintaining an architecture that can be extended to true multi-window support.**

The `chen08209/FlClash` repository implements a sophisticated desktop window management system using Flutter’s desktop embedding APIs. While the application currently enforces a single-instance pattern, the underlying **FlClash window manager** architecture is built on generic window creation primitives that separate window control from UI rendering, enabling robust state persistence and multi-monitor awareness.

## Architecture of the Window Management Stack

The window system centers on two primary components: the global `Window` singleton defined in `lib/common/window.dart` and the `WindowManager` class in `lib/manager/window_manager.dart`. These work together with the `window_manager` plugin to bridge Flutter’s widget tree with native OS window APIs.

- **`Window`** – Handles initialization, lifecycle methods (`show`, `hide`, `close`), and coordinate validation using `screen_retriever`.
- **`WindowManager`** – Registers as a listener for native events (move, resize, focus, minimize) and forwards state changes to Riverpod providers.
- **`WindowHeader`** – A custom widget implementing draggable regions and window controls that proxy calls to `windowManager` methods like `startDragging()` and `setAlwaysOnTop()`.

## Window Initialization and State Restoration

When the application launches, `Window.init()` in `lib/common/window.dart` executes the following sequence:

1. Acquires a **single-instance lock** via `singleInstanceLock.acquire()` to prevent multiple processes.
2. Initializes the native window handle with `windowManager.ensureInitialized()`.
3. Applies saved geometry from `config.windowProps` (a `WindowProps` object stored in `lib/providers/config.dart`).
4. Validates coordinates against all connected displays using `screenRetriever.getAllDisplays()`.

If the saved position falls outside any monitor bounds, the window is recentered to prevent off-screen placement.

```dart
// From lib/common/window.dart
await window.init(
  version,                // affects macOS bar styling
  config.windowProps,     // persisted WindowProps (top, left, width, height)
);

```

## Event Handling and Custom Title Bar

The `WindowManager` class attaches listeners during construction to capture native window events. These callbacks update the `windowSettingProvider` Riverpod state, ensuring the config file reflects the latest geometry.

- **`onWindowMoved`** – Calls `windowManager.getPosition()` and updates provider state.
- **`onWindowResized`** – Retrieves size via `windowManager.getSize()` and persists dimensions.
- **`onWindowFocus`** / **`onWindowMinimize`** – Controls the rendering loop to reduce CPU usage.

The `WindowHeader` widget in `lib/manager/window_manager.dart` provides custom chrome buttons (pin, minimize, maximize, close) that invoke corresponding `windowManager` methods:

```dart
// Pin toggle implementation
final alwaysOnTop = await windowManager.isAlwaysOnTop();
await windowManager.setAlwaysOnTop(!alwaysOnTop);
isPinNotifier.value = await windowManager.isAlwaysOnTop();

// Maximize/Restore toggle
final maximized = await windowManager.isMaximized();
maximized ? await windowManager.unmaximize() : await windowManager.maximize();
isMaximizedNotifier.value = await windowManager.isMaximized();

```

## Single-Instance Enforcement and Multi-Window Potential

FlClash deliberately limits itself to one native window. In `Window.init()`, lines 20–23 acquire a process-wide lock:

```dart
// Single-instance guard
if (!await singleInstanceLock.acquire()) {
  exit(0);  // Terminate if another instance exists
}

```

This design choice means **FlClash does not currently open multiple independent windows**. However, the architecture supports extension: the `window_manager` plugin exposes `createWindow` APIs, and the `WindowHeader` logic could be instantiated per-window. Adding true multi-window functionality would require removing the single-instance lock and managing multiple `WindowManager` instances mapped to distinct window IDs.

## Multi-Monitor Position Validation

To support multi-window functionality across diverse desktop environments, FlClash validates saved coordinates against the entire display space. The `_windowPosition` getter in `lib/common/window.dart` iterates through `screenRetriever.getAllDisplays()` to ensure the requested `(left, top)` coordinates intersect with at least one monitor. If validation fails, the window defaults to centered positioning.

## Rendering Optimization on Focus Changes

The window manager integrates with Flutter’s rendering pipeline to conserve resources. When `onWindowFocus` fires, the manager calls `render?.resume()`; conversely, `onWindowMinimize` triggers `render?.pause()`. This ensures the proxy engine ceases heavy computation when the window is not visible.

## Summary

- **FlClash** uses a **single native window** enforced by a process lock, but built on APIs capable of supporting multiple windows.
- **Window state** (size, position, pin status) persists across launches via `WindowProps` stored in `lib/providers/config.dart`.
- **Multi-monitor awareness** validates coordinates against all connected displays to prevent off-screen placement.
- **Custom title bar** actions proxy to `window_manager` methods for OS-level control.
- **Rendering lifecycle** pauses on minimize/focus loss to optimize CPU usage.

## Frequently Asked Questions

### Does FlClash support multiple independent windows?

No. FlClash enforces a single-instance pattern using `singleInstanceLock.acquire()` in `lib/common/window.dart`. If you attempt to launch a second instance, the process exits immediately. While the underlying `window_manager` plugin supports `createWindow`, the current architecture is designed around a single native window.

### How does FlClash remember window position across restarts?

The `WindowManager` listens for `onWindowMoved` and `onWindowResized` events, reads the current geometry via `windowManager.getPosition()` and `windowManager.getSize()`, and updates the `windowSettingProvider`. This Riverpod provider writes a `WindowProps` object to disk during the application shutdown sequence, which is reloaded during the next `Window.init()` call.

### What happens if a monitor is disconnected and the saved window position is off-screen?

Before applying saved coordinates, `Window._windowPosition` validates the stored `(left, top)` values against the bounds of all displays returned by `screenRetriever.getAllDisplays()`. If the coordinates do not intersect with any monitor, the method returns `null`, causing `Window.init()` to center the window on the primary display instead of positioning it off-screen.

### Can I extend FlClash to open settings in a separate window?

Yes, but it requires architectural changes. You would need to remove the `singleInstanceLock` check in `lib/common/window.dart`, invoke `windowManager.createWindow()` (available in the underlying plugin), and instantiate a new `WindowManager` or `WindowHeader` for the secondary window context. The current codebase isolates window control logic in a way that facilitates this extension, though the single-instance guard must be disabled first.