Kaynağa Gözat

Merge pull request #63 from linhanyu/master

fix example build problem of flutter-windows for new version of flutter.
xuty 4 yıl önce
ebeveyn
işleme
4305aeea90

+ 29 - 0
example/analysis_options.yaml

@@ -0,0 +1,29 @@
+# This file configures the analyzer, which statically analyzes Dart code to
+# check for errors, warnings, and lints.
+#
+# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
+# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
+# invoked from the command line by running `flutter analyze`.
+
+# The following line activates a set of recommended lints for Flutter apps,
+# packages, and plugins designed to encourage good coding practices.
+include: package:flutter_lints/flutter.yaml
+
+linter:
+  # The lint rules applied to this project can be customized in the
+  # section below to disable rules from the `package:flutter_lints/flutter.yaml`
+  # included above or to enable additional rules. A list of all available lints
+  # and their documentation is published at
+  # https://dart-lang.github.io/linter/lints/index.html.
+  #
+  # Instead of disabling a lint rule for the entire project in the
+  # section below, it can also be suppressed for a single line of code
+  # or a specific dart file by using the `// ignore: name_of_lint` and
+  # `// ignore_for_file: name_of_lint` syntax on the line or in the file
+  # producing the lint.
+  rules:
+    # avoid_print: false  # Uncomment to disable the `avoid_print` rule
+    # prefer_single_quotes: true  # Uncomment to enable the `prefer_single_quotes` rule
+
+# Additional information about this file can be found at
+# https://dart.dev/guides/language/analysis-options

+ 12 - 0
example/android/app/src/main/res/drawable-v21/launch_background.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Modify this file to customize your launch splash screen -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="?android:colorBackground" />
+
+    <!-- You can insert your own image assets here -->
+    <!-- <item>
+        <bitmap
+            android:gravity="center"
+            android:src="@mipmap/launch_image" />
+    </item> -->
+</layer-list>

+ 6 - 11
example/lib/isolate.dart

