window_manager is built on nativeapi, a Flutter binding of one C++ core library (libnativeapi/nativeapi) shared by macOS, Windows and Linux. Coming from 0.5.x? See Upgrading from 0.5.x.
This package lets Flutter desktop apps size, move, show, hide and decorate their own window.
English | 简体中文
| Linux | macOS | Windows |
|---|---|---|
| ✔️ | ✔️ | ✔️ |
Add this to your package's pubspec.yaml file:
dependencies:
window_manager: ^0.6.0Or
dependencies:
window_manager:
git:
url: https://github.com/leanflutter/window_manager.git
ref: main- Flutter 3.47 / Dart 3.13 or later, macOS 10.15 or later.
- Linux build machines need GTK 3, X11 and Xi development files:
sudo apt-get install libgtk-3-dev libx11-dev libxi-dev
import 'package:window_manager/window_manager.dart';
final window = WindowManager.instance.getCurrent()!;
window.title = 'window_manager';
window.setSize(const Size(1000, 700).toNative(), false);
window.minimumSize = const Size(640, 480).toNative();
window.center();
window.show();
// Every window event of every window of this app.
WindowManager.instance.addListener((event) {
switch (event) {
case WindowFocusedEvent():
debugPrint('window ${event.windowId} focused');
case WindowResizedEvent():
debugPrint('window ${event.windowId} is now ${event.newSize.toSize()}');
default:
break;
}
});
// Ask before this window closes, however the user closes it. Close requests
// reach only the window's own listeners.
window.addListener((event) async {
if (event is WindowCloseRequestedEvent && !await confirmClose()) {
event.request.cancel();
}
});Window takes and returns nativeapi's Size, Point, Rectangle and Color, which are
not exported because Flutter has its own: toNative() turns Flutter's into them, and
toSize(), toOffset(), toRect() and toColor() turn them back.
With Flutter's multi-window API, package:window_manager/windowing.dart answers the
Window behind each of Flutter's window controllers:
import 'package:window_manager/windowing.dart';
final window = controller.nativeWindow; // or nativeWindowOf(controller)
window?.title = 'Inspector';A window with no title bar of its own, dragged and resized by widgets:
final window = WindowManager.instance.getCurrent()!;
window.titleBarStyle = TitleBarStyle.hidden;
// In the app:
DragToResizeArea(
child: Column(
children: [
WindowCaption(
brightness: Theme.of(context).brightness,
title: const Text('window_manager'),
),
Expanded(child: body),
],
),
)The example app of this plugin covers the 0.5.x compatible API. For the full example — several windows at once, parent and child windows, every native property — see nativeapi's window_example.
Code written for window_manager 0.5.x keeps working by importing
package:window_manager/legacy.dart instead of
package:window_manager/window_manager.dart. It provides the old windowManager,
WindowListener, WindowOptions and calcWindowPosition on top of the native API.
The import has to change on purpose: legacy.dart is a bridge, not the future of this
package. Its classes are marked @Deprecated and will be removed in a later
release — move to the native API above when you can.
import 'package:window_manager/legacy.dart';
await windowManager.ensureInitialized();
await windowManager.waitUntilReadyToShow(
const WindowOptions(size: Size(1000, 700), center: true),
() async {
await windowManager.show();
await windowManager.focus();
},
);What differs from 0.5.x:
- Builds need Flutter 3.47 / Dart 3.13 and macOS 10.15 (0.5.x: Flutter 3.3, macOS 10.11),
and no longer need the plugin's own setup in
MainFlutterWindow.swift,my_application.ccor the Windows runner — there is no platform plugin code left. close(),destroy()andsetPreventClose()behave as before: withsetPreventClose(true)the title bar's close button andclose()reportonWindowCloseand leave the window open, anddestroy()closes it anyway. Closing the last window ends the app, as the platform's runner decides.onWindowResizedandonWindowMovedarrive together withonWindowResizeandonWindowMove: nativeapi reports one event per change, not a stream and a final one.- Aero-snap docking is gone:
isDockable()answers false,isDocked()null,dock()does nothing,undock()answers false, andonWindowDocked/onWindowUndockednever fire.grabKeyboard()/ungrabKeyboard()(Linux) are gone the same way. popUpWindowMenu()opens the system menu at the cursor on Windows and on Linux window managers that have one, and does nothing on macOS.forwardofsetIgnoreMouseEventskeeps hover events where the platform can (macOS, Windows and X11); elsewhere the window ignores the mouse without them.- Arguments the core library has no use for are accepted and ignored:
verticallyofmaximize,animateofsetPositionandsetBounds,visibleOnFullScreenofsetVisibleOnAllWorkspaces. getId()answers nativeapi's own window id, not theNSWindownumber or theHWND.setAsFrameless()hides the title bar and its buttons; it no longer removes the window's border.setAlignmenthandles anyAlignment, not only the nine constants.WindowCaption's close button closes the window, through its close listeners, sosetPreventCloseholds for it too. On Windows 11 its maximize button opens the snap layouts.startDragging()andstartResizing()are no longer skipped on Windows while the window is in full screen: the compatibility layer keeps noPlatformbranch of its own, the core library decides.screen_retrieverandpathare no longer dependencies.- New example on
package:flutter/widgets.dartalone; the full one is nativeapi's window_example.
0.5.x (legacy.dart) |
Native API (window_manager.dart) |
|---|---|
windowManager (the app's one window) |
WindowManager.instance.getCurrent() — or get(id), getAll(), getWindowAtPoint(); every window is a Window of its own |
await windowManager.getSize(), setSize(size) |
window.size.toSize(), window.setSize(size.toNative(), animate) — synchronous, no await |
getBounds() / setBounds(rect) |
window.bounds.toRect(), window.bounds = rect.toNative(); window.contentBounds for the area without decorations |
getPosition() / setPosition(offset) |
window.position.toOffset(), window.position = offset.toNative() |
setMinimumSize / setMaximumSize / setAspectRatio |
window.minimumSize, window.maximumSize, window.aspectRatio |
show() / show(inactive: true) / hide() |
window.show() / window.showInactive() / window.hide() |
focus(), blur(), isFocused() |
window.focus(), window.blur(), window.isFocused |
maximize(), unmaximize(), minimize(), restore() |
the same names on window, without await |
setFullScreen(bool) / isFullScreen() |
window.isFullScreen |
setResizable, setMovable, setMinimizable, setMaximizable, setClosable |
window.isResizable, isMovable, isMinimizable, isMaximizable, isClosable — also isFullScreenable |
setAlwaysOnTop / setAlwaysOnBottom |
window.isAlwaysOnTop / window.isAlwaysOnBottom |
setSkipTaskbar(true) |
window.isVisibleInTaskbar = false |
setTitle / getTitle |
window.title |
setTitleBarStyle(style, windowButtonVisibility:) |
window.titleBarStyle, window.isWindowControlButtonsVisible — also setTitleBarColors() |
setHasShadow, setOpacity, setBackgroundColor |
window.hasShadow, window.opacity, window.backgroundColor — also window.visualEffect |
setIgnoreMouseEvents(ignore, forward:) |
window.setIgnoreMouseEvents(ignore, forward) |
close() / destroy() |
window.close(), which asks the window's close listeners first |
setPreventClose(true) with onWindowClose |
window.addListener((event) { if (event is WindowCloseRequestedEvent) event.request.cancel(); }) |
popUpWindowMenu() |
window.showSystemMenu(position) — Window.isSystemMenuSupported() says where it works |
setVisibleOnAllWorkspaces(bool) |
window.isVisibleOnAllWorkspaces |
startDragging() / startResizing(edge) |
the same names on window; DragToMoveArea and DragToResizeArea call them for you |
setProgressBar, setBadgeLabel, setIcon, setBrightness |
Application.instance — they belong to the app, not to one window |
WindowListener |
window.addListener((event) { switch (event) { case WindowFocusedEvent(): … } }) for one window, WindowManager.instance.addListener for all — also WindowBlurredEvent, WindowMinimizedEvent, WindowMaximizedEvent, WindowRestoredEvent, WindowMovedEvent, WindowResizedEvent, WindowEnteredFullScreenEvent, WindowExitedFullScreenEvent, WindowCreatedEvent, WindowClosedEvent |
calcWindowPosition(size, alignment) |
DisplayManager.instance — getAll(), getPrimary(), getCursorPosition(), and each Display's workArea |
waitUntilReadyToShow, ensureInitialized, setAsFrameless and getDevicePixelRatio
have no native counterpart: set the properties you want and call window.show() when
you are ready.
- AuthPass - Password Manager based on Flutter for all platforms. Keepass 2.x (kdbx 3.x) compatible.
- Biyi (比译) - A convenient translation and dictionary app written in dart / Flutter.
- BlueBubbles - BlueBubbles is an ecosystem of apps bringing iMessage to Android, Windows, and Linux
- LunaSea - A self-hosted controller for mobile and macOS built using the Flutter framework.
- Linwood Butterfly - Open source note taking app written in Flutter
- RustDesk - Yet another remote desktop software, written in Rust. Works out of the box, no configuration required.
- Ubuntu Desktop Installer - This project is a modern implementation of the Ubuntu Desktop installer.
window_manager now re-exports the windowing APIs of nativeapi — Window,
WindowManager, TitleBarStyle, ResizeEdge, VisualEffect, the window events with
EventRequest for answering a close, and from nativeapi_flutter the DragToMoveArea,
DragToResizeArea and MaximizeButtonArea widgets and the type conversions —
alongside its own WindowCaption, WindowCaptionButton and VirtualWindowFrame. Import
package:window_manager/legacy.dart only for code that still uses the 0.5.x API.