From 46c606ef29f187196f46519b5e7a5ff4b9674dde Mon Sep 17 00:00:00 2001 From: Marcel Date: Sun, 4 Oct 2020 14:06:34 +0000 Subject: [PATCH] fix(windows): Recreate windows files to make sure windows compiles --- .gitlab-ci.yml | 28 ++++++++++ .../app/src/main/res/values-night/styles.xml | 18 +++++++ windows/flutter/.template_version | 1 - windows/flutter/CMakeLists.txt | 8 +-- windows/runner/CMakeLists.txt | 2 +- windows/runner/Runner.rc | 51 ++++++++++++++++++ windows/runner/flutter_window.cpp | 51 +++++++++++++++--- windows/runner/flutter_window.h | 14 ++--- windows/runner/main.cpp | 7 ++- windows/runner/resources/app_icon.ico | Bin 33772 -> 12383 bytes windows/runner/run_loop.cpp | 14 ++--- windows/runner/run_loop.h | 14 ++--- windows/runner/utils.h | 6 +-- windows/runner/win32_window.cpp | 33 +++++------- windows/runner/win32_window.h | 16 +++--- windows/runner/window_configuration.cpp | 7 --- windows/runner/window_configuration.h | 18 ------- 17 files changed, 195 insertions(+), 93 deletions(-) create mode 100644 android/app/src/main/res/values-night/styles.xml delete mode 100644 windows/flutter/.template_version delete mode 100644 windows/runner/window_configuration.cpp delete mode 100644 windows/runner/window_configuration.h diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5c0f033..07860ce 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,6 +4,12 @@ image: variables: GIT_SUBMODULE_STRATEGY: recursive +.shared_windows_runners: + tags: + - shared-windows + - windows + - windows-1809 + stages: - coverage - publish @@ -44,6 +50,28 @@ build_web: paths: - build/web/ +build_windows: + extends: + - .shared_windows_runners + stage: publish + script: + # Install chocolately + - Set-ExecutionPolicy Bypass -Scope Process + - Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1')) + - choco install git -y + - choco install visualstudio2019community -y --package-parameters "--add Microsoft.VisualStudio.Product.BuildTools --includeRecommended --includeOptional --passive --locale en-US" + - cd ..; git clone https://github.com/flutter/flutter.git -b dev; $env:path += ";C:\GitLab-Runner\builds\ChristianPauly\flutter\bin"; cd fluffychat-flutter + - flutter doctor + - flutter config --enable-windows-desktop + - flutter build windows + needs: [] + artifacts: + paths: + - build/windows/runner/Release/ + name: "Binairies" + only: + - main + - tags build_android_debug: stage: coverage diff --git a/android/app/src/main/res/values-night/styles.xml b/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000..449a9f9 --- /dev/null +++ b/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/windows/flutter/.template_version b/windows/flutter/.template_version deleted file mode 100644 index 7ed6ff8..0000000 --- a/windows/flutter/.template_version +++ /dev/null @@ -1 +0,0 @@ -5 diff --git a/windows/flutter/CMakeLists.txt b/windows/flutter/CMakeLists.txt index 98bb564..c7a8c76 100644 --- a/windows/flutter/CMakeLists.txt +++ b/windows/flutter/CMakeLists.txt @@ -34,8 +34,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 @@ -80,11 +80,13 @@ 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" diff --git a/windows/runner/CMakeLists.txt b/windows/runner/CMakeLists.txt index 83e5aca..977e38b 100644 --- a/windows/runner/CMakeLists.txt +++ b/windows/runner/CMakeLists.txt @@ -7,12 +7,12 @@ add_executable(${BINARY_NAME} WIN32 "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) diff --git a/windows/runner/Runner.rc b/windows/runner/Runner.rc index 7d86499..ed2b95f 100644 --- a/windows/runner/Runner.rc +++ b/windows/runner/Runner.rc @@ -54,6 +54,57 @@ END // 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", "chat.fluffy" "\0" + VALUE "FileDescription", "A new Flutter project." "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "Fluffychat" "\0" + VALUE "LegalCopyright", "Copyright (C) 2020 chat.fluffy. All rights reserved." "\0" + VALUE "OriginalFilename", "fluffychat.exe" "\0" + VALUE "ProductName", "Fluffychat" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + #endif // English (United States) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/windows/runner/flutter_window.cpp b/windows/runner/flutter_window.cpp index fe980cf..c422723 100644 --- a/windows/runner/flutter_window.cpp +++ b/windows/runner/flutter_window.cpp @@ -1,5 +1,7 @@ #include "flutter_window.h" +#include + #include "flutter/generated_plugin_registrant.h" FlutterWindow::FlutterWindow(RunLoop* run_loop, @@ -8,22 +10,55 @@ FlutterWindow::FlutterWindow(RunLoop* run_loop, FlutterWindow::~FlutterWindow() {} -void FlutterWindow::OnCreate() { - Win32Window::OnCreate(); +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } - // The size here is arbitrary since SetChildContent will resize it. - flutter_controller_ = - std::make_unique(100, 100, project_); - RegisterPlugins(flutter_controller_.get()); - run_loop_->RegisterFlutterInstance(flutter_controller_.get()); + 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()); + run_loop_->RegisterFlutterInstance(flutter_controller_->engine()); SetChildContent(flutter_controller_->view()->GetNativeWindow()); + return true; } void FlutterWindow::OnDestroy() { if (flutter_controller_) { - run_loop_->UnregisterFlutterInstance(flutter_controller_.get()); + run_loop_->UnregisterFlutterInstance(flutter_controller_->engine()); 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 opporutunity 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/windows/runner/flutter_window.h b/windows/runner/flutter_window.h index 4f41e16..b663ddd 100644 --- a/windows/runner/flutter_window.h +++ b/windows/runner/flutter_window.h @@ -1,14 +1,14 @@ -#ifndef FLUTTER_WINDOW_H_ -#define FLUTTER_WINDOW_H_ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ #include #include +#include + #include "run_loop.h" #include "win32_window.h" -#include - // A window that does nothing but host a Flutter view. class FlutterWindow : public Win32Window { public: @@ -20,8 +20,10 @@ class FlutterWindow : public Win32Window { 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. @@ -34,4 +36,4 @@ class FlutterWindow : public Win32Window { std::unique_ptr flutter_controller_; }; -#endif // FLUTTER_WINDOW_H_ +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/windows/runner/main.cpp b/windows/runner/main.cpp index 11b48e9..68fd370 100644 --- a/windows/runner/main.cpp +++ b/windows/runner/main.cpp @@ -5,7 +5,6 @@ #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) { @@ -23,9 +22,9 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, 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)) { + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.CreateAndShow(L"Fluffychat", origin, size)) { return EXIT_FAILURE; } window.SetQuitOnClose(true); diff --git a/windows/runner/resources/app_icon.ico b/windows/runner/resources/app_icon.ico index c04e20caf6370ebb9253ad831cc31de4a9c965f6..f53c6c0053751707f857edab9188c4dcee4f2275 100644 GIT binary patch literal 12383 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 diff --git a/windows/runner/run_loop.cpp b/windows/runner/run_loop.cpp index f91d6d4..2d6636a 100644 --- a/windows/runner/run_loop.cpp +++ b/windows/runner/run_loop.cpp @@ -1,9 +1,6 @@ #include "run_loop.h" -#include -// Don't stomp std::min/std::max -#undef max -#undef min +#include #include @@ -47,20 +44,19 @@ void RunLoop::Run() { } void RunLoop::RegisterFlutterInstance( - flutter::FlutterViewController* flutter_instance) { + flutter::FlutterEngine* flutter_instance) { flutter_instances_.insert(flutter_instance); } void RunLoop::UnregisterFlutterInstance( - flutter::FlutterViewController* flutter_instance) { + flutter::FlutterEngine* 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(); + for (auto instance : flutter_instances_) { + std::chrono::nanoseconds wait_duration = instance->ProcessMessages(); if (wait_duration != std::chrono::nanoseconds::max()) { next_event_time = std::min(next_event_time, TimePoint::clock::now() + wait_duration); diff --git a/windows/runner/run_loop.h b/windows/runner/run_loop.h index 442a58e..000d362 100644 --- a/windows/runner/run_loop.h +++ b/windows/runner/run_loop.h @@ -1,7 +1,7 @@ -#ifndef RUN_LOOP_H_ -#define RUN_LOOP_H_ +#ifndef RUNNER_RUN_LOOP_H_ +#define RUNNER_RUN_LOOP_H_ -#include +#include #include #include @@ -22,11 +22,11 @@ class RunLoop { // Registers the given Flutter instance for event servicing. void RegisterFlutterInstance( - flutter::FlutterViewController* flutter_instance); + flutter::FlutterEngine* flutter_instance); // Unregisters the given Flutter instance from event servicing. void UnregisterFlutterInstance( - flutter::FlutterViewController* flutter_instance); + flutter::FlutterEngine* flutter_instance); private: using TimePoint = std::chrono::steady_clock::time_point; @@ -34,7 +34,7 @@ class RunLoop { // Processes all currently pending messages for registered Flutter instances. TimePoint ProcessFlutterMessages(); - std::set flutter_instances_; + std::set flutter_instances_; }; -#endif // RUN_LOOP_H_ +#endif // RUNNER_RUN_LOOP_H_ diff --git a/windows/runner/utils.h b/windows/runner/utils.h index d247a66..d792603 100644 --- a/windows/runner/utils.h +++ b/windows/runner/utils.h @@ -1,8 +1,8 @@ -#ifndef CONSOLE_UTILS_H_ -#define CONSOLE_UTILS_H_ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ // 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_ +#endif // RUNNER_UTILS_H_ diff --git a/windows/runner/win32_window.cpp b/windows/runner/win32_window.cpp index 677a9a6..efc3eb9 100644 --- a/windows/runner/win32_window.cpp +++ b/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(GetWindowLongPtr(hwnd, GWLP_USERDATA)); - - if (window == nullptr) { - return 0; - } - switch (message) { case WM_DESTROY: window_handle_ = nullptr; @@ -179,8 +174,7 @@ Win32Window::MessageHandler(HWND hwnd, return 0; } case WM_SIZE: - RECT rect; - GetClientRect(hwnd, &rect); + RECT rect = GetClientArea(); if (child_content_ != nullptr) { // Size and position the child window. MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, @@ -193,11 +187,6 @@ Win32Window::MessageHandler(HWND hwnd, 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 +212,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 +220,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 +234,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() { diff --git a/windows/runner/win32_window.h b/windows/runner/win32_window.h index 5cbb5d5..17ba431 100644 --- a/windows/runner/win32_window.h +++ b/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 -#include +#include #include #include @@ -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_ diff --git a/windows/runner/window_configuration.cpp b/windows/runner/window_configuration.cpp deleted file mode 100644 index 154f85b..0000000 --- a/windows/runner/window_configuration.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "window_configuration.h" - -const wchar_t* kFlutterWindowTitle = L"fluffychat"; -const unsigned int kFlutterWindowOriginX = 10; -const unsigned int kFlutterWindowOriginY = 10; -const unsigned int kFlutterWindowWidth = 1280; -const unsigned int kFlutterWindowHeight = 720; diff --git a/windows/runner/window_configuration.h b/windows/runner/window_configuration.h deleted file mode 100644 index ea5cead..0000000 --- a/windows/runner/window_configuration.h +++ /dev/null @@ -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_