fix: windows versioning

This commit is contained in:
Prateek Sunal 2024-03-25 21:58:47 +05:30
parent 704abf1265
commit 86a334a769
13 changed files with 154 additions and 96 deletions

View file

@ -1,11 +1,11 @@
# This file tracks properties of this Flutter project. # This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc. # Used by Flutter tool to assess capabilities and perform upgrades etc.
# #
# This file should be version controlled. # This file should be version controlled and should not be manually edited.
version: version:
revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 revision: "ba393198430278b6595976de84fe170f553cc728"
channel: unknown channel: "[user-branch]"
project_type: app project_type: app
@ -13,17 +13,26 @@ project_type: app
migration: migration:
platforms: platforms:
- platform: root - platform: root
create_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 create_revision: ba393198430278b6595976de84fe170f553cc728
base_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 base_revision: ba393198430278b6595976de84fe170f553cc728
- platform: android
create_revision: ba393198430278b6595976de84fe170f553cc728
base_revision: ba393198430278b6595976de84fe170f553cc728
- platform: ios
create_revision: ba393198430278b6595976de84fe170f553cc728
base_revision: ba393198430278b6595976de84fe170f553cc728
- platform: linux - platform: linux
create_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 create_revision: ba393198430278b6595976de84fe170f553cc728
base_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 base_revision: ba393198430278b6595976de84fe170f553cc728
- platform: macos - platform: macos
create_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 create_revision: ba393198430278b6595976de84fe170f553cc728
base_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 base_revision: ba393198430278b6595976de84fe170f553cc728
- platform: web
create_revision: ba393198430278b6595976de84fe170f553cc728
base_revision: ba393198430278b6595976de84fe170f553cc728
- platform: windows - platform: windows
create_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 create_revision: ba393198430278b6595976de84fe170f553cc728
base_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 base_revision: ba393198430278b6595976de84fe170f553cc728
# User provided section # User provided section

View file

@ -1,6 +1,6 @@
name: ente_auth name: ente_auth
description: ente two-factor authenticator description: ente two-factor authenticator
version: 2.0.43+243 version: 2.0.44+244
publish_to: none publish_to: none
environment: environment:

View file

