flutter_flutter/shell/platform/windows/flutter_windows.cc
stuartmorgan dcbe3d3d3d
[windows] Allow delegation of top-level WindowProc (#20613)
Adds APIs for runners to delegate WindowProc handlers into the Flutter
engine, and for plugins to register as possible delegates.

This allows for plugins to alter top-level window behavior in ways that
can only be done from the WindowProc, such as resize control. This
functionality remains entirely on the native side, so is synchronous.

Part of https://github.com/flutter/flutter/issues/53168
2020-08-19 06:49:39 -07:00

258 lines
9.0 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 <assert.h>
#include <io.h>
#include <algorithm>
#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_platform_handler.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 opaque API handle for the given engine instance.
static FlutterDesktopEngineRef HandleForEngine(
flutter::FlutterWindowsEngine* engine) {
return reinterpret_cast<FlutterDesktopEngineRef>(engine);
}
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();
state->view_wrapper = std::make_unique<FlutterDesktopView>();
state->view_wrapper->view = state->view.get();
// 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;
}
}
return state.release();
}
void FlutterDesktopViewControllerDestroy(
FlutterDesktopViewControllerRef controller) {
delete controller;
}
FlutterDesktopEngineRef FlutterDesktopViewControllerGetEngine(
FlutterDesktopViewControllerRef controller) {
return HandleForEngine(controller->view->GetEngine());
}
FlutterDesktopViewRef FlutterDesktopViewControllerGetView(
FlutterDesktopViewControllerRef controller) {
return controller->view_wrapper.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();
}
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_ref) {
return std::get<HWND>(*view_ref->view->GetRenderTarget());
}
FlutterDesktopViewRef FlutterDesktopPluginRegistrarGetView(
FlutterDesktopPluginRegistrarRef registrar) {
return registrar->view.get();
}
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 FlutterDesktopRegistrarGetMessenger(
FlutterDesktopPluginRegistrarRef registrar) {
return registrar->engine->messenger();
}
void FlutterDesktopRegistrarSetDestructionHandler(
FlutterDesktopPluginRegistrarRef registrar,
FlutterDesktopOnRegistrarDestroyed callback) {
registrar->destruction_handler = 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, 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, &platform_message);
if (response_handle != nullptr) {
FlutterPlatformMessageReleaseResponseHandle(messenger->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, handle, data,
data_length);
}
void FlutterDesktopMessengerSetCallback(FlutterDesktopMessengerRef messenger,
const char* channel,
FlutterDesktopMessageCallback callback,
void* user_data) {
messenger->dispatcher->SetMessageCallback(channel, callback, user_data);
}