@@ -31,19 +31,15 @@ class MyHomePage extends StatefulWidget {
 }
 
 class FakeTerminalBackend extends TerminalBackend {
-  Completer<int> _exitCodeCompleter;
+  final _exitCodeCompleter = Completer<int>();
   // ignore: close_sinks
-  StreamController<String> _outStream;
-
-  FakeTerminalBackend();
+  final _outStream = StreamController<String>();
 
   @override
   Future<int> get exitCode => _exitCodeCompleter.future;
 
   @override
   void init() {
-    _exitCodeCompleter = Completer<int>();
-    _outStream = StreamController<String>();
     _outStream.sink.add('xterm.dart demo');
     _outStream.sink.add('\r\n');
     _outStream.sink.add('\$ ');
@@ -90,15 +86,14 @@ class FakeTerminalBackend extends TerminalBackend {
 }
 
 class _MyHomePageState extends State<MyHomePage> {
-  TerminalIsolate terminal;
+  final terminal = TerminalIsolate(
+    backend: FakeTerminalBackend(),
+    maxLines: 10000,
+  );
 
   @override
   void initState() {
     super.initState();
-    terminal = TerminalIsolate(
-      backend: FakeTerminalBackend(),
-      maxLines: 10000,
-    );
     terminal.start();
   }
 

+ 6 - 16
example/lib/main.dart

@@ -30,19 +30,15 @@ class MyHomePage extends StatefulWidget {
 }
 
 class FakeTerminalBackend extends TerminalBackend {
-  Completer<int> _exitCodeCompleter;
+  final _exitCodeCompleter = Completer<int>();
   // ignore: close_sinks
-  StreamController<String> _outStream;
-
-  FakeTerminalBackend();
+  final _outStream = StreamController<String>();
 
   @override
   Future<int> get exitCode => _exitCodeCompleter.future;
 
   @override
   void init() {
-    _exitCodeCompleter = Completer<int>();
-    _outStream = StreamController<String>();
     _outStream.sink.add('xterm.dart demo');
     _outStream.sink.add('\r\n');
     _outStream.sink.add('\$ ');
@@ -89,16 +85,10 @@ class FakeTerminalBackend extends TerminalBackend {
 }
 
 class _MyHomePageState extends State<MyHomePage> {
-  Terminal terminal;
-
-  @override
-  void initState() {
-    super.initState();
-    terminal = Terminal(
-      backend: FakeTerminalBackend(),
-      maxLines: 10000,
-    );
-  }
+  final terminal = Terminal(
+    backend: FakeTerminalBackend(),
+    maxLines: 10000,
+  );
 
   void onInput(String input) {}
 

+ 1 - 1
example/pubspec.lock

@@ -28,7 +28,7 @@ packages:
       name: characters
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.1.0"
+    version: "1.2.0"
   charcode:
     dependency: transitive
     description:

BIN
example/web/icons/Icon-maskable-192.png


BIN
example/web/icons/Icon-maskable-512.png


+ 1 - 1
example/windows/CMakeLists.txt

@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.15)
+cmake_minimum_required(VERSION 3.14)
 project(example LANGUAGES CXX)
 
 set(BINARY_NAME "example")

+ 0 - 1
example/windows/flutter/.template_version

@@ -1 +0,0 @@
-4

+ 9 - 4
example/windows/flutter/CMakeLists.txt

@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.15)
+cmake_minimum_required(VERSION 3.14)
 
 set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
 
@@ -23,6 +23,7 @@ list(APPEND FLUTTER_LIBRARY_HEADERS
   "flutter_windows.h"
   "flutter_messenger.h"
   "flutter_plugin_registrar.h"
+  "flutter_texture_registrar.h"
 )
 list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/")
 add_library(flutter INTERFACE)
@@ -34,8 +35,8 @@ add_dependencies(flutter flutter_assemble)
 
 # === Wrapper ===
 list(APPEND CPP_WRAPPER_SOURCES_CORE
-  "engine_method_result.cc"
-	"standard_codec.cc"
+  "core_implementations.cc"
+  "standard_codec.cc"
 )
 list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/")
 list(APPEND CPP_WRAPPER_SOURCES_PLUGIN
@@ -43,6 +44,7 @@ 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"
 )
 list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/")
@@ -79,15 +81,18 @@ add_dependencies(flutter_wrapper_app flutter_assemble)
 # _phony_ is a non-existent file to force this command to run every time,
 # since currently there's no way to get a full input/output list from the
 # flutter tool.
+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_PLUGIN}
     ${CPP_WRAPPER_SOURCES_APP}
-    ${CMAKE_CURRENT_BINARY_DIR}/_phony_
+    ${PHONY_OUTPUT}
   COMMAND ${CMAKE_COMMAND} -E env
     ${FLUTTER_TOOL_ENVIRONMENT}
     "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat"
       windows-x64 $<CONFIG>
+  VERBATIM
 )
 add_custom_target(flutter_assemble DEPENDS
   "${FLUTTER_LIBRARY}"

+ 2 - 0
example/windows/flutter/generated_plugin_registrant.cc

@@ -2,6 +2,8 @@
 //  Generated file. Do not edit.
 //
 
+// clang-format off
+
 #include "generated_plugin_registrant.h"
 
 

+ 2 - 0
example/windows/flutter/generated_plugin_registrant.h

@@ -2,6 +2,8 @@
 //  Generated file. Do not edit.
 //
 
+// clang-format off
+
 #ifndef GENERATED_PLUGIN_REGISTRANT_
 #define GENERATED_PLUGIN_REGISTRANT_
 

+ 2 - 3
example/windows/runner/CMakeLists.txt

@@ -1,18 +1,17 @@
-cmake_minimum_required(VERSION 3.15)
+cmake_minimum_required(VERSION 3.14)
 project(runner LANGUAGES CXX)
 
 add_executable(${BINARY_NAME} WIN32
   "flutter_window.cpp"
   "main.cpp"
-  "run_loop.cpp"
   "utils.cpp"
   "win32_window.cpp"
-  "window_configuration.cpp"
   "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
   "Runner.rc"
   "runner.exe.manifest"
 )
 apply_standard_settings(${BINARY_NAME})
+target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX")
 target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app)
 target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
 add_dependencies(${BINARY_NAME} flutter_assemble)

+ 121 - 70
example/windows/runner/Runner.rc

@@ -1,70 +1,121 @@
-// Microsoft Visual C++ generated resource script.
-//
-#pragma code_page(65001)
-#include "resource.h"
-
-#define APSTUDIO_READONLY_SYMBOLS
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 2 resource.
-//
-#include "winres.h"
-
-/////////////////////////////////////////////////////////////////////////////
-#undef APSTUDIO_READONLY_SYMBOLS
-
-/////////////////////////////////////////////////////////////////////////////
-// English (United States) resources
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
-
-#ifdef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// TEXTINCLUDE
-//
-
-1 TEXTINCLUDE
-BEGIN
-    "resource.h\0"
-END
-
-2 TEXTINCLUDE
-BEGIN
-    "#include ""winres.h""\r\n"
-    "\0"
-END
-
-3 TEXTINCLUDE
-BEGIN
-    "\r\n"
-    "\0"
-END
-
-#endif    // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Icon
-//
-
-// Icon with lowest ID value placed first to ensure application icon
-// remains consistent on all systems.
-IDI_APP_ICON            ICON                    "resources\\app_icon.ico"
-
-#endif    // English (United States) resources
-/////////////////////////////////////////////////////////////////////////////
-
-
-
-#ifndef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 3 resource.
-//
-
-
-/////////////////////////////////////////////////////////////////////////////
-#endif    // not APSTUDIO_INVOKED
+// Microsoft Visual C++ generated resource script.
+//
+#pragma code_page(65001)
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "winres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (United States) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+    "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+    "#include ""winres.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_APP_ICON            ICON                    "resources\\app_icon.ico"
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+#ifdef FLUTTER_BUILD_NUMBER
+#define VERSION_AS_NUMBER FLUTTER_BUILD_NUMBER
+#else
+#define VERSION_AS_NUMBER 1,0,0
+#endif
+
+#ifdef FLUTTER_BUILD_NAME
+#define VERSION_AS_STRING #FLUTTER_BUILD_NAME
+#else
+#define VERSION_AS_STRING "1.0.0"
+#endif
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION VERSION_AS_NUMBER
+ PRODUCTVERSION VERSION_AS_NUMBER
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+#ifdef _DEBUG
+ FILEFLAGS VS_FF_DEBUG
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS VOS__WINDOWS32
+ FILETYPE VFT_APP
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904e4"
+        BEGIN
+            VALUE "CompanyName", "com.example" "\0"
+            VALUE "FileDescription", "A new Flutter project." "\0"
+            VALUE "FileVersion", VERSION_AS_STRING "\0"
+            VALUE "InternalName", "example" "\0"
+            VALUE "LegalCopyright", "Copyright (C) 2021 com.example. All rights reserved." "\0"
+            VALUE "OriginalFilename", "example.exe" "\0"
+            VALUE "ProductName", "example" "\0"
+            VALUE "ProductVersion", VERSION_AS_STRING "\0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1252
+    END
+END
+
+#endif    // English (United States) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED

+ 43 - 11
example/windows/runner/flutter_window.cpp

@@ -1,29 +1,61 @@
 #include "flutter_window.h"
 
+#include <optional>
+
 #include "flutter/generated_plugin_registrant.h"
 
-FlutterWindow::FlutterWindow(RunLoop* run_loop,
-                             const flutter::DartProject& project)
-    : run_loop_(run_loop), project_(project) {}
+FlutterWindow::FlutterWindow(const flutter::DartProject& project)
+    : project_(project) {}
 
 FlutterWindow::~FlutterWindow() {}
 
-void FlutterWindow::OnCreate() {
-  Win32Window::OnCreate();
+bool FlutterWindow::OnCreate() {
+  if (!Win32Window::OnCreate()) {
+    return false;
+  }
+
+  RECT frame = GetClientArea();
 
-  // The size here is arbitrary since SetChildContent will resize it.
-  flutter_controller_ =
-      std::make_unique<flutter::FlutterViewController>(100, 100, project_);
-  RegisterPlugins(flutter_controller_.get());
-  run_loop_->RegisterFlutterInstance(flutter_controller_.get());
+  // The size here must match the window dimensions to avoid unnecessary surface
+  // creation / destruction in the startup path.
+  flutter_controller_ = std::make_unique<flutter::FlutterViewController>(
+      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_) {
-    run_loop_->UnregisterFlutterInstance(flutter_controller_.get());
     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<LRESULT> 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);
+}

+ 10 - 14
example/windows/runner/flutter_window.h

@@ -1,32 +1,28 @@
-#ifndef FLUTTER_WINDOW_H_
-#define FLUTTER_WINDOW_H_
+#ifndef RUNNER_FLUTTER_WINDOW_H_
+#define RUNNER_FLUTTER_WINDOW_H_
 
 #include <flutter/dart_project.h>
 #include <flutter/flutter_view_controller.h>
 
-#include "run_loop.h"
-#include "win32_window.h"
-
 #include <memory>
 
+#include "win32_window.h"
+
 // A window that does nothing but host a Flutter view.
 class FlutterWindow : public Win32Window {
  public:
-  // Creates a new FlutterWindow driven by the |run_loop|, hosting a
-  // Flutter view running |project|.
-  explicit FlutterWindow(RunLoop* run_loop,
-                         const flutter::DartProject& project);
+  // Creates a new FlutterWindow hosting a Flutter view running |project|.
+  explicit FlutterWindow(const flutter::DartProject& project);
   virtual ~FlutterWindow();
 
  protected:
   // Win32Window:
-  void OnCreate() override;
+  bool OnCreate() override;
   void OnDestroy() override;
+  LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam,
+                         LPARAM const lparam) noexcept override;
 
  private:
-  // The run loop driving events for this window.
-  RunLoop* run_loop_;
-
   // The project to run.
   flutter::DartProject project_;
 
@@ -34,4 +30,4 @@ class FlutterWindow : public Win32Window {
   std::unique_ptr<flutter::FlutterViewController> flutter_controller_;
 };
 
-#endif  // FLUTTER_WINDOW_H_
+#endif  // RUNNER_FLUTTER_WINDOW_H_

+ 15 - 9
example/windows/runner/main.cpp

@@ -3,9 +3,7 @@
 #include <windows.h>
 
 #include "flutter_window.h"
-#include "run_loop.h"
 #include "utils.h"
-#include "window_configuration.h"
 
 int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
                       _In_ wchar_t *command_line, _In_ int show_command) {
@@ -19,18 +17,26 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
   // plugins.
   ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
 
-  RunLoop run_loop;
-
   flutter::DartProject project(L"data");
-  FlutterWindow window(&run_loop, project);
-  Win32Window::Point origin(kFlutterWindowOriginX, kFlutterWindowOriginY);
-  Win32Window::Size size(kFlutterWindowWidth, kFlutterWindowHeight);
-  if (!window.CreateAndShow(kFlutterWindowTitle, origin, size)) {
+
+  std::vector<std::string> command_line_arguments =
+      GetCommandLineArguments();
+
+  project.set_dart_entrypoint_arguments(std::move(command_line_arguments));
+
+  FlutterWindow window(project);
+  Win32Window::Point origin(10, 10);
+  Win32Window::Size size(1280, 720);
+  if (!window.CreateAndShow(L"example", origin, size)) {
     return EXIT_FAILURE;
   }
   window.SetQuitOnClose(true);
 
-  run_loop.Run();
+  ::MSG msg;
+  while (::GetMessage(&msg, nullptr, 0, 0)) {
+    ::TranslateMessage(&msg);
+    ::DispatchMessage(&msg);
+  }
 
   ::CoUninitialize();
   return EXIT_SUCCESS;

+ 0 - 70
example/windows/runner/run_loop.cpp

@@ -1,70 +0,0 @@
-#include "run_loop.h"
-
-#include <Windows.h>
-// Don't stomp std::min/std::max
-#undef max
-#undef min
-
-#include <algorithm>
-
-RunLoop::RunLoop() {}
-
-RunLoop::~RunLoop() {}
-
-void RunLoop::Run() {
-  bool keep_running = true;
-  TimePoint next_flutter_event_time = TimePoint::clock::now();
-  while (keep_running) {
-    std::chrono::nanoseconds wait_duration =
-        std::max(std::chrono::nanoseconds(0),
-                 next_flutter_event_time - TimePoint::clock::now());
-    ::MsgWaitForMultipleObjects(
-        0, nullptr, FALSE, static_cast<DWORD>(wait_duration.count() / 1000),
-        QS_ALLINPUT);
-    bool processed_events = false;
-    MSG message;
-    // All pending Windows messages must be processed; MsgWaitForMultipleObjects
-    // won't return again for items left in the queue after PeekMessage.
-    while (::PeekMessage(&message, nullptr, 0, 0, PM_REMOVE)) {
-      processed_events = true;
-      if (message.message == WM_QUIT) {
-        keep_running = false;
-        break;
-      }
-      ::TranslateMessage(&message);
-      ::DispatchMessage(&message);
-      // Allow Flutter to process messages each time a Windows message is
-      // processed, to prevent starvation.
-      next_flutter_event_time =
-          std::min(next_flutter_event_time, ProcessFlutterMessages());
-    }
-    // If the PeekMessage loop didn't run, process Flutter messages.
-    if (!processed_events) {
-      next_flutter_event_time =
-          std::min(next_flutter_event_time, ProcessFlutterMessages());
-    }
-  }
-}
-
-void RunLoop::RegisterFlutterInstance(
-    flutter::FlutterViewController* flutter_instance) {
-  flutter_instances_.insert(flutter_instance);
-}
-
-void RunLoop::UnregisterFlutterInstance(
-    flutter::FlutterViewController* flutter_instance) {
-  flutter_instances_.erase(flutter_instance);
-}
-
-RunLoop::TimePoint RunLoop::ProcessFlutterMessages() {
-  TimePoint next_event_time = TimePoint::max();
-  for (auto flutter_controller : flutter_instances_) {
-    std::chrono::nanoseconds wait_duration =
-        flutter_controller->ProcessMessages();
-    if (wait_duration != std::chrono::nanoseconds::max()) {
-      next_event_time =
-          std::min(next_event_time, TimePoint::clock::now() + wait_duration);
-    }
-  }
-  return next_event_time;
-}

+ 0 - 40
example/windows/runner/run_loop.h

@@ -1,40 +0,0 @@
-#ifndef RUN_LOOP_H_
-#define RUN_LOOP_H_
-
-#include <flutter/flutter_view_controller.h>
-
-#include <chrono>
-#include <set>
-
-// A runloop that will service events for Flutter instances as well
-// as native messages.
-class RunLoop {
- public:
-  RunLoop();
-  ~RunLoop();
-
-  // Prevent copying
-  RunLoop(RunLoop const&) = delete;
-  RunLoop& operator=(RunLoop const&) = delete;
-
-  // Runs the run loop until the application quits.
-  void Run();
-
-  // Registers the given Flutter instance for event servicing.
-  void RegisterFlutterInstance(
-      flutter::FlutterViewController* flutter_instance);
-
-  // Unregisters the given Flutter instance from event servicing.
-  void UnregisterFlutterInstance(
-      flutter::FlutterViewController* flutter_instance);
-
- private:
-  using TimePoint = std::chrono::steady_clock::time_point;
-
-  // Processes all currently pending messages for registered Flutter instances.
-  TimePoint ProcessFlutterMessages();
-
-  std::set<flutter::FlutterViewController*> flutter_instances_;
-};
-
-#endif  // RUN_LOOP_H_

+ 42 - 0
example/windows/runner/utils.cpp

@@ -20,3 +20,45 @@ void CreateAndAttachConsole() {
     FlutterDesktopResyncOutputStreams();
   }
 }
+
+std::vector<std::string> GetCommandLineArguments() {
+  // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use.
+  int argc;
+  wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
+  if (argv == nullptr) {
+    return std::vector<std::string>();
+  }
+
+  std::vector<std::string> command_line_arguments;
+
+  // Skip the first argument as it's the binary name.
+  for (int i = 1; i < argc; i++) {
+    command_line_arguments.push_back(Utf8FromUtf16(argv[i]));
+  }
+
+  ::LocalFree(argv);
+
+  return command_line_arguments;
+}
+
+std::string Utf8FromUtf16(const wchar_t* utf16_string) {
+  if (utf16_string == nullptr) {
+    return std::string();
+  }
+  int target_length = ::WideCharToMultiByte(
+      CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
+      -1, nullptr, 0, nullptr, nullptr);
+  if (target_length == 0) {
+    return std::string();
+  }
+  std::string utf8_string;
+  utf8_string.resize(target_length);
+  int converted_length = ::WideCharToMultiByte(
+      CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
+      -1, utf8_string.data(),
+      target_length, nullptr, nullptr);
+  if (converted_length == 0) {
+    return std::string();
+  }
+  return utf8_string;
+}

+ 14 - 3
example/windows/runner/utils.h

@@ -1,8 +1,19 @@
-#ifndef CONSOLE_UTILS_H_
-#define CONSOLE_UTILS_H_
+#ifndef RUNNER_UTILS_H_
+#define RUNNER_UTILS_H_
+
+#include <string>
+#include <vector>
 
 // Creates a console for the process, and redirects stdout and stderr to
 // it for both the runner and the Flutter library.
 void CreateAndAttachConsole();
 
-#endif  // CONSOLE_UTILS_H_
+// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string
+// encoded in UTF-8. Returns an empty std::string on failure.
+std::string Utf8FromUtf16(const wchar_t* utf16_string);
+
+// Gets the command line arguments passed in as a std::vector<std::string>,
+// encoded in UTF-8. Returns an empty std::vector<std::string> on failure.
+std::vector<std::string> GetCommandLineArguments();
+
+#endif  // RUNNER_UTILS_H_

+ 16 - 20
example/windows/runner/win32_window.cpp

@@ -122,9 +122,11 @@ bool Win32Window::CreateAndShow(const std::wstring& title,
       Scale(size.width, scale_factor), Scale(size.height, scale_factor),
       nullptr, nullptr, GetModuleHandle(nullptr), this);
 
-  OnCreate();
+  if (!window) {
+    return false;
+  }
 
-  return window != nullptr;
+  return OnCreate();
 }
 
 // static
@@ -152,13 +154,6 @@ Win32Window::MessageHandler(HWND hwnd,
                             UINT const message,
                             WPARAM const wparam,
                             LPARAM const lparam) noexcept {
-  auto window =
-      reinterpret_cast<Win32Window*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
-
-  if (window == nullptr) {
-    return 0;
-  }
-
   switch (message) {
     case WM_DESTROY:
       window_handle_ = nullptr;
@@ -178,26 +173,21 @@ Win32Window::MessageHandler(HWND hwnd,
 
       return 0;
     }
-    case WM_SIZE:
-      RECT rect;
-      GetClientRect(hwnd, &rect);
+    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;
-
-    // Messages that are directly forwarded to embedding.
-    case WM_FONTCHANGE:
-      SendMessage(child_content_, WM_FONTCHANGE, NULL, NULL);
-      return 0;
   }
 
   return DefWindowProc(window_handle_, message, wparam, lparam);
@@ -223,8 +213,7 @@ Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept {
 void Win32Window::SetChildContent(HWND content) {
   child_content_ = content;
   SetParent(content, window_handle_);
-  RECT frame;
-  GetClientRect(window_handle_, &frame);
+  RECT frame = GetClientArea();
 
   MoveWindow(content, frame.left, frame.top, frame.right - frame.left,
              frame.bottom - frame.top, true);
@@ -232,6 +221,12 @@ void Win32Window::SetChildContent(HWND content) {
   SetFocus(child_content_);
 }
 
+RECT Win32Window::GetClientArea() {
+  RECT frame;
+  GetClientRect(window_handle_, &frame);
+  return frame;
+}
+
 HWND Win32Window::GetHandle() {
   return window_handle_;
 }
@@ -240,8 +235,9 @@ void Win32Window::SetQuitOnClose(bool quit_on_close) {
   quit_on_close_ = quit_on_close;
 }
 
-void Win32Window::OnCreate() {
+bool Win32Window::OnCreate() {
   // No-op; provided for subclasses.
+  return true;
 }
 
 void Win32Window::OnDestroy() {

+ 9 - 7
example/windows/runner/win32_window.h

@@ -1,8 +1,7 @@
-#ifndef WIN32_WINDOW_H_
-#define WIN32_WINDOW_H_
+#ifndef RUNNER_WIN32_WINDOW_H_
+#define RUNNER_WIN32_WINDOW_H_
 
-#include <Windows.h>
-#include <Windowsx.h>
+#include <windows.h>
 
 #include <functional>
 #include <memory>
@@ -52,6 +51,9 @@ class Win32Window {
   // 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
@@ -62,8 +64,8 @@ class Win32Window {
                                  LPARAM const lparam) noexcept;
 
   // Called when CreateAndShow is called, allowing subclass window-related
-  // setup.
-  virtual void OnCreate();
+  // setup. Subclasses should return false if setup fails.
+  virtual bool OnCreate();
 
   // Called when Destroy is called.
   virtual void OnDestroy();
@@ -93,4 +95,4 @@ class Win32Window {
   HWND child_content_ = nullptr;
 };
 
-#endif  // WIN32_WINDOW_H_
+#endif  // RUNNER_WIN32_WINDOW_H_

+ 0 - 7
example/windows/runner/window_configuration.cpp

@@ -1,7 +0,0 @@
-#include "window_configuration.h"
-
-const wchar_t* kFlutterWindowTitle = L"example";
-const unsigned int kFlutterWindowOriginX = 10;
-const unsigned int kFlutterWindowOriginY = 10;
-const unsigned int kFlutterWindowWidth = 1280;
-const unsigned int kFlutterWindowHeight = 720;

+ 0 - 18
example/windows/runner/window_configuration.h

@@ -1,18 +0,0 @@
-#ifndef WINDOW_CONFIGURATION_
-#define WINDOW_CONFIGURATION_
-
-// This is a temporary approach to isolate changes that people are likely to
-// make to main.cpp, where the APIs are still in flux. This will reduce the
-// need to resolve conflicts or re-create changes slightly differently every
-// time the Windows Flutter API surface changes.
-//
-// Longer term there should be simpler configuration options for common
-// customizations like this, without requiring native code changes.
-
-extern const wchar_t* kFlutterWindowTitle;
-extern const unsigned int kFlutterWindowOriginX;
-extern const unsigned int kFlutterWindowOriginY;
-extern const unsigned int kFlutterWindowWidth;
-extern const unsigned int kFlutterWindowHeight;
-
-#endif  // WINDOW_CONFIGURATION_

+ 47 - 1
pubspec.lock

@@ -22,6 +22,13 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "2.2.0"
+  asn1lib:
+    dependency: transitive
+    description:
+      name: asn1lib
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.5.15"
   async:
     dependency: transitive
     description:
@@ -98,7 +105,7 @@ packages:
       name: characters
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.1.0"
+    version: "1.2.0"
   charcode:
     dependency: transitive
     description:
@@ -162,6 +169,15 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "2.0.3"
+  dartssh:
+    dependency: "direct dev"
+    description:
+      path: "."
+      ref: test
+      resolved-ref: "3113e72b9e1b4ac742147be1ad34a586e9cc9bb5"
+      url: "https://github.com/linhanyu/dartssh"
+    source: git
+    version: "1.0.4+4"
   equatable:
     dependency: "direct main"
     description:
@@ -221,6 +237,13 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "2.0.0"
+  http:
+    dependency: transitive
+    description:
+      name: http
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.13.3"
   http_multi_server:
     dependency: transitive
     description:
@@ -319,6 +342,13 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "3.0.0-nullsafety.1"
+  pointycastle:
+    dependency: transitive
+    description:
+      name: pointycastle
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.0.2"
   pool:
     dependency: transitive
     description:
@@ -429,6 +459,15 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "1.0.0"
+  tweetnacl:
+    dependency: transitive
+    description:
+      path: "."
+      ref: HEAD
+      resolved-ref: "68bba352d1972bb72643760b9f97cf44cb75a88d"
+      url: "https://github.com/linhanyu/tweetnacl-dart"
+    source: git
+    version: "0.3.2"
   typed_data:
     dependency: transitive
     description:
@@ -436,6 +475,13 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "1.3.0"
+  validators:
+    dependency: transitive
+    description:
+      name: validators
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "2.0.0+1"
   vector_math:
     dependency: transitive
     description:

+ 2 - 0
pubspec.yaml

@@ -22,6 +22,8 @@ dev_dependencies:
   mockito: ^5.0.15
   build_runner: ^2.1.1
 
+
+
 # For information on the generic Dart part of this file, see the
 # following page: https://dart.dev/tools/pub/pubspec