mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Start work on flutter/flutter#30726 by adding an alternative win32 shell platform implementation for Windows that is not based on GLFW and that uses LIBANGLE for rendering and native win32 windowing and input. This change does not replace the GLFW implementation but rather runs side by side with it producing a secondary flutter_windows_win32.dll artifact. The following items must be added to attain parity with the GLFW implementation: - Custom task scheduling - Support for keyboard modifier keys - Async texture uploads - Correct high DPI handling on Windows versions < 1703 and will be added in subsequent changes.
240 lines
7.8 KiB
C++
240 lines
7.8 KiB
C++
// Copyright 2013 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "flutter/shell/platform/windows/win32_window.h"
|
|
|
|
namespace flutter {
|
|
|
|
Win32Window::Win32Window() {
|
|
// Assume Windows 10 1703 or greater for DPI handling. When running on a
|
|
// older release of Windows where this context doesn't exist, DPI calls will
|
|
// fail and Flutter rendering will be impacted until this is fixed.
|
|
// To handle downlevel correctly, dpi_helper must use the most recent DPI
|
|
// context available should be used: Windows 1703: Per-Monitor V2, 8.1:
|
|
// Per-Monitor V1, Windows 7: System See
|
|
// https://docs.microsoft.com/en-us/windows/win32/hidpi/high-dpi-desktop-application-development-on-windows
|
|
// for more information.
|
|
|
|
// TODO the calling applicaiton should participate in setting the DPI.
|
|
// Currently dpi_helper is asserting per-monitor V2. There are two problems
|
|
// with this: 1) it is advised that the awareness mode is set using manifest,
|
|
// not programatically. 2) The calling executable should be responsible for
|
|
// setting an appropriate scaling mode, not a library. This will be
|
|
// particularly important once there is a means of hosting Flutter content in
|
|
// an existing app.
|
|
|
|
BOOL result = dpi_helper_->SetProcessDpiAwarenessContext(
|
|
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
|
|
|
if (result != TRUE) {
|
|
OutputDebugString(L"Failed to set PMV2");
|
|
}
|
|
}
|
|
Win32Window::~Win32Window() {
|
|
Destroy();
|
|
}
|
|
|
|
void Win32Window::Initialize(const char* title,
|
|
const unsigned int x,
|
|
const unsigned int y,
|
|
const unsigned int width,
|
|
const unsigned int height) {
|
|
Destroy();
|
|
std::wstring converted_title = NarrowToWide(title);
|
|
|
|
WNDCLASS window_class = ResgisterWindowClass(converted_title);
|
|
|
|
CreateWindow(window_class.lpszClassName, converted_title.c_str(),
|
|
WS_OVERLAPPEDWINDOW | WS_VISIBLE, x, y, width, height, nullptr,
|
|
nullptr, window_class.hInstance, this);
|
|
}
|
|
|
|
std::wstring Win32Window::NarrowToWide(const char* source) {
|
|
size_t length = strlen(source);
|
|
size_t outlen = 0;
|
|
std::wstring wideTitle(length, L'#');
|
|
mbstowcs_s(&outlen, &wideTitle[0], length + 1, source, length);
|
|
return wideTitle;
|
|
}
|
|
|
|
WNDCLASS Win32Window::ResgisterWindowClass(std::wstring& title) {
|
|
window_class_name_ = title;
|
|
|
|
WNDCLASS window_class{};
|
|
window_class.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
|
window_class.lpszClassName = title.c_str();
|
|
window_class.style = CS_HREDRAW | CS_VREDRAW;
|
|
window_class.cbClsExtra = 0;
|
|
window_class.cbWndExtra = 0;
|
|
window_class.hInstance = GetModuleHandle(nullptr);
|
|
window_class.hIcon = nullptr;
|
|
window_class.hbrBackground = 0;
|
|
window_class.lpszMenuName = nullptr;
|
|
window_class.lpfnWndProc = WndProc;
|
|
RegisterClass(&window_class);
|
|
return window_class;
|
|
}
|
|
|
|
LRESULT CALLBACK Win32Window::WndProc(HWND const window,
|
|
UINT const message,
|
|
WPARAM const wparam,
|
|
LPARAM const lparam) noexcept {
|
|
if (message == WM_NCCREATE) {
|
|
auto cs = reinterpret_cast<CREATESTRUCT*>(lparam);
|
|
SetWindowLongPtr(window, GWLP_USERDATA,
|
|
reinterpret_cast<LONG_PTR>(cs->lpCreateParams));
|
|
|
|
auto that = static_cast<Win32Window*>(cs->lpCreateParams);
|
|
|
|
// Since the application is running in Per-monitor V2 mode, turn on
|
|
// automatic titlebar scaling
|
|
BOOL result = that->dpi_helper_->EnableNonClientDpiScaling(window);
|
|
if (result != TRUE) {
|
|
OutputDebugString(L"Failed to enable non-client area autoscaling");
|
|
}
|
|
that->current_dpi_ = that->dpi_helper_->GetDpiForWindow(window);
|
|
that->window_handle_ = window;
|
|
} else if (Win32Window* that = GetThisFromHandle(window)) {
|
|
return that->MessageHandler(window, message, wparam, lparam);
|
|
}
|
|
|
|
return DefWindowProc(window, message, wparam, lparam);
|
|
}
|
|
|
|
LRESULT
|
|
Win32Window::MessageHandler(HWND hwnd,
|
|
UINT const message,
|
|
WPARAM const wparam,
|
|
LPARAM const lparam) noexcept {
|
|
int xPos = 0, yPos = 0;
|
|
UINT width = 0, height = 0;
|
|
auto window =
|
|
reinterpret_cast<Win32Window*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
|
|
|
|
if (window != nullptr) {
|
|
switch (message) {
|
|
case WM_DPICHANGED:
|
|
return HandleDpiChange(window_handle_, wparam, lparam);
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
window->OnClose();
|
|
return 0;
|
|
break;
|
|
|
|
case WM_SIZE:
|
|
width = LOWORD(lparam);
|
|
height = HIWORD(lparam);
|
|
|
|
current_width_ = width;
|
|
current_height_ = height;
|
|
window->HandleResize(width, height);
|
|
break;
|
|
|
|
case WM_MOUSEMOVE:
|
|
xPos = GET_X_LPARAM(lparam);
|
|
yPos = GET_Y_LPARAM(lparam);
|
|
|
|
window->OnPointerMove(static_cast<double>(xPos),
|
|
static_cast<double>(yPos));
|
|
break;
|
|
case WM_LBUTTONDOWN:
|
|
xPos = GET_X_LPARAM(lparam);
|
|
yPos = GET_Y_LPARAM(lparam);
|
|
window->OnPointerDown(static_cast<double>(xPos),
|
|
static_cast<double>(yPos));
|
|
break;
|
|
case WM_LBUTTONUP:
|
|
xPos = GET_X_LPARAM(lparam);
|
|
yPos = GET_Y_LPARAM(lparam);
|
|
window->OnPointerUp(static_cast<double>(xPos),
|
|
static_cast<double>(yPos));
|
|
break;
|
|
case WM_MOUSEWHEEL:
|
|
window->OnScroll(
|
|
0.0, -(static_cast<short>(HIWORD(wparam)) / (double)WHEEL_DELTA));
|
|
break;
|
|
case WM_CHAR:
|
|
case WM_SYSCHAR:
|
|
case WM_UNICHAR:
|
|
if (wparam != VK_BACK) {
|
|
window->OnChar(static_cast<unsigned int>(wparam));
|
|
}
|
|
break;
|
|
case WM_KEYDOWN:
|
|
case WM_SYSKEYDOWN:
|
|
case WM_KEYUP:
|
|
case WM_SYSKEYUP:
|
|
unsigned char scancode = ((unsigned char*)&lparam)[2];
|
|
unsigned int virtualKey = MapVirtualKey(scancode, MAPVK_VSC_TO_VK);
|
|
const int key = virtualKey;
|
|
const int action = message == WM_KEYDOWN ? WM_KEYDOWN : WM_KEYUP;
|
|
window->OnKey(key, scancode, action, 0);
|
|
break;
|
|
}
|
|
return DefWindowProc(hwnd, message, wparam, lparam);
|
|
}
|
|
|
|
return DefWindowProc(window_handle_, message, wparam, lparam);
|
|
}
|
|
|
|
UINT Win32Window::GetCurrentDPI() {
|
|
return current_dpi_;
|
|
}
|
|
|
|
UINT Win32Window::GetCurrentWidth() {
|
|
return current_width_;
|
|
}
|
|
|
|
UINT Win32Window::GetCurrentHeight() {
|
|
return current_height_;
|
|
}
|
|
|
|
HWND Win32Window::GetWindowHandle() {
|
|
return window_handle_;
|
|
}
|
|
|
|
void Win32Window::Destroy() {
|
|
if (window_handle_) {
|
|
DestroyWindow(window_handle_);
|
|
window_handle_ = nullptr;
|
|
}
|
|
|
|
UnregisterClass(window_class_name_.c_str(), nullptr);
|
|
}
|
|
|
|
// DPI Change handler. on WM_DPICHANGE resize the window
|
|
LRESULT
|
|
Win32Window::HandleDpiChange(HWND hwnd, WPARAM wparam, LPARAM lparam) {
|
|
if (hwnd != nullptr) {
|
|
auto window =
|
|
reinterpret_cast<Win32Window*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
|
|
|
|
UINT uDpi = HIWORD(wparam);
|
|
current_dpi_ = uDpi;
|
|
window->OnDpiScale(uDpi);
|
|
|
|
// Resize the window
|
|
auto lprcNewScale = reinterpret_cast<RECT*>(lparam);
|
|
LONG newWidth = lprcNewScale->right - lprcNewScale->left;
|
|
LONG newHeight = lprcNewScale->bottom - lprcNewScale->top;
|
|
|
|
SetWindowPos(hwnd, nullptr, lprcNewScale->left, lprcNewScale->top, newWidth,
|
|
newHeight, SWP_NOZORDER | SWP_NOACTIVATE);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void Win32Window::HandleResize(UINT width, UINT height) {
|
|
current_width_ = width;
|
|
current_height_ = height;
|
|
OnResize(width, height);
|
|
}
|
|
|
|
Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept {
|
|
return reinterpret_cast<Win32Window*>(
|
|
GetWindowLongPtr(window, GWLP_USERDATA));
|
|
}
|
|
|
|
} // namespace flutter
|