Introduction

Flutter’s cross‑platform reach now includes full‑featured Windows desktop support. To deliver a truly native experience you need to control the window itself—size, position, title bar, and more. The Desktop Windowing API in flutter gives you that power, letting you treat a Windows app like any other desktop product while still writing a single Dart codebase.

Prerequisites

  • Flutter SDK ≥ 3.10
  • Windows 10 (1809) or later
  • Visual Studio 2022 with the "Desktop development with C++" workload

Enabling Windows Desktop Support

Before you can use the Desktop Windowing API you must enable the Windows target in your Flutter installation.

Code
flutter config --enable-windows-desktop

Run flutter doctor to verify that the Windows toolchain is ready.

💡 Tip: If you see a warning about missing Visual Studio components, open the Visual Studio Installer and add the "Desktop development with C++" workload.

Adding the Desktop Windowing API Dependency

Flutter does not expose the Windows window directly from the core SDK, but the community‑maintained window_manager package wraps the native Desktop Windowing API cleanly.

Code
dependencies:
  flutter:
    sdk: flutter
  window_manager: ^0.3.5

After editing pubspec.yaml, fetch the packages:

Code
flutter pub get

Basic Flutter App Skeleton

Start with a minimal Flutter app that will later be enhanced with window controls.

Dart / Flutter
import 'package:flutter/material.dart';
import 'package:window_manager/window_manager.dart';

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

  // Optional: set default window options before runApp
  WindowOptions windowOptions = const WindowOptions(
    size: Size(900, 600),
    center: true,
    title: 'FlutterFever Windows Demo',
    backgroundColor: Colors.transparent,
    skipTaskbar: false,
    titleBarStyle: TitleBarStyle.normal,
  );
  windowManager.waitUntilReadyToShow(windowOptions, () async {
    await windowManager.show();
    await windowManager.focus();
  });

  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Desktop Windowing API Demo',
      theme: ThemeData.light(),
      home: const HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State createState() => _HomePageState();
}

class _HomePageState extends State with WindowListener {
  @override
  void initState() {
    super.initState();
    windowManager.addListener(this);
  }

  @override
  void dispose() {
    windowManager.removeListener(this);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Desktop Windowing API in flutter')),
      body: const Center(child: Text('Hello, Windows!')),
    );
  }
}

Using the Desktop Windowing API to Customize the Window

Changing Size and Position at Runtime

The API lets you resize or move the window in response to user actions.

Code
Future _resizeWindow() async {
  // Set a new size (width: 1200, height: 800)
  await windowManager.setSize(const Size(1200, 800));
  // Center the window after resizing
  await windowManager.center();
}

Controlling the Title Bar

You can modify the title text, hide the native title bar, or replace it with a custom Flutter widget.

Code
Future _customizeTitleBar() async {
  await windowManager.setTitle('My Custom Flutter Window');
  // Hide the native title bar to draw your own UI
  await windowManager.setTitleBarStyle(TitleBarStyle.hidden);
}

Full‑Screen and Maximized Modes

Switching between windowed, maximized, and full‑screen states is straightforward.

Code
Future _toggleFullScreen() async {
  bool isFullScreen = await windowManager.isFullScreen();
  await windowManager.setFullScreen(!isFullScreen);
}

Future _toggleMaximize() async {
  bool isMaximized = await windowManager.isMaximized();
  if (isMaximized) {
    await windowManager.restore();
  } else {
    await windowManager.maximize();
  }
}

Advanced Window Management

Setting Minimum and Maximum Sizes

Prevent the user from resizing the window beyond sensible limits.

Code
await windowManager.setMinimumSize(const Size(800, 500));
await windowManager.setMaximumSize(const Size(1920, 1080));

Listening to Window Events

The WindowListener mixin (used in the example above) provides callbacks for focus, minimize, restore, and close events.

Code
@override
void onWindowFocus() {
  debugPrint('Window gained focus');
}

@override
void onWindowClose() async {
  bool shouldClose = await _showExitConfirmation();
  if (shouldClose) {
    await windowManager.destroy();
  }
}

Testing and Debugging

  • Run flutter run -d windows to launch the app in a Windows debugger.
  • Use Visual Studio’s native debugger to step through any C++ bridge code if you add custom platform channels.
  • Inspect window properties with the Windows "Inspect" tool (part of the Windows SDK) to verify accessibility attributes.

Performance Considerations

The Desktop Windowing API adds a thin native layer; it does not impact Flutter’s rendering pipeline. However, keep these best practices in mind:

  • Avoid frequent size changes; each call triggers a layout pass on the native side.
  • Batch multiple window operations in a single async block when possible.
  • Dispose of listeners (e.g., windowManager.removeListener) to prevent memory leaks.

Conclusion

By integrating the Desktop Windowing API in flutter you gain fine‑grained control over the Windows desktop experience while preserving the productivity of a single Dart codebase. The patterns shown here—initial configuration, runtime adjustments, and event handling—form a solid foundation for any modern Windows application built with Flutter.

Frequently Asked Questions

Do I need a separate package to use the Desktop Windowing API in Flutter?

Yes. The most common approach is to add the <code>window_manager</code> package, which wraps the native Windows window APIs and exposes them as async Dart methods.

Can I hide the native title bar and draw my own custom title bar?

Absolutely. Call <code>windowManager.setTitleBarStyle(TitleBarStyle.hidden)</code> and then design a Flutter widget that mimics a title bar, handling drag, minimize, maximize, and close actions manually.

Is the Desktop Windowing API compatible with macOS and Linux?

The <code>window_manager</code> package implements similar functionality on macOS and Linux, but the underlying native calls differ. The same Dart API works across all three desktop platforms, making your code portable.

How do I ensure my window size changes do not cause jank?

Batch size or position changes in a single async call and avoid rapid, repeated calls (e.g., on every drag event). Use debouncing if you need to respond to continuous user input.

Do I need to rebuild the Flutter UI after changing the window size?

No. Changing the window size via the Desktop Windowing API does not trigger a Flutter rebuild. However, responsive layouts that depend on <code>MediaQuery.of(context).size</code> will automatically adapt on the next frame.