@ -1,13 +1,16 @@
# Project-level configuration.
cmake_minimum_required(VERSION 3.14) cmake_minimum_required(VERSION 3.14)
project(auth LANGUAGES CXX) project(auth LANGUAGES CXX)
# The name of the executable created for the application. Change this to change
# the on-disk name of your application.
set(BINARY_NAME "auth") set(BINARY_NAME "auth")
cmake_policy(SET CMP0063 NEW) # Explicitly opt in to modern CMake behaviors to avoid warnings with recent
# versions of CMake.
cmake_policy(VERSION 3.14...3.25)
set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") # Define build configuration option.
# Configure build options.
get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(IS_MULTICONFIG) if(IS_MULTICONFIG)
set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release"
@ -20,7 +23,7 @@ else()
"Debug" "Profile" "Release") "Debug" "Profile" "Release")
endif() endif()
endif() endif()
# Define settings for the Profile build mode.
set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}")
set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}")
set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}")
@ -29,7 +32,11 @@ set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}")
# Use Unicode for all projects. # Use Unicode for all projects.
add_definitions(-DUNICODE -D_UNICODE) add_definitions(-DUNICODE -D_UNICODE)
# Compilation ui.settings that should be applied to most targets. # Compilation settings that should be applied to most targets.
#
# Be cautious about adding new options here, as plugins use this function by
# default. In most cases, you should add new options to specific targets instead
# of modifying this function.
function(APPLY_STANDARD_SETTINGS TARGET) function(APPLY_STANDARD_SETTINGS TARGET)
target_compile_features(${TARGET} PUBLIC cxx_std_17) target_compile_features(${TARGET} PUBLIC cxx_std_17)
target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100")
@ -38,14 +45,14 @@ function(APPLY_STANDARD_SETTINGS TARGET)
target_compile_definitions(${TARGET} PRIVATE "$<$<CONFIG:Debug>:_DEBUG>") target_compile_definitions(${TARGET} PRIVATE "$<$<CONFIG:Debug>:_DEBUG>")
endfunction() endfunction()
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
# Flutter library and tool build rules. # Flutter library and tool build rules.
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
add_subdirectory(${FLUTTER_MANAGED_DIR}) add_subdirectory(${FLUTTER_MANAGED_DIR})
# Application build # Application build; see runner/CMakeLists.txt.
add_subdirectory("runner") add_subdirectory("runner")
# Generated plugin build rules, which manage building the plugins and adding # Generated plugin build rules, which manage building the plugins and adding
# them to the application. # them to the application.
include(flutter/generated_plugins.cmake) include(flutter/generated_plugins.cmake)
@ -80,6 +87,12 @@ if(PLUGIN_BUNDLED_LIBRARIES)
COMPONENT Runtime) COMPONENT Runtime)
endif() endif()
# Copy the native assets provided by the build.dart from all packages.
set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/")
install(DIRECTORY "${NATIVE_ASSETS_DIR}"
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
# Fully re-copy the assets directory on each build to avoid having stale files # Fully re-copy the assets directory on each build to avoid having stale files
# from a previous install. # from a previous install.
set(FLUTTER_ASSET_DIR_NAME "flutter_assets") set(FLUTTER_ASSET_DIR_NAME "flutter_assets")

View file

@ -1,3 +1,4 @@
# This file controls Flutter-level build steps. It should not be edited.
cmake_minimum_required(VERSION 3.14) cmake_minimum_required(VERSION 3.14)
set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")

View file

@ -1,6 +1,11 @@
cmake_minimum_required(VERSION 3.14) cmake_minimum_required(VERSION 3.14)
project(runner LANGUAGES CXX) project(runner LANGUAGES CXX)
# Define the application target. To change its name, change BINARY_NAME in the
# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer
# work.
#
# Any new source files that you add to the application should be added here.
add_executable(${BINARY_NAME} WIN32 add_executable(${BINARY_NAME} WIN32
"flutter_window.cpp" "flutter_window.cpp"
"main.cpp" "main.cpp"
@ -10,8 +15,26 @@ add_executable(${BINARY_NAME} WIN32
"Runner.rc" "Runner.rc"
"runner.exe.manifest" "runner.exe.manifest"
) )
# Apply the standard set of build settings. This can be removed for applications
# that need different build settings.
apply_standard_settings(${BINARY_NAME}) 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") 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 flutter flutter_wrapper_app)
target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib")
target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
# Run the Flutter tool portions of the build. This must not be removed.
add_dependencies(${BINARY_NAME} flutter_assemble) add_dependencies(${BINARY_NAME} flutter_assemble)

View file

@ -63,13 +63,13 @@ IDI_APP_ICON ICON "resources\\app_icon.ico"
#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) #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 #define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD
#else #else
#define VERSION_AS_NUMBER 2,0,43,243 #define VERSION_AS_NUMBER 1,0,0,0
#endif #endif
#if defined(FLUTTER_VERSION) #if defined(FLUTTER_VERSION)
#define VERSION_AS_STRING FLUTTER_VERSION #define VERSION_AS_STRING FLUTTER_VERSION
#else #else
#define VERSION_AS_STRING "2.0.43+243" #define VERSION_AS_STRING "1.0.0"
#endif #endif
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
@ -93,7 +93,7 @@ BEGIN
VALUE "FileDescription", "ente Auth" "\0" VALUE "FileDescription", "ente Auth" "\0"
VALUE "FileVersion", VERSION_AS_STRING "\0" VALUE "FileVersion", VERSION_AS_STRING "\0"
VALUE "InternalName", "ente Auth" "\0" VALUE "InternalName", "ente Auth" "\0"
VALUE "LegalCopyright", "Copyright (C) 2022 Ente Technologies, Inc.. All rights reserved." "\0" VALUE "LegalCopyright", "Copyright (C) 2024 Ente Technologies, Inc.. All rights reserved." "\0"
VALUE "OriginalFilename", "auth.exe" "\0" VALUE "OriginalFilename", "auth.exe" "\0"
VALUE "ProductName", "ente Auth" "\0" VALUE "ProductName", "ente Auth" "\0"
VALUE "ProductVersion", VERSION_AS_STRING "\0" VALUE "ProductVersion", VERSION_AS_STRING "\0"

View file

@ -26,6 +26,16 @@ bool FlutterWindow::OnCreate() {
} }
RegisterPlugins(flutter_controller_->engine()); RegisterPlugins(flutter_controller_->engine());
SetChildContent(flutter_controller_->view()->GetNativeWindow()); SetChildContent(flutter_controller_->view()->GetNativeWindow());
flutter_controller_->engine()->SetNextFrameCallback([&]() {
this->Show();
});
// Flutter can complete the first frame before the "show window" callback is
// registered. The following call ensures a frame is pending to ensure the
// window is shown. It is a no-op if the first frame hasn't completed yet.
flutter_controller_->ForceRedraw();
return true; return true;
} }

