diff --git a/examples/multi_window_ref_app/windows/flutter/CMakeLists.txt b/examples/multi_window_ref_app/windows/flutter/CMakeLists.txt index 2eea2a3218180..a71c6e2c5e4f3 100644 --- a/examples/multi_window_ref_app/windows/flutter/CMakeLists.txt +++ b/examples/multi_window_ref_app/windows/flutter/CMakeLists.txt @@ -52,17 +52,12 @@ list(APPEND CPP_WRAPPER_SOURCES_PLUGIN list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") list(APPEND CPP_WRAPPER_SOURCES_APP "flutter_engine.cc" - "flutter_view_controller.cc" - "flutter_window_controller.cc" - "flutter_win32_window.cc" - "win32_window.cc" ) list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") # Wrapper sources needed for a plugin. add_library(flutter_wrapper_plugin STATIC ${CPP_WRAPPER_SOURCES_CORE} - ${CPP_WRAPPER_SOURCES_WINDOWING} ${CPP_WRAPPER_SOURCES_PLUGIN} ) apply_standard_settings(flutter_wrapper_plugin) @@ -79,7 +74,6 @@ add_dependencies(flutter_wrapper_plugin flutter_assemble) # Wrapper sources needed for the runner. add_library(flutter_wrapper_app STATIC ${CPP_WRAPPER_SOURCES_CORE} - ${CPP_WRAPPER_SOURCES_WINDOWING} ${CPP_WRAPPER_SOURCES_APP} ) apply_standard_settings(flutter_wrapper_app) @@ -97,7 +91,7 @@ set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) add_custom_command( OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} - ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_WINDOWING} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} ${CPP_WRAPPER_SOURCES_APP} ${PHONY_OUTPUT} COMMAND ${CMAKE_COMMAND} -E env @@ -110,7 +104,6 @@ add_custom_target(flutter_assemble DEPENDS "${FLUTTER_LIBRARY}" ${FLUTTER_LIBRARY_HEADERS} ${CPP_WRAPPER_SOURCES_CORE} - ${CPP_WRAPPER_SOURCES_WINDOWING} ${CPP_WRAPPER_SOURCES_PLUGIN} ${CPP_WRAPPER_SOURCES_APP} ) diff --git a/examples/multi_window_ref_app/windows/runner/CMakeLists.txt b/examples/multi_window_ref_app/windows/runner/CMakeLists.txt index ae89fc0a64873..697f43451ac08 100644 --- a/examples/multi_window_ref_app/windows/runner/CMakeLists.txt +++ b/examples/multi_window_ref_app/windows/runner/CMakeLists.txt @@ -31,7 +31,6 @@ target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") # Add dependency libraries and include directories. Add any application-specific # dependencies here. target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) -target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") # Run the Flutter tool portions of the build. This must not be removed. diff --git a/examples/multi_window_ref_app/windows/runner/Runner.rc b/examples/multi_window_ref_app/windows/runner/Runner.rc index 34a087abcbc73..d81714ff69411 100644 --- a/examples/multi_window_ref_app/windows/runner/Runner.rc +++ b/examples/multi_window_ref_app/windows/runner/Runner.rc @@ -52,7 +52,7 @@ END // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. -// IDI_APP_ICON ICON "resources\\app_icon.ico" +IDI_APP_ICON ICON "resources\\app_icon.ico" ///////////////////////////////////////////////////////////////////////////// @@ -90,12 +90,12 @@ BEGIN BLOCK "040904e4" BEGIN VALUE "CompanyName", "The Flutter Authors" "\0" - VALUE "FileDescription", "A sample application demonstrating Flutter APIs." "\0" + VALUE "FileDescription", "A reference application demonstrating Flutter's multi-window API." "\0" VALUE "FileVersion", VERSION_AS_STRING "\0" - VALUE "InternalName", "Flutter API Sample" "\0" + VALUE "InternalName", "Flutter Multi-Window Reference App" "\0" VALUE "LegalCopyright", "Copyright 2014 The Flutter Authors. All rights reserved." "\0" - VALUE "OriginalFilename", "flutter_api_samples.exe" "\0" - VALUE "ProductName", "Flutter API Sample" "\0" + VALUE "OriginalFilename", "multi_window_ref_app.exe" "\0" + VALUE "ProductName", "Flutter Multi-Window Reference App" "\0" VALUE "ProductVersion", VERSION_AS_STRING "\0" END END diff --git a/examples/multi_window_ref_app/windows/runner/flutter_window.cpp b/examples/multi_window_ref_app/windows/runner/flutter_window.cpp deleted file mode 100644 index 9cbd3109c3fee..0000000000000 --- a/examples/multi_window_ref_app/windows/runner/flutter_window.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// 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. - -#include "flutter_window.h" - -#include - -#include "flutter/generated_plugin_registrant.h" - -FlutterWindow::FlutterWindow(const flutter::DartProject& project) - : project_(project) {} - -FlutterWindow::~FlutterWindow() {} - -bool FlutterWindow::OnCreate() { - if (!Win32Window::OnCreate()) { - return false; - } - - RECT frame = GetClientArea(); - - // The size here must match the window dimensions to avoid unnecessary surface - // creation / destruction in the startup path. - flutter_controller_ = std::make_unique( - frame.right - frame.left, frame.bottom - frame.top, project_); - // Ensure that basic setup of the controller was successful. - if (!flutter_controller_->engine() || !flutter_controller_->view()) { - return false; - } - RegisterPlugins(flutter_controller_->engine()); - SetChildContent(flutter_controller_->view()->GetNativeWindow()); - return true; -} - -void FlutterWindow::OnDestroy() { - if (flutter_controller_) { - flutter_controller_ = nullptr; - } - - Win32Window::OnDestroy(); -} - -LRESULT -FlutterWindow::MessageHandler(HWND hwnd, UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept { - // Give Flutter, including plugins, an opportunity to handle window messages. - if (flutter_controller_) { - std::optional result = - flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, - lparam); - if (result) { - return *result; - } - } - - switch (message) { - case WM_FONTCHANGE: - flutter_controller_->engine()->ReloadSystemFonts(); - break; - } - - return Win32Window::MessageHandler(hwnd, message, wparam, lparam); -} diff --git a/examples/multi_window_ref_app/windows/runner/flutter_window.h b/examples/multi_window_ref_app/windows/runner/flutter_window.h deleted file mode 100644 index bbc5836c018a2..0000000000000 --- a/examples/multi_window_ref_app/windows/runner/flutter_window.h +++ /dev/null @@ -1,37 +0,0 @@ -// 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. - -#ifndef RUNNER_FLUTTER_WINDOW_H_ -#define RUNNER_FLUTTER_WINDOW_H_ - -#include -#include - -#include - -#include "win32_window.h" - -// A window that does nothing but host a Flutter view. -class FlutterWindow : public Win32Window { - public: - // Creates a new FlutterWindow hosting a Flutter view running |project|. - explicit FlutterWindow(const flutter::DartProject& project); - virtual ~FlutterWindow(); - - protected: - // Win32Window: - bool OnCreate() override; - void OnDestroy() override; - LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, - LPARAM const lparam) noexcept override; - - private: - // The project to run. - flutter::DartProject project_; - - // The Flutter instance hosted by this window. - std::unique_ptr flutter_controller_; -}; - -#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/examples/multi_window_ref_app/windows/runner/main.cpp b/examples/multi_window_ref_app/windows/runner/main.cpp index 6c975ca798ddd..6f944fa05a109 100644 --- a/examples/multi_window_ref_app/windows/runner/main.cpp +++ b/examples/multi_window_ref_app/windows/runner/main.cpp @@ -1,8 +1,6 @@ #include -#include #include -#include -#include +#include #include "utils.h" @@ -26,7 +24,6 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, auto const engine{std::make_shared(project)}; RegisterPlugins(engine.get()); - flutter::FlutterWindowController::GetInstance().SetEngine(engine); engine->Run(); ::MSG msg; diff --git a/examples/multi_window_ref_app/windows/runner/resources/app_icon.ico b/examples/multi_window_ref_app/windows/runner/resources/app_icon.ico new file mode 100644 index 0000000000000..c04e20caf6370 Binary files /dev/null and b/examples/multi_window_ref_app/windows/runner/resources/app_icon.ico differ diff --git a/examples/multi_window_ref_app/windows/runner/win32_window.cpp b/examples/multi_window_ref_app/windows/runner/win32_window.cpp deleted file mode 100644 index 8fef19b0fbfd4..0000000000000 --- a/examples/multi_window_ref_app/windows/runner/win32_window.cpp +++ /dev/null @@ -1,249 +0,0 @@ -// 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. - -#include "win32_window.h" - -#include - -#include "resource.h" - -namespace { - -constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; - -// The number of Win32Window objects that currently exist. -static int g_active_window_count = 0; - -using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); - -// Scale helper to convert logical scaler values to physical using passed in -// scale factor -int Scale(int source, double scale_factor) { - return static_cast(source * scale_factor); -} - -// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. -// This API is only needed for PerMonitor V1 awareness mode. -void EnableFullDpiSupportIfAvailable(HWND hwnd) { - HMODULE user32_module = LoadLibraryA("User32.dll"); - if (!user32_module) { - return; - } - auto enable_non_client_dpi_scaling = - reinterpret_cast( - GetProcAddress(user32_module, "EnableNonClientDpiScaling")); - if (enable_non_client_dpi_scaling != nullptr) { - enable_non_client_dpi_scaling(hwnd); - } - FreeLibrary(user32_module); -} - -} // namespace - -// Manages the Win32Window's window class registration. -class WindowClassRegistrar { - public: - ~WindowClassRegistrar() = default; - - // Returns the singleton registrar instance. - static WindowClassRegistrar* GetInstance() { - if (!instance_) { - instance_ = new WindowClassRegistrar(); - } - return instance_; - } - - // Returns the name of the window class, registering the class if it hasn't - // previously been registered. - const wchar_t* GetWindowClass(); - - // Unregisters the window class. Should only be called if there are no - // instances of the window. - void UnregisterWindowClass(); - - private: - WindowClassRegistrar() = default; - - static WindowClassRegistrar* instance_; - - bool class_registered_ = false; -}; - -WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; - -const wchar_t* WindowClassRegistrar::GetWindowClass() { - if (!class_registered_) { - WNDCLASS window_class{}; - window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); - window_class.lpszClassName = kWindowClassName; - window_class.style = CS_HREDRAW | CS_VREDRAW; - window_class.cbClsExtra = 0; - window_class.cbWndExtra = 0; - window_class.hInstance = GetModuleHandle(nullptr); - window_class.hIcon = - LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); - window_class.hbrBackground = 0; - window_class.lpszMenuName = nullptr; - window_class.lpfnWndProc = Win32Window::WndProc; - RegisterClass(&window_class); - class_registered_ = true; - } - return kWindowClassName; -} - -void WindowClassRegistrar::UnregisterWindowClass() { - UnregisterClass(kWindowClassName, nullptr); - class_registered_ = false; -} - -Win32Window::Win32Window() { - ++g_active_window_count; -} - -Win32Window::~Win32Window() { - --g_active_window_count; - Destroy(); -} - -bool Win32Window::CreateAndShow(const std::wstring& title, - const Point& origin, - const Size& size) { - Destroy(); - - const wchar_t* window_class = - WindowClassRegistrar::GetInstance()->GetWindowClass(); - - const POINT target_point = {static_cast(origin.x), - static_cast(origin.y)}; - HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); - UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); - double scale_factor = dpi / 96.0; - - HWND window = CreateWindow( - window_class, title.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE, - Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), - Scale(size.width, scale_factor), Scale(size.height, scale_factor), - nullptr, nullptr, GetModuleHandle(nullptr), this); - - if (!window) { - return false; - } - - return OnCreate(); -} - -// static -LRESULT CALLBACK Win32Window::WndProc(HWND const window, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept { - if (message == WM_NCCREATE) { - auto window_struct = reinterpret_cast(lparam); - SetWindowLongPtr(window, GWLP_USERDATA, - reinterpret_cast(window_struct->lpCreateParams)); - - auto that = static_cast(window_struct->lpCreateParams); - EnableFullDpiSupportIfAvailable(window); - that->window_handle_ = window; - } else if (Win32Window* that = GetThisFromHandle(window)) { - return that->MessageHandler(window, message, wparam, lparam); - } - - return DefWindowProc(window, message, wparam, lparam); -} - -LRESULT -Win32Window::MessageHandler(HWND hwnd, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept { - switch (message) { - case WM_DESTROY: - window_handle_ = nullptr; - Destroy(); - if (quit_on_close_) { - PostQuitMessage(0); - } - return 0; - - case WM_DPICHANGED: { - auto newRectSize = reinterpret_cast(lparam); - LONG newWidth = newRectSize->right - newRectSize->left; - LONG newHeight = newRectSize->bottom - newRectSize->top; - - SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, - newHeight, SWP_NOZORDER | SWP_NOACTIVATE); - - return 0; - } - case WM_SIZE: { - RECT rect = GetClientArea(); - if (child_content_ != nullptr) { - // Size and position the child window. - MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, - rect.bottom - rect.top, TRUE); - } - return 0; - } - - case WM_ACTIVATE: - if (child_content_ != nullptr) { - SetFocus(child_content_); - } - return 0; - } - - return DefWindowProc(window_handle_, message, wparam, lparam); -} - -void Win32Window::Destroy() { - OnDestroy(); - - if (window_handle_) { - DestroyWindow(window_handle_); - window_handle_ = nullptr; - } - if (g_active_window_count == 0) { - WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); - } -} - -Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { - return reinterpret_cast( - GetWindowLongPtr(window, GWLP_USERDATA)); -} - -void Win32Window::SetChildContent(HWND content) { - child_content_ = content; - SetParent(content, window_handle_); - RECT frame = GetClientArea(); - - MoveWindow(content, frame.left, frame.top, frame.right - frame.left, - frame.bottom - frame.top, true); - - SetFocus(child_content_); -} - -RECT Win32Window::GetClientArea() { - RECT frame; - GetClientRect(window_handle_, &frame); - return frame; -} - -HWND Win32Window::GetHandle() { - return window_handle_; -} - -void Win32Window::SetQuitOnClose(bool quit_on_close) { - quit_on_close_ = quit_on_close; -} - -bool Win32Window::OnCreate() { - // No-op; provided for subclasses. - return true; -} - -void Win32Window::OnDestroy() { - // No-op; provided for subclasses. -} diff --git a/examples/multi_window_ref_app/windows/runner/win32_window.h b/examples/multi_window_ref_app/windows/runner/win32_window.h deleted file mode 100644 index 33786ecd6f0b9..0000000000000 --- a/examples/multi_window_ref_app/windows/runner/win32_window.h +++ /dev/null @@ -1,102 +0,0 @@ -// 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. - -#ifndef RUNNER_WIN32_WINDOW_H_ -#define RUNNER_WIN32_WINDOW_H_ - -#include - -#include -#include -#include - -// A class abstraction for a high DPI-aware Win32 Window. Intended to be -// inherited from by classes that wish to specialize with custom -// rendering and input handling -class Win32Window { - public: - struct Point { - unsigned int x; - unsigned int y; - Point(unsigned int x, unsigned int y) : x(x), y(y) {} - }; - - struct Size { - unsigned int width; - unsigned int height; - Size(unsigned int width, unsigned int height) - : width(width), height(height) {} - }; - - Win32Window(); - virtual ~Win32Window(); - - // Creates and shows a win32 window with |title| and position and size using - // |origin| and |size|. New windows are created on the default monitor. Window - // sizes are specified to the OS in physical pixels, hence to ensure a - // consistent size to will treat the width height passed in to this function - // as logical pixels and scale to appropriate for the default monitor. Returns - // true if the window was created successfully. - bool CreateAndShow(const std::wstring& title, - const Point& origin, - const Size& size); - - // Release OS resources associated with window. - void Destroy(); - - // Inserts |content| into the window tree. - void SetChildContent(HWND content); - - // Returns the backing Window handle to enable clients to set icon and other - // window properties. Returns nullptr if the window has been destroyed. - HWND GetHandle(); - - // If true, closing this window will quit the application. - void SetQuitOnClose(bool quit_on_close); - - // Return a RECT representing the bounds of the current client area. - RECT GetClientArea(); - - protected: - // Processes and route salient window messages for mouse handling, - // size change and DPI. Delegates handling of these to member overloads that - // inheriting classes can handle. - virtual LRESULT MessageHandler(HWND window, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept; - - // Called when CreateAndShow is called, allowing subclass window-related - // setup. Subclasses should return false if setup fails. - virtual bool OnCreate(); - - // Called when Destroy is called. - virtual void OnDestroy(); - - private: - friend class WindowClassRegistrar; - - // OS callback called by message pump. Handles the WM_NCCREATE message which - // is passed when the non-client area is being created and enables automatic - // non-client DPI scaling so that the non-client area automatically - // responds to changes in DPI. All other messages are handled by - // MessageHandler. - static LRESULT CALLBACK WndProc(HWND const window, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept; - - // Retrieves a class instance pointer for |window| - static Win32Window* GetThisFromHandle(HWND const window) noexcept; - - bool quit_on_close_ = false; - - // window handle for top level window. - HWND window_handle_ = nullptr; - - // window handle for hosted content. - HWND child_content_ = nullptr; -}; - -#endif // RUNNER_WIN32_WINDOW_H_ diff --git a/packages/flutter_tools/lib/src/commands/run.dart b/packages/flutter_tools/lib/src/commands/run.dart index 48bb8fa91486f..1bc3692dfbb97 100644 --- a/packages/flutter_tools/lib/src/commands/run.dart +++ b/packages/flutter_tools/lib/src/commands/run.dart @@ -202,6 +202,7 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment addEnableImpellerFlag(verboseHelp: verboseHelp); addEnableVulkanValidationFlag(verboseHelp: verboseHelp); addEnableEmbedderApiFlag(verboseHelp: verboseHelp); + addMultiWindowFlag(verboseHelp: verboseHelp); } bool get traceStartup => boolArg('trace-startup'); @@ -217,6 +218,7 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment bool get enableVulkanValidation => boolArg('enable-vulkan-validation'); bool get uninstallFirst => boolArg('uninstall-first'); bool get enableEmbedderApi => boolArg('enable-embedder-api'); + bool get enableMultiWindow => boolArg('enable-multi-window'); @override bool get refreshWirelessDevices => true; @@ -280,6 +282,7 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment uninstallFirst: uninstallFirst, enableDartProfiling: enableDartProfiling, enableEmbedderApi: enableEmbedderApi, + enableMultiWindow: enableMultiWindow, usingCISystem: usingCISystem, debugLogsDirectoryPath: debugLogsDirectoryPath, ); @@ -338,6 +341,7 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment serveObservatory: boolArg('serve-observatory'), enableDartProfiling: enableDartProfiling, enableEmbedderApi: enableEmbedderApi, + enableMultiWindow: enableMultiWindow, usingCISystem: usingCISystem, debugLogsDirectoryPath: debugLogsDirectoryPath, enableDevTools: boolArg(FlutterCommand.kEnableDevTools), diff --git a/packages/flutter_tools/lib/src/commands/test.dart b/packages/flutter_tools/lib/src/commands/test.dart index ded767a9d8c3b..0d6cd5b6b3f06 100644 --- a/packages/flutter_tools/lib/src/commands/test.dart +++ b/packages/flutter_tools/lib/src/commands/test.dart @@ -79,6 +79,7 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts { usesDeviceUserOption(); usesFlavorOption(); addEnableImpellerFlag(verboseHelp: verboseHelp); + addMultiWindowFlag(verboseHelp: verboseHelp); argParser ..addFlag('experimental-faster-testing', diff --git a/packages/flutter_tools/lib/src/custom_devices/custom_device.dart b/packages/flutter_tools/lib/src/custom_devices/custom_device.dart index c5f7745a4fdeb..667773f8db7a0 100644 --- a/packages/flutter_tools/lib/src/custom_devices/custom_device.dart +++ b/packages/flutter_tools/lib/src/custom_devices/custom_device.dart @@ -328,6 +328,8 @@ class CustomDeviceAppSession { if (debuggingOptions.verboseSystemLogs) 'verbose-logging=true', ], + if (debuggingOptions.enableMultiWindow) + 'enable-multi-window=true', ]; } diff --git a/packages/flutter_tools/lib/src/desktop_device.dart b/packages/flutter_tools/lib/src/desktop_device.dart index 0ec5c5a907a71..c2470ed977bc3 100644 --- a/packages/flutter_tools/lib/src/desktop_device.dart +++ b/packages/flutter_tools/lib/src/desktop_device.dart @@ -311,6 +311,9 @@ abstract class DesktopDevice extends Device { case ImpellerStatus.platformDefault: addFlag('enable-impeller=false'); } + if (debuggingOptions.enableMultiWindow) { + addFlag('enable-multi-window=true'); + } // Options only supported when there is a VM Service connection between the // tool and the device, usually in debug or profile mode. if (debuggingOptions.debuggingEnabled) { diff --git a/packages/flutter_tools/lib/src/device.dart b/packages/flutter_tools/lib/src/device.dart index da778aa5f07e1..97bb537ec781b 100644 --- a/packages/flutter_tools/lib/src/device.dart +++ b/packages/flutter_tools/lib/src/device.dart @@ -1004,6 +1004,7 @@ class DebuggingOptions { this.serveObservatory = false, this.enableDartProfiling = true, this.enableEmbedderApi = false, + this.enableMultiWindow = false, this.usingCISystem = false, this.debugLogsDirectoryPath, this.enableDevTools = true, @@ -1037,6 +1038,7 @@ class DebuggingOptions { this.uninstallFirst = false, this.enableDartProfiling = true, this.enableEmbedderApi = false, + this.enableMultiWindow = false, this.usingCISystem = false, this.debugLogsDirectoryPath, }) : debuggingEnabled = false, @@ -1126,6 +1128,7 @@ class DebuggingOptions { required this.serveObservatory, required this.enableDartProfiling, required this.enableEmbedderApi, + required this.enableMultiWindow, required this.usingCISystem, required this.debugLogsDirectoryPath, required this.enableDevTools, @@ -1174,6 +1177,7 @@ class DebuggingOptions { final bool serveObservatory; final bool enableDartProfiling; final bool enableEmbedderApi; + final bool enableMultiWindow; final bool usingCISystem; final String? debugLogsDirectoryPath; final bool enableDevTools; @@ -1278,6 +1282,7 @@ class DebuggingOptions { if (interfaceType == DeviceConnectionInterface.wireless) '--vm-service-host=${ipv6 ? '::0' : '0.0.0.0'}', if (enableEmbedderApi) '--enable-embedder-api', + if (enableMultiWindow) '--enable-multi-window=true', ]; } @@ -1332,6 +1337,7 @@ class DebuggingOptions { 'serveObservatory': serveObservatory, 'enableDartProfiling': enableDartProfiling, 'enableEmbedderApi': enableEmbedderApi, + 'enableMultiWindow': enableMultiWindow, 'usingCISystem': usingCISystem, 'debugLogsDirectoryPath': debugLogsDirectoryPath, 'enableDevTools': enableDevTools, @@ -1398,6 +1404,7 @@ class DebuggingOptions { serveObservatory: (json['serveObservatory'] as bool?) ?? false, enableDartProfiling: (json['enableDartProfiling'] as bool?) ?? true, enableEmbedderApi: (json['enableEmbedderApi'] as bool?) ?? false, + enableMultiWindow: (json['enableMultiWindow']! as bool?) ?? false, usingCISystem: (json['usingCISystem'] as bool?) ?? false, debugLogsDirectoryPath: json['debugLogsDirectoryPath'] as String?, enableDevTools: (json['enableDevTools'] as bool?) ?? true, diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart index 4e29de50593e5..69f617d856fe2 100644 --- a/packages/flutter_tools/lib/src/runner/flutter_command.dart +++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart @@ -1156,6 +1156,15 @@ abstract class FlutterCommand extends Command { ); } + void addMultiWindowFlag({required bool verboseHelp}) { + argParser.addFlag('enable-multi-window', + hide: !verboseHelp, + help: 'Whether to enable support for multiple windows. ' + 'This flag is only available on Windows, is disabled by default, ' + 'and will be ignored on other platforms.', + ); + } + /// Returns a [FlutterProject] view of the current directory or a ToolExit error, /// if `pubspec.yaml` or `example/pubspec.yaml` is invalid. FlutterProject get project => FlutterProject.current();