10 #include <shared_mutex>
13 #include "flutter/fml/logging.h"
14 #include "flutter/fml/paths.h"
15 #include "flutter/fml/platform/win/wstring_conversion.h"
16 #include "flutter/fml/synchronization/waitable_event.h"
20 #include "flutter/shell/platform/embedder/embedder_struct_macros.h"
30 #include "flutter/third_party/accessibility/ax/ax_node.h"
43 static std::chrono::nanoseconds SnapToNextTick(
44 std::chrono::nanoseconds value,
45 std::chrono::nanoseconds tick_phase,
46 std::chrono::nanoseconds tick_interval) {
47 std::chrono::nanoseconds offset = (tick_phase - value) % tick_interval;
48 if (offset != std::chrono::nanoseconds::zero())
49 offset = offset + tick_interval;
50 return value + offset;
57 FlutterRendererConfig GetOpenGLRendererConfig() {
58 FlutterRendererConfig config = {};
59 config.type = kOpenGL;
60 config.open_gl.struct_size =
sizeof(config.open_gl);
61 config.open_gl.make_current = [](
void*
user_data) ->
bool {
62 auto host =
static_cast<FlutterWindowsEngine*
>(
user_data);
63 if (!host->egl_manager()) {
66 return host->egl_manager()->render_context()->MakeCurrent();
68 config.open_gl.clear_current = [](
void*
user_data) ->
bool {
69 auto host =
static_cast<FlutterWindowsEngine*
>(
user_data);
70 if (!host->egl_manager()) {
73 return host->egl_manager()->render_context()->ClearCurrent();
75 config.open_gl.present = [](
void*
user_data) ->
bool { FML_UNREACHABLE(); };
76 config.open_gl.fbo_reset_after_present =
true;
77 config.open_gl.fbo_with_frame_info_callback =
78 [](
void*
user_data,
const FlutterFrameInfo* info) -> uint32_t {
81 config.open_gl.gl_proc_resolver = [](
void*
user_data,
82 const char* what) ->
void* {
83 return reinterpret_cast<void*
>(eglGetProcAddress(what));
85 config.open_gl.make_resource_current = [](
void*
user_data) ->
bool {
86 auto host =
static_cast<FlutterWindowsEngine*
>(
user_data);
87 if (!host->egl_manager()) {
90 return host->egl_manager()->resource_context()->MakeCurrent();
92 config.open_gl.gl_external_texture_frame_callback =
94 FlutterOpenGLTexture* texture) ->
bool {
95 auto host =
static_cast<FlutterWindowsEngine*
>(
user_data);
96 if (!host->texture_registrar()) {
99 return host->texture_registrar()->PopulateTexture(
texture_id, width, height,
109 FlutterRendererConfig GetSoftwareRendererConfig() {
110 FlutterRendererConfig config = {};
111 config.type = kSoftware;
112 config.software.struct_size =
sizeof(config.software);
113 config.software.surface_present_callback =
114 [](
void*
user_data,
const void* allocation,
size_t row_bytes,
124 const FlutterPlatformMessage& engine_message) {
127 message.channel = engine_message.channel;
128 message.message = engine_message.message;
129 message.message_size = engine_message.message_size;
130 message.response_handle = engine_message.response_handle;
136 FlutterLocale CovertToFlutterLocale(
const LanguageInfo& info) {
137 FlutterLocale locale = {};
138 locale.struct_size =
sizeof(FlutterLocale);
139 locale.language_code = info.language.c_str();
140 if (!info.region.empty()) {
141 locale.country_code = info.region.c_str();
143 if (!info.script.empty()) {
144 locale.script_code = info.script.c_str();
153 std::shared_ptr<WindowsProcTable> windows_proc_table)
155 windows_proc_table_(std::move(windows_proc_table)),
156 aot_data_(nullptr, nullptr),
158 if (windows_proc_table_ ==
nullptr) {
159 windows_proc_table_ = std::make_shared<WindowsProcTable>();
164 embedder_api_.struct_size =
sizeof(FlutterEngineProcTable);
165 FlutterEngineGetProcAddresses(&embedder_api_);
168 std::make_unique<TaskRunner>(
169 embedder_api_.GetCurrentTime, [
this](
const auto* task) {
172 <<
"Cannot post an engine task when engine is not running.";
175 if (embedder_api_.RunTask(engine_, task) != kSuccess) {
176 FML_LOG(ERROR) <<
"Failed to post an engine task.";
183 messenger_->SetEngine(
this);
184 plugin_registrar_ = std::make_unique<FlutterDesktopPluginRegistrar>();
185 plugin_registrar_->engine =
this;
188 std::make_unique<BinaryMessengerImpl>(messenger_->ToRef());
189 message_dispatcher_ =
190 std::make_unique<IncomingMessageDispatcher>(messenger_->ToRef());
193 std::make_unique<FlutterWindowsTextureRegistrar>(
this, gl_);
196 auto& switches = project_->GetSwitches();
197 bool enable_impeller =
true;
199 enable_impeller =
true;
201 enable_impeller =
false;
203 for (
const auto& env_switch : switches) {
204 if (env_switch ==
"--enable-impeller" ||
205 env_switch ==
"--enable-impeller=true") {
206 enable_impeller =
true;
207 }
else if (env_switch ==
"--enable-impeller=false") {
208 enable_impeller =
false;
211 enable_impeller_ = enable_impeller;
215 window_proc_delegate_manager_ = std::make_unique<WindowProcDelegateManager>();
217 display_manager_ = std::make_shared<DisplayManagerWin32>(
this);
219 window_proc_delegate_manager_->RegisterTopLevelWindowProcDelegate(
220 [](HWND hwnd, UINT msg, WPARAM wpar, LPARAM lpar,
void*
user_data,
223 FlutterWindowsEngine* that =
224 static_cast<FlutterWindowsEngine*
>(
user_data);
226 BASE_DCHECK(that->display_manager_);
227 if (that->display_manager_->HandleWindowMessage(hwnd, msg, wpar, lpar,
232 BASE_DCHECK(that->lifecycle_manager_);
234 that->lifecycle_manager_->WindowProc(hwnd, msg, wpar, lpar, result);
238 auto message_result =
239 that->window_manager_->HandleMessage(hwnd, msg, wpar, lpar);
240 if (message_result) {
241 *result = *message_result;
246 static_cast<void*
>(
this));
251 internal_plugin_registrar_ =
252 std::make_unique<PluginRegistrar>(plugin_registrar_.get());
254 accessibility_plugin_ = std::make_unique<AccessibilityPlugin>(
this);
256 accessibility_plugin_.get());
259 std::make_unique<CursorHandler>(messenger_wrapper_.get(),
this);
261 std::make_unique<PlatformHandler>(messenger_wrapper_.get(),
this);
262 window_manager_ = std::make_unique<WindowManager>(
this);
263 settings_plugin_ = std::make_unique<SettingsPlugin>(messenger_wrapper_.get(),
267 FlutterWindowsEngine::~FlutterWindowsEngine() {
268 messenger_->SetEngine(
nullptr);
276 void FlutterWindowsEngine::SetSwitches(
277 const std::vector<std::string>& switches) {
281 bool FlutterWindowsEngine::Run() {
285 bool FlutterWindowsEngine::Run(std::string_view entrypoint) {
286 if (!project_->HasValidPaths()) {
287 FML_LOG(ERROR) <<
"Missing or unresolvable paths to assets.";
290 std::string assets_path_string = fml::PathToUtf8(project_->assets_path());
291 std::string icu_path_string = fml::PathToUtf8(project_->icu_path());
292 if (embedder_api_.RunsAOTCompiledDartCode()) {
293 aot_data_ = project_->LoadAotData(embedder_api_);
295 FML_LOG(ERROR) <<
"Unable to start engine without AOT data.";
303 std::string executable_name = GetExecutableName();
304 std::vector<const char*> argv = {executable_name.c_str()};
305 std::vector<std::string> switches = project_->GetSwitches();
306 if (enable_impeller_) {
307 if (std::find(switches.begin(), switches.end(),
308 "--impeller-use-sdfs=true") == switches.end() &&
309 std::find(switches.begin(), switches.end(),
310 "--impeller-use-sdfs=false") == switches.end()) {
311 switches.push_back(
"--impeller-use-sdfs=true");
313 if (std::find(switches.begin(), switches.end(),
"--enable-impeller") ==
315 std::find(switches.begin(), switches.end(),
"--enable-impeller=true") ==
319 switches.push_back(
"--enable-impeller");
321 }
else if (project_->impeller_switch() == FlutterImpellerSwitch::Disabled) {
322 if (std::find(switches.begin(), switches.end(),
323 "--enable-impeller=false") == switches.end()) {
326 switches.push_back(
"--enable-impeller=false");
329 if (project_->enable_flutter_gpu()) {
330 if (std::find(switches.begin(), switches.end(),
"--enable-flutter-gpu") ==
332 std::find(switches.begin(), switches.end(),
333 "--enable-flutter-gpu=true") == switches.end()) {
336 switches.push_back(
"--enable-flutter-gpu");
340 switches.begin(), switches.end(), std::back_inserter(argv),
341 [](
const std::string& arg) ->
const char* { return arg.c_str(); });
343 const std::vector<std::string>& entrypoint_args =
344 project_->dart_entrypoint_arguments();
345 std::vector<const char*> entrypoint_argv;
347 entrypoint_args.begin(), entrypoint_args.end(),
348 std::back_inserter(entrypoint_argv),
349 [](
const std::string& arg) ->
const char* { return arg.c_str(); });
352 FlutterTaskRunnerDescription platform_task_runner = {};
353 platform_task_runner.struct_size =
sizeof(FlutterTaskRunnerDescription);
354 platform_task_runner.user_data = task_runner_.get();
355 platform_task_runner.runs_task_on_current_thread_callback =
359 platform_task_runner.post_task_callback = [](FlutterTask task,
360 uint64_t target_time_nanos,
365 FlutterCustomTaskRunners custom_task_runners = {};
366 custom_task_runners.struct_size =
sizeof(FlutterCustomTaskRunners);
367 custom_task_runners.platform_task_runner = &platform_task_runner;
368 custom_task_runners.thread_priority_setter =
371 if (project_->ui_thread_policy() !=
373 custom_task_runners.ui_task_runner = &platform_task_runner;
375 FML_LOG(WARNING) <<
"Running with unmerged platform and UI threads. This "
376 "will be removed in future.";
379 FlutterProjectArgs args = {};
380 args.struct_size =
sizeof(FlutterProjectArgs);
381 args.shutdown_dart_vm_when_done =
true;
382 args.assets_path = assets_path_string.c_str();
383 args.icu_data_path = icu_path_string.c_str();
384 args.command_line_argc =
static_cast<int>(argv.size());
385 args.command_line_argv = argv.empty() ? nullptr : argv.data();
386 args.engine_id =
reinterpret_cast<int64_t
>(
this);
394 if (!project_->dart_entrypoint().empty() && !entrypoint.empty() &&
395 project_->dart_entrypoint() != entrypoint) {
396 FML_LOG(ERROR) <<
"Conflicting entrypoints were specified in "
397 "FlutterDesktopEngineProperties.dart_entrypoint and "
398 "FlutterDesktopEngineRun(engine, entry_point). ";
401 if (!entrypoint.empty()) {
402 args.custom_dart_entrypoint = entrypoint.data();
403 }
else if (!project_->dart_entrypoint().empty()) {
404 args.custom_dart_entrypoint = project_->dart_entrypoint().c_str();
406 args.dart_entrypoint_argc =
static_cast<int>(entrypoint_argv.size());
407 args.dart_entrypoint_argv =
408 entrypoint_argv.empty() ? nullptr : entrypoint_argv.data();
409 args.platform_message_callback =
410 [](
const FlutterPlatformMessage* engine_message,
415 args.vsync_callback = [](
void*
user_data, intptr_t baton) ->
void {
419 args.on_pre_engine_restart_callback = [](
void*
user_data) {
423 args.update_semantics_callback2 = [](
const FlutterSemanticsUpdate2* update,
427 auto view = host->
view(update->view_id);
433 if (!accessibility_bridge) {
437 for (
size_t i = 0; i < update->node_count; i++) {
438 const FlutterSemanticsNode2* node = update->nodes[i];
439 accessibility_bridge->AddFlutterSemanticsNodeUpdate(*node);
442 for (
size_t i = 0; i < update->custom_action_count; i++) {
443 const FlutterSemanticsCustomAction2*
action = update->custom_actions[i];
444 accessibility_bridge->AddFlutterSemanticsCustomActionUpdate(*
action);
447 accessibility_bridge->CommitUpdates();
449 args.root_isolate_create_callback = [](
void*
user_data) {
451 if (host->root_isolate_create_callback_) {
452 host->root_isolate_create_callback_();
455 args.channel_update_callback = [](
const FlutterChannelUpdate* update,
458 if (SAFE_ACCESS(update, channel,
nullptr) !=
nullptr) {
459 std::string channel_name(update->channel);
460 host->OnChannelUpdate(std::move(channel_name),
461 SAFE_ACCESS(update, listening,
false));
464 args.view_focus_change_request_callback =
465 [](
const FlutterViewFocusChangeRequest* request,
void*
user_data) {
470 args.custom_task_runners = &custom_task_runners;
472 if (!platform_view_plugin_) {
473 platform_view_plugin_ = std::make_unique<PlatformViewPlugin>(
474 messenger_wrapper_.get(), task_runner_.get());
477 auto resolver = [](
const char* name) ->
void* {
478 return reinterpret_cast<void*
>(::eglGetProcAddress(name));
484 std::make_unique<CompositorOpenGL>(
this, resolver, enable_impeller_);
486 compositor_ = std::make_unique<CompositorSoftware>();
489 FlutterCompositor compositor = {};
490 compositor.struct_size =
sizeof(FlutterCompositor);
491 compositor.user_data =
this;
492 compositor.create_backing_store_callback =
493 [](
const FlutterBackingStoreConfig* config,
494 FlutterBackingStore* backing_store_out,
void*
user_data) ->
bool {
497 return host->compositor_->CreateBackingStore(*config, backing_store_out);
500 compositor.collect_backing_store_callback =
501 [](
const FlutterBackingStore* backing_store,
void*
user_data) ->
bool {
504 return host->compositor_->CollectBackingStore(backing_store);
507 compositor.present_view_callback =
508 [](
const FlutterPresentViewInfo* info) ->
bool {
511 return host->Present(info);
513 args.compositor = &compositor;
516 args.aot_data = aot_data_.get();
521 FML_DCHECK(!egl_manager_ || !egl_manager_->HasContextCurrent());
523 FlutterRendererConfig renderer_config;
525 if (enable_impeller_) {
529 FML_LOG(ERROR) <<
"Could not create surface manager. Impeller backend "
530 "does not support software rendering.";
533 renderer_config = GetOpenGLRendererConfig();
536 egl_manager_ ? GetOpenGLRendererConfig() : GetSoftwareRendererConfig();
539 auto result = embedder_api_.Run(FLUTTER_ENGINE_VERSION, &renderer_config,
540 &args,
this, &engine_);
541 if (result != kSuccess || engine_ ==
nullptr) {
542 FML_LOG(ERROR) <<
"Failed to start Flutter engine: error " << result;
546 display_manager_->UpdateDisplays();
550 settings_plugin_->StartWatching();
551 settings_plugin_->SendSettings();
553 InitializeKeyboard();
558 bool FlutterWindowsEngine::Stop() {
560 window_manager_->OnEngineShutdown();
561 for (
const auto& [
callback, registrar] :
562 plugin_registrar_destruction_callbacks_) {
565 FlutterEngineResult result = embedder_api_.Shutdown(engine_);
567 return (result == kSuccess);
572 std::unique_ptr<FlutterWindowsView> FlutterWindowsEngine::CreateView(
573 std::unique_ptr<WindowBindingHandler> window,
574 bool is_sized_to_content,
575 const BoxConstraints& box_constraints,
577 auto view_id = next_view_id_;
578 auto view = std::make_unique<FlutterWindowsView>(
579 view_id,
this, std::move(window), is_sized_to_content, box_constraints,
580 sizing_delegate, windows_proc_table_);
582 view->CreateRenderSurface();
583 view->UpdateSemanticsEnabled(semantics_enabled_);
590 std::unique_lock write_lock(views_mutex_);
591 FML_DCHECK(views_.find(view_id) == views_.end());
592 views_[view_id] = view.get();
595 if (!view->IsImplicitView()) {
596 FML_DCHECK(running());
599 fml::AutoResetWaitableEvent latch;
602 Captures captures = {};
604 FlutterWindowMetricsEvent metrics = view->CreateWindowMetricsEvent();
606 FlutterAddViewInfo info = {};
607 info.struct_size =
sizeof(FlutterAddViewInfo);
608 info.view_id = view_id;
609 info.view_metrics = &metrics;
610 info.user_data = &captures;
611 info.add_view_callback = [](
const FlutterAddViewResult* result) {
612 Captures* captures =
reinterpret_cast<Captures*
>(result->user_data);
613 captures->added = result->added;
614 captures->latch.Signal();
617 FlutterEngineResult result = embedder_api_.AddView(engine_, &info);
618 if (result != kSuccess) {
620 <<
"Starting the add view operation failed. FlutterEngineAddView "
621 "returned an unexpected result: "
622 << result <<
". This indicates a bug in the Windows embedder.";
632 captures.latch.Wait();
634 if (!captures.added) {
638 FML_LOG(ERROR) <<
"FlutterEngineAddView failed to add view";
639 std::unique_lock write_lock(views_mutex_);
640 views_.erase(view_id);
645 return std::move(view);
649 FML_DCHECK(running());
656 fml::AutoResetWaitableEvent latch;
659 Captures captures = {};
661 FlutterRemoveViewInfo info = {};
662 info.struct_size =
sizeof(FlutterRemoveViewInfo);
663 info.view_id = view_id;
664 info.user_data = &captures;
665 info.remove_view_callback = [](
const FlutterRemoveViewResult* result) {
669 Captures* captures =
reinterpret_cast<Captures*
>(result->user_data);
670 captures->removed = result->removed;
671 captures->latch.Signal();
674 FlutterEngineResult result = embedder_api_.RemoveView(engine_, &info);
675 if (result != kSuccess) {
676 FML_LOG(ERROR) <<
"Starting the remove view operation failed. "
677 "FlutterEngineRemoveView "
678 "returned an unexpected result: "
680 <<
". This indicates a bug in the Windows embedder.";
690 captures.latch.Wait();
692 if (!captures.removed) {
695 FML_LOG(ERROR) <<
"FlutterEngineRemoveView failed to remove view";
703 std::unique_lock write_lock(views_mutex_);
705 FML_DCHECK(views_.find(view_id) != views_.end());
709 if (text_input_plugin_) {
710 text_input_plugin_->OnViewRemoved(view_id);
713 views_.erase(view_id);
717 void FlutterWindowsEngine::OnVsync(intptr_t baton) {
718 std::chrono::nanoseconds current_time =
719 std::chrono::nanoseconds(embedder_api_.GetCurrentTime());
720 std::chrono::nanoseconds frame_interval = FrameInterval();
721 auto next = SnapToNextTick(current_time, start_time_, frame_interval);
722 embedder_api_.OnVsync(engine_, baton, next.count(),
723 (next + frame_interval).count());
726 std::chrono::nanoseconds FlutterWindowsEngine::FrameInterval() {
727 if (frame_interval_override_.has_value()) {
728 return frame_interval_override_.value();
730 uint64_t interval = 16600000;
732 DWM_TIMING_INFO timing_info = {};
733 timing_info.cbSize =
sizeof(timing_info);
734 HRESULT result = DwmGetCompositionTimingInfo(NULL, &timing_info);
735 if (result == S_OK && timing_info.rateRefresh.uiDenominator > 0 &&
736 timing_info.rateRefresh.uiNumerator > 0) {
737 interval =
static_cast<double>(timing_info.rateRefresh.uiDenominator *
739 static_cast<double>(timing_info.rateRefresh.uiNumerator);
742 return std::chrono::nanoseconds(interval);
746 std::shared_lock read_lock(views_mutex_);
748 auto iterator = views_.find(view_id);
749 if (iterator == views_.end()) {
753 return iterator->second;
758 return plugin_registrar_.get();
761 void FlutterWindowsEngine::AddPluginRegistrarDestructionCallback(
764 plugin_registrar_destruction_callbacks_[
callback] = registrar;
767 void FlutterWindowsEngine::UpdateDisplay(
768 const std::vector<FlutterEngineDisplay>&
displays) {
770 embedder_api_.NotifyDisplayUpdate(engine_,
771 kFlutterEngineDisplaysUpdateTypeStartup,
776 void FlutterWindowsEngine::SendWindowMetricsEvent(
777 const FlutterWindowMetricsEvent& event) {
779 embedder_api_.SendWindowMetricsEvent(engine_, &event);
783 void FlutterWindowsEngine::SendPointerEvent(
const FlutterPointerEvent& event) {
785 embedder_api_.SendPointerEvent(engine_, &event, 1);
789 void FlutterWindowsEngine::SendKeyEvent(
const FlutterKeyEvent& event,
797 void FlutterWindowsEngine::SendViewFocusEvent(
798 const FlutterViewFocusEvent& event) {
800 embedder_api_.SendViewFocusEvent(engine_, &event);
804 bool FlutterWindowsEngine::SendPlatformMessage(
807 const size_t message_size,
810 FlutterPlatformMessageResponseHandle* response_handle =
nullptr;
811 if (reply !=
nullptr &&
user_data !=
nullptr) {
812 FlutterEngineResult result =
813 embedder_api_.PlatformMessageCreateResponseHandle(
814 engine_, reply,
user_data, &response_handle);
815 if (result != kSuccess) {
816 FML_LOG(ERROR) <<
"Failed to create response handle";
821 FlutterPlatformMessage platform_message = {
822 sizeof(FlutterPlatformMessage),
829 FlutterEngineResult message_result =
830 embedder_api_.SendPlatformMessage(engine_, &platform_message);
831 if (response_handle !=
nullptr) {
832 embedder_api_.PlatformMessageReleaseResponseHandle(engine_,
835 return message_result == kSuccess;
838 void FlutterWindowsEngine::SendPlatformMessageResponse(
841 size_t data_length) {
842 embedder_api_.SendPlatformMessageResponse(engine_, handle, data, data_length);
845 void FlutterWindowsEngine::HandlePlatformMessage(
846 const FlutterPlatformMessage* engine_message) {
847 if (engine_message->struct_size !=
sizeof(FlutterPlatformMessage)) {
848 FML_LOG(ERROR) <<
"Invalid message size received. Expected: "
849 <<
sizeof(FlutterPlatformMessage) <<
" but received "
850 << engine_message->struct_size;
854 auto message = ConvertToDesktopMessage(*engine_message);
856 message_dispatcher_->HandleMessage(
message, [
this] {}, [
this] {});
859 void FlutterWindowsEngine::ReloadSystemFonts() {
860 embedder_api_.ReloadSystemFonts(engine_);
863 void FlutterWindowsEngine::ScheduleFrame() {
864 embedder_api_.ScheduleFrame(engine_);
867 void FlutterWindowsEngine::SetNextFrameCallback(fml::closure
callback) {
868 next_frame_callback_ = std::move(
callback);
870 embedder_api_.SetNextFrameCallback(
878 self->task_runner_->PostTask(std::move(self->next_frame_callback_));
883 HCURSOR FlutterWindowsEngine::GetCursorByName(
884 const std::string& cursor_name)
const {
885 static auto* cursors =
new std::map<std::string, const wchar_t*>{
886 {
"allScroll", IDC_SIZEALL},
887 {
"basic", IDC_ARROW},
889 {
"forbidden", IDC_NO},
891 {
"move", IDC_SIZEALL},
894 {
"precise", IDC_CROSS},
895 {
"progress", IDC_APPSTARTING},
897 {
"resizeColumn", IDC_SIZEWE},
898 {
"resizeDown", IDC_SIZENS},
899 {
"resizeDownLeft", IDC_SIZENESW},
900 {
"resizeDownRight", IDC_SIZENWSE},
901 {
"resizeLeft", IDC_SIZEWE},
902 {
"resizeLeftRight", IDC_SIZEWE},
903 {
"resizeRight", IDC_SIZEWE},
904 {
"resizeRow", IDC_SIZENS},
905 {
"resizeUp", IDC_SIZENS},
906 {
"resizeUpDown", IDC_SIZENS},
907 {
"resizeUpLeft", IDC_SIZENWSE},
908 {
"resizeUpRight", IDC_SIZENESW},
909 {
"resizeUpLeftDownRight", IDC_SIZENWSE},
910 {
"resizeUpRightDownLeft", IDC_SIZENESW},
913 const wchar_t* idc_name = IDC_ARROW;
914 auto it = cursors->find(cursor_name);
915 if (it != cursors->end()) {
916 idc_name = it->second;
918 return windows_proc_table_->LoadCursor(
nullptr, idc_name);
923 std::shared_lock read_lock(views_mutex_);
924 auto const iterator =
925 std::find_if(views_.begin(), views_.end(), [hwnd](
auto const& pair) {
926 FlutterWindowsView* const view = pair.second;
927 return GetAncestor(view->GetWindowHandle(), GA_ROOT) == hwnd;
929 if (iterator != views_.end()) {
930 return iterator->second;
935 void FlutterWindowsEngine::SendSystemLocales() {
936 std::vector<LanguageInfo> languages =
938 std::vector<FlutterLocale> flutter_locales;
939 flutter_locales.reserve(languages.size());
940 for (
const auto& info : languages) {
941 flutter_locales.push_back(CovertToFlutterLocale(info));
944 std::vector<const FlutterLocale*> flutter_locale_list;
945 flutter_locale_list.reserve(flutter_locales.size());
946 std::transform(flutter_locales.begin(), flutter_locales.end(),
947 std::back_inserter(flutter_locale_list),
948 [](
const auto& arg) ->
const auto* { return &arg; });
949 embedder_api_.UpdateLocales(engine_, flutter_locale_list.data(),
950 flutter_locale_list.size());
953 void FlutterWindowsEngine::InitializeKeyboard() {
954 auto internal_plugin_messenger = internal_plugin_registrar_->messenger();
955 KeyboardKeyEmbedderHandler::GetKeyStateHandler get_key_state = GetKeyState;
956 KeyboardKeyEmbedderHandler::MapVirtualKeyToScanCode map_vk_to_scan =
957 [](UINT virtual_key,
bool extended) {
958 return MapVirtualKey(virtual_key,
959 extended ? MAPVK_VK_TO_VSC_EX : MAPVK_VK_TO_VSC);
961 keyboard_key_handler_ = std::move(CreateKeyboardKeyHandler(
962 internal_plugin_messenger, get_key_state, map_vk_to_scan));
964 std::move(CreateTextInputPlugin(internal_plugin_messenger));
967 std::unique_ptr<KeyboardHandlerBase>
968 FlutterWindowsEngine::CreateKeyboardKeyHandler(
972 auto keyboard_key_handler = std::make_unique<KeyboardKeyHandler>(messenger);
973 keyboard_key_handler->AddDelegate(
974 std::make_unique<KeyboardKeyEmbedderHandler>(
975 [
this](
const FlutterKeyEvent& event, FlutterKeyEventCallback
callback,
979 get_key_state, map_vk_to_scan));
980 keyboard_key_handler->AddDelegate(
981 std::make_unique<KeyboardKeyChannelHandler>(messenger));
982 keyboard_key_handler->InitKeyboardChannel();
983 return keyboard_key_handler;
986 std::unique_ptr<TextInputPlugin> FlutterWindowsEngine::CreateTextInputPlugin(
988 return std::make_unique<TextInputPlugin>(messenger,
this);
991 bool FlutterWindowsEngine::RegisterExternalTexture(int64_t
texture_id) {
992 return (embedder_api_.RegisterExternalTexture(engine_,
texture_id) ==
996 bool FlutterWindowsEngine::UnregisterExternalTexture(int64_t
texture_id) {
997 return (embedder_api_.UnregisterExternalTexture(engine_,
texture_id) ==
1001 bool FlutterWindowsEngine::MarkExternalTextureFrameAvailable(
1003 return (embedder_api_.MarkExternalTextureFrameAvailable(
1007 bool FlutterWindowsEngine::PostRasterThreadTask(fml::closure
callback)
const {
1011 auto captures =
new Captures();
1012 captures->callback = std::move(
callback);
1013 if (embedder_api_.PostRenderThreadTask(
1016 auto captures = reinterpret_cast<Captures*>(opaque);
1017 captures->callback();
1020 captures) == kSuccess) {
1027 bool FlutterWindowsEngine::DispatchSemanticsAction(
1030 FlutterSemanticsAction
action,
1031 fml::MallocMapping data) {
1032 FlutterSendSemanticsActionInfo info{
1033 .struct_size =
sizeof(FlutterSendSemanticsActionInfo),
1037 .data = data.GetMapping(),
1038 .data_length = data.GetSize(),
1040 return (embedder_api_.SendSemanticsAction(engine_, &info));
1043 void FlutterWindowsEngine::UpdateSemanticsEnabled(
bool enabled) {
1044 if (engine_ && semantics_enabled_ != enabled) {
1045 std::shared_lock read_lock(views_mutex_);
1047 semantics_enabled_ = enabled;
1048 embedder_api_.UpdateSemanticsEnabled(engine_, enabled);
1049 for (
auto iterator = views_.begin(); iterator != views_.end(); iterator++) {
1050 iterator->second->UpdateSemanticsEnabled(enabled);
1055 void FlutterWindowsEngine::OnPreEngineRestart() {
1057 InitializeKeyboard();
1060 std::string FlutterWindowsEngine::GetExecutableName()
const {
1061 std::pair<bool, std::string> result = fml::paths::GetExecutablePath();
1063 const std::string& executable_path = result.second;
1064 size_t last_separator = executable_path.find_last_of(
"/\\");
1065 if (last_separator == std::string::npos ||
1066 last_separator == executable_path.size() - 1) {
1067 return executable_path;
1069 return executable_path.substr(last_separator + 1);
1074 void FlutterWindowsEngine::UpdateAccessibilityFeatures() {
1075 UpdateHighContrastMode();
1078 void FlutterWindowsEngine::UpdateHighContrastMode() {
1079 high_contrast_enabled_ = windows_proc_table_->GetHighContrastEnabled();
1081 SendAccessibilityFeatures();
1082 settings_plugin_->UpdateHighContrastMode(high_contrast_enabled_);
1085 void FlutterWindowsEngine::SendAccessibilityFeatures() {
1088 if (high_contrast_enabled_) {
1090 FlutterAccessibilityFeature::kFlutterAccessibilityFeatureHighContrast;
1093 embedder_api_.UpdateAccessibilityFeatures(
1094 engine_,
static_cast<FlutterAccessibilityFeature
>(flags));
1097 void FlutterWindowsEngine::RequestApplicationQuit(HWND hwnd,
1101 platform_handler_->RequestAppExit(hwnd, wparam, lparam, exit_type, 0);
1104 void FlutterWindowsEngine::OnQuit(std::optional<HWND> hwnd,
1105 std::optional<WPARAM> wparam,
1106 std::optional<LPARAM> lparam,
1108 lifecycle_manager_->Quit(hwnd, wparam, lparam, exit_code);
1111 void FlutterWindowsEngine::OnDwmCompositionChanged() {
1112 if (display_manager_) {
1113 display_manager_->UpdateDisplays();
1116 std::shared_lock read_lock(views_mutex_);
1117 for (
auto iterator = views_.begin(); iterator != views_.end(); iterator++) {
1118 iterator->second->OnDwmCompositionChanged();
1122 void FlutterWindowsEngine::OnWindowStateEvent(HWND hwnd,
1124 lifecycle_manager_->OnWindowStateEvent(hwnd, event);
1127 std::optional<LRESULT> FlutterWindowsEngine::ProcessExternalWindowMessage(
1132 if (lifecycle_manager_) {
1133 return lifecycle_manager_->ExternalWindowMessage(hwnd,
message, wparam,
1136 return std::nullopt;
1139 void FlutterWindowsEngine::UpdateFlutterCursor(
1140 const std::string& cursor_name)
const {
1141 SetFlutterCursor(GetCursorByName(cursor_name));
1144 void FlutterWindowsEngine::SetFlutterCursor(HCURSOR cursor)
const {
1145 windows_proc_table_->SetCursor(cursor);
1148 void FlutterWindowsEngine::OnChannelUpdate(std::string name,
bool listening) {
1149 if (name ==
"flutter/platform" && listening) {
1150 lifecycle_manager_->BeginProcessingExit();
1151 }
else if (name ==
"flutter/lifecycle" && listening) {
1152 lifecycle_manager_->BeginProcessingLifecycle();
1156 void FlutterWindowsEngine::OnViewFocusChangeRequest(
1157 const FlutterViewFocusChangeRequest* request) {
1158 std::shared_lock read_lock(views_mutex_);
1160 auto iterator = views_.find(request->view_id);
1161 if (iterator == views_.end()) {
1169 bool FlutterWindowsEngine::Present(
const FlutterPresentViewInfo* info) {
1173 std::shared_lock read_lock(views_mutex_);
1175 auto iterator = views_.find(info->view_id);
1176 if (iterator == views_.end()) {
1180 FlutterWindowsView* view = iterator->second;
1182 return compositor_->Present(view, info->layers, info->layers_count);
1185 bool FlutterWindowsEngine::HandleDisplayMonitorMessage(HWND hwnd,
1190 if (!display_manager_) {
1194 return display_manager_->HandleWindowMessage(hwnd,
message, wparam, lparam,
static void SetUp(BinaryMessenger *binary_messenger, AccessibilityPlugin *plugin)
FlutterWindowsEngine(const FlutterProjectBundle &project, std::shared_ptr< WindowsProcTable > windows_proc_table=nullptr)
FlutterWindowsView * view(FlutterViewId view_id) const
void OnPreEngineRestart()
virtual void OnViewFocusChangeRequest(const FlutterViewFocusChangeRequest *request)
void HandlePlatformMessage(const FlutterPlatformMessage *)
void OnVsync(intptr_t baton)
void SetSwitches(const std::vector< std::string > &switches)
std::weak_ptr< AccessibilityBridgeWindows > accessibility_bridge()
std::function< SHORT(UINT, bool)> MapVirtualKeyToScanCode
std::function< SHORT(int)> GetKeyStateHandler
static std::unique_ptr< Manager > Create(GpuPreference gpu_preference)
static std::shared_ptr< ProcTable > Create()
std::vector< FlutterEngineDisplay > * displays
void(* FlutterDesktopBinaryReply)(const uint8_t *data, size_t data_size, void *user_data)
struct _FlutterPlatformMessageResponseHandle FlutterDesktopMessageResponseHandle
void(* FlutterDesktopOnPluginRegistrarDestroyed)(FlutterDesktopPluginRegistrarRef)
static constexpr char kAccessibilityChannelName[]
FlutterDesktopBinaryReply callback
std::vector< LanguageInfo > GetPreferredLanguageInfo(const WindowsProcTable &windows_proc_table)
WindowStateEvent
An event representing a change in window state that may update the.
static void WindowsPlatformThreadPrioritySetter(FlutterThreadPriority priority)
constexpr FlutterViewId kImplicitViewId