Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions dev/devicelab/lib/tasks/integration_tests.dart
Original file line number Diff line number Diff line change
Expand Up @@ -189,13 +189,14 @@ TaskFunction dartDefinesTask() {
}

TaskFunction featureFlagsTask() {
return DriverTest(
'${flutterDirectory.path}/dev/integration_tests/ui',
'lib/feature_flags.dart',
// TODO(loic-sharma): Turn on a framework feature flag once one exists.
// https://github.com/flutter/flutter/issues/167668
environment: const <String, String>{},
).call;
return () async {
await flutter('config', options: const <String>['--enable-multi-window']);

return DriverTest(
'${flutterDirectory.path}/dev/integration_tests/ui',
'lib/feature_flags.dart',
).call();
};
}

TaskFunction createEndToEndIntegrationTest() {
Expand Down
4 changes: 1 addition & 3 deletions dev/integration_tests/ui/test_driver/feature_flags_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ void main() {
});

test('Can run with feature flags enabled', () async {
// TODO(loic-sharma): Turn on a framework feature flag once one exists.
// https://github.com/flutter/flutter/issues/167668
await driver?.waitFor(find.text('Feature flags: "{}"'));
await driver?.waitFor(find.text('Feature flags: "{multi_window}"'));
}, timeout: Timeout.none);
}
15 changes: 15 additions & 0 deletions packages/flutter/lib/src/foundation/_features.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,21 @@

import 'package:meta/meta.dart';

/// Whether the multi-window feature is enabled for the current
/// application.
///
/// Do not use this API. Flutter will make breaking changes
/// to this API, even in patch versions.
///
/// If this returns `false`, `@internal` APIs in the following
/// files will throw an `UnsupportedError`:
///
/// 1. packages/flutter/lib/src/widgets/_windowing.dart
///
/// See: https://github.com/flutter/flutter/issues/30701.
@internal
bool isWindowingEnabled = debugEnabledFeatureFlags.contains('multi_window');

/// The feature flags this app was built with.
///
/// Do not use this API. Flutter can and will make breaking changes to this API.
Expand Down
7 changes: 7 additions & 0 deletions packages/flutter/lib/src/material/dialog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import 'dart:ui' show SemanticsRole, clampDouble, lerpDouble;

import 'package:flutter/cupertino.dart';

