flutter_flutter/shell/platform/windows/flutter_windows.cc
stuartmorgan 91eab23eb3
Switch Windows embedding to proc table embedder API (#22211)
Switches the Windows embedding from the standard C API to the new proctable version, to allow for unit testing of the embedding layer separately from the embedder APIs implementation. This includes moving some engine messaging that was still in flutter_windows to the C++ engine class to better encapsulate the proc table.
2020-11-03 14:36:18 -08:00

247 lines
8.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/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) {
EngineFromHandle(engine)->ReloadSystemFonts();
}
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) {
return messenger->engine->SendPlatformMessage(channel, message, message_size,
reply, user_data);
}
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) {
messenger->engine->SendPlatformMessageResponse(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);
}