diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 5c0f0334..07860ce1 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 00000000..449a9f93
--- /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 7ed6ff82..00000000
--- a/windows/flutter/.template_version
+++ /dev/null
@@ -1 +0,0 @@
-5
diff --git a/windows/flutter/CMakeLists.txt b/windows/flutter/CMakeLists.txt
index 98bb5646..c7a8c760 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 83e5acaa..977e38b5 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 7d864996..ed2b95fa 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 fe980cf8..c4227230 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 4f41e16f..b663ddd5 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 11b48e95..68fd370e 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 c04e20ca..f53c6c00 100644
Binary files a/windows/runner/resources/app_icon.ico and b/windows/runner/resources/app_icon.ico differ
diff --git a/windows/runner/run_loop.cpp b/windows/runner/run_loop.cpp
index f91d6d4c..2d6636ab 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 442a58e5..000d3624 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 d247a663..d792603b 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 677a9a6c..efc3eb9f 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 5cbb5d59..17ba4311 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 154f85b2..00000000
--- 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 ea5cead4..00000000
--- 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_