| // 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/flutter_windows_view.h" |
| |
| #include <chrono> |
| |
| namespace flutter { |
| |
| FlutterWindowsView::FlutterWindowsView( |
| std::unique_ptr<WindowBindingHandler> window_binding) { |
| surface_manager_ = std::make_unique<AngleSurfaceManager>(); |
| |
| // Take the binding handler, and give it a pointer back to self. |
| binding_handler_ = std::move(window_binding); |
| binding_handler_->SetView(this); |
| |
| render_target_ = std::make_unique<WindowsRenderTarget>( |
| binding_handler_->GetRenderTarget()); |
| } |
| |
| FlutterWindowsView::~FlutterWindowsView() { |
| DestroyRenderSurface(); |
| } |
| |
| void FlutterWindowsView::SetEngine( |
| std::unique_ptr<FlutterWindowsEngine> engine) { |
| engine_ = std::move(engine); |
| |
| engine_->SetView(this); |
| |
| internal_plugin_registrar_ = |
| std::make_unique<flutter::PluginRegistrar>(engine_->GetRegistrar()); |
| |
| // Set up the system channel handlers. |
| auto internal_plugin_messenger = internal_plugin_registrar_->messenger(); |
| keyboard_hook_handlers_.push_back( |
| std::make_unique<flutter::KeyEventHandler>(internal_plugin_messenger)); |
| keyboard_hook_handlers_.push_back( |
| std::make_unique<flutter::TextInputPlugin>(internal_plugin_messenger)); |
| platform_handler_ = std::make_unique<flutter::PlatformHandler>( |
| internal_plugin_messenger, this); |
| cursor_handler_ = std::make_unique<flutter::CursorHandler>( |
| internal_plugin_messenger, binding_handler_.get()); |
| |
| PhysicalWindowBounds bounds = binding_handler_->GetPhysicalWindowBounds(); |
| |
| SendWindowMetrics(bounds.width, bounds.height, |
| binding_handler_->GetDpiScale()); |
| } |
| |
| void FlutterWindowsView::OnWindowSizeChanged(size_t width, |
| size_t height) const { |
| surface_manager_->ResizeSurface(GetRenderTarget(), width, height); |
| SendWindowMetrics(width, height, binding_handler_->GetDpiScale()); |
| } |
| |
| void FlutterWindowsView::OnPointerMove(double x, double y) { |
| SendPointerMove(x, y); |
| } |
| |
| void FlutterWindowsView::OnPointerDown( |
| double x, |
| double y, |
| FlutterPointerMouseButtons flutter_button) { |
| if (flutter_button != 0) { |
| uint64_t mouse_buttons = mouse_state_.buttons | flutter_button; |
| SetMouseButtons(mouse_buttons); |
| SendPointerDown(x, y); |
| } |
| } |
| |
| void FlutterWindowsView::OnPointerUp( |
| double x, |
| double y, |
| FlutterPointerMouseButtons flutter_button) { |
| if (flutter_button != 0) { |
| uint64_t mouse_buttons = mouse_state_.buttons & ~flutter_button; |
| SetMouseButtons(mouse_buttons); |
| SendPointerUp(x, y); |
| } |
| } |
| |
| void FlutterWindowsView::OnPointerLeave() { |
| SendPointerLeave(); |
| } |
| |
| void FlutterWindowsView::OnText(const std::u16string& text) { |
| SendText(text); |
| } |
| |
| void FlutterWindowsView::OnKey(int key, |
| int scancode, |
| int action, |
| char32_t character) { |
| SendKey(key, scancode, action, character); |
| } |
| |
| void FlutterWindowsView::OnScroll(double x, |
| double y, |
| double delta_x, |
| double delta_y, |
| int scroll_offset_multiplier) { |
| SendScroll(x, y, delta_x, delta_y, scroll_offset_multiplier); |
| } |
| |
| // Sends new size information to FlutterEngine. |
| void FlutterWindowsView::SendWindowMetrics(size_t width, |
| size_t height, |
| double dpiScale) const { |
| if (engine_->engine() == nullptr) { |
| return; |
| } |
| |
| FlutterWindowMetricsEvent event = {}; |
| event.struct_size = sizeof(event); |
| event.width = width; |
| event.height = height; |
| event.pixel_ratio = dpiScale; |
| auto result = FlutterEngineSendWindowMetricsEvent(engine_->engine(), &event); |
| } |
| |
| void FlutterWindowsView::SendInitialBounds() { |
| PhysicalWindowBounds bounds = binding_handler_->GetPhysicalWindowBounds(); |
| |
| SendWindowMetrics(bounds.width, bounds.height, |
| binding_handler_->GetDpiScale()); |
| } |
| |
| // Set's |event_data|'s phase to either kMove or kHover depending on the current |
| // primary mouse button state. |
| void FlutterWindowsView::SetEventPhaseFromCursorButtonState( |
| FlutterPointerEvent* event_data) const { |
| // For details about this logic, see FlutterPointerPhase in the embedder.h |
| // file. |
| event_data->phase = |
| mouse_state_.buttons == 0 |
| ? mouse_state_.flutter_state_is_down ? FlutterPointerPhase::kUp |
| : FlutterPointerPhase::kHover |
| : mouse_state_.flutter_state_is_down ? FlutterPointerPhase::kMove |
| : FlutterPointerPhase::kDown; |
| } |
| |
| void FlutterWindowsView::SendPointerMove(double x, double y) { |
| FlutterPointerEvent event = {}; |
| event.x = x; |
| event.y = y; |
| SetEventPhaseFromCursorButtonState(&event); |
| SendPointerEventWithData(event); |
| } |
| |
| void FlutterWindowsView::SendPointerDown(double x, double y) { |
| FlutterPointerEvent event = {}; |
| SetEventPhaseFromCursorButtonState(&event); |
| event.x = x; |
| event.y = y; |
| SendPointerEventWithData(event); |
| SetMouseFlutterStateDown(true); |
| } |
| |
| void FlutterWindowsView::SendPointerUp(double x, double y) { |
| FlutterPointerEvent event = {}; |
| SetEventPhaseFromCursorButtonState(&event); |
| event.x = x; |
| event.y = y; |
| SendPointerEventWithData(event); |
| if (event.phase == FlutterPointerPhase::kUp) { |
| SetMouseFlutterStateDown(false); |
| } |
| } |
| |
| void FlutterWindowsView::SendPointerLeave() { |
| FlutterPointerEvent event = {}; |
| event.phase = FlutterPointerPhase::kRemove; |
| SendPointerEventWithData(event); |
| } |
| |
| void FlutterWindowsView::SendText(const std::u16string& text) { |
| for (const auto& handler : keyboard_hook_handlers_) { |
| handler->TextHook(this, text); |
| } |
| } |
| |
| void FlutterWindowsView::SendKey(int key, |
| int scancode, |
| int action, |
| char32_t character) { |
| for (const auto& handler : keyboard_hook_handlers_) { |
| handler->KeyboardHook(this, key, scancode, action, character); |
| } |
| } |
| |
| void FlutterWindowsView::SendScroll(double x, |
| double y, |
| double delta_x, |
| double delta_y, |
| int scroll_offset_multiplier) { |
| FlutterPointerEvent event = {}; |
| SetEventPhaseFromCursorButtonState(&event); |
| event.signal_kind = FlutterPointerSignalKind::kFlutterPointerSignalKindScroll; |
| event.x = x; |
| event.y = y; |
| event.scroll_delta_x = delta_x * scroll_offset_multiplier; |
| event.scroll_delta_y = delta_y * scroll_offset_multiplier; |
| SendPointerEventWithData(event); |
| } |
| |
| void FlutterWindowsView::SendPointerEventWithData( |
| const FlutterPointerEvent& event_data) { |
| // If sending anything other than an add, and the pointer isn't already added, |
| // synthesize an add to satisfy Flutter's expectations about events. |
| if (!mouse_state_.flutter_state_is_added && |
| event_data.phase != FlutterPointerPhase::kAdd) { |
| FlutterPointerEvent event = {}; |
| event.phase = FlutterPointerPhase::kAdd; |
| event.x = event_data.x; |
| event.y = event_data.y; |
| event.buttons = 0; |
| SendPointerEventWithData(event); |
| } |
| // Don't double-add (e.g., if events are delivered out of order, so an add has |
| // already been synthesized). |
| if (mouse_state_.flutter_state_is_added && |
| event_data.phase == FlutterPointerPhase::kAdd) { |
| return; |
| } |
| |
| FlutterPointerEvent event = event_data; |
| event.device_kind = kFlutterPointerDeviceKindMouse; |
| event.buttons = mouse_state_.buttons; |
| |
| // Set metadata that's always the same regardless of the event. |
| event.struct_size = sizeof(event); |
| event.timestamp = |
| std::chrono::duration_cast<std::chrono::microseconds>( |
| std::chrono::high_resolution_clock::now().time_since_epoch()) |
| .count(); |
| |
| FlutterEngineSendPointerEvent(engine_->engine(), &event, 1); |
| |
| if (event_data.phase == FlutterPointerPhase::kAdd) { |
| SetMouseFlutterStateAdded(true); |
| } else if (event_data.phase == FlutterPointerPhase::kRemove) { |
| SetMouseFlutterStateAdded(false); |
| ResetMouseState(); |
| } |
| } |
| |
| bool FlutterWindowsView::MakeCurrent() { |
| return surface_manager_->MakeCurrent(); |
| } |
| |
| bool FlutterWindowsView::MakeResourceCurrent() { |
| return surface_manager_->MakeResourceCurrent(); |
| } |
| |
| bool FlutterWindowsView::ClearContext() { |
| return surface_manager_->ClearContext(); |
| } |
| |
| bool FlutterWindowsView::SwapBuffers() { |
| return surface_manager_->SwapBuffers(); |
| } |
| |
| void FlutterWindowsView::CreateRenderSurface() { |
| PhysicalWindowBounds bounds = binding_handler_->GetPhysicalWindowBounds(); |
| surface_manager_->CreateSurface(GetRenderTarget(), bounds.width, |
| bounds.height); |
| } |
| |
| void FlutterWindowsView::DestroyRenderSurface() { |
| if (surface_manager_) { |
| surface_manager_->DestroySurface(); |
| } |
| } |
| |
| WindowsRenderTarget* FlutterWindowsView::GetRenderTarget() const { |
| return render_target_.get(); |
| } |
| |
| FlutterWindowsEngine* FlutterWindowsView::GetEngine() { |
| return engine_.get(); |
| } |
| |
| } // namespace flutter |