diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 1e22176412b1d..56045fcf06964 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1307,6 +1307,8 @@ FILE: ../../../flutter/shell/platform/windows/client_wrapper/include/flutter/flu 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/client_wrapper/plugin_registrar_windows_unittests.cc +FILE: ../../../flutter/shell/platform/windows/cursor_handler.cc +FILE: ../../../flutter/shell/platform/windows/cursor_handler.h FILE: ../../../flutter/shell/platform/windows/flutter_windows.cc FILE: ../../../flutter/shell/platform/windows/flutter_windows_view.cc FILE: ../../../flutter/shell/platform/windows/flutter_windows_view.h diff --git a/shell/platform/windows/BUILD.gn b/shell/platform/windows/BUILD.gn index a5760a2522e6c..27a2cdb366c3f 100644 --- a/shell/platform/windows/BUILD.gn +++ b/shell/platform/windows/BUILD.gn @@ -41,6 +41,8 @@ source_set("flutter_windows_source") { sources = [ "angle_surface_manager.cc", "angle_surface_manager.h", + "cursor_handler.cc", + "cursor_handler.h", "flutter_windows.cc", "flutter_windows_view.cc", "flutter_windows_view.h", diff --git a/shell/platform/windows/cursor_handler.cc b/shell/platform/windows/cursor_handler.cc new file mode 100644 index 0000000000000..cb696e5f63425 --- /dev/null +++ b/shell/platform/windows/cursor_handler.cc @@ -0,0 +1,53 @@ +// 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/cursor_handler.h" + +#include + +#include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/standard_method_codec.h" + +static constexpr char kChannelName[] = "flutter/mousecursor"; + +static constexpr char kActivateSystemCursorMethod[] = "activateSystemCursor"; + +static constexpr char kKindKey[] = "kind"; + +namespace flutter { + +CursorHandler::CursorHandler(flutter::BinaryMessenger* messenger, + WindowBindingHandler* delegate) + : channel_(std::make_unique>( + messenger, + kChannelName, + &flutter::StandardMethodCodec::GetInstance())), + delegate_(delegate) { + channel_->SetMethodCallHandler( + [this](const flutter::MethodCall& call, + std::unique_ptr> result) { + HandleMethodCall(call, std::move(result)); + }); +} + +void CursorHandler::HandleMethodCall( + const flutter::MethodCall& method_call, + std::unique_ptr> result) { + const std::string& method = method_call.method_name(); + if (method.compare(kActivateSystemCursorMethod) == 0) { + const flutter::EncodableMap& arguments = + method_call.arguments()->MapValue(); + auto kind_iter = arguments.find(EncodableValue(kKindKey)); + if (kind_iter == arguments.end()) { + result->Error("Argument error", + "Missing argument while trying to activate system cursor"); + } + const std::string& kind = kind_iter->second.StringValue(); + delegate_->UpdateFlutterCursor(kind); + result->Success(); + } else { + result->NotImplemented(); + } +} + +} // namespace flutter diff --git a/shell/platform/windows/cursor_handler.h b/shell/platform/windows/cursor_handler.h new file mode 100644 index 0000000000000..b5775748da948 --- /dev/null +++ b/shell/platform/windows/cursor_handler.h @@ -0,0 +1,37 @@ +// 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_CURSOR_HANDLER_H_ +#define FLUTTER_SHELL_PLATFORM_WINDOWS_CURSOR_HANDLER_H_ + +#include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/binary_messenger.h" +#include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/encodable_value.h" +#include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/method_channel.h" +#include "flutter/shell/platform/windows/public/flutter_windows.h" +#include "flutter/shell/platform/windows/window_binding_handler.h" + +namespace flutter { + +// Handler for the cursor system channel. +class CursorHandler { + public: + explicit CursorHandler(flutter::BinaryMessenger* messenger, + WindowBindingHandler* delegate); + + private: + // Called when a method is called on |channel_|; + void HandleMethodCall( + const flutter::MethodCall& method_call, + std::unique_ptr> result); + + // The MethodChannel used for communication with the Flutter engine. + std::unique_ptr> channel_; + + // The delegate for cursor updates. + WindowBindingHandler* delegate_; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_CURSOR_HANDLER_H_ diff --git a/shell/platform/windows/flutter_windows.cc b/shell/platform/windows/flutter_windows.cc index b3dec79eb20cd..19bf9c97c77ec 100644 --- a/shell/platform/windows/flutter_windows.cc +++ b/shell/platform/windows/flutter_windows.cc @@ -20,9 +20,6 @@ #include "flutter/shell/platform/common/cpp/path_utils.h" #include "flutter/shell/platform/embedder/embedder.h" #include "flutter/shell/platform/windows/flutter_windows_view.h" -#include "flutter/shell/platform/windows/key_event_handler.h" -#include "flutter/shell/platform/windows/keyboard_hook_handler.h" -#include "flutter/shell/platform/windows/text_input_plugin.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" diff --git a/shell/platform/windows/flutter_windows_view.cc b/shell/platform/windows/flutter_windows_view.cc index 4f6f55e12dc58..db650a4e0ae7d 100644 --- a/shell/platform/windows/flutter_windows_view.cc +++ b/shell/platform/windows/flutter_windows_view.cc @@ -65,6 +65,8 @@ void FlutterWindowsView::SetState(FLUTTER_API_SYMBOL(FlutterEngine) eng) { std::make_unique(internal_plugin_messenger)); platform_handler_ = std::make_unique( internal_plugin_messenger, this); + cursor_handler_ = std::make_unique( + internal_plugin_messenger, binding_handler_.get()); PhysicalWindowBounds bounds = binding_handler_->GetPhysicalWindowBounds(); diff --git a/shell/platform/windows/flutter_windows_view.h b/shell/platform/windows/flutter_windows_view.h index 9a7b0994d2438..f19e9f97ac02a 100644 --- a/shell/platform/windows/flutter_windows_view.h +++ b/shell/platform/windows/flutter_windows_view.h @@ -14,6 +14,7 @@ #include "flutter/shell/platform/common/cpp/incoming_message_dispatcher.h" #include "flutter/shell/platform/embedder/embedder.h" #include "flutter/shell/platform/windows/angle_surface_manager.h" +#include "flutter/shell/platform/windows/cursor_handler.h" #include "flutter/shell/platform/windows/key_event_handler.h" #include "flutter/shell/platform/windows/keyboard_hook_handler.h" #include "flutter/shell/platform/windows/public/flutter_windows.h" @@ -213,6 +214,9 @@ class FlutterWindowsView : public WindowBindingHandlerDelegate { // Handler for the flutter/platform channel. std::unique_ptr platform_handler_; + // Handler for cursor events. + std::unique_ptr cursor_handler_; + // Currently configured WindowBindingHandler for view. std::unique_ptr binding_handler_; }; diff --git a/shell/platform/windows/testing/win32_window_test.cc b/shell/platform/windows/testing/win32_window_test.cc index da4bc43b9dabe..c7aaf6038bf9a 100644 --- a/shell/platform/windows/testing/win32_window_test.cc +++ b/shell/platform/windows/testing/win32_window_test.cc @@ -19,6 +19,8 @@ void Win32WindowTest::OnPointerUp(double x, double y, UINT button) {} void Win32WindowTest::OnPointerLeave() {} +void Win32WindowTest::OnSetCursor() {} + void Win32WindowTest::OnText(const std::u16string& text) {} void Win32WindowTest::OnKey(int key, diff --git a/shell/platform/windows/testing/win32_window_test.h b/shell/platform/windows/testing/win32_window_test.h index 5d8630c0181c6..dade7a4061e69 100644 --- a/shell/platform/windows/testing/win32_window_test.h +++ b/shell/platform/windows/testing/win32_window_test.h @@ -41,6 +41,9 @@ class Win32WindowTest : public Win32Window { // |Win32Window| void OnPointerLeave() override; + // |Win32Window| + void OnSetCursor() override; + // |Win32Window| void OnText(const std::u16string& text) override; diff --git a/shell/platform/windows/win32_flutter_window.cc b/shell/platform/windows/win32_flutter_window.cc index a05e5ebfa3c23..6fea467183870 100644 --- a/shell/platform/windows/win32_flutter_window.cc +++ b/shell/platform/windows/win32_flutter_window.cc @@ -1,9 +1,12 @@ #include "flutter/shell/platform/windows/win32_flutter_window.h" #include +#include namespace flutter { +namespace { + // The Windows DPI system is based on this // constant for machines running at 100% scaling. constexpr int base_dpi = 96; @@ -12,9 +15,33 @@ constexpr int base_dpi = 96; // arbitrarily to get something that feels reasonable. constexpr int kScrollOffsetMultiplier = 20; +// Maps a Flutter cursor name to an HCURSOR. +// +// Returns the arrow cursor for unknown constants. +static HCURSOR GetCursorByName(const std::string& cursor_name) { + static auto* cursors = new std::map{ + {"none", nullptr}, + {"basic", IDC_ARROW}, + {"click", IDC_HAND}, + {"text", IDC_IBEAM}, + {"forbidden", IDC_NO}, + {"horizontalDoubleArrow", IDC_SIZEWE}, + {"verticalDoubleArrow", IDC_SIZENS}, + }; + 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); +} + +} // namespace + Win32FlutterWindow::Win32FlutterWindow(int width, int height) : binding_handler_delegate_(nullptr) { Win32Window::InitializeChild("FLUTTERVIEW", width, height); + current_cursor_ = ::LoadCursor(nullptr, IDC_ARROW); } Win32FlutterWindow::~Win32FlutterWindow() {} @@ -35,6 +62,10 @@ PhysicalWindowBounds Win32FlutterWindow::GetPhysicalWindowBounds() { return {GetCurrentWidth(), GetCurrentHeight()}; } +void Win32FlutterWindow::UpdateFlutterCursor(const std::string& cursor_name) { + current_cursor_ = GetCursorByName(cursor_name); +} + // Translates button codes from Win32 API to FlutterPointerMouseButtons. static uint64_t ConvertWinButtonToFlutterButton(UINT button) { switch (button) { @@ -90,6 +121,10 @@ void Win32FlutterWindow::OnPointerLeave() { binding_handler_delegate_->OnPointerLeave(); } +void Win32FlutterWindow::OnSetCursor() { + ::SetCursor(current_cursor_); +} + void Win32FlutterWindow::OnText(const std::u16string& text) { binding_handler_delegate_->OnText(text); } diff --git a/shell/platform/windows/win32_flutter_window.h b/shell/platform/windows/win32_flutter_window.h index 150a6edd485fb..b97d9b38b01ee 100644 --- a/shell/platform/windows/win32_flutter_window.h +++ b/shell/platform/windows/win32_flutter_window.h @@ -12,7 +12,6 @@ #include #include "flutter/shell/platform/embedder/embedder.h" - #include "flutter/shell/platform/windows/flutter_windows_view.h" #include "flutter/shell/platform/windows/win32_window.h" #include "flutter/shell/platform/windows/window_binding_handler.h" @@ -48,6 +47,9 @@ class Win32FlutterWindow : public Win32Window, public WindowBindingHandler { // |Win32Window| void OnPointerLeave() override; + // |Win32Window| + void OnSetCursor() override; + // |Win32Window| void OnText(const std::u16string& text) override; @@ -72,9 +74,16 @@ class Win32FlutterWindow : public Win32Window, public WindowBindingHandler { // |FlutterWindowBindingHandler| PhysicalWindowBounds GetPhysicalWindowBounds() override; + // |FlutterWindowBindingHandler| + void UpdateFlutterCursor(const std::string& cursor_name) override; + + private: // A pointer to a FlutterWindowsView that can be used to update engine // windowing and input state. WindowBindingHandlerDelegate* binding_handler_delegate_; + + // The last cursor set by Flutter. Defaults to the arrow cursor. + HCURSOR current_cursor_; }; } // namespace flutter diff --git a/shell/platform/windows/win32_window.cc b/shell/platform/windows/win32_window.cc index 08da305aa9206..4f7f83405df4f 100644 --- a/shell/platform/windows/win32_window.cc +++ b/shell/platform/windows/win32_window.cc @@ -150,6 +150,14 @@ Win32Window::MessageHandler(HWND hwnd, // detected again. tracking_mouse_leave_ = false; break; + case WM_SETCURSOR: { + UINT hit_test_result = LOWORD(lparam); + if (hit_test_result == HTCLIENT) { + window->OnSetCursor(); + return TRUE; + } + break; + } case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_MBUTTONDOWN: diff --git a/shell/platform/windows/win32_window.h b/shell/platform/windows/win32_window.h index 91da3f333794c..61e3a4a338508 100644 --- a/shell/platform/windows/win32_window.h +++ b/shell/platform/windows/win32_window.h @@ -86,6 +86,9 @@ class Win32Window { // Called when the mouse leaves the window. virtual void OnPointerLeave() = 0; + // Called when the cursor should be set for the client area. + virtual void OnSetCursor() = 0; + // Called when text input occurs. virtual void OnText(const std::u16string& text) = 0; diff --git a/shell/platform/windows/window_binding_handler.h b/shell/platform/windows/window_binding_handler.h index 730c3dd821a37..50eba0587765f 100644 --- a/shell/platform/windows/window_binding_handler.h +++ b/shell/platform/windows/window_binding_handler.h @@ -5,13 +5,12 @@ #ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_WINDOW_BINDING_HANDLER_H_ #define FLUTTER_SHELL_PLATFORM_WINDOWS_WINDOW_BINDING_HANDLER_H_ -#include "flutter/shell/platform/windows/public/flutter_windows.h" +#include #include #include -#include - +#include "flutter/shell/platform/windows/public/flutter_windows.h" #include "flutter/shell/platform/windows/window_binding_handler_delegate.h" namespace flutter { @@ -45,6 +44,10 @@ 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; }; } // namespace flutter