import '../foundation/_features.dart';
import '../widgets/_windowing.dart';
import 'color_scheme.dart';
import 'colors.dart';
import 'debug.dart';
Expand Down Expand Up @@ -275,6 +277,11 @@ class Dialog extends StatelessWidget {

Widget dialogChild;

if (isWindowingEnabled) {
// TODO(team-desktop): Use a window if necessary.
Copy link
Contributor

@justinmc justinmc Jul 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this TODO mean?

Edit: I think I was just confused by the fact that the createWindow call is already there.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is super hypothetical code for demonstration purposes only. We shouldn't actually land a PR that contains this :)

createWindow();
}

if (_fullscreen) {
dialogChild = Material(
color: backgroundColor ?? dialogTheme.backgroundColor ?? defaults.backgroundColor,
Expand Down
66 changes: 66 additions & 0 deletions packages/flutter/lib/src/widgets/_windowing.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Do not import this file in production applications or packages published
// to pub.dev. Flutter will make breaking changes to this file, even in patch
// versions.
//
// All APIs in this file must be private or must:
//
// 1. Have the `@internal` attribute.
// 2. Throw an `UnsupportedError` if `isWindowingEnabled`
// is `false.
//
// See: https://github.com/flutter/flutter/issues/30701.

import 'package:flutter/foundation.dart';

import '../foundation/_features.dart';

/// Create a new window.
///
/// {@template flutter.widgets.windowing.experimental}
/// Do not use this API in production applications or packages published to
/// pub.dev. Flutter will make breaking changes to this API, even in patch
/// versions.
///
/// This API throws an [UnsupportedError] error unless Flutter’s windowing
/// feature is enabled by [isWindowingEnabled].
///
/// See: https://github.com/flutter/flutter/issues/30701.
/// {@endtemplate}
@internal
void createWindow() {
_throwIfWindowingDisabled();

// TODO(team-windows): Add logic.
}

/// Resize a window.
///
/// {@macro flutter.widgets.windowing.experimental}
@internal
void resizeWindow() {
_throwIfWindowingDisabled();

// TODO(team-windows): Add logic.
}

void _throwIfWindowingDisabled() {
if (!isWindowingEnabled) {
throw UnsupportedError('''
Windowing APIs are not enabled.

Windowing APIs are currently experimental. Do not use windowing APIs in
production applications or plugins published to pub.dev.

To try experimental windowing APIs:

1. Switch to Flutter's main release channel.
2. Turn on the multi-window feature flag.

See: https://github.com/flutter/flutter/issues/30701.
''');
}
}
15 changes: 15 additions & 0 deletions packages/flutter_tools/lib/src/features.dart
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ abstract class FeatureFlags {
/// Tracking removal: <https://github.com/flutter/flutter/issues/171900>.
bool get isOmitLegacyVersionFileEnabled;

/// Whether desktop multi-window is enabled.
bool get isMultiWindowEnabled;

/// Whether a particular feature is enabled for the current channel.
///
/// Prefer using one of the specific getters above instead of this API.
Expand All @@ -83,6 +86,7 @@ abstract class FeatureFlags {
nativeAssets,
swiftPackageManager,
omitLegacyVersionFile,
multiWindowFeature,
];

/// All current Flutter feature flags that can be configured.
Expand Down Expand Up @@ -203,6 +207,17 @@ const omitLegacyVersionFile = Feature(
stable: FeatureChannelSetting(available: true),
);

/// Whether desktop multi-window is enabled.
///
/// See: https://github.com/flutter/flutter/issues/30701.
const multiWindowFeature = Feature(
name: 'support for multi-window on macOS, Linux, and Windows',
configSetting: 'enable-multi-window',
environmentOverride: 'FLUTTER_MULTI_WINDOW',
runtimeId: 'multi_window',
master: FeatureChannelSetting(available: true),
);

/// A [Feature] is a process for conditionally enabling tool features.
///
/// All settings are optional, and if not provided will generally default to
Expand Down
3 changes: 3 additions & 0 deletions packages/flutter_tools/lib/src/flutter_features.dart
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ mixin FlutterFeatureFlagsIsEnabled implements FeatureFlags {

@override
bool get isOmitLegacyVersionFileEnabled => isEnabled(omitLegacyVersionFile);

@override
bool get isMultiWindowEnabled => isEnabled(multiWindowFeature);
}

interface class FlutterFeatureFlags extends FeatureFlags with FlutterFeatureFlagsIsEnabled {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,9 @@ class FakeFlutterFeatures extends FeatureFlags {
@override
bool get isOmitLegacyVersionFileEnabled => _enabled;

@override
bool get isMultiWindowEnabled => _enabled;

@override
final List<Feature> allFeatures;

Expand Down
6 changes: 6 additions & 0 deletions packages/flutter_tools/test/src/fakes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,7 @@ class TestFeatureFlags implements FeatureFlags {
this.isNativeAssetsEnabled = false,
this.isSwiftPackageManagerEnabled = false,
this.isOmitLegacyVersionFileEnabled = false,
this.isMultiWindowEnabled = false,
});

@override
Expand Down Expand Up @@ -540,6 +541,9 @@ class TestFeatureFlags implements FeatureFlags {
@override
final bool isOmitLegacyVersionFileEnabled;

@override
final bool isMultiWindowEnabled;

@override
bool isEnabled(Feature feature) {
return switch (feature) {
Expand All @@ -554,6 +558,7 @@ class TestFeatureFlags implements FeatureFlags {
cliAnimation => isCliAnimationEnabled,
nativeAssets => isNativeAssetsEnabled,
omitLegacyVersionFile => isOmitLegacyVersionFileEnabled,
multiWindowFeature => isMultiWindowEnabled,
_ => false,
};
}
Expand All @@ -572,6 +577,7 @@ class TestFeatureFlags implements FeatureFlags {
nativeAssets,
swiftPackageManager,
omitLegacyVersionFile,
multiWindowFeature,
];

@override
Expand Down