mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Update the mouse cursor handler to work with multi-view on Windows (#163855)
Partially fixes https://github.com/flutter/flutter/issues/142845. This PR removes implicit view assumptions from the `'flutter/mousecursor'` channel handler on Windows. The cursor is now set for all existing views, ensuring that the current `FlutterWindow` with the cursor in its client area uses the correct cursor. The method arguments remain unchanged. Cursor handler tests have also been updated to avoid assuming an implicit view. ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
This commit is contained in:
parent
71010953aa
commit
02f3ddf989
@ -8,7 +8,6 @@
|
||||
|
||||
#include "flutter/shell/platform/common/client_wrapper/include/flutter/standard_method_codec.h"
|
||||
#include "flutter/shell/platform/windows/flutter_windows_engine.h"
|
||||
#include "flutter/shell/platform/windows/flutter_windows_view.h"
|
||||
|
||||
static constexpr char kChannelName[] = "flutter/mousecursor";
|
||||
|
||||
@ -74,16 +73,7 @@ void CursorHandler::HandleMethodCall(
|
||||
return;
|
||||
}
|
||||
const auto& kind = std::get<std::string>(kind_iter->second);
|
||||
|
||||
// TODO(loicsharma): Remove implicit view assumption.
|
||||
// https://github.com/flutter/flutter/issues/142845
|
||||
FlutterWindowsView* view = engine_->view(kImplicitViewId);
|
||||
if (view == nullptr) {
|
||||
result->Error(kCursorError,
|
||||
"Cursor is not available in Windows headless mode");
|
||||
return;
|
||||
}
|
||||
view->UpdateFlutterCursor(kind);
|
||||
engine_->UpdateFlutterCursor(kind);
|
||||
result->Success();
|
||||
} else if (method.compare(kCreateCustomCursorMethod) == 0) {
|
||||
const auto& arguments = std::get<EncodableMap>(*method_call.arguments());
|
||||
@ -167,16 +157,7 @@ void CursorHandler::HandleMethodCall(
|
||||
return;
|
||||
}
|
||||
HCURSOR cursor = custom_cursors_[name];
|
||||
|
||||
// TODO(loicsharma): Remove implicit view assumption.
|
||||
// https://github.com/flutter/flutter/issues/142845
|
||||
FlutterWindowsView* view = engine_->view(kImplicitViewId);
|
||||
if (view == nullptr) {
|
||||
result->Error(kCursorError,
|
||||
"Cursor is not available in Windows headless mode");
|
||||
return;
|
||||
}
|
||||
view->SetFlutterCursor(cursor);
|
||||
engine_->SetFlutterCursor(cursor);
|
||||
result->Success();
|
||||
} else if (method.compare(kDeleteCustomCursorMethod) == 0) {
|
||||
const auto& arguments = std::get<EncodableMap>(*method_call.arguments());
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
#include "flutter/shell/platform/windows/testing/engine_modifier.h"
|
||||
#include "flutter/shell/platform/windows/testing/flutter_windows_engine_builder.h"
|
||||
#include "flutter/shell/platform/windows/testing/mock_window_binding_handler.h"
|
||||
#include "flutter/shell/platform/windows/testing/mock_windows_proc_table.h"
|
||||
#include "flutter/shell/platform/windows/testing/test_binary_messenger.h"
|
||||
#include "flutter/shell/platform/windows/testing/windows_test.h"
|
||||
#include "gmock/gmock.h"
|
||||
@ -24,6 +25,7 @@ namespace testing {
|
||||
|
||||
namespace {
|
||||
using ::testing::_;
|
||||
using ::testing::IsNull;
|
||||
using ::testing::NotNull;
|
||||
using ::testing::Return;
|
||||
|
||||
@ -63,6 +65,7 @@ class CursorHandlerTest : public WindowsTest {
|
||||
FlutterWindowsEngine* engine() { return engine_.get(); }
|
||||
FlutterWindowsView* view() { return view_.get(); }
|
||||
MockWindowBindingHandler* window() { return window_; }
|
||||
MockWindowsProcTable* proc_table() { return windows_proc_table_.get(); }
|
||||
|
||||
void UseHeadlessEngine() {
|
||||
FlutterWindowsEngineBuilder builder{GetContext()};
|
||||
@ -71,7 +74,10 @@ class CursorHandlerTest : public WindowsTest {
|
||||
}
|
||||
|
||||
void UseEngineWithView() {
|
||||
windows_proc_table_ = std::make_shared<MockWindowsProcTable>();
|
||||
|
||||
FlutterWindowsEngineBuilder builder{GetContext()};
|
||||
builder.SetWindowsProcTable(windows_proc_table_);
|
||||
|
||||
auto window = std::make_unique<MockWindowBindingHandler>();
|
||||
EXPECT_CALL(*window.get(), SetView).Times(1);
|
||||
@ -79,17 +85,14 @@ class CursorHandlerTest : public WindowsTest {
|
||||
|
||||
window_ = window.get();
|
||||
engine_ = builder.Build();
|
||||
view_ = std::make_unique<FlutterWindowsView>(kImplicitViewId, engine_.get(),
|
||||
std::move(window));
|
||||
|
||||
EngineModifier modifier{engine_.get()};
|
||||
modifier.SetImplicitView(view_.get());
|
||||
view_ = engine_->CreateView(std::move(window));
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<FlutterWindowsEngine> engine_;
|
||||
std::unique_ptr<FlutterWindowsView> view_;
|
||||
MockWindowBindingHandler* window_;
|
||||
std::shared_ptr<MockWindowsProcTable> windows_proc_table_;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(CursorHandlerTest);
|
||||
};
|
||||
@ -100,7 +103,8 @@ TEST_F(CursorHandlerTest, ActivateSystemCursor) {
|
||||
TestBinaryMessenger messenger;
|
||||
CursorHandler cursor_handler(&messenger, engine());
|
||||
|
||||
EXPECT_CALL(*window(), UpdateFlutterCursor("click")).Times(1);
|
||||
EXPECT_CALL(*proc_table(), LoadCursor(IsNull(), IDC_HAND)).Times(1);
|
||||
EXPECT_CALL(*proc_table(), SetCursor).Times(1);
|
||||
|
||||
bool success = false;
|
||||
MethodResultFunctions<> result_handler(
|
||||
@ -120,33 +124,6 @@ TEST_F(CursorHandlerTest, ActivateSystemCursor) {
|
||||
EXPECT_TRUE(success);
|
||||
}
|
||||
|
||||
TEST_F(CursorHandlerTest, ActivateSystemCursorRequiresView) {
|
||||
UseHeadlessEngine();
|
||||
|
||||
TestBinaryMessenger messenger;
|
||||
CursorHandler cursor_handler(&messenger, engine());
|
||||
|
||||
bool error = false;
|
||||
MethodResultFunctions<> result_handler(
|
||||
nullptr,
|
||||
[&error](const std::string& error_code, const std::string& error_message,
|
||||
const EncodableValue* value) {
|
||||
error = true;
|
||||
EXPECT_EQ(error_message,
|
||||
"Cursor is not available in Windows headless mode");
|
||||
},
|
||||
nullptr);
|
||||
|
||||
SimulateCursorMessage(&messenger, kActivateSystemCursorMethod,
|
||||
std::make_unique<EncodableValue>(EncodableMap{
|
||||
{EncodableValue("device"), EncodableValue(0)},
|
||||
{EncodableValue("kind"), EncodableValue("click")},
|
||||
}),
|
||||
&result_handler);
|
||||
|
||||
EXPECT_TRUE(error);
|
||||
}
|
||||
|
||||
TEST_F(CursorHandlerTest, CreateCustomCursor) {
|
||||
UseEngineWithView();
|
||||
|
||||
@ -196,7 +173,8 @@ TEST_F(CursorHandlerTest, SetCustomCursor) {
|
||||
},
|
||||
nullptr, nullptr);
|
||||
|
||||
EXPECT_CALL(*window(), SetFlutterCursor(/*cursor=*/NotNull())).Times(1);
|
||||
EXPECT_CALL(*proc_table(), LoadCursor).Times(0);
|
||||
EXPECT_CALL(*proc_table(), SetCursor(NotNull())).Times(1);
|
||||
|
||||
SimulateCursorMessage(&messenger, kCreateCustomCursorMethod,
|
||||
std::make_unique<EncodableValue>(EncodableMap{
|
||||
@ -218,47 +196,6 @@ TEST_F(CursorHandlerTest, SetCustomCursor) {
|
||||
EXPECT_TRUE(success);
|
||||
}
|
||||
|
||||
TEST_F(CursorHandlerTest, SetCustomCursorRequiresView) {
|
||||
UseHeadlessEngine();
|
||||
|
||||
TestBinaryMessenger messenger;
|
||||
CursorHandler cursor_handler(&messenger, engine());
|
||||
|
||||
// Create a 4x4 raw BGRA test cursor buffer.
|
||||
std::vector<uint8_t> buffer(4 * 4 * 4, 0);
|
||||
|
||||
bool error = false;
|
||||
MethodResultFunctions<> create_result_handler(nullptr, nullptr, nullptr);
|
||||
MethodResultFunctions<> set_result_handler(
|
||||
nullptr,
|
||||
[&error](const std::string& error_code, const std::string& error_message,
|
||||
const EncodableValue* value) {
|
||||
error = true;
|
||||
EXPECT_EQ(error_message,
|
||||
"Cursor is not available in Windows headless mode");
|
||||
},
|
||||
nullptr);
|
||||
|
||||
SimulateCursorMessage(&messenger, kCreateCustomCursorMethod,
|
||||
std::make_unique<EncodableValue>(EncodableMap{
|
||||
{EncodableValue("name"), EncodableValue("hello")},
|
||||
{EncodableValue("buffer"), EncodableValue(buffer)},
|
||||
{EncodableValue("width"), EncodableValue(4)},
|
||||
{EncodableValue("height"), EncodableValue(4)},
|
||||
{EncodableValue("hotX"), EncodableValue(0.0)},
|
||||
{EncodableValue("hotY"), EncodableValue(0.0)},
|
||||
}),
|
||||
&create_result_handler);
|
||||
|
||||
SimulateCursorMessage(&messenger, kSetCustomCursorMethod,
|
||||
std::make_unique<EncodableValue>(EncodableMap{
|
||||
{EncodableValue("name"), EncodableValue("hello")},
|
||||
}),
|
||||
&set_result_handler);
|
||||
|
||||
EXPECT_TRUE(error);
|
||||
}
|
||||
|
||||
TEST_F(CursorHandlerTest, SetNonexistentCustomCursor) {
|
||||
UseEngineWithView();
|
||||
|
||||
@ -277,7 +214,8 @@ TEST_F(CursorHandlerTest, SetNonexistentCustomCursor) {
|
||||
},
|
||||
nullptr);
|
||||
|
||||
EXPECT_CALL(*window(), SetFlutterCursor).Times(0);
|
||||
EXPECT_CALL(*proc_table(), LoadCursor).Times(0);
|
||||
EXPECT_CALL(*proc_table(), SetCursor).Times(0);
|
||||
|
||||
SimulateCursorMessage(&messenger, kSetCustomCursorMethod,
|
||||
std::make_unique<EncodableValue>(EncodableMap{
|
||||
|
||||
@ -30,49 +30,6 @@ static const int kMaxTouchDeviceId = 128;
|
||||
|
||||
static const int kLinesPerScrollWindowsDefault = 3;
|
||||
|
||||
// Maps a Flutter cursor name to an HCURSOR.
|
||||
//
|
||||
// Returns the arrow cursor for unknown constants.
|
||||
//
|
||||
// This map must be kept in sync with Flutter framework's
|
||||
// services/mouse_cursor.dart.
|
||||
static HCURSOR GetCursorByName(const std::string& cursor_name) {
|
||||
static auto* cursors = new std::map<std::string, const wchar_t*>{
|
||||
{"allScroll", IDC_SIZEALL},
|
||||
{"basic", IDC_ARROW},
|
||||
{"click", IDC_HAND},
|
||||
{"forbidden", IDC_NO},
|
||||
{"help", IDC_HELP},
|
||||
{"move", IDC_SIZEALL},
|
||||
{"none", nullptr},
|
||||
{"noDrop", IDC_NO},
|
||||
{"precise", IDC_CROSS},
|
||||
{"progress", IDC_APPSTARTING},
|
||||
{"text", IDC_IBEAM},
|
||||
{"resizeColumn", IDC_SIZEWE},
|
||||
{"resizeDown", IDC_SIZENS},
|
||||
{"resizeDownLeft", IDC_SIZENESW},
|
||||
{"resizeDownRight", IDC_SIZENWSE},
|
||||
{"resizeLeft", IDC_SIZEWE},
|
||||
{"resizeLeftRight", IDC_SIZEWE},
|
||||
{"resizeRight", IDC_SIZEWE},
|
||||
{"resizeRow", IDC_SIZENS},
|
||||
{"resizeUp", IDC_SIZENS},
|
||||
{"resizeUpDown", IDC_SIZENS},
|
||||
{"resizeUpLeft", IDC_SIZENWSE},
|
||||
{"resizeUpRight", IDC_SIZENESW},
|
||||
{"resizeUpLeftDownRight", IDC_SIZENWSE},
|
||||
{"resizeUpRightDownLeft", IDC_SIZENESW},
|
||||
{"wait", IDC_WAIT},
|
||||
};
|
||||
const wchar_t* idc_name = IDC_ARROW;
|
||||
auto it = cursors->find(cursor_name);
|
||||
if (it != cursors->end()) {
|
||||
idc_name = it->second;
|
||||
}
|
||||
return ::LoadCursor(nullptr, idc_name);
|
||||
}
|
||||
|
||||
static constexpr int32_t kDefaultPointerDeviceId = 0;
|
||||
|
||||
// This method is only valid during a window message related to mouse/touch
|
||||
@ -144,7 +101,6 @@ FlutterWindow::FlutterWindow(
|
||||
keyboard_manager_ = std::make_unique<KeyboardManager>(this);
|
||||
|
||||
InitializeChild("FLUTTERVIEW", width, height);
|
||||
current_cursor_ = ::LoadCursor(nullptr, IDC_ARROW);
|
||||
}
|
||||
|
||||
// Base constructor for mocks
|
||||
@ -176,15 +132,6 @@ PhysicalWindowBounds FlutterWindow::GetPhysicalWindowBounds() {
|
||||
return {GetCurrentWidth(), GetCurrentHeight()};
|
||||
}
|
||||
|
||||
void FlutterWindow::UpdateFlutterCursor(const std::string& cursor_name) {
|
||||
SetFlutterCursor(GetCursorByName(cursor_name));
|
||||
}
|
||||
|
||||
void FlutterWindow::SetFlutterCursor(HCURSOR cursor) {
|
||||
current_cursor_ = cursor;
|
||||
::SetCursor(current_cursor_);
|
||||
}
|
||||
|
||||
bool FlutterWindow::Focus() {
|
||||
auto hwnd = GetWindowHandle();
|
||||
if (hwnd == nullptr) {
|
||||
@ -257,10 +204,6 @@ void FlutterWindow::OnPointerLeave(double x,
|
||||
binding_handler_delegate_->OnPointerLeave(x, y, device_kind, device_id);
|
||||
}
|
||||
|
||||
void FlutterWindow::OnSetCursor() {
|
||||
::SetCursor(current_cursor_);
|
||||
}
|
||||
|
||||
void FlutterWindow::OnText(const std::u16string& text) {
|
||||
binding_handler_delegate_->OnText(text);
|
||||
}
|
||||
@ -649,7 +592,8 @@ FlutterWindow::HandleMessage(UINT const message,
|
||||
case WM_SETCURSOR: {
|
||||
UINT hit_test_result = LOWORD(lparam);
|
||||
if (hit_test_result == HTCLIENT) {
|
||||
OnSetCursor();
|
||||
// Halt further processing to prevent DefWindowProc from setting the
|
||||
// cursor back to the registered class cursor.
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -104,9 +104,6 @@ class FlutterWindow : public KeyboardManager::WindowDelegate,
|
||||
FlutterPointerDeviceKind device_kind,
|
||||
int32_t device_id);
|
||||
|
||||
// Called when the cursor should be set for the client area.
|
||||
virtual void OnSetCursor();
|
||||
|
||||
// |WindowBindingHandlerDelegate|
|
||||
virtual void OnText(const std::u16string& text) override;
|
||||
|
||||
@ -161,12 +158,6 @@ class FlutterWindow : public KeyboardManager::WindowDelegate,
|
||||
// |FlutterWindowBindingHandler|
|
||||
virtual PhysicalWindowBounds GetPhysicalWindowBounds() override;
|
||||
|
||||
// |FlutterWindowBindingHandler|
|
||||
virtual void UpdateFlutterCursor(const std::string& cursor_name) override;
|
||||
|
||||
// |FlutterWindowBindingHandler|
|
||||
virtual void SetFlutterCursor(HCURSOR cursor) override;
|
||||
|
||||
// |FlutterWindowBindingHandler|
|
||||
virtual bool OnBitmapSurfaceCleared() override;
|
||||
|
||||
@ -329,9 +320,6 @@ class FlutterWindow : public KeyboardManager::WindowDelegate,
|
||||
// windowing and input state.
|
||||
WindowBindingHandlerDelegate* binding_handler_delegate_ = nullptr;
|
||||
|
||||
// The last cursor set by Flutter. Defaults to the arrow cursor.
|
||||
HCURSOR current_cursor_;
|
||||
|
||||
// The cursor rect set by Flutter.
|
||||
RECT cursor_rect_;
|
||||
|
||||
|
||||
@ -66,7 +66,6 @@ class MockFlutterWindow : public FlutterWindow {
|
||||
OnPointerLeave,
|
||||
(double, double, FlutterPointerDeviceKind, int32_t),
|
||||
(override));
|
||||
MOCK_METHOD(void, OnSetCursor, (), (override));
|
||||
MOCK_METHOD(float, GetScrollOffsetMultiplier, (), (override));
|
||||
MOCK_METHOD(float, GetDpiScale, (), (override));
|
||||
MOCK_METHOD(void, UpdateCursorRect, (const Rect&), (override));
|
||||
@ -422,12 +421,5 @@ TEST_F(FlutterWindowTest, CachedLifecycleMessage) {
|
||||
EXPECT_TRUE(restored);
|
||||
}
|
||||
|
||||
TEST_F(FlutterWindowTest, UpdateCursor) {
|
||||
FlutterWindow win32window(100, 100);
|
||||
win32window.UpdateFlutterCursor("text");
|
||||
HCURSOR cursor = ::GetCursor();
|
||||
EXPECT_EQ(cursor, ::LoadCursor(nullptr, IDC_IBEAM));
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace flutter
|
||||
|
||||
@ -801,6 +801,44 @@ void FlutterWindowsEngine::SetNextFrameCallback(fml::closure callback) {
|
||||
this);
|
||||
}
|
||||
|
||||
HCURSOR FlutterWindowsEngine::GetCursorByName(
|
||||
const std::string& cursor_name) const {
|
||||
static auto* cursors = new std::map<std::string, const wchar_t*>{
|
||||
{"allScroll", IDC_SIZEALL},
|
||||
{"basic", IDC_ARROW},
|
||||
{"click", IDC_HAND},
|
||||
{"forbidden", IDC_NO},
|
||||
{"help", IDC_HELP},
|
||||
{"move", IDC_SIZEALL},
|
||||
{"none", nullptr},
|
||||
{"noDrop", IDC_NO},
|
||||
{"precise", IDC_CROSS},
|
||||
{"progress", IDC_APPSTARTING},
|
||||
{"text", IDC_IBEAM},
|
||||
{"resizeColumn", IDC_SIZEWE},
|
||||
{"resizeDown", IDC_SIZENS},
|
||||
{"resizeDownLeft", IDC_SIZENESW},
|
||||
{"resizeDownRight", IDC_SIZENWSE},
|
||||
{"resizeLeft", IDC_SIZEWE},
|
||||
{"resizeLeftRight", IDC_SIZEWE},
|
||||
{"resizeRight", IDC_SIZEWE},
|
||||
{"resizeRow", IDC_SIZENS},
|
||||
{"resizeUp", IDC_SIZENS},
|
||||
{"resizeUpDown", IDC_SIZENS},
|
||||
{"resizeUpLeft", IDC_SIZENWSE},
|
||||
{"resizeUpRight", IDC_SIZENESW},
|
||||
{"resizeUpLeftDownRight", IDC_SIZENWSE},
|
||||
{"resizeUpRightDownLeft", IDC_SIZENESW},
|
||||
{"wait", IDC_WAIT},
|
||||
};
|
||||
const wchar_t* idc_name = IDC_ARROW;
|
||||
auto it = cursors->find(cursor_name);
|
||||
if (it != cursors->end()) {
|
||||
idc_name = it->second;
|
||||
}
|
||||
return windows_proc_table_->LoadCursor(nullptr, idc_name);
|
||||
}
|
||||
|
||||
void FlutterWindowsEngine::SendSystemLocales() {
|
||||
std::vector<LanguageInfo> languages =
|
||||
GetPreferredLanguageInfo(*windows_proc_table_);
|
||||
@ -995,6 +1033,15 @@ std::optional<LRESULT> FlutterWindowsEngine::ProcessExternalWindowMessage(
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void FlutterWindowsEngine::UpdateFlutterCursor(
|
||||
const std::string& cursor_name) const {
|
||||
SetFlutterCursor(GetCursorByName(cursor_name));
|
||||
}
|
||||
|
||||
void FlutterWindowsEngine::SetFlutterCursor(HCURSOR cursor) const {
|
||||
windows_proc_table_->SetCursor(cursor);
|
||||
}
|
||||
|
||||
void FlutterWindowsEngine::OnChannelUpdate(std::string name, bool listening) {
|
||||
if (name == "flutter/platform" && listening) {
|
||||
lifecycle_manager_->BeginProcessingExit();
|
||||
|
||||
@ -307,6 +307,13 @@ class FlutterWindowsEngine {
|
||||
return windows_proc_table_;
|
||||
}
|
||||
|
||||
// Sets the cursor that should be used when the mouse is over the Flutter
|
||||
// content. See mouse_cursor.dart for the values and meanings of cursor_name.
|
||||
void UpdateFlutterCursor(const std::string& cursor_name) const;
|
||||
|
||||
// Sets the cursor directly from a cursor handle.
|
||||
void SetFlutterCursor(HCURSOR cursor) const;
|
||||
|
||||
protected:
|
||||
// Creates the keyboard key handler.
|
||||
//
|
||||
@ -341,6 +348,14 @@ class FlutterWindowsEngine {
|
||||
// Allows swapping out embedder_api_ calls in tests.
|
||||
friend class EngineModifier;
|
||||
|
||||
// Maps a Flutter cursor name to an HCURSOR.
|
||||
//
|
||||
// Returns the arrow cursor for unknown constants.
|
||||
//
|
||||
// This map must be kept in sync with Flutter framework's
|
||||
// services/mouse_cursor.dart.
|
||||
HCURSOR GetCursorByName(const std::string& cursor_name) const;
|
||||
|
||||
// Sends system locales to the engine.
|
||||
//
|
||||
// Should be called just after the engine is run, and after any relevant
|
||||
|
||||
@ -176,14 +176,6 @@ bool FlutterWindowsView::OnFrameGenerated(size_t width, size_t height) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void FlutterWindowsView::UpdateFlutterCursor(const std::string& cursor_name) {
|
||||
binding_handler_->UpdateFlutterCursor(cursor_name);
|
||||
}
|
||||
|
||||
void FlutterWindowsView::SetFlutterCursor(HCURSOR cursor) {
|
||||
binding_handler_->SetFlutterCursor(cursor);
|
||||
}
|
||||
|
||||
void FlutterWindowsView::ForceRedraw() {
|
||||
if (resize_status_ == ResizeState::kDone) {
|
||||
// Request new frame.
|
||||
|
||||
@ -125,13 +125,6 @@ class FlutterWindowsView : public WindowBindingHandlerDelegate {
|
||||
// This completes a view resize if one is pending.
|
||||
virtual void OnFramePresented();
|
||||
|
||||
// Sets the cursor that should be used when the mouse is over the Flutter
|
||||
// content. See mouse_cursor.dart for the values and meanings of cursor_name.
|
||||
void UpdateFlutterCursor(const std::string& cursor_name);
|
||||
|
||||
// Sets the cursor directly from a cursor handle.
|
||||
void SetFlutterCursor(HCURSOR cursor);
|
||||
|
||||
// |WindowBindingHandlerDelegate|
|
||||
bool OnWindowSizeChanged(size_t width, size_t height) override;
|
||||
|
||||
|
||||
@ -54,7 +54,6 @@ class MockWindow : public FlutterWindow {
|
||||
OnPointerLeave,
|
||||
(double, double, FlutterPointerDeviceKind, int32_t),
|
||||
(override));
|
||||
MOCK_METHOD(void, OnSetCursor, (), (override));
|
||||
MOCK_METHOD(void, OnText, (const std::u16string&), (override));
|
||||
MOCK_METHOD(void,
|
||||
OnKey,
|
||||
|
||||
@ -23,11 +23,6 @@ class MockWindowBindingHandler : public WindowBindingHandler {
|
||||
MOCK_METHOD(HWND, GetWindowHandle, (), (override));
|
||||
MOCK_METHOD(float, GetDpiScale, (), (override));
|
||||
MOCK_METHOD(PhysicalWindowBounds, GetPhysicalWindowBounds, (), (override));
|
||||
MOCK_METHOD(void,
|
||||
UpdateFlutterCursor,
|
||||
(const std::string& cursor_name),
|
||||
(override));
|
||||
MOCK_METHOD(void, SetFlutterCursor, (HCURSOR cursor_name), (override));
|
||||
MOCK_METHOD(void, OnCursorRectUpdated, (const Rect& rect), (override));
|
||||
MOCK_METHOD(void, OnResetImeComposing, (), (override));
|
||||
MOCK_METHOD(bool, OnBitmapSurfaceCleared, (), (override));
|
||||
|
||||
@ -34,6 +34,13 @@ class MockWindowsProcTable : public WindowsProcTable {
|
||||
|
||||
MOCK_METHOD(HRESULT, DwmFlush, (), (const, override));
|
||||
|
||||
MOCK_METHOD(HCURSOR,
|
||||
LoadCursor,
|
||||
(HINSTANCE instance, LPCWSTR cursor_name),
|
||||
(const, override));
|
||||
|
||||
MOCK_METHOD(HCURSOR, SetCursor, (HCURSOR cursor), (const, override));
|
||||
|
||||
private:
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(MockWindowsProcTable);
|
||||
};
|
||||
|
||||
@ -54,13 +54,6 @@ class WindowBindingHandler {
|
||||
// Returns the bounds of the backing window in physical pixels.
|
||||
virtual PhysicalWindowBounds GetPhysicalWindowBounds() = 0;
|
||||
|
||||
// Sets the cursor that should be used when the mouse is over the Flutter
|
||||
// content. See mouse_cursor.dart for the values and meanings of cursor_name.
|
||||
virtual void UpdateFlutterCursor(const std::string& cursor_name) = 0;
|
||||
|
||||
// Sets the cursor directly from a cursor handle.
|
||||
virtual void SetFlutterCursor(HCURSOR cursor) = 0;
|
||||
|
||||
// Invoked when the cursor/composing rect has been updated in the framework.
|
||||
virtual void OnCursorRectUpdated(const Rect& rect) = 0;
|
||||
|
||||
|
||||
@ -58,4 +58,13 @@ HRESULT WindowsProcTable::DwmFlush() const {
|
||||
return ::DwmFlush();
|
||||
}
|
||||
|
||||
HCURSOR WindowsProcTable::LoadCursor(HINSTANCE instance,
|
||||
LPCWSTR cursor_name) const {
|
||||
return ::LoadCursorW(instance, cursor_name);
|
||||
}
|
||||
|
||||
HCURSOR WindowsProcTable::SetCursor(HCURSOR cursor) const {
|
||||
return ::SetCursor(cursor);
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
@ -57,6 +57,19 @@ class WindowsProcTable {
|
||||
// https://learn.microsoft.com/windows/win32/api/dwmapi/nf-dwmapi-dwmflush
|
||||
virtual HRESULT DwmFlush() const;
|
||||
|
||||
// Loads the specified cursor resource from the executable (.exe) file
|
||||
// associated with an application instance.
|
||||
//
|
||||
// See:
|
||||
// https://learn.microsoft.com/windows/win32/api/winuser/nf-winuser-loadcursorw
|
||||
virtual HCURSOR LoadCursor(HINSTANCE instance, LPCWSTR cursor_name) const;
|
||||
|
||||
// Sets the cursor shape.
|
||||
//
|
||||
// See:
|
||||
// https://learn.microsoft.com/windows/win32/api/winuser/nf-winuser-setcursor
|
||||
virtual HCURSOR SetCursor(HCURSOR cursor) const;
|
||||
|
||||
private:
|
||||
using GetPointerType_ = BOOL __stdcall(UINT32 pointerId,
|
||||
POINTER_INPUT_TYPE* pointerType);
|
||||
|
||||
@ -408,8 +408,7 @@ abstract final class SystemMouseCursors {
|
||||
//
|
||||
// * Android: shell/platform/android/io/flutter/plugin/mouse/MouseCursorPlugin.java
|
||||
// * Web: lib/web_ui/lib/src/engine/mouse_cursor.dart
|
||||
// * Windows: shell/platform/windows/win32_flutter_window_win32.cc
|
||||
// * Windows UWP: shell/platform/windows/win32_flutter_window_winuwp.cc
|
||||
// * Windows: shell/platform/windows/flutter_windows_engine.cc
|
||||
// * Linux: shell/platform/linux/fl_mouse_cursor_plugin.cc
|
||||
// * macOS: shell/platform/darwin/macos/framework/Source/FlutterMouseCursorPlugin.mm
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user