未验证 提交 51a376d7 编写于 作者: J James Clarke 提交者: GitHub

[Windows] Update API for alternative Windows shell platform implementation (#11327)

* Begin API evolution to a more native win32 API

* Child-window based hosting

* Plumb through an initial size for child window to avoid reallocated surface on start

* Windows API cleanup part 1

* Fix wrapper tests

* Ensure flutter's HWND resources are destroyed

* Final API cleanup

* Fix dynamic DPI handling

* Cleanup

* Fix a bug that was causing engine to not be shutdown correctly

* CR feedback

* auto format

* CR feedback: combine FlutterView and FlutterViewController

* The one that clang-format seems to always get wrong

* expletive

* fix sources for licesnse file

* CR Feedback

* cleanup

* Update GetNativeWindow() to return an HWND rather than a long

* fix formatting
上级 3deb8f5e
......@@ -994,10 +994,9 @@ FILE: ../../../flutter/shell/platform/glfw/text_input_plugin.cc
FILE: ../../../flutter/shell/platform/glfw/text_input_plugin.h
FILE: ../../../flutter/shell/platform/windows/angle_surface_manager.cc
FILE: ../../../flutter/shell/platform/windows/angle_surface_manager.h
FILE: ../../../flutter/shell/platform/windows/client_wrapper/flutter_window_controller.cc
FILE: ../../../flutter/shell/platform/windows/client_wrapper/flutter_window_controller_unittests.cc
FILE: ../../../flutter/shell/platform/windows/client_wrapper/include/flutter/flutter_window.h
FILE: ../../../flutter/shell/platform/windows/client_wrapper/include/flutter/flutter_window_controller.h
FILE: ../../../flutter/shell/platform/windows/client_wrapper/flutter_view_controller.cc
FILE: ../../../flutter/shell/platform/windows/client_wrapper/flutter_view_controller_unittests.cc
FILE: ../../../flutter/shell/platform/windows/client_wrapper/include/flutter/flutter_view_controller.h
FILE: ../../../flutter/shell/platform/windows/client_wrapper/include/flutter/plugin_registrar_windows.h
FILE: ../../../flutter/shell/platform/windows/flutter_windows.cc
FILE: ../../../flutter/shell/platform/windows/key_event_handler.cc
......
......@@ -153,6 +153,10 @@ EGLSurface AngleSurfaceManager::CreateSurface(HWND window) {
surface = eglCreateWindowSurface(egl_display_, egl_config_,
static_cast<EGLNativeWindowType>(window),
surfaceAttributes);
if (surface == EGL_NO_SURFACE) {
OutputDebugString(L"Surface creation failed.");
}
return surface;
}
......
......@@ -5,9 +5,9 @@
import("$flutter_root/shell/platform/common/cpp/client_wrapper/publish.gni")
import("$flutter_root/testing/testing.gni")
_wrapper_includes = [ "include/flutter/flutter_window_controller.h" ]
_wrapper_includes = [ "include/flutter/flutter_view_controller.h" ]
_wrapper_sources = [ "flutter_window_controller.cc" ]
_wrapper_sources = [ "flutter_view_controller.cc" ]
# This code will be merged into .../common/cpp/client_wrapper for client use,
# so uses header paths that assume the merged state. Include the header
......@@ -68,7 +68,7 @@ executable("client_wrapper_windows_unittests") {
# TODO: Add more unit tests.
sources = [
"flutter_window_controller_unittests.cc",
"flutter_view_controller_unittests.cc",
]
deps = [
......
......@@ -2,43 +2,22 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "include/flutter/flutter_window_controller.h"
#include "include/flutter/flutter_view_controller.h"
#include <algorithm>
#include <iostream>
namespace flutter {
FlutterWindowController::FlutterWindowController(
const std::string& icu_data_path)
: icu_data_path_(icu_data_path) {
init_succeeded_ = FlutterDesktopInit();
}
FlutterWindowController::~FlutterWindowController() {
if (controller_) {
FlutterDesktopDestroyWindow(controller_);
}
if (init_succeeded_) {
FlutterDesktopTerminate();
}
}
bool FlutterWindowController::CreateWindow(
FlutterViewController::FlutterViewController(
const std::string& icu_data_path,
int width,
int height,
const std::string& title,
const std::string& assets_path,
const std::vector<std::string>& arguments) {
if (!init_succeeded_) {
std::cerr << "Could not create window; FlutterDesktopInit failed."
<< std::endl;
return false;
}
const std::vector<std::string>& arguments)
: icu_data_path_(icu_data_path) {
if (controller_) {
std::cerr << "Only one Flutter window can exist at a time." << std::endl;
return false;
std::cerr << "Only one Flutter view can exist at a time." << std::endl;
}
std::vector<const char*> engine_arguments;
......@@ -47,19 +26,29 @@ bool FlutterWindowController::CreateWindow(
[](const std::string& arg) -> const char* { return arg.c_str(); });
size_t arg_count = engine_arguments.size();
controller_ = FlutterDesktopCreateWindow(
width, height, title.c_str(), assets_path.c_str(), icu_data_path_.c_str(),
controller_ = FlutterDesktopCreateViewController(
width, height, assets_path.c_str(), icu_data_path_.c_str(),
arg_count > 0 ? &engine_arguments[0] : nullptr, arg_count);
if (!controller_) {
std::cerr << "Failed to create window." << std::endl;
return false;
std::cerr << "Failed to create view." << std::endl;
}
window_ =
std::make_unique<FlutterWindow>(FlutterDesktopGetWindow(controller_));
return true;
}
FlutterDesktopPluginRegistrarRef FlutterWindowController::GetRegistrarForPlugin(
FlutterViewController::~FlutterViewController() {
if (controller_) {
FlutterDesktopDestroyViewController(controller_);
}
}
HWND FlutterViewController::GetNativeWindow() {
return FlutterDesktopGetHWND(controller_);
}
void FlutterViewController::ProcessMessages() {
FlutterDesktopProcessMessages();
}
FlutterDesktopPluginRegistrarRef FlutterViewController::GetRegistrarForPlugin(
const std::string& plugin_name) {
if (!controller_) {
std::cerr << "Cannot get plugin registrar without a window; call "
......@@ -70,12 +59,4 @@ FlutterDesktopPluginRegistrarRef FlutterWindowController::GetRegistrarForPlugin(
return FlutterDesktopGetPluginRegistrar(controller_, plugin_name.c_str());
}
void FlutterWindowController::RunEventLoop() {
if (controller_) {
FlutterDesktopRunWindowLoop(controller_);
}
window_ = nullptr;
controller_ = nullptr;
}
} // namespace flutter
......@@ -5,7 +5,7 @@
#include <memory>
#include <string>
#include "flutter/shell/platform/windows/client_wrapper/include/flutter/flutter_window_controller.h"
#include "flutter/shell/platform/windows/client_wrapper/include/flutter/flutter_view_controller.h"
#include "flutter/shell/platform/windows/client_wrapper/testing/stub_flutter_windows_api.h"
#include "gtest/gtest.h"
......@@ -14,25 +14,7 @@ namespace flutter {
namespace {
// Stub implementation to validate calls to the API.
class TestWindowsApi : public testing::StubFlutterWindowsApi {
public:
// |flutter::testing::StubFlutterWindowsApi|
bool Init() override {
init_called_ = true;
return true;
}
// |flutter::testing::StubFlutterWindowsApi|
void Terminate() override { terminate_called_ = true; }
bool init_called() { return init_called_; }
bool terminate_called() { return terminate_called_; }
private:
bool init_called_ = false;
bool terminate_called_ = false;
};
class TestWindowsApi : public testing::StubFlutterWindowsApi {};
} // namespace
......@@ -42,12 +24,10 @@ TEST(FlutterViewControllerTest, CreateDestroy) {
std::make_unique<TestWindowsApi>());
auto test_api = static_cast<TestWindowsApi*>(scoped_api_stub.stub());
{
FlutterWindowController controller(icu_data_path);
EXPECT_EQ(test_api->init_called(), true);
EXPECT_EQ(test_api->terminate_called(), false);
FlutterViewController controller(icu_data_path, 100, 100,
std::string("fake"),
std::vector<std::string>{});
}
EXPECT_EQ(test_api->init_called(), true);
EXPECT_EQ(test_api->terminate_called(), true);
}
} // namespace flutter
......@@ -2,44 +2,32 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_FLUTTER_WINDOW_CONTROLLER_H_
#define FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_FLUTTER_WINDOW_CONTROLLER_H_
#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_FLUTTER_VIEW_CONTROLLER_H_
#define FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_FLUTTER_VIEW_CONTROLLER_H_
#include <flutter_windows.h>
#include <string>
#include <vector>
#include "flutter_window.h"
#include "plugin_registrar.h"
namespace flutter {
// A controller for a window displaying Flutter content.
// A controller for a view displaying Flutter content.
//
// This is the primary wrapper class for the desktop C API.
// If you use this class, you should not call any of the setup or teardown
// methods in the C API directly, as this class will do that internally.
//
// Note: This is an early implementation which
// requires control of the application's event loop, and is thus useful
// primarily for building a simple one-window shell hosting a Flutter
// application. The final implementation and API will be very different.
class FlutterWindowController {
class FlutterViewController {
public:
// There must be only one instance of this class in an application at any
// given time, as Flutter does not support multiple engines in one process,
// or multiple views in one engine.
explicit FlutterWindowController(const std::string& icu_data_path);
~FlutterWindowController();
// Prevent copying.
FlutterWindowController(FlutterWindowController const&) = delete;
FlutterWindowController& operator=(FlutterWindowController const&) = delete;
// Creates a FlutterView that can be parented into a Windows View hierarchy
// either using HWNDs or in the future into a CoreWindow, or using compositor.
// Creates and displays a window for displaying Flutter content.
//
// The |assets_path| is the path to the flutter_assets folder for the Flutter
// application to be run. |icu_data_path| is the path to the icudtl.dat file
// for the version of Flutter you are using.
......@@ -47,13 +35,17 @@ class FlutterWindowController {
// The |arguments| are passed to the Flutter engine. See:
// https://github.com/flutter/engine/blob/master/shell/common/switches.h for
// for details. Not all arguments will apply to desktop.
//
// Only one Flutter window can exist at a time; see constructor comment.
bool CreateWindow(int width,
int height,
const std::string& title,
const std::string& assets_path,
const std::vector<std::string>& arguments);
explicit FlutterViewController(const std::string& icu_data_path,
int width,
int height,
const std::string& assets_path,
const std::vector<std::string>& arguments);
~FlutterViewController();
// Prevent copying.
FlutterViewController(FlutterViewController const&) = delete;
FlutterViewController& operator=(FlutterViewController const&) = delete;
// Returns the FlutterDesktopPluginRegistrarRef to register a plugin with the
// given name.
......@@ -62,28 +54,22 @@ class FlutterWindowController {
FlutterDesktopPluginRegistrarRef GetRegistrarForPlugin(
const std::string& plugin_name);
// The FlutterWindow managed by this controller, if any. Returns nullptr
// before CreateWindow is called, and after RunEventLoop returns;
FlutterWindow* window() { return window_.get(); }
// Return backing HWND for manipulation in host application.
HWND GetNativeWindow();
// Loops on Flutter window events until the window closes.
void RunEventLoop();
// Must be called in run loop to enable the view to do work on each tick of
// loop.
void ProcessMessages();
private:
// The path to the ICU data file. Set at creation time since it is the same
// for any window created.
// for any view created.
std::string icu_data_path_;
// Whether or not FlutterDesktopInit succeeded at creation time.
bool init_succeeded_ = false;
// The owned FlutterWindow, if any.
std::unique_ptr<FlutterWindow> window_;
// Handle for interacting with the C API's window controller, if any.
FlutterDesktopWindowControllerRef controller_ = nullptr;
// Handle for interacting with the C API's view controller, if any.
FlutterDesktopViewControllerRef controller_ = nullptr;
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_FLUTTER_WINDOW_CONTROLLER_H_
#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_FLUTTER_VIEW_CONTROLLER_H_
// 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.
#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_FLUTTER_WINDOW_H_
#define FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_FLUTTER_WINDOW_H_
#include <flutter_windows.h>
#include <string>
#include <vector>
#include "plugin_registrar.h"
namespace flutter {
// A data type for window position and size.
struct WindowFrame {
int left;
int top;
int width;
int height;
};
// A window displaying Flutter content.
class FlutterWindow {
public:
explicit FlutterWindow(FlutterDesktopWindowRef window) : window_(window) {}
~FlutterWindow() = default;
// Prevent copying.
FlutterWindow(FlutterWindow const&) = delete;
FlutterWindow& operator=(FlutterWindow const&) = delete;
// Enables or disables hover tracking.
//
// If hover is enabled, mouse movement will send hover events to the Flutter
// engine, rather than only tracking the mouse while the button is pressed.
// Defaults to off.
void SetHoverEnabled(bool enabled) {
FlutterDesktopWindowSetHoverEnabled(window_, enabled);
}
// Sets the displayed title of the window.
void SetTitle(const std::string& title) {
FlutterDesktopWindowSetTitle(window_, title.c_str());
}
// Sets the displayed icon for the window.
//
// The pixel format is 32-bit RGBA. The provided image data only needs to be
// valid for the duration of the call to this method. Pass a nullptr to revert
// to the default icon.
void SetIcon(uint8_t* pixel_data, int width, int height) {
FlutterDesktopWindowSetIcon(window_, pixel_data, width, height);
}
// Returns the frame of the window, including any decoration (e.g., title
// bar), in screen coordinates.
WindowFrame GetFrame() {
WindowFrame frame = {};
FlutterDesktopWindowGetFrame(window_, &frame.left, &frame.top, &frame.width,
&frame.height);
return frame;
}
// Set the frame of the window, including any decoration (e.g., title
// bar), in screen coordinates.
void SetFrame(const WindowFrame& frame) {
FlutterDesktopWindowSetFrame(window_, frame.left, frame.top, frame.width,
frame.height);
}
// Returns the number of pixels per screen coordinate for the window.
//
// Flutter uses pixel coordinates, so this is the ratio of positions and sizes
// seen by Flutter as compared to the screen.
double GetScaleFactor() {
return FlutterDesktopWindowGetScaleFactor(window_);
}
private:
// Handle for interacting with the C API's window.
//
// Note: window_ is conceptually owned by the controller, not this object.
FlutterDesktopWindowRef window_;
};
} // namespace flutter
#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_CLIENT_WRAPPER_INCLUDE_FLUTTER_FLUTTER_WINDOW_H_
......@@ -35,67 +35,38 @@ ScopedStubFlutterWindowsApi::~ScopedStubFlutterWindowsApi() {
// Forwarding dummy implementations of the C API.
bool FlutterDesktopInit() {
if (s_stub_implementation) {
s_stub_implementation->Init();
}
return true;
}
void FlutterDesktopTerminate() {
if (s_stub_implementation) {
s_stub_implementation->Terminate();
}
}
FlutterDesktopWindowControllerRef FlutterDesktopCreateWindow(
FlutterDesktopViewControllerRef FlutterDesktopCreateViewController(
int initial_width,
int initial_height,
const char* title,
const char* assets_path,
const char* icu_data_path,
const char** arguments,
size_t argument_count) {
if (s_stub_implementation) {
return s_stub_implementation->CreateWindow(
initial_width, initial_height, title, assets_path, icu_data_path,
arguments, argument_count);
return s_stub_implementation->CreateViewController(
initial_width, initial_height, assets_path, icu_data_path, arguments,
argument_count);
}
return nullptr;
}
void FlutterDesktopDestroyWindow(FlutterDesktopWindowControllerRef controller) {
if (s_stub_implementation) {
s_stub_implementation->DestroyWindow();
}
}
void FlutterDesktopSetHoverEnabled(FlutterDesktopWindowRef flutter_window,
bool enabled) {
if (s_stub_implementation) {
s_stub_implementation->SetHoverEnabled(enabled);
}
}
void FlutterDesktopSetWindowTitle(FlutterDesktopWindowRef flutter_window,
const char* title) {
void FlutterDesktopDestroyViewController(
FlutterDesktopViewControllerRef controller) {
if (s_stub_implementation) {
s_stub_implementation->SetWindowTitle(title);
s_stub_implementation->DestroyViewController();
}
}
void FlutterDesktopSetWindowIcon(FlutterDesktopWindowRef flutter_window,
uint8_t* pixel_data,
int width,
int height) {
HWND FlutterDesktopGetHWND(FlutterDesktopViewControllerRef controller) {
if (s_stub_implementation) {
s_stub_implementation->SetWindowIcon(pixel_data, width, height);
return s_stub_implementation->FlutterDesktopGetHWND();
}
return reinterpret_cast<HWND>(-1);
}
void FlutterDesktopRunWindowLoop(FlutterDesktopWindowControllerRef controller) {
void FlutterDesktopProcessMessages() {
if (s_stub_implementation) {
s_stub_implementation->RunWindowLoop();
return s_stub_implementation->FlutterDesktopProcessMessages();
}
}
......@@ -117,14 +88,8 @@ bool FlutterDesktopShutDownEngine(FlutterDesktopEngineRef engine_ref) {
return true;
}
FlutterDesktopWindowRef FlutterDesktopGetWindow(
FlutterDesktopWindowControllerRef controller) {
// The stub ignores this, so just return an arbitrary non-zero value.
return reinterpret_cast<FlutterDesktopWindowRef>(1);
}
FlutterDesktopPluginRegistrarRef FlutterDesktopGetPluginRegistrar(
FlutterDesktopWindowControllerRef controller,
FlutterDesktopViewControllerRef controller,
const char* plugin_name) {
// The stub ignores this, so just return an arbitrary non-zero value.
return reinterpret_cast<FlutterDesktopPluginRegistrarRef>(1);
......
......@@ -29,17 +29,10 @@ class StubFlutterWindowsApi {
virtual ~StubFlutterWindowsApi() {}
// Called for FlutterDesktopInit.
virtual bool Init() { return true; }
// Called for FlutterDesktopTerminate.
virtual void Terminate() {}
// Called for FlutterDesktopCreateWindow.
virtual FlutterDesktopWindowControllerRef CreateWindow(
// Called for FlutterDesktopCreateView.
virtual FlutterDesktopViewControllerRef CreateViewController(
int initial_width,
int initial_height,
const char* title,
const char* assets_path,
const char* icu_data_path,
const char** arguments,
......@@ -47,20 +40,14 @@ class StubFlutterWindowsApi {
return nullptr;
}
// Called for FlutterDesktopDestroyWindow.
virtual void DestroyWindow() {}
// Called for FlutterDesktopSetHoverEnabled.
virtual void SetHoverEnabled(bool enabled) {}
// Called for FlutterDesktopSetWindowTitle.
virtual void SetWindowTitle(const char* title) {}
// Called for FlutterDesktopDestroyView.
virtual void DestroyViewController() {}
// Called for FlutterDesktopSetWindowIcon.
virtual void SetWindowIcon(uint8_t* pixel_data, int width, int height) {}
// Called for FlutterDesktopProcessMessages
virtual void FlutterDesktopProcessMessages() {}
// Called for FlutterDesktopRunWindowLoop.
virtual void RunWindowLoop() {}
// Called for FlutterDesktopProcessMessages
virtual HWND FlutterDesktopGetHWND() { return reinterpret_cast<HWND>(1); }
// Called for FlutterDesktopRunEngine.
virtual FlutterDesktopEngineRef RunEngine(const char* assets_path,
......
......@@ -49,7 +49,7 @@ static FLUTTER_API_SYMBOL(FlutterEngine)
FlutterRendererConfig config = {};
// Provide the necessary callbacks for rendering within a win32 window.
// Provide the necessary callbacks for rendering within a win32 child window.
config.type = kOpenGL;
config.open_gl.struct_size = sizeof(config.open_gl);
config.open_gl.make_current = [](void* user_data) -> bool {
......@@ -97,84 +97,52 @@ static FLUTTER_API_SYMBOL(FlutterEngine)
return engine;
}
bool FlutterDesktopInit() {
return true;
}
void FlutterDesktopTerminate() {}
FlutterDesktopWindowControllerRef FlutterDesktopCreateWindow(
FlutterDesktopViewControllerRef FlutterDesktopCreateViewController(
int initial_width,
int initial_height,
const char* title,
const char* assets_path,
const char* icu_data_path,
const char** arguments,
size_t argument_count) {
FlutterDesktopWindowControllerRef state =
flutter::Win32FlutterWindow::CreateWin32FlutterWindow(
title, 10, 10, initial_width, initial_height);
FlutterDesktopViewControllerRef state =
flutter::Win32FlutterWindow::CreateWin32FlutterWindow(initial_width,
initial_height);
auto engine = RunFlutterEngine(state->window.get(), assets_path,
icu_data_path, arguments, argument_count);
auto engine = RunFlutterEngine(state->view.get(), assets_path, icu_data_path,
arguments, argument_count);
if (engine == nullptr) {
return nullptr;
}
state->window->SetState(engine);
// Trigger an initial size callback to send size information to Flutter.
state->window->SendWindowMetrics();
state->view->SetState(engine);
state->engine = engine;
return state;
}
void FlutterDesktopDestroyWindow(FlutterDesktopWindowControllerRef controller) {
FlutterEngineShutdown(controller->engine);
delete controller;
}
void FlutterDesktopWindowSetHoverEnabled(FlutterDesktopWindowRef flutter_window,
bool enabled) {
// todo either implement or remove once embedder project has moved
}
void FlutterDesktopWindowSetTitle(FlutterDesktopWindowRef flutter_window,
const char* title) {
// todo either implement or remove
void FlutterDesktopProcessMessages() {
__FlutterEngineFlushPendingTasksNow();
}
void FlutterDesktopWindowSetIcon(FlutterDesktopWindowRef flutter_window,
uint8_t* pixel_data,
int width,
int height) {
// todo either implement or remove
HWND FlutterDesktopGetHWND(FlutterDesktopViewControllerRef controller) {
return (controller)->view->GetWindowHandle();
}
void FlutterDesktopRunWindowLoop(FlutterDesktopWindowControllerRef controller) {
controller->window->FlutterMessageLoop();
FlutterDesktopDestroyWindow(controller);
}
FlutterDesktopWindowRef FlutterDesktopGetWindow(
FlutterDesktopWindowControllerRef controller) {
// 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 controller->window_wrapper.get();
void FlutterDesktopDestroyViewController(
FlutterDesktopViewControllerRef controller) {
FlutterEngineShutdown(controller->engine);
delete controller;
}
FlutterDesktopPluginRegistrarRef FlutterDesktopGetPluginRegistrar(
FlutterDesktopWindowControllerRef controller,
FlutterDesktopViewControllerRef controller,
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 controller->window->GetRegistrar();
return controller->view->GetRegistrar();
}
FlutterDesktopEngineRef FlutterDesktopRunEngine(const char* assets_path,
......
......@@ -12,29 +12,23 @@
#include "flutter_messenger.h"
#include "flutter_plugin_registrar.h"
#include "Windows.h"
#if defined(__cplusplus)
extern "C" {
#endif
// Opaque reference to a Flutter window controller.
typedef struct FlutterDesktopWindowControllerState*
FlutterDesktopWindowControllerRef;
typedef struct FlutterDesktopViewControllerState*
FlutterDesktopViewControllerRef;
// Opaque reference to a Flutter window.
typedef struct FlutterDesktopWindow* FlutterDesktopWindowRef;
typedef struct FlutterDesktopView* FlutterDesktopViewRef;
// Opaque reference to a Flutter engine instance.
typedef struct FlutterDesktopEngineState* FlutterDesktopEngineRef;
// TODO: remove once the embedder project has swiched to native windows
FLUTTER_EXPORT bool FlutterDesktopInit();
// TODO: remove once the embedder project has swiched to native windows
FLUTTER_EXPORT void FlutterDesktopTerminate();
// Creates a Window running a Flutter Application.
//
// FlutterDesktopInit() must be called prior to this function.
// Creates a View running a Flutter Application.
//
// The |assets_path| is the path to the flutter_assets folder for the Flutter
// application to be run. |icu_data_path| is the path to the icudtl.dat file
......@@ -44,95 +38,36 @@ FLUTTER_EXPORT void FlutterDesktopTerminate();
// https://github.com/flutter/engine/blob/master/shell/common/switches.h for
// for details. Not all arguments will apply to desktop.
//
// Returns a null pointer in the event of an error. Otherwise, the pointer is
// valid until FlutterDesktopRunWindowLoop has been called and returned.
// Note that calling FlutterDesktopCreateWindow without later calling
// FlutterDesktopRunWindowLoop on the returned reference is a memory leak.
FLUTTER_EXPORT FlutterDesktopWindowControllerRef
FlutterDesktopCreateWindow(int initial_width,
int initial_height,
const char* title,
const char* assets_path,
const char* icu_data_path,
const char** arguments,
size_t argument_count);
// Returns a null pointer in the event of an error.
FLUTTER_EXPORT FlutterDesktopViewControllerRef
FlutterDesktopCreateViewController(int initial_width,
int initial_height,
const char* assets_path,
const char* icu_data_path,
const char** arguments,
size_t argument_count);
// Shuts down the engine instance associated with |controller|, and cleans up
// associated state.
//
// |controller| is no longer valid after this call.
FLUTTER_EXPORT void FlutterDesktopDestroyWindow(
FlutterDesktopWindowControllerRef controller);
// Loops on Flutter window events until the window is closed.
//
// Once this function returns, |controller| is no longer valid, and must not be
// be used again, as it calls FlutterDesktopDestroyWindow internally.
//
// TODO: Replace this with a method that allows running the runloop
// incrementally.
FLUTTER_EXPORT void FlutterDesktopRunWindowLoop(
FlutterDesktopWindowControllerRef controller);
// Returns the window handle for the window associated with
// FlutterDesktopWindowControllerRef.
//
// Its lifetime is the same as the |controller|'s.
FLUTTER_EXPORT FlutterDesktopWindowRef
FlutterDesktopGetWindow(FlutterDesktopWindowControllerRef controller);
FLUTTER_EXPORT void FlutterDesktopDestroyViewController(
FlutterDesktopViewControllerRef controller);
// Returns the plugin registrar handle for the plugin with the given name.
//
// The name must be unique across the application.
FLUTTER_EXPORT FlutterDesktopPluginRegistrarRef
FlutterDesktopGetPluginRegistrar(FlutterDesktopWindowControllerRef controller,
FlutterDesktopGetPluginRegistrar(FlutterDesktopViewControllerRef controller,
const char* plugin_name);
// Enables or disables hover tracking.
//
// If hover is enabled, mouse movement will send hover events to the Flutter
// engine, rather than only tracking the mouse while the button is pressed.
// Defaults to on.
FLUTTER_EXPORT void FlutterDesktopWindowSetHoverEnabled(
FlutterDesktopWindowRef flutter_window,
bool enabled);
// Sets the displayed title for |flutter_window|.
FLUTTER_EXPORT void FlutterDesktopWindowSetTitle(
FlutterDesktopWindowRef flutter_window,
const char* title);
// Sets the displayed icon for |flutter_window|.
//
// The pixel format is 32-bit RGBA. The provided image data only needs to be
// valid for the duration of the call to this method. Pass a nullptr to revert
// to the default icon.
FLUTTER_EXPORT void FlutterDesktopWindowSetIcon(
FlutterDesktopWindowRef flutter_window,
uint8_t* pixel_data,
int width,
int height);
// Gets the position and size of |flutter_window| in screen coordinates.
FLUTTER_EXPORT void FlutterDesktopWindowGetFrame(
FlutterDesktopWindowRef flutter_window,
int* x,
int* y,
int* width,
int* height);
// Sets the position and size of |flutter_window| in screen coordinates.
FLUTTER_EXPORT void FlutterDesktopWindowSetFrame(
FlutterDesktopWindowRef flutter_window,
int x,
int y,
int width,
int height);
// Returns the scale factor--the number of pixels per screen coordinate--for
// |flutter_window|.
FLUTTER_EXPORT double FlutterDesktopWindowGetScaleFactor(
FlutterDesktopWindowRef flutter_window);
// Return backing HWND for manipulation in host application.
FLUTTER_EXPORT HWND
FlutterDesktopGetHWND(FlutterDesktopViewControllerRef controller);
// Must be called in run loop to enable the view to do work on each tick of
// loop.
FLUTTER_EXPORT void FlutterDesktopProcessMessages();
// Runs an instance of a headless Flutter engine.
//
......@@ -156,11 +91,6 @@ FlutterDesktopRunEngine(const char* assets_path,
FLUTTER_EXPORT bool FlutterDesktopShutDownEngine(
FlutterDesktopEngineRef engine_ref);
// TODO: remove once embedder project has switched to native windows
// imlpementation
FLUTTER_EXPORT FlutterDesktopWindowRef
FlutterDesktopRegistrarGetWindow(FlutterDesktopPluginRegistrarRef registrar);
#if defined(__cplusplus)
} // extern "C"
#endif
......
......@@ -8,37 +8,26 @@ namespace flutter {
// constant for machines running at 100% scaling.
constexpr int base_dpi = 96;
Win32FlutterWindow::Win32FlutterWindow() {
Win32FlutterWindow::Win32FlutterWindow(int width, int height) {
surface_manager = std::make_unique<AngleSurfaceManager>();
}
Win32FlutterWindow::Win32FlutterWindow(const char* title,
const int x,
const int y,
const int width,
const int height) noexcept
: Win32FlutterWindow() {
Win32Window::Initialize(title, x, y, width, height);
Win32Window::InitializeChild("FLUTTERVIEW", width, height);
}
Win32FlutterWindow::~Win32FlutterWindow() {
DestroyRenderSurface();
Win32Window::Destroy();
}
FlutterDesktopWindowControllerRef Win32FlutterWindow::CreateWin32FlutterWindow(
const char* title,
const int x,
const int y,
FlutterDesktopViewControllerRef Win32FlutterWindow::CreateWin32FlutterWindow(
const int width,
const int height) {
auto state = std::make_unique<FlutterDesktopWindowControllerState>();
state->window = std::make_unique<flutter::Win32FlutterWindow>(title, 10, 10,
width, height);
auto state = std::make_unique<FlutterDesktopViewControllerState>();
state->view = std::make_unique<flutter::Win32FlutterWindow>(width, height);
// a window wrapper for the state block, distinct from the
// window_wrapper handed to plugin_registrar.
state->window_wrapper = std::make_unique<FlutterDesktopWindow>();
state->window_wrapper->window = state->window.get();
state->view_wrapper = std::make_unique<FlutterDesktopView>();
state->view_wrapper->window = state->view.get();
return state.release();
}
......@@ -51,7 +40,7 @@ void Win32FlutterWindow::SetState(FLUTTER_API_SYMBOL(FlutterEngine) eng) {
messenger->engine = engine_;
messenger->dispatcher = message_dispatcher_.get();
window_wrapper_ = std::make_unique<FlutterDesktopWindow>();
window_wrapper_ = std::make_unique<FlutterDesktopView>();
window_wrapper_->window = this;
plugin_registrar_ = std::make_unique<FlutterDesktopPluginRegistrar>();
......@@ -70,7 +59,7 @@ void Win32FlutterWindow::SetState(FLUTTER_API_SYMBOL(FlutterEngine) eng) {
platform_handler_ = std::make_unique<flutter::PlatformHandler>(
internal_plugin_messenger, this);
auto state = std::make_unique<FlutterDesktopWindowControllerState>();
auto state = std::make_unique<FlutterDesktopViewControllerState>();
state->engine = engine_;
process_events_ = true;
......@@ -158,20 +147,6 @@ void Win32FlutterWindow::OnClose() {
messageloop_running_ = false;
}
void Win32FlutterWindow::FlutterMessageLoop() {
MSG message;
messageloop_running_ = true;
// TODO: need either non-blocking meesage loop or custom dispatch
// implementation per https://github.com/flutter/flutter/issues/36420
while (GetMessage(&message, nullptr, 0, 0) && messageloop_running_) {
TranslateMessage(&message);
DispatchMessage(&message);
__FlutterEngineFlushPendingTasksNow();
}
}
// Sends new size information to FlutterEngine.
void Win32FlutterWindow::SendWindowMetrics() {
if (engine_ == nullptr) {
......
......@@ -24,28 +24,19 @@
namespace flutter {
// A win32 flutter window. In the future, there will likely be a
// CoreWindow-based FlutterWindow as well. At the point may make sense to
// dependency inject the native window rather than inherit.
// A win32 flutter child window used as implementatin for flutter view. In the
// future, there will likely be a CoreWindow-based FlutterWindow as well. At
// the point may make sense to dependency inject the native window rather than
// inherit.
class Win32FlutterWindow : public Win32Window {
public:
Win32FlutterWindow();
Win32FlutterWindow(const char* title,
const int x,
const int y,
const int width,
const int height) noexcept;
~Win32FlutterWindow();
// Create flutter Window for use as child window
Win32FlutterWindow(int width, int height);
static FlutterDesktopWindowControllerRef CreateWin32FlutterWindow(
const char* title,
const int x,
const int y,
const int width,
const int height);
~Win32FlutterWindow();
// Run a Windows message pump that also pumps plugin messages.
void FlutterMessageLoop();
static FlutterDesktopViewControllerRef
Win32FlutterWindow::CreateWin32FlutterWindow(int width, int height);
// |Win32Window|
void OnDpiScale(unsigned int dpi) override;
......@@ -149,7 +140,7 @@ class Win32FlutterWindow : public Win32Window {
bool pointer_currently_added_ = false;
// The window handle given to API clients.
std::unique_ptr<FlutterDesktopWindow> window_wrapper_;
std::unique_ptr<FlutterDesktopView> window_wrapper_;
// The plugin registrar handle given to API clients.
std::unique_ptr<FlutterDesktopPluginRegistrar> plugin_registrar_;
......
......@@ -15,39 +15,35 @@ Win32Window::Win32Window() {
// 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) {
void Win32Window::InitializeChild(const char* title,
unsigned int width,
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);
auto* result = CreateWindowEx(
0, window_class.lpszClassName, converted_title.c_str(),
WS_CHILD | WS_VISIBLE, CW_DEFAULT, CW_DEFAULT, width, height,
HWND_MESSAGE, nullptr, window_class.hInstance, this);
if (result == nullptr) {
auto error = GetLastError();
LPWSTR message = nullptr;
size_t size = FormatMessageW(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPWSTR>(&message), 0, NULL);
OutputDebugString(message);
LocalFree(message);
}
}
std::wstring Win32Window::NarrowToWide(const char* source) {
......@@ -115,9 +111,11 @@ Win32Window::MessageHandler(HWND hwnd,
if (window != nullptr) {
switch (message) {
case WM_DPICHANGED:
return HandleDpiChange(window_handle_, wparam, lparam);
return HandleDpiChange(window_handle_, wparam, lparam, true);
break;
case kWmDpiChangedBeforeParent:
return HandleDpiChange(window_handle_, wparam, lparam, false);
break;
case WM_DESTROY:
window->OnClose();
return 0;
......@@ -206,22 +204,34 @@ void Win32Window::Destroy() {
// DPI Change handler. on WM_DPICHANGE resize the window
LRESULT
Win32Window::HandleDpiChange(HWND hwnd, WPARAM wparam, LPARAM lparam) {
Win32Window::HandleDpiChange(HWND hwnd,
WPARAM wparam,
LPARAM lparam,
bool toplevel) {
if (hwnd != nullptr) {
auto window =
reinterpret_cast<Win32Window*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
UINT uDpi = HIWORD(wparam);
// The DPI is only passed for DPI change messages on top level windows,
// hence call function to get DPI if needed.
if (uDpi == 0) {
uDpi = dpi_helper_->GetDpiForWindow(hwnd);
}
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;
if (toplevel) {
// Resize the window only for toplevel windows which have a suggested
// size.
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);
SetWindowPos(hwnd, nullptr, lprcNewScale->left, lprcNewScale->top,
newWidth, newHeight, SWP_NOZORDER | SWP_NOACTIVATE);
}
}
return 0;
}
......
......@@ -17,23 +17,24 @@ namespace flutter {
// A class abstraction for a high DPI aware Win32 Window. Intended to be
// inherited from by classes that wish to specialize with custom
// rendering and input handling
// rendering and input handling.
class Win32Window {
public:
Win32Window();
~Win32Window();
// Initializes and shows window with |title| and position and size using |x|,
// |y|, |width| and |height|
void Initialize(const char* title,
const unsigned int x,
const unsigned int y,
const unsigned int width,
const unsigned int height);
// Initializes as a child window with size using |width| and |height| and
// |title| to identify the windowclass. Does not show window, window must be
// parented into window hierarchy by caller.
void InitializeChild(const char* title,
unsigned int width,
unsigned int height);
// Release OS resources asociated with window.
virtual void Destroy();
HWND GetWindowHandle();
protected:
// Converts a c string to a wide unicode string.
std::wstring NarrowToWide(const char* source);
......@@ -61,10 +62,12 @@ class Win32Window {
WPARAM const wparam,
LPARAM const lparam) noexcept;
// When WM_DPICHANGE resizes the window to the new suggested
// size and notifies inheriting class.
// When WM_DPICHANGE process it using |hWnd|, |wParam|. If
// |top_level| is set, extract the suggested new size from |lParam| and resize
// the window to the new suggested size. If |top_level| is not set, the
// |lParam| will not contain a suggested size hence ignore it.
LRESULT
HandleDpiChange(HWND hWnd, WPARAM wParam, LPARAM lParam);
HandleDpiChange(HWND hWnd, WPARAM wParam, LPARAM lParam, bool top_level);
// Called when the DPI changes either when a
// user drags the window between monitors of differing DPI or when the user
......@@ -103,8 +106,6 @@ class Win32Window {
UINT GetCurrentHeight();
HWND GetWindowHandle();
private:
// Stores new width and height and calls |OnResize| to notify inheritors
void HandleResize(UINT width, UINT height);
......@@ -115,6 +116,10 @@ class Win32Window {
int current_width_ = 0;
int current_height_ = 0;
// WM_DPICHANGED_BEFOREPARENT defined in more recent Windows
// SDK
const static long kWmDpiChangedBeforeParent = 0x02E2;
// Member variable to hold window handle.
HWND window_handle_ = nullptr;
......
......@@ -17,21 +17,21 @@ struct flutter::Win32FlutterWindow;
// Struct for storing state within an instance of the windows native (HWND or
// CoreWindow) Window.
struct FlutterDesktopWindowControllerState {
struct FlutterDesktopViewControllerState {
//// The win32 window that owns this state object.
std::unique_ptr<flutter::Win32FlutterWindow> window;
std::unique_ptr<flutter::Win32FlutterWindow> view;
// The handle to the Flutter engine instance.
FLUTTER_API_SYMBOL(FlutterEngine) engine;
// The window handle given to API clients.
std::unique_ptr<FlutterDesktopWindow> window_wrapper;
std::unique_ptr<FlutterDesktopView> view_wrapper;
};
// Opaque reference for the native windows itself. This is separate from the
// controller so that it can be provided to plugins without giving them access
// to all of the controller-based functionality.
struct FlutterDesktopWindow {
struct FlutterDesktopView {
// The window that (indirectly) owns this state object.
flutter::Win32FlutterWindow* window;
};
......@@ -48,7 +48,7 @@ struct FlutterDesktopPluginRegistrar {
std::unique_ptr<FlutterDesktopMessenger> messenger;
// The handle for the window associated with this registrar.
FlutterDesktopWindow* window;
FlutterDesktopView* window;
};
// State associated with the messenger used to communicate with the engine.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册