aboutsummaryrefslogtreecommitdiff
path: root/windows/runner
diff options
context:
space:
mode:
authordavidpkj <davidpenkow1@gmail.com>2023-03-05 12:08:46 +0100
committerdavidpkj <davidpenkow1@gmail.com>2023-03-05 12:08:46 +0100
commitb40f1fc758f0d4a922de4cdcc197bb8a64be0e60 (patch)
tree7cc73e1c10f2eb47b3bfcefc893fe817131ce5ac /windows/runner
parent1855978738793fd0f80023e3e8ff09c939c33dfe (diff)
Updated web & windows projects strucutre
Diffstat (limited to 'windows/runner')
-rw-r--r--windows/runner/CMakeLists.txt8
-rw-r--r--windows/runner/Runner.rc14
-rw-r--r--windows/runner/flutter_window.cpp5
-rw-r--r--windows/runner/main.cpp2
-rw-r--r--windows/runner/runner.exe.manifest2
-rw-r--r--windows/runner/utils.cpp9
-rw-r--r--windows/runner/win32_window.cpp55
-rw-r--r--windows/runner/win32_window.h20
8 files changed, 88 insertions, 27 deletions
diff --git a/windows/runner/CMakeLists.txt b/windows/runner/CMakeLists.txt
index b9e550f..394917c 100644
--- a/windows/runner/CMakeLists.txt
+++ b/windows/runner/CMakeLists.txt
@@ -20,12 +20,20 @@ add_executable(${BINARY_NAME} WIN32
# that need different build settings.
apply_standard_settings(${BINARY_NAME})
+# Add preprocessor definitions for the build version.
+target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"")
+target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}")
+target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}")
+target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}")
+target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}")
+
# Disable Windows macros that collide with C++ standard library functions.
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/windows/runner/Runner.rc b/windows/runner/Runner.rc
index c8bde50..628a40b 100644
--- a/windows/runner/Runner.rc
+++ b/windows/runner/Runner.rc
@@ -60,14 +60,14 @@ IDI_APP_ICON ICON "resources\\app_icon.ico"
// Version
//
-#ifdef FLUTTER_BUILD_NUMBER
-#define VERSION_AS_NUMBER FLUTTER_BUILD_NUMBER
+#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD)
+#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD
#else
-#define VERSION_AS_NUMBER 1,0,0
+#define VERSION_AS_NUMBER 1,0,0,0
#endif
-#ifdef FLUTTER_BUILD_NAME
-#define VERSION_AS_STRING #FLUTTER_BUILD_NAME
+#if defined(FLUTTER_VERSION)
+#define VERSION_AS_STRING FLUTTER_VERSION
#else
#define VERSION_AS_STRING "1.0.0"
#endif
@@ -89,11 +89,11 @@ BEGIN
BEGIN
BLOCK "040904e4"
BEGIN
- VALUE "CompanyName", "com.example" "\0"
+ VALUE "CompanyName", "com.davidpenkowoj" "\0"
VALUE "FileDescription", "kulinar_app" "\0"
VALUE "FileVersion", VERSION_AS_STRING "\0"
VALUE "InternalName", "kulinar_app" "\0"
- VALUE "LegalCopyright", "Copyright (C) 2022 com.example. All rights reserved." "\0"
+ VALUE "LegalCopyright", "Copyright (C) 2023 com.davidpenkowoj. All rights reserved." "\0"
VALUE "OriginalFilename", "kulinar_app.exe" "\0"
VALUE "ProductName", "kulinar_app" "\0"
VALUE "ProductVersion", VERSION_AS_STRING "\0"
diff --git a/windows/runner/flutter_window.cpp b/windows/runner/flutter_window.cpp
index b43b909..b25e363 100644
--- a/windows/runner/flutter_window.cpp
+++ b/windows/runner/flutter_window.cpp
@@ -26,6 +26,11 @@ bool FlutterWindow::OnCreate() {
}
RegisterPlugins(flutter_controller_->engine());
SetChildContent(flutter_controller_->view()->GetNativeWindow());
+
+ flutter_controller_->engine()->SetNextFrameCallback([&]() {
+ this->Show();
+ });
+
return true;
}
diff --git a/windows/runner/main.cpp b/windows/runner/main.cpp
index f04af4f..8670a94 100644
--- a/windows/runner/main.cpp
+++ b/windows/runner/main.cpp
@@ -27,7 +27,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
FlutterWindow window(project);
Win32Window::Point origin(10, 10);
Win32Window::Size size(1280, 720);
- if (!window.CreateAndShow(L"kulinar_app", origin, size)) {
+ if (!window.Create(L"kulinar_app", origin, size)) {
return EXIT_FAILURE;
}
window.SetQuitOnClose(true);
diff --git a/windows/runner/runner.exe.manifest b/windows/runner/runner.exe.manifest
index c977c4a..a42ea76 100644
--- a/windows/runner/runner.exe.manifest
+++ b/windows/runner/runner.exe.manifest
@@ -7,7 +7,7 @@
</application>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
- <!-- Windows 10 -->
+ <!-- Windows 10 and Windows 11 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
diff --git a/windows/runner/utils.cpp b/windows/runner/utils.cpp
index f5bf9fa..b2b0873 100644
--- a/windows/runner/utils.cpp
+++ b/windows/runner/utils.cpp
@@ -47,16 +47,17 @@ std::string Utf8FromUtf16(const wchar_t* utf16_string) {
}
int target_length = ::WideCharToMultiByte(
CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
- -1, nullptr, 0, nullptr, nullptr);
+ -1, nullptr, 0, nullptr, nullptr)
+ -1; // remove the trailing null character
+ int input_length = (int)wcslen(utf16_string);
std::string utf8_string;
- if (target_length == 0 || target_length > utf8_string.max_size()) {
+ if (target_length <= 0 || target_length > utf8_string.max_size()) {
return 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);
+ input_length, utf8_string.data(), target_length, nullptr, nullptr);
if (converted_length == 0) {
return std::string();
}
diff --git a/windows/runner/win32_window.cpp b/windows/runner/win32_window.cpp
index c10f08d..60608d0 100644
--- a/windows/runner/win32_window.cpp
+++ b/windows/runner/win32_window.cpp
@@ -1,13 +1,31 @@
#include "win32_window.h"
+#include <dwmapi.h>
#include <flutter_windows.h>
#include "resource.h"
namespace {
+/// Window attribute that enables dark mode window decorations.
+///
+/// Redefined in case the developer's machine has a Windows SDK older than
+/// version 10.0.22000.0.
+/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute
+#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE
+#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
+#endif
+
constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW";
+/// Registry key for app theme preference.
+///
+/// A value of 0 indicates apps should use dark mode. A non-zero or missing
+/// value indicates apps should use light mode.
+constexpr const wchar_t kGetPreferredBrightnessRegKey[] =
+ L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize";
+constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme";
+
// The number of Win32Window objects that currently exist.
static int g_active_window_count = 0;
@@ -31,8 +49,8 @@ void EnableFullDpiSupportIfAvailable(HWND hwnd) {
GetProcAddress(user32_module, "EnableNonClientDpiScaling"));
if (enable_non_client_dpi_scaling != nullptr) {
enable_non_client_dpi_scaling(hwnd);
- FreeLibrary(user32_module);
}
+ FreeLibrary(user32_module);
}
} // namespace
@@ -42,7 +60,7 @@ class WindowClassRegistrar {
public:
~WindowClassRegistrar() = default;
- // Returns the singleton registar instance.
+ // Returns the singleton registrar instance.
static WindowClassRegistrar* GetInstance() {
if (!instance_) {
instance_ = new WindowClassRegistrar();
@@ -102,9 +120,9 @@ Win32Window::~Win32Window() {
Destroy();
}
-bool Win32Window::CreateAndShow(const std::wstring& title,
- const Point& origin,
- const Size& size) {
+bool Win32Window::Create(const std::wstring& title,
+ const Point& origin,
+ const Size& size) {
Destroy();
const wchar_t* window_class =
@@ -117,7 +135,7 @@ bool Win32Window::CreateAndShow(const std::wstring& title,
double scale_factor = dpi / 96.0;
HWND window = CreateWindow(
- window_class, title.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE,
+ window_class, title.c_str(), WS_OVERLAPPEDWINDOW,
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);
@@ -126,9 +144,15 @@ bool Win32Window::CreateAndShow(const std::wstring& title,
return false;
}
+ UpdateTheme(window);
+
return OnCreate();
}
+bool Win32Window::Show() {
+ return ShowWindow(window_handle_, SW_SHOWNORMAL);
+}
+
// static
LRESULT CALLBACK Win32Window::WndProc(HWND const window,
UINT const message,
@@ -188,6 +212,10 @@ Win32Window::MessageHandler(HWND hwnd,
SetFocus(child_content_);
}
return 0;
+
+ case WM_DWMCOLORIZATIONCOLORCHANGED:
+ UpdateTheme(hwnd);
+ return 0;
}
return DefWindowProc(window_handle_, message, wparam, lparam);
@@ -243,3 +271,18 @@ bool Win32Window::OnCreate() {
void Win32Window::OnDestroy() {
// No-op; provided for subclasses.
}
+
+void Win32Window::UpdateTheme(HWND const window) {
+ DWORD light_mode;
+ DWORD light_mode_size = sizeof(light_mode);
+ LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey,
+ kGetPreferredBrightnessRegValue,
+ RRF_RT_REG_DWORD, nullptr, &light_mode,
+ &light_mode_size);
+
+ if (result == ERROR_SUCCESS) {
+ BOOL enable_dark_mode = light_mode == 0;
+ DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE,
+ &enable_dark_mode, sizeof(enable_dark_mode));
+ }
+}
diff --git a/windows/runner/win32_window.h b/windows/runner/win32_window.h
index 17ba431..e901dde 100644
--- a/windows/runner/win32_window.h
+++ b/windows/runner/win32_window.h
@@ -28,15 +28,16 @@ class Win32Window {
Win32Window();
virtual ~Win32Window();
- // Creates and shows a win32 window with |title| and position and size using
+ // Creates a win32 window with |title| that is positioned and sized 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);
+ // consistent size this function will scale the inputted width and height as
+ // as appropriate for the default monitor. The window is invisible until
+ // |Show| is called. Returns true if the window was created successfully.
+ bool Create(const std::wstring& title, const Point& origin, const Size& size);
+
+ // Show the current window. Returns true if the window was successfully shown.
+ bool Show();
// Release OS resources associated with window.
void Destroy();
@@ -76,7 +77,7 @@ class Win32Window {
// 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
- // responsponds to changes in DPI. All other messages are handled by
+ // responds to changes in DPI. All other messages are handled by
// MessageHandler.
static LRESULT CALLBACK WndProc(HWND const window,
UINT const message,
@@ -86,6 +87,9 @@ class Win32Window {
// Retrieves a class instance pointer for |window|
static Win32Window* GetThisFromHandle(HWND const window) noexcept;
+ // Update the window frame's theme to match the system theme.
+ static void UpdateTheme(HWND const window);
+
bool quit_on_close_ = false;
// window handle for top level window.