View file

@ -29,7 +29,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
FlutterWindow window(project); FlutterWindow window(project);
Win32Window::Point origin(10, 10); Win32Window::Point origin(10, 10);
Win32Window::Size size(1280, 720); Win32Window::Size size(1280, 720);
if (!window.CreateAndShow(L"ente Auth", origin, size)) if (!window.Create(L"ente Auth", origin, size))
{ {
return EXIT_FAILURE; return EXIT_FAILURE;
} }

View file

@ -1,4 +1,4 @@
// //{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file. // Microsoft Visual C++ generated include file.
// Used by Runner.rc // Used by Runner.rc
// //

View file

@ -7,7 +7,7 @@
</application> </application>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application> <application>
<!-- Windows 10 --> <!-- Windows 10 and Windows 11 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/> <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
<!-- Windows 8.1 --> <!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/> <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>

View file

@ -47,16 +47,17 @@ std::string Utf8FromUtf16(const wchar_t* utf16_string) {
} }
int target_length = ::WideCharToMultiByte( int target_length = ::WideCharToMultiByte(
CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
-1, nullptr, 0, nullptr, nullptr); -1, nullptr, 0, nullptr, nullptr)
if (target_length == 0) { -1; // remove the trailing null character
return std::string(); int input_length = (int)wcslen(utf16_string);
}
std::string utf8_string; std::string utf8_string;
if (target_length <= 0 || target_length > utf8_string.max_size()) {
return utf8_string;
}
utf8_string.resize(target_length); utf8_string.resize(target_length);
int converted_length = ::WideCharToMultiByte( int converted_length = ::WideCharToMultiByte(
CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
-1, utf8_string.data(), input_length, utf8_string.data(), target_length, nullptr, nullptr);
target_length, nullptr, nullptr);
if (converted_length == 0) { if (converted_length == 0) {
return std::string(); return std::string();
} }

View file

