The Webview Univeral Flutter package for Appeto SDK.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 
 
 

289 lignes
8.3 KiB

  1. #include "win32_window.h"
  2. #include <dwmapi.h>
  3. #include <flutter_windows.h>
  4. #include "resource.h"
  5. namespace {
  6. /// Window attribute that enables dark mode window decorations.
  7. ///
  8. /// Redefined in case the developer's machine has a Windows SDK older than
  9. /// version 10.0.22000.0.
  10. /// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute
  11. #ifndef DWMWA_USE_IMMERSIVE_DARK_MODE
  12. #define DWMWA_USE_IMMERSIVE_DARK_MODE 20
  13. #endif
  14. constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW";
  15. /// Registry key for app theme preference.
  16. ///
  17. /// A value of 0 indicates apps should use dark mode. A non-zero or missing
  18. /// value indicates apps should use light mode.
  19. constexpr const wchar_t kGetPreferredBrightnessRegKey[] =
  20. L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize";
  21. constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme";
  22. // The number of Win32Window objects that currently exist.
  23. static int g_active_window_count = 0;
  24. using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd);
  25. // Scale helper to convert logical scaler values to physical using passed in
  26. // scale factor
  27. int Scale(int source, double scale_factor) {
  28. return static_cast<int>(source * scale_factor);
  29. }
  30. // Dynamically loads the |EnableNonClientDpiScaling| from the User32 module.
  31. // This API is only needed for PerMonitor V1 awareness mode.
  32. void EnableFullDpiSupportIfAvailable(HWND hwnd) {
  33. HMODULE user32_module = LoadLibraryA("User32.dll");
  34. if (!user32_module) {
  35. return;
  36. }
  37. auto enable_non_client_dpi_scaling =
  38. reinterpret_cast<EnableNonClientDpiScaling*>(
  39. GetProcAddress(user32_module, "EnableNonClientDpiScaling"));
  40. if (enable_non_client_dpi_scaling != nullptr) {
  41. enable_non_client_dpi_scaling(hwnd);
  42. }
  43. FreeLibrary(user32_module);
  44. }
  45. } // namespace
  46. // Manages the Win32Window's window class registration.
  47. class WindowClassRegistrar {
  48. public:
  49. ~WindowClassRegistrar() = default;
  50. // Returns the singleton registar instance.
  51. static WindowClassRegistrar* GetInstance() {
  52. if (!instance_) {
  53. instance_ = new WindowClassRegistrar();
  54. }
  55. return instance_;
  56. }
  57. // Returns the name of the window class, registering the class if it hasn't
  58. // previously been registered.
  59. const wchar_t* GetWindowClass();
  60. // Unregisters the window class. Should only be called if there are no
  61. // instances of the window.
  62. void UnregisterWindowClass();
  63. private:
  64. WindowClassRegistrar() = default;
  65. static WindowClassRegistrar* instance_;
  66. bool class_registered_ = false;
  67. };
  68. WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr;
  69. const wchar_t* WindowClassRegistrar::GetWindowClass() {
  70. if (!class_registered_) {
  71. WNDCLASS window_class{};
  72. window_class.hCursor = LoadCursor(nullptr, IDC_ARROW);
  73. window_class.lpszClassName = kWindowClassName;
  74. window_class.style = CS_HREDRAW | CS_VREDRAW;
  75. window_class.cbClsExtra = 0;
  76. window_class.cbWndExtra = 0;
  77. window_class.hInstance = GetModuleHandle(nullptr);
  78. window_class.hIcon =
  79. LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON));
  80. window_class.hbrBackground = 0;
  81. window_class.lpszMenuName = nullptr;
  82. window_class.lpfnWndProc = Win32Window::WndProc;
  83. RegisterClass(&window_class);
  84. class_registered_ = true;
  85. }
  86. return kWindowClassName;
  87. }
  88. void WindowClassRegistrar::UnregisterWindowClass() {
  89. UnregisterClass(kWindowClassName, nullptr);
  90. class_registered_ = false;
  91. }
  92. Win32Window::Win32Window() {
  93. ++g_active_window_count;
  94. }
  95. Win32Window::~Win32Window() {
  96. --g_active_window_count;
  97. Destroy();
  98. }
  99. bool Win32Window::Create(const std::wstring& title,
  100. const Point& origin,
  101. const Size& size) {
  102. Destroy();
  103. const wchar_t* window_class =
  104. WindowClassRegistrar::GetInstance()->GetWindowClass();
  105. const POINT target_point = {static_cast<LONG>(origin.x),
  106. static_cast<LONG>(origin.y)};
  107. HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST);
  108. UINT dpi = FlutterDesktopGetDpiForMonitor(monitor);
  109. double scale_factor = dpi / 96.0;
  110. HWND window = CreateWindow(
  111. window_class, title.c_str(), WS_OVERLAPPEDWINDOW,
  112. Scale(origin.x, scale_factor), Scale(origin.y, scale_factor),
  113. Scale(size.width, scale_factor), Scale(size.height, scale_factor),
  114. nullptr, nullptr, GetModuleHandle(nullptr), this);
  115. if (!window) {
  116. return false;
  117. }
  118. UpdateTheme(window);
  119. return OnCreate();
  120. }
  121. bool Win32Window::Show() {
  122. return ShowWindow(window_handle_, SW_SHOWNORMAL);
  123. }
  124. // static
  125. LRESULT CALLBACK Win32Window::WndProc(HWND const window,
  126. UINT const message,
  127. WPARAM const wparam,
  128. LPARAM const lparam) noexcept {
  129. if (message == WM_NCCREATE) {
  130. auto window_struct = reinterpret_cast<CREATESTRUCT*>(lparam);
  131. SetWindowLongPtr(window, GWLP_USERDATA,
  132. reinterpret_cast<LONG_PTR>(window_struct->lpCreateParams));
  133. auto that = static_cast<Win32Window*>(window_struct->lpCreateParams);
  134. EnableFullDpiSupportIfAvailable(window);
  135. that->window_handle_ = window;
  136. } else if (Win32Window* that = GetThisFromHandle(window)) {
  137. return that->MessageHandler(window, message, wparam, lparam);
  138. }
  139. return DefWindowProc(window, message, wparam, lparam);
  140. }
  141. LRESULT
  142. Win32Window::MessageHandler(HWND hwnd,
  143. UINT const message,
  144. WPARAM const wparam,
  145. LPARAM const lparam) noexcept {
  146. switch (message) {
  147. case WM_DESTROY:
  148. window_handle_ = nullptr;
  149. Destroy();
  150. if (quit_on_close_) {
  151. PostQuitMessage(0);
  152. }
  153. return 0;
  154. case WM_DPICHANGED: {
  155. auto newRectSize = reinterpret_cast<RECT*>(lparam);
  156. LONG newWidth = newRectSize->right - newRectSize->left;
  157. LONG newHeight = newRectSize->bottom - newRectSize->top;
  158. SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth,
  159. newHeight, SWP_NOZORDER | SWP_NOACTIVATE);
  160. return 0;
  161. }
  162. case WM_SIZE: {
  163. RECT rect = GetClientArea();
  164. if (child_content_ != nullptr) {
  165. // Size and position the child window.
  166. MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left,
  167. rect.bottom - rect.top, TRUE);
  168. }
  169. return 0;
  170. }
  171. case WM_ACTIVATE:
  172. if (child_content_ != nullptr) {
  173. SetFocus(child_content_);
  174. }
  175. return 0;
  176. case WM_DWMCOLORIZATIONCOLORCHANGED:
  177. UpdateTheme(hwnd);
  178. return 0;
  179. }
  180. return DefWindowProc(window_handle_, message, wparam, lparam);
  181. }
  182. void Win32Window::Destroy() {
  183. OnDestroy();
  184. if (window_handle_) {
  185. DestroyWindow(window_handle_);
  186. window_handle_ = nullptr;
  187. }
  188. if (g_active_window_count == 0) {
  189. WindowClassRegistrar::GetInstance()->UnregisterWindowClass();
  190. }
  191. }
  192. Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept {
  193. return reinterpret_cast<Win32Window*>(
  194. GetWindowLongPtr(window, GWLP_USERDATA));
  195. }
  196. void Win32Window::SetChildContent(HWND content) {
  197. child_content_ = content;
  198. SetParent(content, window_handle_);
  199. RECT frame = GetClientArea();
  200. MoveWindow(content, frame.left, frame.top, frame.right - frame.left,
  201. frame.bottom - frame.top, true);
  202. SetFocus(child_content_);
  203. }
  204. RECT Win32Window::GetClientArea() {
  205. RECT frame;
  206. GetClientRect(window_handle_, &frame);
  207. return frame;
  208. }
  209. HWND Win32Window::GetHandle() {
  210. return window_handle_;
  211. }
  212. void Win32Window::SetQuitOnClose(bool quit_on_close) {
  213. quit_on_close_ = quit_on_close;
  214. }
  215. bool Win32Window::OnCreate() {
  216. // No-op; provided for subclasses.
  217. return true;
  218. }
  219. void Win32Window::OnDestroy() {
  220. // No-op; provided for subclasses.
  221. }
  222. void Win32Window::UpdateTheme(HWND const window) {
  223. DWORD light_mode;
  224. DWORD light_mode_size = sizeof(light_mode);
  225. LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey,
  226. kGetPreferredBrightnessRegValue,
  227. RRF_RT_REG_DWORD, nullptr, &light_mode,
  228. &light_mode_size);
  229. if (result == ERROR_SUCCESS) {
  230. BOOL enable_dark_mode = light_mode == 0;
  231. DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE,
  232. &enable_dark_mode, sizeof(enable_dark_mode));
  233. }
  234. }