• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "flutter/shell/platform/windows/win32_window.h"
6 
7 namespace flutter {
8 
Win32Window()9 Win32Window::Win32Window() {
10   // Assume Windows 10 1703 or greater for DPI handling.  When running on a
11   // older release of Windows where this context doesn't exist, DPI calls will
12   // fail and Flutter rendering will be impacted until this is fixed.
13   // To handle downlevel correctly, dpi_helper must use the most recent DPI
14   // context available should be used: Windows 1703: Per-Monitor V2, 8.1:
15   // Per-Monitor V1, Windows 7: System See
16   // https://docs.microsoft.com/en-us/windows/win32/hidpi/high-dpi-desktop-application-development-on-windows
17   // for more information.
18 
19   // TODO the calling applicaiton should participate in setting the DPI.
20   // Currently dpi_helper is asserting per-monitor V2.  There are two problems
21   // with this: 1) it is advised that the awareness mode is set using manifest,
22   // not programatically.  2) The calling executable should be responsible for
23   // setting an appropriate scaling mode, not a library.  This will be
24   // particularly important once there is a means of hosting Flutter content in
25   // an existing app.
26 
27   BOOL result = dpi_helper_->SetProcessDpiAwarenessContext(
28       DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
29 
30   if (result != TRUE) {
31     OutputDebugString(L"Failed to set PMV2");
32   }
33 }
~Win32Window()34 Win32Window::~Win32Window() {
35   Destroy();
36 }
37 
Initialize(const char * title,const unsigned int x,const unsigned int y,const unsigned int width,const unsigned int height)38 void Win32Window::Initialize(const char* title,
39                              const unsigned int x,
40                              const unsigned int y,
41                              const unsigned int width,
42                              const unsigned int height) {
43   Destroy();
44   std::wstring converted_title = NarrowToWide(title);
45 
46   WNDCLASS window_class = ResgisterWindowClass(converted_title);
47 
48   CreateWindow(window_class.lpszClassName, converted_title.c_str(),
49                WS_OVERLAPPEDWINDOW | WS_VISIBLE, x, y, width, height, nullptr,
50                nullptr, window_class.hInstance, this);
51 }
52 
NarrowToWide(const char * source)53 std::wstring Win32Window::NarrowToWide(const char* source) {
54   size_t length = strlen(source);
55   size_t outlen = 0;
56   std::wstring wideTitle(length, L'#');
57   mbstowcs_s(&outlen, &wideTitle[0], length + 1, source, length);
58   return wideTitle;
59 }
60 
ResgisterWindowClass(std::wstring & title)61 WNDCLASS Win32Window::ResgisterWindowClass(std::wstring& title) {
62   window_class_name_ = title;
63 
64   WNDCLASS window_class{};
65   window_class.hCursor = LoadCursor(nullptr, IDC_ARROW);
66   window_class.lpszClassName = title.c_str();
67   window_class.style = CS_HREDRAW | CS_VREDRAW;
68   window_class.cbClsExtra = 0;
69   window_class.cbWndExtra = 0;
70   window_class.hInstance = GetModuleHandle(nullptr);
71   window_class.hIcon = nullptr;
72   window_class.hbrBackground = 0;
73   window_class.lpszMenuName = nullptr;
74   window_class.lpfnWndProc = WndProc;
75   RegisterClass(&window_class);
76   return window_class;
77 }
78 
WndProc(HWND const window,UINT const message,WPARAM const wparam,LPARAM const lparam)79 LRESULT CALLBACK Win32Window::WndProc(HWND const window,
80                                       UINT const message,
81                                       WPARAM const wparam,
82                                       LPARAM const lparam) noexcept {
83   if (message == WM_NCCREATE) {
84     auto cs = reinterpret_cast<CREATESTRUCT*>(lparam);
85     SetWindowLongPtr(window, GWLP_USERDATA,
86                      reinterpret_cast<LONG_PTR>(cs->lpCreateParams));
87 
88     auto that = static_cast<Win32Window*>(cs->lpCreateParams);
89 
90     // Since the application is running in Per-monitor V2 mode, turn on
91     // automatic titlebar scaling
92     BOOL result = that->dpi_helper_->EnableNonClientDpiScaling(window);
93     if (result != TRUE) {
94       OutputDebugString(L"Failed to enable non-client area autoscaling");
95     }
96     that->current_dpi_ = that->dpi_helper_->GetDpiForWindow(window);
97     that->window_handle_ = window;
98   } else if (Win32Window* that = GetThisFromHandle(window)) {
99     return that->MessageHandler(window, message, wparam, lparam);
100   }
101 
102   return DefWindowProc(window, message, wparam, lparam);
103 }
104 
105 LRESULT
MessageHandler(HWND hwnd,UINT const message,WPARAM const wparam,LPARAM const lparam)106 Win32Window::MessageHandler(HWND hwnd,
107                             UINT const message,
108                             WPARAM const wparam,
109                             LPARAM const lparam) noexcept {
110   int xPos = 0, yPos = 0;
111   UINT width = 0, height = 0;
112   auto window =
113       reinterpret_cast<Win32Window*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
114 
115   if (window != nullptr) {
116     switch (message) {
117       case WM_DPICHANGED:
118         return HandleDpiChange(window_handle_, wparam, lparam);
119         break;
120 
121       case WM_DESTROY:
122         window->OnClose();
123         return 0;
124         break;
125 
126       case WM_SIZE:
127         width = LOWORD(lparam);
128         height = HIWORD(lparam);
129 
130         current_width_ = width;
131         current_height_ = height;
132         window->HandleResize(width, height);
133         break;
134 
135       case WM_MOUSEMOVE:
136         xPos = GET_X_LPARAM(lparam);
137         yPos = GET_Y_LPARAM(lparam);
138 
139         window->OnPointerMove(static_cast<double>(xPos),
140                               static_cast<double>(yPos));
141         break;
142       case WM_LBUTTONDOWN:
143         xPos = GET_X_LPARAM(lparam);
144         yPos = GET_Y_LPARAM(lparam);
145         window->OnPointerDown(static_cast<double>(xPos),
146                               static_cast<double>(yPos));
147         break;
148       case WM_LBUTTONUP:
149         xPos = GET_X_LPARAM(lparam);
150         yPos = GET_Y_LPARAM(lparam);
151         window->OnPointerUp(static_cast<double>(xPos),
152                             static_cast<double>(yPos));
153         break;
154       case WM_MOUSEWHEEL:
155         window->OnScroll(
156             0.0, -(static_cast<short>(HIWORD(wparam)) / (double)WHEEL_DELTA));
157         break;
158       case WM_CHAR:
159       case WM_SYSCHAR:
160       case WM_UNICHAR:
161         if (wparam != VK_BACK) {
162           window->OnChar(static_cast<unsigned int>(wparam));
163         }
164         break;
165       case WM_KEYDOWN:
166       case WM_SYSKEYDOWN:
167       case WM_KEYUP:
168       case WM_SYSKEYUP:
169         unsigned char scancode = ((unsigned char*)&lparam)[2];
170         unsigned int virtualKey = MapVirtualKey(scancode, MAPVK_VSC_TO_VK);
171         const int key = virtualKey;
172         const int action = message == WM_KEYDOWN ? WM_KEYDOWN : WM_KEYUP;
173         window->OnKey(key, scancode, action, 0);
174         break;
175     }
176     return DefWindowProc(hwnd, message, wparam, lparam);
177   }
178 
179   return DefWindowProc(window_handle_, message, wparam, lparam);
180 }
181 
GetCurrentDPI()182 UINT Win32Window::GetCurrentDPI() {
183   return current_dpi_;
184 }
185 
GetCurrentWidth()186 UINT Win32Window::GetCurrentWidth() {
187   return current_width_;
188 }
189 
GetCurrentHeight()190 UINT Win32Window::GetCurrentHeight() {
191   return current_height_;
192 }
193 
GetWindowHandle()194 HWND Win32Window::GetWindowHandle() {
195   return window_handle_;
196 }
197 
Destroy()198 void Win32Window::Destroy() {
199   if (window_handle_) {
200     DestroyWindow(window_handle_);
201     window_handle_ = nullptr;
202   }
203 
204   UnregisterClass(window_class_name_.c_str(), nullptr);
205 }
206 
207 // DPI Change handler. on WM_DPICHANGE resize the window
208 LRESULT
HandleDpiChange(HWND hwnd,WPARAM wparam,LPARAM lparam)209 Win32Window::HandleDpiChange(HWND hwnd, WPARAM wparam, LPARAM lparam) {
210   if (hwnd != nullptr) {
211     auto window =
212         reinterpret_cast<Win32Window*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
213 
214     UINT uDpi = HIWORD(wparam);
215     current_dpi_ = uDpi;
216     window->OnDpiScale(uDpi);
217 
218     // Resize the window
219     auto lprcNewScale = reinterpret_cast<RECT*>(lparam);
220     LONG newWidth = lprcNewScale->right - lprcNewScale->left;
221     LONG newHeight = lprcNewScale->bottom - lprcNewScale->top;
222 
223     SetWindowPos(hwnd, nullptr, lprcNewScale->left, lprcNewScale->top, newWidth,
224                  newHeight, SWP_NOZORDER | SWP_NOACTIVATE);
225   }
226   return 0;
227 }
228 
HandleResize(UINT width,UINT height)229 void Win32Window::HandleResize(UINT width, UINT height) {
230   current_width_ = width;
231   current_height_ = height;
232   OnResize(width, height);
233 }
234 
GetThisFromHandle(HWND const window)235 Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept {
236   return reinterpret_cast<Win32Window*>(
237       GetWindowLongPtr(window, GWLP_USERDATA));
238 }
239 
240 }  // namespace flutter