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"
28 #include "flutter/third_party/accessibility/ax/ax_node.h"
41 static std::chrono::nanoseconds SnapToNextTick(
42 std::chrono::nanoseconds value,
43 std::chrono::nanoseconds tick_phase,
44 std::chrono::nanoseconds tick_interval) {
45 std::chrono::nanoseconds offset = (tick_phase - value) % tick_interval;
46 if (offset != std::chrono::nanoseconds::zero())
47 offset = offset + tick_interval;
48 return value + offset;
55 FlutterRendererConfig GetOpenGLRendererConfig() {
56 FlutterRendererConfig config = {};
57 config.type = kOpenGL;
58 config.open_gl.struct_size =
sizeof(config.open_gl);
59 config.open_gl.make_current = [](
void*
user_data) ->
bool {
60 auto host =
static_cast<FlutterWindowsEngine*
>(
user_data);
61 if (!host->egl_manager()) {
64 return host->egl_manager()->render_context()->MakeCurrent();
66 config.open_gl.clear_current = [](
void*
user_data) ->
bool {
67 auto host =
static_cast<FlutterWindowsEngine*
>(
user_data);
68 if (!host->egl_manager()) {
71 return host->egl_manager()->render_context()->ClearCurrent();
73 config.open_gl.present = [](
void*
user_data) ->
bool { FML_UNREACHABLE(); };
74 config.open_gl.fbo_reset_after_present =
true;
75 config.open_gl.fbo_with_frame_info_callback =
76 [](
void*
user_data,
const FlutterFrameInfo* info) -> uint32_t {
79 config.open_gl.gl_proc_resolver = [](
void*
user_data,
80 const char* what) ->
void* {
81 return reinterpret_cast<void*
>(eglGetProcAddress(what));
83 config.open_gl.make_resource_current = [](
void*
user_data) ->
bool {
84 auto host =
static_cast<FlutterWindowsEngine*
>(
user_data);
85 if (!host->egl_manager()) {
88 return host->egl_manager()->resource_context()->MakeCurrent();
90 config.open_gl.gl_external_texture_frame_callback =
92 FlutterOpenGLTexture* texture) ->
bool {
93 auto host =
static_cast<FlutterWindowsEngine*
>(
user_data);
94 if (!host->texture_registrar()) {
97 return host->texture_registrar()->PopulateTexture(
texture_id, width, height,
107 FlutterRendererConfig GetSoftwareRendererConfig() {
108 FlutterRendererConfig config = {};
109 config.type = kSoftware;
110 config.software.struct_size =
sizeof(config.software);
111 config.software.surface_present_callback =
112 [](
void*
user_data,
const void* allocation,
size_t row_bytes,
122 const FlutterPlatformMessage& engine_message) {
125 message.channel = engine_message.channel;
126 message.message = engine_message.message;
127 message.message_size = engine_message.message_size;
128 message.response_handle = engine_message.response_handle;
134 FlutterLocale CovertToFlutterLocale(
const LanguageInfo& info) {
135 FlutterLocale locale = {};
136 locale.struct_size =
sizeof(FlutterLocale);
137 locale.language_code = info.language.c_str();
138 if (!info.region.empty()) {
139 locale.country_code = info.region.c_str();
141 if (!info.script.empty()) {
142 locale.script_code = info.script.c_str();
151 std::shared_ptr<WindowsProcTable> windows_proc_table)
153 windows_proc_table_(std::move(windows_proc_table)),
154 aot_data_(nullptr, nullptr),
156 if (windows_proc_table_ ==
nullptr) {
157 windows_proc_table_ = std::make_shared<WindowsProcTable>();
162 embedder_api_.struct_size =
sizeof(FlutterEngineProcTable);
163 FlutterEngineGetProcAddresses(&embedder_api_);
166 std::make_unique<TaskRunner>(
167 embedder_api_.GetCurrentTime, [
this](
const auto* task) {
170 <<
"Cannot post an engine task when engine is not running.";
173 if (embedder_api_.RunTask(engine_, task) != kSuccess) {
174 FML_LOG(ERROR) <<
"Failed to post an engine task.";
181 messenger_->SetEngine(
this);
182 plugin_registrar_ = std::make_unique<FlutterDesktopPluginRegistrar>();
183 plugin_registrar_->engine =
this;
186 std::make_unique<BinaryMessengerImpl>(messenger_->ToRef());
187 message_dispatcher_ =
188 std::make_unique<IncomingMessageDispatcher>(messenger_->ToRef());
191 std::make_unique<FlutterWindowsTextureRegistrar>(
this, gl_);
194 auto& switches = project_->GetSwitches();
195 enable_impeller_ = std::find(switches.begin(), switches.end(),
196 "--enable-impeller=true") != switches.end();
200 window_proc_delegate_manager_ = std::make_unique<WindowProcDelegateManager>();
201 window_proc_delegate_manager_->RegisterTopLevelWindowProcDelegate(
202 [](HWND hwnd, UINT msg, WPARAM wpar, LPARAM lpar,
void*
user_data,
207 BASE_DCHECK(that->lifecycle_manager_);
208 return that->lifecycle_manager_->WindowProc(hwnd, msg, wpar, lpar,
211 static_cast<void*
>(
this));
216 internal_plugin_registrar_ =
217 std::make_unique<PluginRegistrar>(plugin_registrar_.get());
219 accessibility_plugin_ = std::make_unique<AccessibilityPlugin>(
this);
221 accessibility_plugin_.get());
224 std::make_unique<CursorHandler>(messenger_wrapper_.get(),
this);
226 std::make_unique<PlatformHandler>(messenger_wrapper_.get(),
this);
227 settings_plugin_ = std::make_unique<SettingsPlugin>(messenger_wrapper_.get(),
231 FlutterWindowsEngine::~FlutterWindowsEngine() {
232 messenger_->SetEngine(
nullptr);
240 void FlutterWindowsEngine::SetSwitches(
241 const std::vector<std::string>& switches) {
245 bool FlutterWindowsEngine::Run() {
249 bool FlutterWindowsEngine::Run(std::string_view entrypoint) {
250 if (!project_->HasValidPaths()) {
251 FML_LOG(ERROR) <<
"Missing or unresolvable paths to assets.";
254 std::string assets_path_string = project_->assets_path().u8string();
255 std::string icu_path_string = project_->icu_path().u8string();
256 if (embedder_api_.RunsAOTCompiledDartCode()) {
257 aot_data_ = project_->LoadAotData(embedder_api_);
259 FML_LOG(ERROR) <<
"Unable to start engine without AOT data.";
267 std::string executable_name = GetExecutableName();
268 std::vector<const char*> argv = {executable_name.c_str()};
269 std::vector<std::string> switches = project_->GetSwitches();
271 switches.begin(), switches.end(), std::back_inserter(argv),
272 [](
const std::string& arg) ->
const char* { return arg.c_str(); });
274 const std::vector<std::string>& entrypoint_args =
275 project_->dart_entrypoint_arguments();
276 std::vector<const char*> entrypoint_argv;
278 entrypoint_args.begin(), entrypoint_args.end(),
279 std::back_inserter(entrypoint_argv),
280 [](
const std::string& arg) ->
const char* { return arg.c_str(); });
283 FlutterTaskRunnerDescription platform_task_runner = {};
284 platform_task_runner.struct_size =
sizeof(FlutterTaskRunnerDescription);
285 platform_task_runner.user_data = task_runner_.get();
286 platform_task_runner.runs_task_on_current_thread_callback =
290 platform_task_runner.post_task_callback = [](FlutterTask task,
291 uint64_t target_time_nanos,
296 FlutterCustomTaskRunners custom_task_runners = {};
297 custom_task_runners.struct_size =
sizeof(FlutterCustomTaskRunners);
298 custom_task_runners.platform_task_runner = &platform_task_runner;
299 custom_task_runners.thread_priority_setter =
302 if (project_->ui_thread_policy() ==
305 <<
"Running with merged platform and UI thread. Experimental.";
306 custom_task_runners.ui_task_runner = &platform_task_runner;
309 FlutterProjectArgs args = {};
310 args.struct_size =
sizeof(FlutterProjectArgs);
311 args.shutdown_dart_vm_when_done =
true;
312 args.assets_path = assets_path_string.c_str();
313 args.icu_data_path = icu_path_string.c_str();
314 args.command_line_argc =
static_cast<int>(argv.size());
315 args.command_line_argv = argv.empty() ? nullptr : argv.data();
316 args.engine_id =
reinterpret_cast<int64_t
>(
this);
324 if (!project_->dart_entrypoint().empty() && !entrypoint.empty() &&
325 project_->dart_entrypoint() != entrypoint) {
326 FML_LOG(ERROR) <<
"Conflicting entrypoints were specified in "
327 "FlutterDesktopEngineProperties.dart_entrypoint and "
328 "FlutterDesktopEngineRun(engine, entry_point). ";
331 if (!entrypoint.empty()) {
332 args.custom_dart_entrypoint = entrypoint.data();
333 }
else if (!project_->dart_entrypoint().empty()) {
334 args.custom_dart_entrypoint = project_->dart_entrypoint().c_str();
336 args.dart_entrypoint_argc =
static_cast<int>(entrypoint_argv.size());
337 args.dart_entrypoint_argv =
338 entrypoint_argv.empty() ? nullptr : entrypoint_argv.data();
339 args.platform_message_callback =
340 [](
const FlutterPlatformMessage* engine_message,
345 args.vsync_callback = [](
void*
user_data, intptr_t baton) ->
void {
349 args.on_pre_engine_restart_callback = [](
void*
user_data) {
353 args.update_semantics_callback2 = [](
const FlutterSemanticsUpdate2* update,
365 if (!accessibility_bridge) {
369 for (
size_t i = 0; i < update->node_count; i++) {
370 const FlutterSemanticsNode2* node = update->nodes[i];
371 accessibility_bridge->AddFlutterSemanticsNodeUpdate(*node);
374 for (
size_t i = 0; i < update->custom_action_count; i++) {
375 const FlutterSemanticsCustomAction2*
action = update->custom_actions[i];
376 accessibility_bridge->AddFlutterSemanticsCustomActionUpdate(*
action);
379 accessibility_bridge->CommitUpdates();
381 args.root_isolate_create_callback = [](
void*
user_data) {
383 if (host->root_isolate_create_callback_) {
384 host->root_isolate_create_callback_();
387 args.channel_update_callback = [](
const FlutterChannelUpdate* update,
390 if (SAFE_ACCESS(update, channel,
nullptr) !=
nullptr) {
391 std::string channel_name(update->channel);
392 host->OnChannelUpdate(std::move(channel_name),
393 SAFE_ACCESS(update, listening,
false));
396 args.view_focus_change_request_callback =
397 [](
const FlutterViewFocusChangeRequest* request,
void*
user_data) {
402 args.custom_task_runners = &custom_task_runners;
404 if (!platform_view_plugin_) {
405 platform_view_plugin_ = std::make_unique<PlatformViewPlugin>(
406 messenger_wrapper_.get(), task_runner_.get());
409 auto resolver = [](
const char* name) ->
void* {
410 return reinterpret_cast<void*
>(::eglGetProcAddress(name));
416 std::make_unique<CompositorOpenGL>(
this, resolver, enable_impeller_);
418 compositor_ = std::make_unique<CompositorSoftware>();
421 FlutterCompositor compositor = {};
422 compositor.struct_size =
sizeof(FlutterCompositor);
423 compositor.user_data =
this;
424 compositor.create_backing_store_callback =
425 [](
const FlutterBackingStoreConfig* config,
426 FlutterBackingStore* backing_store_out,
void*
user_data) ->
bool {
429 return host->compositor_->CreateBackingStore(*config, backing_store_out);
432 compositor.collect_backing_store_callback =
433 [](
const FlutterBackingStore* backing_store,
void*
user_data) ->
bool {
436 return host->compositor_->CollectBackingStore(backing_store);
439 compositor.present_view_callback =
440 [](
const FlutterPresentViewInfo* info) ->
bool {
443 return host->Present(info);
445 args.compositor = &compositor;
448 args.aot_data = aot_data_.get();
453 FML_DCHECK(!egl_manager_ || !egl_manager_->HasContextCurrent());
455 FlutterRendererConfig renderer_config;
457 if (enable_impeller_) {
461 FML_LOG(ERROR) <<
"Could not create surface manager. Impeller backend "
462 "does not support software rendering.";
465 renderer_config = GetOpenGLRendererConfig();
468 egl_manager_ ? GetOpenGLRendererConfig() : GetSoftwareRendererConfig();
471 auto result = embedder_api_.Run(FLUTTER_ENGINE_VERSION, &renderer_config,
472 &args,
this, &engine_);
473 if (result != kSuccess || engine_ ==
nullptr) {
474 FML_LOG(ERROR) <<
"Failed to start Flutter engine: error " << result;
479 FlutterEngineDisplay display = {};
480 display.struct_size =
sizeof(FlutterEngineDisplay);
481 display.display_id = 0;
482 display.single_display =
true;
483 display.refresh_rate =
484 1.0 / (
static_cast<double>(FrameInterval().count()) / 1000000000.0);
486 std::vector<FlutterEngineDisplay> displays = {display};
487 embedder_api_.NotifyDisplayUpdate(engine_,
488 kFlutterEngineDisplaysUpdateTypeStartup,
489 displays.data(), displays.size());
494 settings_plugin_->StartWatching();
495 settings_plugin_->SendSettings();
497 InitializeKeyboard();
502 bool FlutterWindowsEngine::Stop() {
504 for (
const auto& [
callback, registrar] :
505 plugin_registrar_destruction_callbacks_) {
508 FlutterEngineResult result = embedder_api_.Shutdown(engine_);
510 return (result == kSuccess);
515 std::unique_ptr<FlutterWindowsView> FlutterWindowsEngine::CreateView(
516 std::unique_ptr<WindowBindingHandler> window) {
517 auto view_id = next_view_id_;
518 auto view = std::make_unique<FlutterWindowsView>(
519 view_id,
this, std::move(window), windows_proc_table_);
521 view->CreateRenderSurface();
528 std::unique_lock write_lock(views_mutex_);
529 FML_DCHECK(views_.find(view_id) == views_.end());
530 views_[view_id] = view.get();
533 if (!view->IsImplicitView()) {
534 FML_DCHECK(running());
537 fml::AutoResetWaitableEvent latch;
540 Captures captures = {};
542 FlutterWindowMetricsEvent metrics = view->CreateWindowMetricsEvent();
544 FlutterAddViewInfo info = {};
545 info.struct_size =
sizeof(FlutterAddViewInfo);
546 info.view_id = view_id;
547 info.view_metrics = &metrics;
548 info.user_data = &captures;
549 info.add_view_callback = [](
const FlutterAddViewResult* result) {
550 Captures* captures =
reinterpret_cast<Captures*
>(result->user_data);
551 captures->added = result->added;
552 captures->latch.Signal();
555 FlutterEngineResult result = embedder_api_.AddView(engine_, &info);
556 if (result != kSuccess) {
558 <<
"Starting the add view operation failed. FlutterEngineAddView "
559 "returned an unexpected result: "
560 << result <<
". This indicates a bug in the Windows embedder.";
570 captures.latch.Wait();
572 if (!captures.added) {
576 FML_LOG(ERROR) <<
"FlutterEngineAddView failed to add view";
577 std::unique_lock write_lock(views_mutex_);
578 views_.erase(view_id);
583 return std::move(view);
587 FML_DCHECK(running());
594 fml::AutoResetWaitableEvent latch;
597 Captures captures = {};
599 FlutterRemoveViewInfo info = {};
600 info.struct_size =
sizeof(FlutterRemoveViewInfo);
601 info.view_id = view_id;
602 info.user_data = &captures;
603 info.remove_view_callback = [](
const FlutterRemoveViewResult* result) {
607 Captures* captures =
reinterpret_cast<Captures*
>(result->user_data);
608 captures->removed = result->removed;
609 captures->latch.Signal();
612 FlutterEngineResult result = embedder_api_.RemoveView(engine_, &info);
613 if (result != kSuccess) {
614 FML_LOG(ERROR) <<
"Starting the remove view operation failed. "
615 "FlutterEngineRemoveView "
616 "returned an unexpected result: "
618 <<
". This indicates a bug in the Windows embedder.";
628 captures.latch.Wait();
630 if (!captures.removed) {
633 FML_LOG(ERROR) <<
"FlutterEngineRemoveView failed to remove view";
641 std::unique_lock write_lock(views_mutex_);
643 FML_DCHECK(views_.find(view_id) != views_.end());
644 views_.erase(view_id);
648 void FlutterWindowsEngine::OnVsync(intptr_t baton) {
649 std::chrono::nanoseconds current_time =
650 std::chrono::nanoseconds(embedder_api_.GetCurrentTime());
651 std::chrono::nanoseconds frame_interval = FrameInterval();
652 auto next = SnapToNextTick(current_time, start_time_, frame_interval);
653 embedder_api_.OnVsync(engine_, baton, next.count(),
654 (next + frame_interval).count());
657 std::chrono::nanoseconds FlutterWindowsEngine::FrameInterval() {
658 if (frame_interval_override_.has_value()) {
659 return frame_interval_override_.value();
661 uint64_t interval = 16600000;
663 DWM_TIMING_INFO timing_info = {};
664 timing_info.cbSize =
sizeof(timing_info);
665 HRESULT result = DwmGetCompositionTimingInfo(NULL, &timing_info);
666 if (result == S_OK && timing_info.rateRefresh.uiDenominator > 0 &&
667 timing_info.rateRefresh.uiNumerator > 0) {
668 interval =
static_cast<double>(timing_info.rateRefresh.uiDenominator *
670 static_cast<double>(timing_info.rateRefresh.uiNumerator);
673 return std::chrono::nanoseconds(interval);
677 std::shared_lock read_lock(views_mutex_);
679 auto iterator = views_.find(view_id);
680 if (iterator == views_.end()) {
684 return iterator->second;
689 return plugin_registrar_.get();
692 void FlutterWindowsEngine::AddPluginRegistrarDestructionCallback(
695 plugin_registrar_destruction_callbacks_[
callback] = registrar;
698 void FlutterWindowsEngine::SendWindowMetricsEvent(
699 const FlutterWindowMetricsEvent& event) {
701 embedder_api_.SendWindowMetricsEvent(engine_, &event);
705 void FlutterWindowsEngine::SendPointerEvent(
const FlutterPointerEvent& event) {
707 embedder_api_.SendPointerEvent(engine_, &event, 1);
711 void FlutterWindowsEngine::SendKeyEvent(
const FlutterKeyEvent& event,
719 void FlutterWindowsEngine::SendViewFocusEvent(
720 const FlutterViewFocusEvent& event) {
722 embedder_api_.SendViewFocusEvent(engine_, &event);
726 bool FlutterWindowsEngine::SendPlatformMessage(
729 const size_t message_size,
732 FlutterPlatformMessageResponseHandle* response_handle =
nullptr;
733 if (reply !=
nullptr &&
user_data !=
nullptr) {
734 FlutterEngineResult result =
735 embedder_api_.PlatformMessageCreateResponseHandle(
736 engine_, reply,
user_data, &response_handle);
737 if (result != kSuccess) {
738 FML_LOG(ERROR) <<
"Failed to create response handle";
743 FlutterPlatformMessage platform_message = {
744 sizeof(FlutterPlatformMessage),
751 FlutterEngineResult message_result =
752 embedder_api_.SendPlatformMessage(engine_, &platform_message);
753 if (response_handle !=
nullptr) {
754 embedder_api_.PlatformMessageReleaseResponseHandle(engine_,
757 return message_result == kSuccess;
760 void FlutterWindowsEngine::SendPlatformMessageResponse(
763 size_t data_length) {
764 embedder_api_.SendPlatformMessageResponse(engine_, handle, data, data_length);
767 void FlutterWindowsEngine::HandlePlatformMessage(
768 const FlutterPlatformMessage* engine_message) {
769 if (engine_message->struct_size !=
sizeof(FlutterPlatformMessage)) {
770 FML_LOG(ERROR) <<
"Invalid message size received. Expected: "
771 <<
sizeof(FlutterPlatformMessage) <<
" but received "
772 << engine_message->struct_size;
776 auto message = ConvertToDesktopMessage(*engine_message);
778 message_dispatcher_->HandleMessage(
message, [
this] {}, [
this] {});
781 void FlutterWindowsEngine::ReloadSystemFonts() {
782 embedder_api_.ReloadSystemFonts(engine_);
785 void FlutterWindowsEngine::ScheduleFrame() {
786 embedder_api_.ScheduleFrame(engine_);
789 void FlutterWindowsEngine::SetNextFrameCallback(fml::closure
callback) {
790 next_frame_callback_ = std::move(
callback);
792 embedder_api_.SetNextFrameCallback(
800 self->task_runner_->PostTask(std::move(self->next_frame_callback_));
806 if (lifecycle_manager_) {
807 lifecycle_manager_->SetLifecycleState(state);
811 void FlutterWindowsEngine::SendSystemLocales() {
812 std::vector<LanguageInfo> languages =
814 std::vector<FlutterLocale> flutter_locales;
815 flutter_locales.reserve(languages.size());
816 for (
const auto& info : languages) {
817 flutter_locales.push_back(CovertToFlutterLocale(info));
820 std::vector<const FlutterLocale*> flutter_locale_list;
821 flutter_locale_list.reserve(flutter_locales.size());
822 std::transform(flutter_locales.begin(), flutter_locales.end(),
823 std::back_inserter(flutter_locale_list),
824 [](
const auto& arg) ->
const auto* { return &arg; });
825 embedder_api_.UpdateLocales(engine_, flutter_locale_list.data(),
826 flutter_locale_list.size());
829 void FlutterWindowsEngine::InitializeKeyboard() {
830 auto internal_plugin_messenger = internal_plugin_registrar_->messenger();
831 KeyboardKeyEmbedderHandler::GetKeyStateHandler get_key_state = GetKeyState;
832 KeyboardKeyEmbedderHandler::MapVirtualKeyToScanCode map_vk_to_scan =
833 [](UINT virtual_key,
bool extended) {
834 return MapVirtualKey(virtual_key,
835 extended ? MAPVK_VK_TO_VSC_EX : MAPVK_VK_TO_VSC);
837 keyboard_key_handler_ = std::move(CreateKeyboardKeyHandler(
838 internal_plugin_messenger, get_key_state, map_vk_to_scan));
840 std::move(CreateTextInputPlugin(internal_plugin_messenger));
843 std::unique_ptr<KeyboardHandlerBase>
844 FlutterWindowsEngine::CreateKeyboardKeyHandler(
848 auto keyboard_key_handler = std::make_unique<KeyboardKeyHandler>(messenger);
849 keyboard_key_handler->AddDelegate(
850 std::make_unique<KeyboardKeyEmbedderHandler>(
851 [
this](
const FlutterKeyEvent& event, FlutterKeyEventCallback
callback,
855 get_key_state, map_vk_to_scan));
856 keyboard_key_handler->AddDelegate(
857 std::make_unique<KeyboardKeyChannelHandler>(messenger));
858 keyboard_key_handler->InitKeyboardChannel();
859 return keyboard_key_handler;
862 std::unique_ptr<TextInputPlugin> FlutterWindowsEngine::CreateTextInputPlugin(
864 return std::make_unique<TextInputPlugin>(messenger,
this);
867 bool FlutterWindowsEngine::RegisterExternalTexture(int64_t
texture_id) {
868 return (embedder_api_.RegisterExternalTexture(engine_,
texture_id) ==
872 bool FlutterWindowsEngine::UnregisterExternalTexture(int64_t
texture_id) {
873 return (embedder_api_.UnregisterExternalTexture(engine_,
texture_id) ==
877 bool FlutterWindowsEngine::MarkExternalTextureFrameAvailable(
879 return (embedder_api_.MarkExternalTextureFrameAvailable(
883 bool FlutterWindowsEngine::PostRasterThreadTask(fml::closure
callback)
const {
887 auto captures =
new Captures();
888 captures->callback = std::move(
callback);
889 if (embedder_api_.PostRenderThreadTask(
892 auto captures = reinterpret_cast<Captures*>(opaque);
893 captures->callback();
896 captures) == kSuccess) {
903 bool FlutterWindowsEngine::DispatchSemanticsAction(
905 FlutterSemanticsAction
action,
906 fml::MallocMapping data) {
907 return (embedder_api_.DispatchSemanticsAction(engine_, target,
action,
909 data.GetSize()) == kSuccess);
912 void FlutterWindowsEngine::UpdateSemanticsEnabled(
bool enabled) {
913 if (engine_ && semantics_enabled_ != enabled) {
914 std::shared_lock read_lock(views_mutex_);
916 semantics_enabled_ = enabled;
917 embedder_api_.UpdateSemanticsEnabled(engine_, enabled);
918 for (
auto iterator = views_.begin(); iterator != views_.end(); iterator++) {
919 iterator->second->UpdateSemanticsEnabled(enabled);
924 void FlutterWindowsEngine::OnPreEngineRestart() {
926 InitializeKeyboard();
929 std::string FlutterWindowsEngine::GetExecutableName()
const {
930 std::pair<bool, std::string> result = fml::paths::GetExecutablePath();
932 const std::string& executable_path = result.second;
933 size_t last_separator = executable_path.find_last_of(
"/\\");
934 if (last_separator == std::string::npos ||
935 last_separator == executable_path.size() - 1) {
936 return executable_path;
938 return executable_path.substr(last_separator + 1);
943 void FlutterWindowsEngine::UpdateAccessibilityFeatures() {
944 UpdateHighContrastMode();
947 void FlutterWindowsEngine::UpdateHighContrastMode() {
948 high_contrast_enabled_ = windows_proc_table_->GetHighContrastEnabled();
950 SendAccessibilityFeatures();
951 settings_plugin_->UpdateHighContrastMode(high_contrast_enabled_);
954 void FlutterWindowsEngine::SendAccessibilityFeatures() {
957 if (high_contrast_enabled_) {
959 FlutterAccessibilityFeature::kFlutterAccessibilityFeatureHighContrast;
962 embedder_api_.UpdateAccessibilityFeatures(
963 engine_,
static_cast<FlutterAccessibilityFeature
>(flags));
966 void FlutterWindowsEngine::RequestApplicationQuit(HWND hwnd,
970 platform_handler_->RequestAppExit(hwnd, wparam, lparam, exit_type, 0);
973 void FlutterWindowsEngine::OnQuit(std::optional<HWND> hwnd,
974 std::optional<WPARAM> wparam,
975 std::optional<LPARAM> lparam,
977 lifecycle_manager_->Quit(hwnd, wparam, lparam, exit_code);
980 void FlutterWindowsEngine::OnDwmCompositionChanged() {
981 std::shared_lock read_lock(views_mutex_);
983 for (
auto iterator = views_.begin(); iterator != views_.end(); iterator++) {
984 iterator->second->OnDwmCompositionChanged();
988 void FlutterWindowsEngine::OnWindowStateEvent(HWND hwnd,
990 lifecycle_manager_->OnWindowStateEvent(hwnd, event);
993 std::optional<LRESULT> FlutterWindowsEngine::ProcessExternalWindowMessage(
998 if (lifecycle_manager_) {
999 return lifecycle_manager_->ExternalWindowMessage(hwnd,
message, wparam,
1002 return std::nullopt;
1005 void FlutterWindowsEngine::OnChannelUpdate(std::string name,
bool listening) {
1006 if (name ==
"flutter/platform" && listening) {
1007 lifecycle_manager_->BeginProcessingExit();
1008 }
else if (name ==
"flutter/lifecycle" && listening) {
1009 lifecycle_manager_->BeginProcessingLifecycle();
1013 void FlutterWindowsEngine::OnViewFocusChangeRequest(
1014 const FlutterViewFocusChangeRequest* request) {
1015 std::shared_lock read_lock(views_mutex_);
1017 auto iterator = views_.find(request->view_id);
1018 if (iterator == views_.end()) {
1026 bool FlutterWindowsEngine::Present(
const FlutterPresentViewInfo* info) {
1030 std::shared_lock read_lock(views_mutex_);
1032 auto iterator = views_.find(info->view_id);
1033 if (iterator == views_.end()) {
1037 FlutterWindowsView* view = iterator->second;
1039 return compositor_->Present(view, info->layers, info->layers_count);