@ -1,15 +1,32 @@
#include "win32_window.h" #include "win32_window.h"
#include <dwmapi.h>
#include <flutter_windows.h> #include <flutter_windows.h>
#include "resource.h" #include "resource.h"
#include "app_links/app_links_plugin_c_api.h"
namespace 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"; 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. // The number of Win32Window objects that currently exist.
static int g_active_window_count = 0; static int g_active_window_count = 0;
@ -37,8 +54,8 @@ namespace
if (enable_non_client_dpi_scaling != nullptr) if (enable_non_client_dpi_scaling != nullptr)
{ {
enable_non_client_dpi_scaling(hwnd); enable_non_client_dpi_scaling(hwnd);
FreeLibrary(user32_module);
} }
FreeLibrary(user32_module);
} }
} // namespace } // namespace
@ -49,7 +66,7 @@ class WindowClassRegistrar
public: public:
~WindowClassRegistrar() = default; ~WindowClassRegistrar() = default;
// Returns the singleton registar instance. // Returns the singleton registrar instance.
static WindowClassRegistrar *GetInstance() static WindowClassRegistrar *GetInstance()
{ {
if (!instance_) if (!instance_)
@ -116,14 +133,10 @@ Win32Window::~Win32Window()
Destroy(); Destroy();
} }
bool Win32Window::CreateAndShow(const std::wstring &title, bool Win32Window::Create(const std::wstring &title,
const Point &origin, const Point &origin,
const Size &size) const Size &size)
{ {
if (SendAppLinkToInstance(title))
{
return false;
}
Destroy(); Destroy();
const wchar_t *window_class = const wchar_t *window_class =
@ -136,18 +149,24 @@ bool Win32Window::CreateAndShow(const std::wstring &title,
double scale_factor = dpi / 96.0; double scale_factor = dpi / 96.0;
HWND window = CreateWindow( HWND window = CreateWindow(
window_class, title.c_str(), window_class, title.c_str(), WS_OVERLAPPEDWINDOW,
WS_OVERLAPPEDWINDOW, // do not add WS_VISIBLE since the window will be shown later
Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), Scale(origin.x, scale_factor), Scale(origin.y, scale_factor),
Scale(size.width, scale_factor), Scale(size.height, scale_factor), Scale(size.width, scale_factor), Scale(size.height, scale_factor),
nullptr, nullptr, GetModuleHandle(nullptr), this); nullptr, nullptr, GetModuleHandle(nullptr), this);
if (!window) if (!window)
{ {
return false; return false;
} }
return OnCreate(); UpdateTheme(window);
return OnCreate();
}
bool Win32Window::Show()
{
return ShowWindow(window_handle_, SW_SHOWNORMAL);
} }
// static // static
@ -220,6 +239,10 @@ Win32Window::MessageHandler(HWND hwnd,
SetFocus(child_content_); SetFocus(child_content_);
} }
return 0; return 0;
case WM_DWMCOLORIZATIONCOLORCHANGED:
UpdateTheme(hwnd);
return 0;
} }
return DefWindowProc(window_handle_, message, wparam, lparam); return DefWindowProc(window_handle_, message, wparam, lparam);
@ -286,40 +309,19 @@ void Win32Window::OnDestroy()
// No-op; provided for subclasses. // No-op; provided for subclasses.
} }
bool Win32Window::SendAppLinkToInstance(const std::wstring &title) void Win32Window::UpdateTheme(HWND const window)
{ {
// Find our exact window DWORD light_mode;
HWND hwnd = ::FindWindow(kWindowClassName, title.c_str()); 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 (hwnd) if (result == ERROR_SUCCESS)
{ {
// Dispatch new link to current window BOOL enable_dark_mode = light_mode == 0;
SendAppLink(hwnd); DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE,
&enable_dark_mode, sizeof(enable_dark_mode));
// (Optional) Restore our window to front in same state
WINDOWPLACEMENT place = {sizeof(WINDOWPLACEMENT)};
GetWindowPlacement(hwnd, &place);
switch (place.showCmd)
{
case SW_SHOWMAXIMIZED:
ShowWindow(hwnd, SW_SHOWMAXIMIZED);
break;
case SW_SHOWMINIMIZED:
ShowWindow(hwnd, SW_RESTORE);
break;
default:
ShowWindow(hwnd, SW_NORMAL);
break;
}
SetWindowPos(0, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE);
SetForegroundWindow(hwnd);
// END Restore
// Window has been found, don't create another one.
return true;
} }
}
return false;
}

View file

@ -31,15 +31,16 @@ public:
Win32Window(); Win32Window();
virtual ~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 // |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 // 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 // consistent size this function will scale the inputted width and height as
// as logical pixels and scale to appropriate for the default monitor. Returns // as appropriate for the default monitor. The window is invisible until
// true if the window was created successfully. // |Show| is called. Returns true if the window was created successfully.
bool CreateAndShow(const std::wstring &title, bool Create(const std::wstring &title, const Point &origin, const Size &size);
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. // Release OS resources associated with window.
void Destroy(); void Destroy();
@ -76,15 +77,10 @@ protected:
private: private:
friend class WindowClassRegistrar; friend class WindowClassRegistrar;
// Dispatches link if any.
// This method enables our app to be with a single instance too.
// This is mandatory if you want to catch further links in same app.
bool SendAppLinkToInstance(const std::wstring &title);
// OS callback called by message pump. Handles the WM_NCCREATE message which // 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 // is passed when the non-client area is being created and enables automatic
// non-client DPI scaling so that the non-client area automatically // 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. // MessageHandler.
static LRESULT CALLBACK WndProc(HWND const window, static LRESULT CALLBACK WndProc(HWND const window,
UINT const message, UINT const message,
@ -94,6 +90,9 @@ private:
// Retrieves a class instance pointer for |window| // Retrieves a class instance pointer for |window|
static Win32Window *GetThisFromHandle(HWND const window) noexcept; 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; bool quit_on_close_ = false;
// window handle for top level window. // window handle for top level window.