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.
flutter config --enable-windows-desktopRun 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.
dependencies:
flutter:
sdk: flutter
window_manager: ^0.3.5After editing pubspec.yaml, fetch the packages:
flutter pub getBasic Flutter App Skeleton
Start with a minimal Flutter app that will later be enhanced with window controls.
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.
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.
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.
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.
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.
@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 windowsto 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.