persistent_window_manager

pub package License: MIT

Saves and restores a Flutter desktop window's position, size, maximized, and full-screen state between sessions.

Built on top of window_manager, screen_retriever, and hydrated_bloc.

Features

  • Zero-flicker restoration: Restores the last saved size, position, and window state before displaying the window on startup.
  • Smart debouncing: Listens to window events and persists position/size changes without impacting UI performance during live resizing.
  • Off-screen prevention: Ensures windows aren't restored outside visible bounds if monitor setups change.
  • Cross-platform safety: Automatically no-ops on web and mobile platforms, keeping your main() unified across all targets.

Supported Platforms

  • Windows
  • macOS
  • Linux

Setup

1. Add dependency

Add the package to your pubspec.yaml:

dependencies:
  persistent_window_manager: ^2.0.0

2. Initialize HydratedBloc.storage

HydratedBloc.storage must be initialized before the package is used. Keeping this explicit ensures your app retains full control over storage directory logic:

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:hydrated_bloc/hydrated_bloc.dart';
import 'package:path_provider/path_provider.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  HydratedBloc.storage = await HydratedStorage.build(
    storageDirectory: kIsWeb
        ? HydratedStorageDirectory.web
        : HydratedStorageDirectory((await getApplicationSupportDirectory()).path),
  );

  // ...
}

3. Wrap Your App

Wrap your root widget with PeWiMaWrapper to enable persistent window management:

import 'package:flutter/material.dart';
import 'package:persistent_window_manager/persistent_window_manager.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // ... HydratedBloc.storage initialization ...

  runApp(
    PeWiMaWrapper(
      const MyApp(),
      windowOptions: const CustomWindowOptions(
        minimumSize: Size(700, 600),
        title: 'My App',
      ),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('Home')),
        body: const Center(child: Text('Hello World')),
      ),
    );
  }
}

Note: PeWiMaWrapper automatically handles platform detection. On web and mobile platforms, it simply renders the child widget without window management. This allows you to write a unified main() function that works across all targets.

See example/lib/main.dart for a complete runnable implementation.

Support & Contributions

If this package saved you time or made your Flutter desktop development smoother, consider supporting its development!

Buy Me a Tea

(And let's be honest, tea is far superior to coffee anyway 🫖)