skip to content

In a Flutter desktop app, where do you set the initial window size and title, and why is that not in Dart code?

level: juniorimportance: should knowfreq 38%

answer

  1. a generated native host program
  2. the runner owns the OS window
  3. Win32Window::Size in main.cpp
  4. gtk_window_set_default_size on Linux
  5. MainMenu.xib frame on macOS

basics

~20 s

Each desktop target has a generated native runner that creates the OS window before Dart runs: windows/runner/main.cpp, linux/runner/my_application.cc and the macOS MainMenu.xib window. Size and title are set there; the Dart windowing API is still experimental.

solid answer

~40 s

`flutter create` generates a small native **runner** per desktop platform. The runner creates the operating-system window, starts the Flutter engine inside it and registers plugins; Dart only receives a view to draw into. So the initial size and title live in native code: on Windows `windows/runner/main.cpp` has `Win32Window::Size size(1280, 720)` and `window.Create(L"<title>", origin, size)`; on Linux `linux/runner/my_application.cc` calls `gtk_window_set_default_size(window, 1280, 720)` and sets the header-bar title; on macOS the window comes from `Runner/Base.lproj/MainMenu.xib`, 800 by 600 in the template, hosted by `MainFlutterWindow.swift`. Flutter 3.47's framework windowing API is experimental and internal, so stable apps edit the runner or use a community plugin.

go deeper

for a junior

Recall that the runner files per platform set the initial window size and title: main.cpp, my_application.cc and MainMenu.xib.

for a middle

Explain what the runner does before Dart starts, why MediaQuery reports a view size rather than controlling the window, and the first-frame show.

for a senior

Show when fixed runner edits are enough and when runtime window control needs native code or a plugin, and check it on every shipped platform.

for a principal

Weigh depending on experimental windowing APIs or third-party plugins against keeping window behaviour in owned native runner code.

## What the runner is A Flutter desktop app is not a Dart program that opens a window by itself. `flutter create` generates a **runner**: a small native application for each desktop platform that 1. creates the operating-system window, 2. starts the Flutter engine and attaches a Flutter view to that window, 3. registers the native side of every plugin, 4. runs the platform's message loop and forwards events to Flutter. Dart code starts only after the runner has done this, and what it sees is a **view** with a size, not a window it owns. `MediaQuery` and `View.of(context)` report that view's size; they do not create or resize the window. ## Where each platform sets size and title | Platform | File | What to change | |---|---|---| | Windows | `windows/runner/main.cpp` | `Win32Window::Point origin(10, 10)`, `Win32Window::Size size(1280, 720)` and the title passed to `window.Create(...)` | | Linux | `linux/runner/my_application.cc` | `gtk_window_set_default_size(window, 1280, 720)` and the GTK header-bar or window title | | macOS | `macos/Runner/Base.lproj/MainMenu.xib` and `MainFlutterWindow.swift` | the window's content rect, 800 by 600 in the template, and any frame changes before the Flutter view controller is attached | On Windows the executable's file name comes from `BINARY_NAME` in `windows/CMakeLists.txt`, and the icon from `windows/runner/resources/app_icon.ico`. ```cpp // windows/runner/main.cpp (excerpt) FlutterWindow window(project); Win32Window::Point origin(10, 10); Win32Window::Size size(1280, 720); if (!window.Create(L"Shop Invoices", origin, size)) { return EXIT_FAILURE; } window.SetQuitOnClose(true); ``` ## A detail worth knowing: showing on the first frame The generated Windows `FlutterWindow` registers a callback with the engine for the next frame and calls `Show()` from it. The window therefore appears once Flutter has drawn something, instead of flashing an empty rectangle while the engine starts. If you restructure the runner, keep that behaviour. ## Why not Dart? - The window must exist before the engine can run Dart at all. - Window chrome, minimum size, position memory and multiple windows are platform features that differ between Win32, AppKit and GTK. - Flutter 3.47 contains a framework **windowing API**, but it is **experimental**: marked internal and guarded by an enable flag, and the release notes describe multi-window work as ongoing. Stable apps should not depend on it. That leaves two practical options: - **Edit the runner** for fixed values such as initial size, position and title. This is what the Flutter docs describe. - **Use a community plugin** when the app must change the window at runtime, for example to restore the last size or enforce a minimum. Check that it supports every desktop platform you ship. ## Common mistakes - Trying to size the window from `MaterialApp`, `SizedBox` or `MediaQuery`: those size widgets inside a view that already exists. - Editing only one platform's runner and assuming the others follow; each OS has its own file. - Changing the window title in the runner but not the executable name or app icon, which live in `CMakeLists.txt`, `Runner.rc` and `app_icon.ico` on Windows. - Deleting the next-frame `Show()` logic while refactoring the runner, which brings back a blank window at launch. ## Worked example A small-shop invoice tool on Windows and macOS wants a 1100 by 750 window titled "Shop Invoices". The team changes `size` and the title in `main.cpp`, edits the window's content rect in `MainMenu.xib` for macOS, and renames the Windows executable through `BINARY_NAME`. Nothing in `lib/` changes.

  • Why does the generated Flutter Windows runner call Show() from a next-frame callback instead of right after creating the window?
    So the window becomes visible only once Flutter has rendered its first frame. Showing it immediately would display an empty window while the engine and Dart start. `FlutterWindow` registers the callback with the engine and calls `Show()` from it.
  • The Flutter invoice tool should reopen at the size the user last chose. Is editing main.cpp enough?
    No. The runner values are fixed defaults applied at launch. Remembering a size means reading the current window size at runtime, storing it and applying it on the next launch, which needs native code or a desktop windowing plugin, since the framework windowing API in 3.47 is still experimental.

saying these in an interview costs you the question

  • Set the window size with MaterialApp or MediaQuery in main.dart.
  • The initial desktop window size is configured in pubspec.yaml.
  • Dart creates the desktop window before the engine starts.
  • Flutter 3.47 has a stable multi-window API for production apps.
  • Changing the title in MaterialApp renames the Windows executable.