mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Originally font change notification was handled by forwarding WM_FONTCHANGE to the Flutter HWND, to avoid adding new API surface, but that's not a good solution in a multi-window scenario, and it would require a completely different solution for UWP. It also requires non-obvious plumbing in the runner. This replaces that with an explicit API, so that there's a clean and obvious way for the runner to trigger this event.
273 lines
9.6 KiB
C++
273 lines
9.6 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/public/flutter_windows.h"
|
|
|
|
#include <io.h>
|
|
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
#include <chrono>
|
|
#include <cstdlib>
|
|
#include <filesystem>
|
|
#include <iostream>
|
|
#include <memory>
|
|
#include <vector>
|
|
|
|
#include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/plugin_registrar.h"
|
|
#include "flutter/shell/platform/common/cpp/incoming_message_dispatcher.h"
|
|
#include "flutter/shell/platform/common/cpp/path_utils.h"
|
|
#include "flutter/shell/platform/embedder/embedder.h"
|
|
#include "flutter/shell/platform/windows/flutter_project_bundle.h"
|
|
#include "flutter/shell/platform/windows/flutter_windows_engine.h"
|
|
#include "flutter/shell/platform/windows/flutter_windows_view.h"
|
|
#include "flutter/shell/platform/windows/win32_dpi_utils.h"
|
|
#include "flutter/shell/platform/windows/win32_flutter_window.h"
|
|
#include "flutter/shell/platform/windows/win32_task_runner.h"
|
|
#include "flutter/shell/platform/windows/window_binding_handler.h"
|
|
#include "flutter/shell/platform/windows/window_state.h"
|
|
|
|
static_assert(FLUTTER_ENGINE_VERSION == 1, "");
|
|
|
|
// Returns the engine corresponding to the given opaque API handle.
|
|
static flutter::FlutterWindowsEngine* EngineFromHandle(
|
|
FlutterDesktopEngineRef ref) {
|
|
return reinterpret_cast<flutter::FlutterWindowsEngine*>(ref);
|
|
}
|
|
|
|
// Returns the opaque API handle for the given engine instance.
|
|
static FlutterDesktopEngineRef HandleForEngine(
|
|
flutter::FlutterWindowsEngine* engine) {
|
|
return reinterpret_cast<FlutterDesktopEngineRef>(engine);
|
|
}
|
|
|
|
// Returns the view corresponding to the given opaque API handle.
|
|
static flutter::FlutterWindowsView* ViewFromHandle(FlutterDesktopViewRef ref) {
|
|
return reinterpret_cast<flutter::FlutterWindowsView*>(ref);
|
|
}
|
|
|
|
// Returns the opaque API handle for the given view instance.
|
|
static FlutterDesktopViewRef HandleForView(flutter::FlutterWindowsView* view) {
|
|
return reinterpret_cast<FlutterDesktopViewRef>(view);
|
|
}
|
|
|
|
FlutterDesktopViewControllerRef FlutterDesktopViewControllerCreate(
|
|
int width,
|
|
int height,
|
|
FlutterDesktopEngineRef engine) {
|
|
std::unique_ptr<flutter::WindowBindingHandler> window_wrapper =
|
|
std::make_unique<flutter::Win32FlutterWindow>(width, height);
|
|
|
|
auto state = std::make_unique<FlutterDesktopViewControllerState>();
|
|
state->view =
|
|
std::make_unique<flutter::FlutterWindowsView>(std::move(window_wrapper));
|
|
state->view->CreateRenderSurface();
|
|
|
|
// Take ownership of the engine, starting it if necessary.
|
|
state->view->SetEngine(
|
|
std::unique_ptr<flutter::FlutterWindowsEngine>(EngineFromHandle(engine)));
|
|
if (!state->view->GetEngine()->running()) {
|
|
if (!state->view->GetEngine()->RunWithEntrypoint(nullptr)) {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
// Must happen after engine is running.
|
|
state->view->SendInitialBounds();
|
|
return state.release();
|
|
}
|
|
|
|
void FlutterDesktopViewControllerDestroy(
|
|
FlutterDesktopViewControllerRef controller) {
|
|
delete controller;
|
|
}
|
|
|
|
FlutterDesktopEngineRef FlutterDesktopViewControllerGetEngine(
|
|
FlutterDesktopViewControllerRef controller) {
|
|
return HandleForEngine(controller->view->GetEngine());
|
|
}
|
|
|
|
FlutterDesktopViewRef FlutterDesktopViewControllerGetView(
|
|
FlutterDesktopViewControllerRef controller) {
|
|
return HandleForView(controller->view.get());
|
|
}
|
|
|
|
bool FlutterDesktopViewControllerHandleTopLevelWindowProc(
|
|
FlutterDesktopViewControllerRef controller,
|
|
HWND hwnd,
|
|
UINT message,
|
|
WPARAM wparam,
|
|
LPARAM lparam,
|
|
LRESULT* result) {
|
|
std::optional<LRESULT> delegate_result =
|
|
controller->view->GetEngine()
|
|
->window_proc_delegate_manager()
|
|
->OnTopLevelWindowProc(hwnd, message, wparam, lparam);
|
|
if (delegate_result) {
|
|
*result = *delegate_result;
|
|
}
|
|
return delegate_result.has_value();
|
|
}
|
|
|
|
FlutterDesktopEngineRef FlutterDesktopEngineCreate(
|
|
const FlutterDesktopEngineProperties& engine_properties) {
|
|
flutter::FlutterProjectBundle project(engine_properties);
|
|
auto engine = std::make_unique<flutter::FlutterWindowsEngine>(project);
|
|
return HandleForEngine(engine.release());
|
|
}
|
|
|
|
bool FlutterDesktopEngineDestroy(FlutterDesktopEngineRef engine_ref) {
|
|
flutter::FlutterWindowsEngine* engine = EngineFromHandle(engine_ref);
|
|
bool result = true;
|
|
if (engine->running()) {
|
|
result = engine->Stop();
|
|
}
|
|
delete engine;
|
|
return result;
|
|
}
|
|
|
|
bool FlutterDesktopEngineRun(FlutterDesktopEngineRef engine,
|
|
const char* entry_point) {
|
|
return EngineFromHandle(engine)->RunWithEntrypoint(entry_point);
|
|
}
|
|
|
|
uint64_t FlutterDesktopEngineProcessMessages(FlutterDesktopEngineRef engine) {
|
|
return EngineFromHandle(engine)->task_runner()->ProcessTasks().count();
|
|
}
|
|
|
|
void FlutterDesktopEngineReloadSystemFonts(FlutterDesktopEngineRef engine) {
|
|
FlutterEngineReloadSystemFonts(EngineFromHandle(engine)->engine());
|
|
}
|
|
|
|
FlutterDesktopPluginRegistrarRef FlutterDesktopEngineGetPluginRegistrar(
|
|
FlutterDesktopEngineRef engine,
|
|
const char* plugin_name) {
|
|
// Currently, one registrar acts as the registrar for all plugins, so the
|
|
// name is ignored. It is part of the API to reduce churn in the future when
|
|
// aligning more closely with the Flutter registrar system.
|
|
|
|
return EngineFromHandle(engine)->GetRegistrar();
|
|
}
|
|
|
|
FlutterDesktopMessengerRef FlutterDesktopEngineGetMessenger(
|
|
FlutterDesktopEngineRef engine) {
|
|
return EngineFromHandle(engine)->messenger();
|
|
}
|
|
|
|
HWND FlutterDesktopViewGetHWND(FlutterDesktopViewRef view) {
|
|
return std::get<HWND>(*ViewFromHandle(view)->GetRenderTarget());
|
|
}
|
|
|
|
FlutterDesktopViewRef FlutterDesktopPluginRegistrarGetView(
|
|
FlutterDesktopPluginRegistrarRef registrar) {
|
|
return HandleForView(registrar->engine->view());
|
|
}
|
|
|
|
void FlutterDesktopPluginRegistrarRegisterTopLevelWindowProcDelegate(
|
|
FlutterDesktopPluginRegistrarRef registrar,
|
|
FlutterDesktopWindowProcCallback delegate,
|
|
void* user_data) {
|
|
registrar->engine->window_proc_delegate_manager()
|
|
->RegisterTopLevelWindowProcDelegate(delegate, user_data);
|
|
}
|
|
|
|
void FlutterDesktopPluginRegistrarUnregisterTopLevelWindowProcDelegate(
|
|
FlutterDesktopPluginRegistrarRef registrar,
|
|
FlutterDesktopWindowProcCallback delegate) {
|
|
registrar->engine->window_proc_delegate_manager()
|
|
->UnregisterTopLevelWindowProcDelegate(delegate);
|
|
}
|
|
|
|
UINT FlutterDesktopGetDpiForHWND(HWND hwnd) {
|
|
return flutter::GetDpiForHWND(hwnd);
|
|
}
|
|
|
|
UINT FlutterDesktopGetDpiForMonitor(HMONITOR monitor) {
|
|
return flutter::GetDpiForMonitor(monitor);
|
|
}
|
|
|
|
void FlutterDesktopResyncOutputStreams() {
|
|
FILE* unused;
|
|
if (freopen_s(&unused, "CONOUT$", "w", stdout)) {
|
|
_dup2(_fileno(stdout), 1);
|
|
}
|
|
if (freopen_s(&unused, "CONOUT$", "w", stderr)) {
|
|
_dup2(_fileno(stdout), 2);
|
|
}
|
|
std::ios::sync_with_stdio();
|
|
}
|
|
|
|
// Implementations of common/cpp/ API methods.
|
|
|
|
FlutterDesktopMessengerRef FlutterDesktopPluginRegistrarGetMessenger(
|
|
FlutterDesktopPluginRegistrarRef registrar) {
|
|
return registrar->engine->messenger();
|
|
}
|
|
|
|
void FlutterDesktopPluginRegistrarSetDestructionHandler(
|
|
FlutterDesktopPluginRegistrarRef registrar,
|
|
FlutterDesktopOnPluginRegistrarDestroyed callback) {
|
|
registrar->engine->SetPluginRegistrarDestructionCallback(callback);
|
|
}
|
|
|
|
bool FlutterDesktopMessengerSendWithReply(FlutterDesktopMessengerRef messenger,
|
|
const char* channel,
|
|
const uint8_t* message,
|
|
const size_t message_size,
|
|
const FlutterDesktopBinaryReply reply,
|
|
void* user_data) {
|
|
FlutterPlatformMessageResponseHandle* response_handle = nullptr;
|
|
if (reply != nullptr && user_data != nullptr) {
|
|
FlutterEngineResult result = FlutterPlatformMessageCreateResponseHandle(
|
|
messenger->engine->engine(), reply, user_data, &response_handle);
|
|
if (result != kSuccess) {
|
|
std::cout << "Failed to create response handle\n";
|
|
return false;
|
|
}
|
|
}
|
|
|
|
FlutterPlatformMessage platform_message = {
|
|
sizeof(FlutterPlatformMessage),
|
|
channel,
|
|
message,
|
|
message_size,
|
|
response_handle,
|
|
};
|
|
|
|
FlutterEngineResult message_result = FlutterEngineSendPlatformMessage(
|
|
messenger->engine->engine(), &platform_message);
|
|
|
|
if (response_handle != nullptr) {
|
|
FlutterPlatformMessageReleaseResponseHandle(messenger->engine->engine(),
|
|
response_handle);
|
|
}
|
|
|
|
return message_result == kSuccess;
|
|
}
|
|
|
|
bool FlutterDesktopMessengerSend(FlutterDesktopMessengerRef messenger,
|
|
const char* channel,
|
|
const uint8_t* message,
|
|
const size_t message_size) {
|
|
return FlutterDesktopMessengerSendWithReply(messenger, channel, message,
|
|
message_size, nullptr, nullptr);
|
|
}
|
|
|
|
void FlutterDesktopMessengerSendResponse(
|
|
FlutterDesktopMessengerRef messenger,
|
|
const FlutterDesktopMessageResponseHandle* handle,
|
|
const uint8_t* data,
|
|
size_t data_length) {
|
|
FlutterEngineSendPlatformMessageResponse(messenger->engine->engine(), handle,
|
|
data, data_length);
|
|
}
|
|
|
|
void FlutterDesktopMessengerSetCallback(FlutterDesktopMessengerRef messenger,
|
|
const char* channel,
|
|
FlutterDesktopMessageCallback callback,
|
|
void* user_data) {
|
|
messenger->engine->message_dispatcher()->SetMessageCallback(channel, callback,
|
|
user_data);
|
|
}
|