Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 
 
 
 

244 rader
7.5 KiB

  1. //
  2. // Created by yangbin on 2021/10/20.
  3. //
  4. #include <windows.h>
  5. #include "webview_window.h"
  6. #include <tchar.h>
  7. #include <utility>
  8. #include "strconv.h"
  9. #include "utils.h"
  10. #include "include/webview_universal/webview_universal_plugin.h"
  11. namespace {
  12. TCHAR kWebViewWindowClassName[] = _T("WebviewWindow");
  13. using namespace webview_window;
  14. // Scale helper to convert logical scaler values to physical using passed in
  15. // scale factor
  16. int Scale(int source, double scale_factor) {
  17. return static_cast<int>(source * scale_factor);
  18. }
  19. }
  20. using namespace Microsoft::WRL;
  21. WebviewWindow::WebviewWindow(
  22. MethodChannelPtr method_channel,
  23. int64_t window_id,
  24. int title_bar_height,
  25. std::function<void()> on_close_callback
  26. ) : method_channel_(std::move(method_channel)),
  27. window_id_(window_id),
  28. on_close_callback_(std::move(on_close_callback)),
  29. hwnd_(),
  30. title_bar_height_(title_bar_height) {
  31. }
  32. WebviewWindow::~WebviewWindow() {
  33. flutter_action_bar_.reset();
  34. web_view_.reset();
  35. SetWindowLongPtr(hwnd_.get(), GWLP_USERDATA, 0);
  36. hwnd_.reset();
  37. }
  38. void WebviewWindow::CreateAndShow(const std::wstring &title, int height, int width,
  39. const std::wstring &userDataFolder,
  40. CreateCallback callback) {
  41. RegisterWindowClass(kWebViewWindowClassName, WebviewWindow::WndProc);
  42. // the same as flutter default main.cpp
  43. const POINT target_point = {static_cast<LONG>(10),
  44. static_cast<LONG>(10)};
  45. HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST);
  46. UINT dpi = FlutterDesktopGetDpiForMonitor(monitor);
  47. double scale_factor = dpi / 96.0;
  48. hwnd_ = wil::unique_hwnd(::CreateWindow(
  49. kWebViewWindowClassName, title.c_str(),
  50. WS_OVERLAPPEDWINDOW | WS_VISIBLE,
  51. CW_USEDEFAULT, CW_USEDEFAULT,
  52. Scale(width, scale_factor), Scale(height, scale_factor),
  53. nullptr, nullptr, GetModuleHandle(nullptr), this));
  54. if (!hwnd_) {
  55. callback(false);
  56. return;
  57. }
  58. // Centered window on screen.
  59. RECT rc;
  60. GetClientRect(hwnd_.get(), &rc);
  61. ClipOrCenterRectToMonitor(&rc, MONITOR_CENTER);
  62. SetWindowPos(hwnd_.get(), nullptr, rc.left, rc.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
  63. auto title_bar_height = Scale(title_bar_height_, scale_factor);
  64. // Create the browser view.
  65. web_view_ = std::make_unique<webview_window::WebView>(
  66. method_channel_, window_id_, userDataFolder,
  67. [callback](HRESULT hr) {
  68. if (SUCCEEDED(hr)) {
  69. callback(true);
  70. } else {
  71. callback(false);
  72. }
  73. });
  74. auto web_view_handle = web_view_->NativeWindow().get();
  75. SetParent(web_view_handle, hwnd_.get());
  76. MoveWindow(web_view_handle, 0, title_bar_height,
  77. rc.right - rc.left,
  78. rc.bottom - rc.top - title_bar_height,
  79. true);
  80. ShowWindow(web_view_handle, SW_SHOW);
  81. // Create the title bar view.
  82. std::vector<std::string> args = {"web_view_title_bar", std::to_string(window_id_)};
  83. flutter_action_bar_ = std::make_unique<webview_window::FlutterView>(std::move(args));
  84. auto title_bar_handle = flutter_action_bar_->GetWindow();
  85. SetParent(title_bar_handle, hwnd_.get());
  86. MoveWindow(title_bar_handle, 0, 0, rc.right - rc.left, title_bar_height, true);
  87. ShowWindow(title_bar_handle, SW_SHOW);
  88. assert(hwnd_ != nullptr);
  89. ShowWindow(hwnd_.get(), SW_SHOW);
  90. UpdateWindow(hwnd_.get());
  91. }
  92. void WebviewWindow::SetBrightness(int brightness) {
  93. }
  94. // static
  95. LRESULT CALLBACK
  96. WebviewWindow::WndProc(
  97. HWND window,
  98. UINT message,
  99. WPARAM wparam,
  100. LPARAM lparam
  101. ) noexcept {
  102. if (message == WM_NCCREATE) {
  103. auto window_struct = reinterpret_cast<CREATESTRUCT *>(lparam);
  104. SetWindowLongPtr(window, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(window_struct->lpCreateParams));
  105. // auto that = static_cast<WebviewWindow *>(window_struct->lpCreateParams);
  106. // that->hwnd_ = window;
  107. } else if (WebviewWindow *that = GetThisFromHandle(window)) {
  108. return that->MessageHandler(window, message, wparam, lparam);
  109. }
  110. return DefWindowProc(window, message, wparam, lparam);
  111. }
  112. LRESULT
  113. WebviewWindow::MessageHandler(
  114. HWND hwnd,
  115. UINT message,
  116. WPARAM wparam,
  117. LPARAM lparam
  118. ) noexcept {
  119. // Give Flutter, including plugins, an opportunity to handle window messages.
  120. if (flutter_action_bar_) {
  121. std::optional<LRESULT> result = flutter_action_bar_->HandleTopLevelWindowProc(hwnd, message, wparam, lparam);
  122. if (result) {
  123. return *result;
  124. }
  125. }
  126. switch (message) {
  127. case WM_DESTROY: {
  128. flutter_action_bar_.reset();
  129. web_view_.reset();
  130. // might receive multiple WM_DESTROY messages.
  131. if (!destroyed_) {
  132. destroyed_ = true;
  133. auto args = flutter::EncodableMap{
  134. {flutter::EncodableValue("id"), flutter::EncodableValue(window_id_)}
  135. };
  136. method_channel_->InvokeMethod(
  137. "onWindowClose",
  138. std::make_unique<flutter::EncodableValue>(args)
  139. );
  140. if (on_close_callback_) {
  141. on_close_callback_();
  142. }
  143. }
  144. return 0;
  145. }
  146. case WM_DPICHANGED: {
  147. auto newRectSize = reinterpret_cast<RECT *>(lparam);
  148. LONG newWidth = newRectSize->right - newRectSize->left;
  149. LONG newHeight = newRectSize->bottom - newRectSize->top;
  150. SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth,
  151. newHeight, SWP_NOZORDER | SWP_NOACTIVATE);
  152. return 0;
  153. }
  154. case WM_SIZE: {
  155. RECT rect;
  156. GetClientRect(hwnd, &rect);
  157. HMONITOR monitor = MonitorFromRect(&rect, MONITOR_DEFAULTTONEAREST);
  158. UINT dpi = FlutterDesktopGetDpiForMonitor(monitor);
  159. double scale_factor = dpi / 96.0;
  160. auto title_bar_height = Scale(title_bar_height_, scale_factor);
  161. if (web_view_ != nullptr) {
  162. MoveWindow(web_view_->NativeWindow().get(), 0, title_bar_height,
  163. rect.right - rect.left, rect.bottom - rect.top - title_bar_height,
  164. true);
  165. web_view_->UpdateBounds();
  166. }
  167. if (flutter_action_bar_) {
  168. // FIXME(BOYAN) remove this trick if flutter provide a properly way to force redraw the flutter view.
  169. // When user only change the height of window, flutter title bar height will not change, because the title_bar_height
  170. // is a fixed value. In this situation, the flutter view will not perform draw since no size changed. So we need
  171. // perform a force redraw to flutter view. Although flutter provide a function FlutterDesktopViewControllerForceRedraw.
  172. // https://github.com/flutter/engine/pull/24186 But we can not use this because it not provided on wrapper.
  173. if (last_title_bar_width_ != rect.right - rect.left) {
  174. // Size and position the flutter window.
  175. last_title_bar_width_ = rect.right - rect.left;
  176. MoveWindow(flutter_action_bar_->GetWindow(), 0, 0,
  177. last_title_bar_width_, title_bar_height, true);
  178. } else {
  179. last_title_bar_width_ = rect.right - rect.left + 1;
  180. MoveWindow(flutter_action_bar_->GetWindow(), 0, 0,
  181. last_title_bar_width_, title_bar_height, true);
  182. }
  183. }
  184. return 0;
  185. }
  186. case WM_FONTCHANGE: {
  187. if (flutter_action_bar_) {
  188. flutter_action_bar_->ReloadSystemFonts();
  189. }
  190. break;
  191. }
  192. case WM_ACTIVATE: {
  193. return 0;
  194. }
  195. }
  196. return DefWindowProc(hwnd, message, wparam, lparam);
  197. }
  198. // static
  199. WebviewWindow *WebviewWindow::GetThisFromHandle(HWND const window) noexcept {
  200. return reinterpret_cast<WebviewWindow *>(
  201. GetWindowLongPtr(window, GWLP_USERDATA));
  202. }