Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
flutter_windows_engine.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
7#include <dwmapi.h>
8
9#include <filesystem>
10#include <shared_mutex>
11#include <sstream>
12
13#include "flutter/fml/logging.h"
14#include "flutter/fml/paths.h"
32
33// winbase.h defines GetCurrentTime as a macro.
34#undef GetCurrentTime
35
36static constexpr char kAccessibilityChannelName[] = "flutter/accessibility";
37
38namespace flutter {
39
40namespace {
41
42// Lifted from vsync_waiter_fallback.cc
43static 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;
51}
52
53// Creates and returns a FlutterRendererConfig that renders to the view (if any)
54// of a FlutterWindowsEngine, using OpenGL (via ANGLE).
55// The user_data received by the render callbacks refers to the
56// FlutterWindowsEngine.
57FlutterRendererConfig 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()) {
64 return false;
65 }
66 return host->egl_manager()->render_context()->MakeCurrent();
67 };
68 config.open_gl.clear_current = [](void* user_data) -> bool {
69 auto host = static_cast<FlutterWindowsEngine*>(user_data);
70 if (!host->egl_manager()) {
71 return false;
72 }
73 return host->egl_manager()->render_context()->ClearCurrent();
74 };
75 config.open_gl.present = [](void* user_data) -> bool { FML_UNREACHABLE(); };
76 config.open_gl.fbo_reset_after_present = true;
78 [](void* user_data, const FlutterFrameInfo* info) -> uint32_t {
80 };
81 config.open_gl.gl_proc_resolver = [](void* user_data,
82 const char* what) -> void* {
83 return reinterpret_cast<void*>(eglGetProcAddress(what));
84 };
85 config.open_gl.make_resource_current = [](void* user_data) -> bool {
86 auto host = static_cast<FlutterWindowsEngine*>(user_data);
87 if (!host->egl_manager()) {
88 return false;
89 }
90 return host->egl_manager()->resource_context()->MakeCurrent();
91 };
93 [](void* user_data, int64_t texture_id, size_t width, size_t height,
95 auto host = static_cast<FlutterWindowsEngine*>(user_data);
96 if (!host->texture_registrar()) {
97 return false;
98 }
99 return host->texture_registrar()->PopulateTexture(texture_id, width, height,
100 texture);
101 };
102 return config;
103}
104
105// Creates and returns a FlutterRendererConfig that renders to the view (if any)
106// of a FlutterWindowsEngine, using software rasterization.
107// The user_data received by the render callbacks refers to the
108// FlutterWindowsEngine.
109FlutterRendererConfig GetSoftwareRendererConfig() {
110 FlutterRendererConfig config = {};
111 config.type = kSoftware;
112 config.software.struct_size = sizeof(config.software);
114 [](void* user_data, const void* allocation, size_t row_bytes,
115 size_t height) {
117 return false;
118 };
119 return config;
120}
121
122// Converts a FlutterPlatformMessage to an equivalent FlutterDesktopMessage.
124 const FlutterPlatformMessage& engine_message) {
126 message.struct_size = sizeof(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;
131 return message;
132}
133
134// Converts a LanguageInfo struct to a FlutterLocale struct. |info| must outlive
135// the returned value, since the returned FlutterLocale has pointers into it.
136FlutterLocale 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();
142 }
143 if (!info.script.empty()) {
144 locale.script_code = info.script.c_str();
145 }
146 return locale;
147}
148
149} // namespace
150
152 const FlutterProjectBundle& project,
153 std::shared_ptr<WindowsProcTable> windows_proc_table)
154 : project_(std::make_unique<FlutterProjectBundle>(project)),
155 windows_proc_table_(std::move(windows_proc_table)),
156 aot_data_(nullptr, nullptr),
157 lifecycle_manager_(std::make_unique<WindowsLifecycleManager>(this)) {
158 if (windows_proc_table_ == nullptr) {
159 windows_proc_table_ = std::make_shared<WindowsProcTable>();
160 }
161
163
164 embedder_api_.struct_size = sizeof(FlutterEngineProcTable);
165 FlutterEngineGetProcAddresses(&embedder_api_);
166
167 task_runner_ =
168 std::make_unique<TaskRunner>(
169 embedder_api_.GetCurrentTime, [this](const auto* task) {
170 if (!engine_) {
171 FML_LOG(ERROR)
172 << "Cannot post an engine task when engine is not running.";
173 return;
174 }
175 if (embedder_api_.RunTask(engine_, task) != kSuccess) {
176 FML_LOG(ERROR) << "Failed to post an engine task.";
177 }
178 });
179
180 // Set up the legacy structs backing the API handles.
181 messenger_ =
183 messenger_->SetEngine(this);
184 plugin_registrar_ = std::make_unique<FlutterDesktopPluginRegistrar>();
185 plugin_registrar_->engine = this;
186
187 messenger_wrapper_ =
188 std::make_unique<BinaryMessengerImpl>(messenger_->ToRef());
189 message_dispatcher_ =
190 std::make_unique<IncomingMessageDispatcher>(messenger_->ToRef());
191
192 texture_registrar_ =
193 std::make_unique<FlutterWindowsTextureRegistrar>(this, gl_);
194
195 // Check for impeller support.
196 auto& switches = project_->GetSwitches();
197 bool enable_impeller = true;
198 if (project_->impeller_switch() == FlutterImpellerSwitch::Enabled) {
199 enable_impeller = true;
200 } else if (project_->impeller_switch() == FlutterImpellerSwitch::Disabled) {
201 enable_impeller = false;
202 }
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;
209 }
210 }
211 enable_impeller_ = enable_impeller;
212
213 egl_manager_ = egl::Manager::Create(
214 static_cast<egl::GpuPreference>(project_->gpu_preference()));
215 window_proc_delegate_manager_ = std::make_unique<WindowProcDelegateManager>();
216
217 display_manager_ = std::make_shared<DisplayManagerWin32>(this);
218
219 window_proc_delegate_manager_->RegisterTopLevelWindowProcDelegate(
220 [](HWND hwnd, UINT msg, WPARAM wpar, LPARAM lpar, void* user_data,
221 LRESULT* result) {
223 FlutterWindowsEngine* that =
224 static_cast<FlutterWindowsEngine*>(user_data);
225
226 BASE_DCHECK(that->display_manager_);
227 if (that->display_manager_->HandleWindowMessage(hwnd, msg, wpar, lpar,
228 result)) {
229 return true;
230 }
231
232 BASE_DCHECK(that->lifecycle_manager_);
233 bool handled =
234 that->lifecycle_manager_->WindowProc(hwnd, msg, wpar, lpar, result);
235 if (handled) {
236 return true;
237 }
238 auto message_result =
239 that->window_manager_->HandleMessage(hwnd, msg, wpar, lpar);
240 if (message_result) {
241 *result = *message_result;
242 return true;
243 }
244 return false;
245 },
246 static_cast<void*>(this));
247
248 // Set up internal channels.
249 // TODO: Replace this with an embedder.h API. See
250 // https://github.com/flutter/flutter/issues/71099
251 internal_plugin_registrar_ =
252 std::make_unique<PluginRegistrar>(plugin_registrar_.get());
253
254 accessibility_plugin_ = std::make_unique<AccessibilityPlugin>(this);
255 AccessibilityPlugin::SetUp(messenger_wrapper_.get(),
256 accessibility_plugin_.get());
257
258 cursor_handler_ =
259 std::make_unique<CursorHandler>(messenger_wrapper_.get(), this);
260 platform_handler_ =
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(),
264 task_runner_.get());
265}
266
267FlutterWindowsEngine::~FlutterWindowsEngine() {
268 messenger_->SetEngine(nullptr);
269 Stop();
270}
271
272FlutterWindowsEngine* FlutterWindowsEngine::GetEngineForId(int64_t engine_id) {
273 return reinterpret_cast<FlutterWindowsEngine*>(engine_id);
274}
275
276void FlutterWindowsEngine::SetSwitches(
277 const std::vector<std::string>& switches) {
278 project_->SetSwitches(switches);
279}
280
281bool FlutterWindowsEngine::Run() {
282 return Run("");
283}
284
285bool FlutterWindowsEngine::Run(std::string_view entrypoint) {
286 if (!project_->HasValidPaths()) {
287 FML_LOG(ERROR) << "Missing or unresolvable paths to assets.";
288 return false;
289 }
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_);
294 if (!aot_data_) {
295 FML_LOG(ERROR) << "Unable to start engine without AOT data.";
296 return false;
297 }
298 }
299
300 // FlutterProjectArgs is expecting a full argv, so when processing it for
301 // flags the first item is treated as the executable and ignored. Add a dummy
302 // value so that all provided arguments are used.
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");
312 }
313 if (std::find(switches.begin(), switches.end(), "--enable-impeller") ==
314 switches.end() &&
315 std::find(switches.begin(), switches.end(), "--enable-impeller=true") ==
316 switches.end()) {
317 // Impeller was enabled programmatically, so forward the switch to the
318 // engine.
319 switches.push_back("--enable-impeller");
320 }
321 } else if (project_->impeller_switch() == FlutterImpellerSwitch::Disabled) {
322 if (std::find(switches.begin(), switches.end(),
323 "--enable-impeller=false") == switches.end()) {
324 // Impeller was disabled programmatically, so forward the switch to the
325 // engine.
326 switches.push_back("--enable-impeller=false");
327 }
328 }
329 std::transform(
330 switches.begin(), switches.end(), std::back_inserter(argv),
331 [](const std::string& arg) -> const char* { return arg.c_str(); });
332
333 const std::vector<std::string>& entrypoint_args =
334 project_->dart_entrypoint_arguments();
335 std::vector<const char*> entrypoint_argv;
336 std::transform(
337 entrypoint_args.begin(), entrypoint_args.end(),
338 std::back_inserter(entrypoint_argv),
339 [](const std::string& arg) -> const char* { return arg.c_str(); });
340
341 // Configure task runners.
342 FlutterTaskRunnerDescription platform_task_runner = {};
343 platform_task_runner.struct_size = sizeof(FlutterTaskRunnerDescription);
344 platform_task_runner.user_data = task_runner_.get();
345 platform_task_runner.runs_task_on_current_thread_callback =
346 [](void* user_data) -> bool {
347 return static_cast<TaskRunner*>(user_data)->RunsTasksOnCurrentThread();
348 };
349 platform_task_runner.post_task_callback = [](FlutterTask task,
350 uint64_t target_time_nanos,
351 void* user_data) -> void {
352 static_cast<TaskRunner*>(user_data)->PostFlutterTask(task,
353 target_time_nanos);
354 };
355 FlutterCustomTaskRunners custom_task_runners = {};
356 custom_task_runners.struct_size = sizeof(FlutterCustomTaskRunners);
357 custom_task_runners.platform_task_runner = &platform_task_runner;
358 custom_task_runners.thread_priority_setter =
359 &WindowsPlatformThreadPrioritySetter;
360
361 if (project_->ui_thread_policy() !=
362 FlutterUIThreadPolicy::RunOnSeparateThread) {
363 custom_task_runners.ui_task_runner = &platform_task_runner;
364 } else {
365 FML_LOG(WARNING) << "Running with unmerged platform and UI threads. This "
366 "will be removed in future.";
367 }
368
371 args.shutdown_dart_vm_when_done = true;
372 args.assets_path = assets_path_string.c_str();
373 args.icu_data_path = icu_path_string.c_str();
374 args.command_line_argc = static_cast<int>(argv.size());
375 args.command_line_argv = argv.empty() ? nullptr : argv.data();
376 args.engine_id = reinterpret_cast<int64_t>(this);
377
378 // Fail if conflicting non-default entrypoints are specified in the method
379 // argument and the project.
380 //
381 // TODO(cbracken): https://github.com/flutter/flutter/issues/109285
382 // The entrypoint method parameter should eventually be removed from this
383 // method and only the entrypoint specified in project_ should be used.
384 if (!project_->dart_entrypoint().empty() && !entrypoint.empty() &&
385 project_->dart_entrypoint() != entrypoint) {
386 FML_LOG(ERROR) << "Conflicting entrypoints were specified in "
387 "FlutterDesktopEngineProperties.dart_entrypoint and "
388 "FlutterDesktopEngineRun(engine, entry_point). ";
389 return false;
390 }
391 if (!entrypoint.empty()) {
392 args.custom_dart_entrypoint = entrypoint.data();
393 } else if (!project_->dart_entrypoint().empty()) {
394 args.custom_dart_entrypoint = project_->dart_entrypoint().c_str();
395 }
396 args.dart_entrypoint_argc = static_cast<int>(entrypoint_argv.size());
397 args.dart_entrypoint_argv =
398 entrypoint_argv.empty() ? nullptr : entrypoint_argv.data();
399 args.platform_message_callback =
400 [](const FlutterPlatformMessage* engine_message,
401 void* user_data) -> void {
402 auto host = static_cast<FlutterWindowsEngine*>(user_data);
403 return host->HandlePlatformMessage(engine_message);
404 };
405 args.vsync_callback = [](void* user_data, intptr_t baton) -> void {
406 auto host = static_cast<FlutterWindowsEngine*>(user_data);
407 host->OnVsync(baton);
408 };
409 args.on_pre_engine_restart_callback = [](void* user_data) {
410 auto host = static_cast<FlutterWindowsEngine*>(user_data);
411 host->OnPreEngineRestart();
412 };
413 args.update_semantics_callback2 = [](const FlutterSemanticsUpdate2* update,
414 void* user_data) {
415 auto host = static_cast<FlutterWindowsEngine*>(user_data);
416
417 auto view = host->view(update->view_id);
418 if (!view) {
419 return;
420 }
421
422 auto accessibility_bridge = view->accessibility_bridge().lock();
423 if (!accessibility_bridge) {
424 return;
425 }
426
427 for (size_t i = 0; i < update->node_count; i++) {
428 const FlutterSemanticsNode2* node = update->nodes[i];
429 accessibility_bridge->AddFlutterSemanticsNodeUpdate(*node);
430 }
431
432 for (size_t i = 0; i < update->custom_action_count; i++) {
434 accessibility_bridge->AddFlutterSemanticsCustomActionUpdate(*action);
435 }
436
437 accessibility_bridge->CommitUpdates();
438 };
439 args.root_isolate_create_callback = [](void* user_data) {
440 auto host = static_cast<FlutterWindowsEngine*>(user_data);
441 if (host->root_isolate_create_callback_) {
442 host->root_isolate_create_callback_();
443 }
444 };
445 args.channel_update_callback = [](const FlutterChannelUpdate* update,
446 void* user_data) {
447 auto host = static_cast<FlutterWindowsEngine*>(user_data);
448 if (SAFE_ACCESS(update, channel, nullptr) != nullptr) {
449 std::string channel_name(update->channel);
450 host->OnChannelUpdate(std::move(channel_name),
451 SAFE_ACCESS(update, listening, false));
452 }
453 };
454 args.view_focus_change_request_callback =
455 [](const FlutterViewFocusChangeRequest* request, void* user_data) {
456 auto host = static_cast<FlutterWindowsEngine*>(user_data);
457 host->OnViewFocusChangeRequest(request);
458 };
459
460 args.custom_task_runners = &custom_task_runners;
461
462 if (!platform_view_plugin_) {
463 platform_view_plugin_ = std::make_unique<PlatformViewPlugin>(
464 messenger_wrapper_.get(), task_runner_.get());
465 }
466 if (egl_manager_) {
467 auto resolver = [](const char* name) -> void* {
468 return reinterpret_cast<void*>(::eglGetProcAddress(name));
469 };
470
471 // TODO(schectman) Pass the platform view manager to the compositor
472 // constructors: https://github.com/flutter/flutter/issues/143375
473 compositor_ =
474 std::make_unique<CompositorOpenGL>(this, resolver, enable_impeller_);
475 } else {
476 compositor_ = std::make_unique<CompositorSoftware>();
477 }
478
479 FlutterCompositor compositor = {};
480 compositor.struct_size = sizeof(FlutterCompositor);
481 compositor.user_data = this;
482 compositor.create_backing_store_callback =
483 [](const FlutterBackingStoreConfig* config,
484 FlutterBackingStore* backing_store_out, void* user_data) -> bool {
485 auto host = static_cast<FlutterWindowsEngine*>(user_data);
486
487 return host->compositor_->CreateBackingStore(*config, backing_store_out);
488 };
489
490 compositor.collect_backing_store_callback =
491 [](const FlutterBackingStore* backing_store, void* user_data) -> bool {
492 auto host = static_cast<FlutterWindowsEngine*>(user_data);
493
494 return host->compositor_->CollectBackingStore(backing_store);
495 };
496
497 compositor.present_view_callback =
498 [](const FlutterPresentViewInfo* info) -> bool {
499 auto host = static_cast<FlutterWindowsEngine*>(info->user_data);
500
501 return host->Present(info);
502 };
503 args.compositor = &compositor;
504
505 if (aot_data_) {
506 args.aot_data = aot_data_.get();
507 }
508
509 // The platform thread creates OpenGL contexts. These
510 // must be released to be used by the engine's threads.
511 FML_DCHECK(!egl_manager_ || !egl_manager_->HasContextCurrent());
512
513 FlutterRendererConfig renderer_config;
514
515 if (enable_impeller_) {
516 // Impeller does not support a Software backend. Avoid falling back and
517 // confusing the engine on which renderer is selected.
518 if (!egl_manager_) {
519 FML_LOG(ERROR) << "Could not create surface manager. Impeller backend "
520 "does not support software rendering.";
521 return false;
522 }
523 renderer_config = GetOpenGLRendererConfig();
524 } else {
525 renderer_config =
526 egl_manager_ ? GetOpenGLRendererConfig() : GetSoftwareRendererConfig();
527 }
528
529 auto result = embedder_api_.Run(FLUTTER_ENGINE_VERSION, &renderer_config,
530 &args, this, &engine_);
531 if (result != kSuccess || engine_ == nullptr) {
532 FML_LOG(ERROR) << "Failed to start Flutter engine: error " << result;
533 return false;
534 }
535
536 display_manager_->UpdateDisplays();
537
538 SendSystemLocales();
539
540 settings_plugin_->StartWatching();
541 settings_plugin_->SendSettings();
542
543 InitializeKeyboard();
544
545 return true;
546}
547
548bool FlutterWindowsEngine::Stop() {
549 if (engine_) {
550 window_manager_->OnEngineShutdown();
551 for (const auto& [callback, registrar] :
552 plugin_registrar_destruction_callbacks_) {
553 callback(registrar);
554 }
555 FlutterEngineResult result = embedder_api_.Shutdown(engine_);
556 engine_ = nullptr;
557 return (result == kSuccess);
558 }
559 return false;
560}
561
562std::unique_ptr<FlutterWindowsView> FlutterWindowsEngine::CreateView(
563 std::unique_ptr<WindowBindingHandler> window,
564 bool is_sized_to_content,
565 const BoxConstraints& box_constraints,
566 FlutterWindowsViewSizingDelegate* sizing_delegate) {
567 auto view_id = next_view_id_;
568 auto view = std::make_unique<FlutterWindowsView>(
569 view_id, this, std::move(window), is_sized_to_content, box_constraints,
570 sizing_delegate, windows_proc_table_);
571
572 view->CreateRenderSurface();
573 view->UpdateSemanticsEnabled(semantics_enabled_);
574
575 next_view_id_++;
576
577 {
578 // Add the view to the embedder. This must happen before the engine
579 // is notified the view exists and starts presenting to it.
580 std::unique_lock write_lock(views_mutex_);
581 FML_DCHECK(views_.find(view_id) == views_.end());
582 views_[view_id] = view.get();
583 }
584
585 if (!view->IsImplicitView()) {
586 FML_DCHECK(running());
587
588 struct Captures {
590 bool added;
591 };
592 Captures captures = {};
593
594 FlutterWindowMetricsEvent metrics = view->CreateWindowMetricsEvent();
595
596 FlutterAddViewInfo info = {};
597 info.struct_size = sizeof(FlutterAddViewInfo);
598 info.view_id = view_id;
599 info.view_metrics = &metrics;
600 info.user_data = &captures;
601 info.add_view_callback = [](const FlutterAddViewResult* result) {
602 Captures* captures = reinterpret_cast<Captures*>(result->user_data);
603 captures->added = result->added;
604 captures->latch.Signal();
605 };
606
607 FlutterEngineResult result = embedder_api_.AddView(engine_, &info);
608 if (result != kSuccess) {
609 FML_LOG(ERROR)
610 << "Starting the add view operation failed. FlutterEngineAddView "
611 "returned an unexpected result: "
612 << result << ". This indicates a bug in the Windows embedder.";
613 FML_DCHECK(false);
614 return nullptr;
615 }
616
617 // Block the platform thread until the engine has added the view.
618 // TODO(loicsharma): This blocks the platform thread eagerly and can
619 // cause unnecessary delay in input processing. Instead, this should block
620 // lazily only when the app does an operation which needs the view.
621 // https://github.com/flutter/flutter/issues/146248
622 captures.latch.Wait();
623
624 if (!captures.added) {
625 // Adding the view failed. Update the embedder's state to match the
626 // engine's state. This is unexpected and indicates a bug in the Windows
627 // embedder.
628 FML_LOG(ERROR) << "FlutterEngineAddView failed to add view";
629 std::unique_lock write_lock(views_mutex_);
630 views_.erase(view_id);
631 return nullptr;
632 }
633 }
634
635 return std::move(view);
636}
637
638void FlutterWindowsEngine::RemoveView(FlutterViewId view_id) {
639 FML_DCHECK(running());
640
641 // Notify the engine to stop rendering to the view if it isn't the implicit
642 // view. The engine and framework assume the implicit view always exists and
643 // can continue presenting.
644 if (view_id != kImplicitViewId) {
645 struct Captures {
647 bool removed;
648 };
649 Captures captures = {};
650
651 FlutterRemoveViewInfo info = {};
652 info.struct_size = sizeof(FlutterRemoveViewInfo);
653 info.view_id = view_id;
654 info.user_data = &captures;
655 info.remove_view_callback = [](const FlutterRemoveViewResult* result) {
656 // This is invoked on an engine thread. If
657 // |FlutterRemoveViewResult.removed| is `true`, the engine guarantees the
658 // view won't be presented.
659 Captures* captures = reinterpret_cast<Captures*>(result->user_data);
660 captures->removed = result->removed;
661 captures->latch.Signal();
662 };
663
664 FlutterEngineResult result = embedder_api_.RemoveView(engine_, &info);
665 if (result != kSuccess) {
666 FML_LOG(ERROR) << "Starting the remove view operation failed. "
667 "FlutterEngineRemoveView "
668 "returned an unexpected result: "
669 << result
670 << ". This indicates a bug in the Windows embedder.";
671 FML_DCHECK(false);
672 return;
673 }
674
675 // Block the platform thread until the engine has removed the view.
676 // TODO(loicsharma): This blocks the platform thread eagerly and can
677 // cause unnecessary delay in input processing. Instead, this should block
678 // lazily only when an operation needs the view.
679 // https://github.com/flutter/flutter/issues/146248
680 captures.latch.Wait();
681
682 if (!captures.removed) {
683 // Removing the view failed. This is unexpected and indicates a bug in the
684 // Windows embedder.
685 FML_LOG(ERROR) << "FlutterEngineRemoveView failed to remove view";
686 return;
687 }
688 }
689
690 {
691 // The engine no longer presents to the view. Remove the view from the
692 // embedder.
693 std::unique_lock write_lock(views_mutex_);
694
695 FML_DCHECK(views_.find(view_id) != views_.end());
696
697 // Reset text input state if the removed view is the active text input
698 // view, to prevent stale view references.
699 if (text_input_plugin_) {
700 text_input_plugin_->OnViewRemoved(view_id);
701 }
702
703 views_.erase(view_id);
704 }
705}
706
707void FlutterWindowsEngine::OnVsync(intptr_t baton) {
708 std::chrono::nanoseconds current_time =
709 std::chrono::nanoseconds(embedder_api_.GetCurrentTime());
710 std::chrono::nanoseconds frame_interval = FrameInterval();
711 auto next = SnapToNextTick(current_time, start_time_, frame_interval);
712 embedder_api_.OnVsync(engine_, baton, next.count(),
713 (next + frame_interval).count());
714}
715
716std::chrono::nanoseconds FlutterWindowsEngine::FrameInterval() {
717 if (frame_interval_override_.has_value()) {
718 return frame_interval_override_.value();
719 }
720 uint64_t interval = 16600000;
721
722 DWM_TIMING_INFO timing_info = {};
723 timing_info.cbSize = sizeof(timing_info);
724 HRESULT result = DwmGetCompositionTimingInfo(NULL, &timing_info);
725 if (result == S_OK && timing_info.rateRefresh.uiDenominator > 0 &&
726 timing_info.rateRefresh.uiNumerator > 0) {
727 interval = static_cast<double>(timing_info.rateRefresh.uiDenominator *
728 1000000000.0) /
729 static_cast<double>(timing_info.rateRefresh.uiNumerator);
730 }
731
732 return std::chrono::nanoseconds(interval);
733}
734
735FlutterWindowsView* FlutterWindowsEngine::view(FlutterViewId view_id) const {
736 std::shared_lock read_lock(views_mutex_);
737
738 auto iterator = views_.find(view_id);
739 if (iterator == views_.end()) {
740 return nullptr;
741 }
742
743 return iterator->second;
744}
745
746// Returns the currently configured Plugin Registrar.
747FlutterDesktopPluginRegistrarRef FlutterWindowsEngine::GetRegistrar() {
748 return plugin_registrar_.get();
749}
750
751void FlutterWindowsEngine::AddPluginRegistrarDestructionCallback(
754 plugin_registrar_destruction_callbacks_[callback] = registrar;
755}
756
757void FlutterWindowsEngine::UpdateDisplay(
758 const std::vector<FlutterEngineDisplay>& displays) {
759 if (engine_) {
760 embedder_api_.NotifyDisplayUpdate(engine_,
762 displays.data(), displays.size());
763 }
764}
765
766void FlutterWindowsEngine::SendWindowMetricsEvent(
767 const FlutterWindowMetricsEvent& event) {
768 if (engine_) {
769 embedder_api_.SendWindowMetricsEvent(engine_, &event);
770 }
771}
772
773void FlutterWindowsEngine::SendPointerEvent(const FlutterPointerEvent& event) {
774 if (engine_) {
775 embedder_api_.SendPointerEvent(engine_, &event, 1);
776 }
777}
778
779void FlutterWindowsEngine::SendKeyEvent(const FlutterKeyEvent& event,
781 void* user_data) {
782 if (engine_) {
783 embedder_api_.SendKeyEvent(engine_, &event, callback, user_data);
784 }
785}
786
787void FlutterWindowsEngine::SendViewFocusEvent(
788 const FlutterViewFocusEvent& event) {
789 if (engine_) {
790 embedder_api_.SendViewFocusEvent(engine_, &event);
791 }
792}
793
794bool FlutterWindowsEngine::SendPlatformMessage(
795 const char* channel,
796 const uint8_t* message,
797 const size_t message_size,
798 const FlutterDesktopBinaryReply reply,
799 void* user_data) {
800 FlutterPlatformMessageResponseHandle* response_handle = nullptr;
801 if (reply != nullptr && user_data != nullptr) {
802 FlutterEngineResult result =
803 embedder_api_.PlatformMessageCreateResponseHandle(
804 engine_, reply, user_data, &response_handle);
805 if (result != kSuccess) {
806 FML_LOG(ERROR) << "Failed to create response handle";
807 return false;
808 }
809 }
810
811 FlutterPlatformMessage platform_message = {
813 channel,
814 message,
815 message_size,
816 response_handle,
817 };
818
819 FlutterEngineResult message_result =
820 embedder_api_.SendPlatformMessage(engine_, &platform_message);
821 if (response_handle != nullptr) {
822 embedder_api_.PlatformMessageReleaseResponseHandle(engine_,
823 response_handle);
824 }
825 return message_result == kSuccess;
826}
827
828void FlutterWindowsEngine::SendPlatformMessageResponse(
830 const uint8_t* data,
831 size_t data_length) {
832 embedder_api_.SendPlatformMessageResponse(engine_, handle, data, data_length);
833}
834
835void FlutterWindowsEngine::HandlePlatformMessage(
836 const FlutterPlatformMessage* engine_message) {
837 if (engine_message->struct_size != sizeof(FlutterPlatformMessage)) {
838 FML_LOG(ERROR) << "Invalid message size received. Expected: "
839 << sizeof(FlutterPlatformMessage) << " but received "
840 << engine_message->struct_size;
841 return;
842 }
843
844 auto message = ConvertToDesktopMessage(*engine_message);
845
846 message_dispatcher_->HandleMessage(message, [this] {}, [this] {});
847}
848
849void FlutterWindowsEngine::ReloadSystemFonts() {
850 embedder_api_.ReloadSystemFonts(engine_);
851}
852
853void FlutterWindowsEngine::ScheduleFrame() {
854 embedder_api_.ScheduleFrame(engine_);
855}
856
857void FlutterWindowsEngine::SetNextFrameCallback(fml::closure callback) {
858 next_frame_callback_ = std::move(callback);
859
860 embedder_api_.SetNextFrameCallback(
861 engine_,
862 [](void* user_data) {
863 // Embedder callback runs on raster thread. Switch back to platform
864 // thread.
866 static_cast<FlutterWindowsEngine*>(user_data);
867
868 self->task_runner_->PostTask(std::move(self->next_frame_callback_));
869 },
870 this);
871}
872
873HCURSOR FlutterWindowsEngine::GetCursorByName(
874 const std::string& cursor_name) const {
875 static auto* cursors = new std::map<std::string, const wchar_t*>{
876 {"allScroll", IDC_SIZEALL},
877 {"basic", IDC_ARROW},
878 {"click", IDC_HAND},
879 {"forbidden", IDC_NO},
880 {"help", IDC_HELP},
881 {"move", IDC_SIZEALL},
882 {"none", nullptr},
883 {"noDrop", IDC_NO},
884 {"precise", IDC_CROSS},
885 {"progress", IDC_APPSTARTING},
886 {"text", IDC_IBEAM},
887 {"resizeColumn", IDC_SIZEWE},
888 {"resizeDown", IDC_SIZENS},
889 {"resizeDownLeft", IDC_SIZENESW},
890 {"resizeDownRight", IDC_SIZENWSE},
891 {"resizeLeft", IDC_SIZEWE},
892 {"resizeLeftRight", IDC_SIZEWE},
893 {"resizeRight", IDC_SIZEWE},
894 {"resizeRow", IDC_SIZENS},
895 {"resizeUp", IDC_SIZENS},
896 {"resizeUpDown", IDC_SIZENS},
897 {"resizeUpLeft", IDC_SIZENWSE},
898 {"resizeUpRight", IDC_SIZENESW},
899 {"resizeUpLeftDownRight", IDC_SIZENWSE},
900 {"resizeUpRightDownLeft", IDC_SIZENESW},
901 {"wait", IDC_WAIT},
902 };
903 const wchar_t* idc_name = IDC_ARROW;
904 auto it = cursors->find(cursor_name);
905 if (it != cursors->end()) {
906 idc_name = it->second;
907 }
908 return windows_proc_table_->LoadCursor(nullptr, idc_name);
909}
910
911FlutterWindowsView* FlutterWindowsEngine::GetViewFromTopLevelWindow(
912 HWND hwnd) const {
913 std::shared_lock read_lock(views_mutex_);
914 auto const iterator =
915 std::find_if(views_.begin(), views_.end(), [hwnd](auto const& pair) {
916 FlutterWindowsView* const view = pair.second;
917 return GetAncestor(view->GetWindowHandle(), GA_ROOT) == hwnd;
918 });
919 if (iterator != views_.end()) {
920 return iterator->second;
921 }
922 return nullptr;
923}
924
925void FlutterWindowsEngine::SendSystemLocales() {
926 std::vector<LanguageInfo> languages =
927 GetPreferredLanguageInfo(*windows_proc_table_);
928 std::vector<FlutterLocale> flutter_locales;
929 flutter_locales.reserve(languages.size());
930 for (const auto& info : languages) {
931 flutter_locales.push_back(CovertToFlutterLocale(info));
932 }
933 // Convert the locale list to the locale pointer list that must be provided.
934 std::vector<const FlutterLocale*> flutter_locale_list;
935 flutter_locale_list.reserve(flutter_locales.size());
936 std::transform(flutter_locales.begin(), flutter_locales.end(),
937 std::back_inserter(flutter_locale_list),
938 [](const auto& arg) -> const auto* { return &arg; });
939 embedder_api_.UpdateLocales(engine_, flutter_locale_list.data(),
940 flutter_locale_list.size());
941}
942
943void FlutterWindowsEngine::InitializeKeyboard() {
944 auto internal_plugin_messenger = internal_plugin_registrar_->messenger();
945 KeyboardKeyEmbedderHandler::GetKeyStateHandler get_key_state = GetKeyState;
946 KeyboardKeyEmbedderHandler::MapVirtualKeyToScanCode map_vk_to_scan =
947 [](UINT virtual_key, bool extended) {
948 return MapVirtualKey(virtual_key,
949 extended ? MAPVK_VK_TO_VSC_EX : MAPVK_VK_TO_VSC);
950 };
951 keyboard_key_handler_ = std::move(CreateKeyboardKeyHandler(
952 internal_plugin_messenger, get_key_state, map_vk_to_scan));
953 text_input_plugin_ =
954 std::move(CreateTextInputPlugin(internal_plugin_messenger));
955}
956
957std::unique_ptr<KeyboardHandlerBase>
958FlutterWindowsEngine::CreateKeyboardKeyHandler(
959 BinaryMessenger* messenger,
962 auto keyboard_key_handler = std::make_unique<KeyboardKeyHandler>(messenger);
963 keyboard_key_handler->AddDelegate(
964 std::make_unique<KeyboardKeyEmbedderHandler>(
966 void* user_data) {
967 return SendKeyEvent(event, callback, user_data);
968 },
969 get_key_state, map_vk_to_scan));
970 keyboard_key_handler->AddDelegate(
971 std::make_unique<KeyboardKeyChannelHandler>(messenger));
972 keyboard_key_handler->InitKeyboardChannel();
973 return keyboard_key_handler;
974}
975
976std::unique_ptr<TextInputPlugin> FlutterWindowsEngine::CreateTextInputPlugin(
977 BinaryMessenger* messenger) {
978 return std::make_unique<TextInputPlugin>(messenger, this);
979}
980
981bool FlutterWindowsEngine::RegisterExternalTexture(int64_t texture_id) {
982 return (embedder_api_.RegisterExternalTexture(engine_, texture_id) ==
983 kSuccess);
984}
985
986bool FlutterWindowsEngine::UnregisterExternalTexture(int64_t texture_id) {
987 return (embedder_api_.UnregisterExternalTexture(engine_, texture_id) ==
988 kSuccess);
989}
990
991bool FlutterWindowsEngine::MarkExternalTextureFrameAvailable(
992 int64_t texture_id) {
993 return (embedder_api_.MarkExternalTextureFrameAvailable(
994 engine_, texture_id) == kSuccess);
995}
996
997bool FlutterWindowsEngine::PostRasterThreadTask(fml::closure callback) const {
998 struct Captures {
1000 };
1001 auto captures = new Captures();
1002 captures->callback = std::move(callback);
1003 if (embedder_api_.PostRenderThreadTask(
1004 engine_,
1005 [](void* opaque) {
1006 auto captures = reinterpret_cast<Captures*>(opaque);
1007 captures->callback();
1008 delete captures;
1009 },
1010 captures) == kSuccess) {
1011 return true;
1012 }
1013 delete captures;
1014 return false;
1015}
1016
1017bool FlutterWindowsEngine::DispatchSemanticsAction(
1019 uint64_t target,
1021 fml::MallocMapping data) {
1024 .view_id = view_id,
1025 .node_id = target,
1026 .action = action,
1027 .data = data.GetMapping(),
1028 .data_length = data.GetSize(),
1029 };
1030 return (embedder_api_.SendSemanticsAction(engine_, &info));
1031}
1032
1033void FlutterWindowsEngine::UpdateSemanticsEnabled(bool enabled) {
1034 if (engine_ && semantics_enabled_ != enabled) {
1035 std::shared_lock read_lock(views_mutex_);
1036
1037 semantics_enabled_ = enabled;
1038 embedder_api_.UpdateSemanticsEnabled(engine_, enabled);
1039 for (auto iterator = views_.begin(); iterator != views_.end(); iterator++) {
1040 iterator->second->UpdateSemanticsEnabled(enabled);
1041 }
1042 }
1043}
1044
1045void FlutterWindowsEngine::OnPreEngineRestart() {
1046 // Reset the keyboard's state on hot restart.
1047 InitializeKeyboard();
1048}
1049
1050std::string FlutterWindowsEngine::GetExecutableName() const {
1051 std::pair<bool, std::string> result = fml::paths::GetExecutablePath();
1052 if (result.first) {
1053 const std::string& executable_path = result.second;
1054 size_t last_separator = executable_path.find_last_of("/\\");
1055 if (last_separator == std::string::npos ||
1056 last_separator == executable_path.size() - 1) {
1057 return executable_path;
1058 }
1059 return executable_path.substr(last_separator + 1);
1060 }
1061 return "Flutter";
1062}
1063
1064void FlutterWindowsEngine::UpdateAccessibilityFeatures() {
1065 UpdateHighContrastMode();
1066}
1067
1068void FlutterWindowsEngine::UpdateHighContrastMode() {
1069 high_contrast_enabled_ = windows_proc_table_->GetHighContrastEnabled();
1070
1071 SendAccessibilityFeatures();
1072 settings_plugin_->UpdateHighContrastMode(high_contrast_enabled_);
1073}
1074
1075void FlutterWindowsEngine::SendAccessibilityFeatures() {
1076 int flags = 0;
1077
1078 if (high_contrast_enabled_) {
1079 flags |=
1081 }
1082
1083 embedder_api_.UpdateAccessibilityFeatures(
1084 engine_, static_cast<FlutterAccessibilityFeature>(flags));
1085}
1086
1087void FlutterWindowsEngine::RequestApplicationQuit(HWND hwnd,
1088 WPARAM wparam,
1089 LPARAM lparam,
1090 AppExitType exit_type) {
1091 platform_handler_->RequestAppExit(hwnd, wparam, lparam, exit_type, 0);
1092}
1093
1094void FlutterWindowsEngine::OnQuit(std::optional<HWND> hwnd,
1095 std::optional<WPARAM> wparam,
1096 std::optional<LPARAM> lparam,
1097 UINT exit_code) {
1098 lifecycle_manager_->Quit(hwnd, wparam, lparam, exit_code);
1099}
1100
1101void FlutterWindowsEngine::OnDwmCompositionChanged() {
1102 if (display_manager_) {
1103 display_manager_->UpdateDisplays();
1104 }
1105
1106 std::shared_lock read_lock(views_mutex_);
1107 for (auto iterator = views_.begin(); iterator != views_.end(); iterator++) {
1108 iterator->second->OnDwmCompositionChanged();
1109 }
1110}
1111
1112void FlutterWindowsEngine::OnWindowStateEvent(HWND hwnd,
1113 WindowStateEvent event) {
1114 lifecycle_manager_->OnWindowStateEvent(hwnd, event);
1115}
1116
1117std::optional<LRESULT> FlutterWindowsEngine::ProcessExternalWindowMessage(
1118 HWND hwnd,
1119 UINT message,
1120 WPARAM wparam,
1121 LPARAM lparam) {
1122 if (lifecycle_manager_) {
1123 return lifecycle_manager_->ExternalWindowMessage(hwnd, message, wparam,
1124 lparam);
1125 }
1126 return std::nullopt;
1127}
1128
1129void FlutterWindowsEngine::UpdateFlutterCursor(
1130 const std::string& cursor_name) const {
1131 SetFlutterCursor(GetCursorByName(cursor_name));
1132}
1133
1134void FlutterWindowsEngine::SetFlutterCursor(HCURSOR cursor) const {
1135 windows_proc_table_->SetCursor(cursor);
1136}
1137
1138void FlutterWindowsEngine::OnChannelUpdate(std::string name, bool listening) {
1139 if (name == "flutter/platform" && listening) {
1140 lifecycle_manager_->BeginProcessingExit();
1141 } else if (name == "flutter/lifecycle" && listening) {
1142 lifecycle_manager_->BeginProcessingLifecycle();
1143 }
1144}
1145
1146void FlutterWindowsEngine::OnViewFocusChangeRequest(
1147 const FlutterViewFocusChangeRequest* request) {
1148 std::shared_lock read_lock(views_mutex_);
1149
1150 auto iterator = views_.find(request->view_id);
1151 if (iterator == views_.end()) {
1152 return;
1153 }
1154
1155 FlutterWindowsView* view = iterator->second;
1156 view->Focus();
1157}
1158
1159bool FlutterWindowsEngine::Present(const FlutterPresentViewInfo* info) {
1160 // This runs on the raster thread. Lock the views map for the entirety of the
1161 // present operation to block the platform thread from destroying the
1162 // view during the present.
1163 std::shared_lock read_lock(views_mutex_);
1164
1165 auto iterator = views_.find(info->view_id);
1166 if (iterator == views_.end()) {
1167 return false;
1168 }
1169
1170 FlutterWindowsView* view = iterator->second;
1171
1172 return compositor_->Present(view, info->layers, info->layers_count);
1173}
1174
1175bool FlutterWindowsEngine::HandleDisplayMonitorMessage(HWND hwnd,
1176 UINT message,
1177 WPARAM wparam,
1178 LPARAM lparam,
1179 LRESULT* result) {
1180 if (!display_manager_) {
1181 return false;
1182 }
1183
1184 return display_manager_->HandleWindowMessage(hwnd, message, wparam, lparam,
1185 result);
1186}
1187
1188} // namespace flutter
static void SetUp(BinaryMessenger *binary_messenger, AccessibilityPlugin *plugin)
FlutterWindowsEngine(const FlutterProjectBundle &project, std::shared_ptr< WindowsProcTable > windows_proc_table=nullptr)
void SetSwitches(const std::vector< std::string > &switches)
std::function< SHORT(UINT, bool)> MapVirtualKeyToScanCode
static std::unique_ptr< Manager > Create(GpuPreference gpu_preference)
Definition manager.cc:17
static std::shared_ptr< ProcTable > Create()
Definition proc_table.cc:12
A Mapping like NonOwnedMapping, but uses Free as its release proc.
Definition mapping.h:144
int32_t value
FlutterEngineResult FlutterEngineGetProcAddresses(FlutterEngineProcTable *table)
Gets the table of engine function pointers.
Definition embedder.cc:3741
@ kOpenGL
Definition embedder.h:80
FlutterAccessibilityFeature
Definition embedder.h:91
@ kFlutterAccessibilityFeatureHighContrast
Request that UI be rendered with darker colors.
Definition embedder.h:105
FlutterEngineResult
Definition embedder.h:72
@ kSuccess
Definition embedder.h:73
@ kFlutterEngineDisplaysUpdateTypeStartup
Definition embedder.h:2379
FlutterSemanticsAction
Definition embedder.h:122
void(* FlutterKeyEventCallback)(bool, void *)
Definition embedder.h:1482
#define FLUTTER_ENGINE_VERSION
Definition embedder.h:70
#define SAFE_ACCESS(pointer, member, default_value)
GLFWwindow * window
Definition main.cc:60
FlView * view
const char * message
if(engine==nullptr)
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
const gchar * channel
uint32_t * target
G_BEGIN_DECLS FlutterViewId view_id
static FlutterDesktopMessage ConvertToDesktopMessage(const FlutterPlatformMessage &engine_message)
void(* FlutterDesktopBinaryReply)(const uint8_t *data, size_t data_size, void *user_data)
void(* FlutterDesktopOnPluginRegistrarDestroyed)(FlutterDesktopPluginRegistrarRef)
static constexpr char kAccessibilityChannelName[]
FlutterDesktopBinaryReply callback
#define FML_LOG(severity)
Definition logging.h:101
#define FML_UNREACHABLE()
Definition logging.h:128
#define FML_DCHECK(condition)
Definition logging.h:122
const char * name
Definition fuchsia.cc:50
static constexpr FlutterViewId kImplicitViewId
char ** argv
Definition library.h:9
FlTexture * texture
WindowStateEvent
An event representing a change in window state that may update the.
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service host
Definition switch_defs.h:69
std::vector< LanguageInfo > GetPreferredLanguageInfo()
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition switch_defs.h:36
int64_t FlutterViewId
std::pair< bool, std::string > GetExecutablePath()
std::string PathToUtf8(const std::filesystem::path &path)
std::function< void()> closure
Definition closure.h:14
Definition ref_ptr.h:261
std::vector< FlutterEngineDisplay > * displays
int32_t height
int32_t width
FlutterAddViewCallback add_view_callback
Definition embedder.h:1147
FlutterViewId view_id
The identifier for the view to add. This must be unique.
Definition embedder.h:1127
const FlutterWindowMetricsEvent * view_metrics
Definition embedder.h:1132
An update to whether a message channel has a listener set or not.
Definition embedder.h:1884
void(* thread_priority_setter)(FlutterThreadPriority)
Definition embedder.h:1959
const FlutterTaskRunnerDescription * ui_task_runner
Definition embedder.h:1963
const FlutterTaskRunnerDescription * platform_task_runner
Definition embedder.h:1951
size_t struct_size
The size of this struct. Must be sizeof(FlutterCustomTaskRunners).
Definition embedder.h:1946
Function-pointer-based versions of the APIs above.
Definition embedder.h:3763
size_t struct_size
The size of this struct. Must be sizeof(FlutterEngineProcs).
Definition embedder.h:3765
FlutterEngineGetCurrentTimeFnPtr GetCurrentTime
Definition embedder.h:3796
FlutterEngineRunTaskFnPtr RunTask
Definition embedder.h:3797
const char * language_code
Definition embedder.h:2314
size_t struct_size
This size of this struct. Must be sizeof(FlutterLocale).
Definition embedder.h:2310
const char * script_code
Definition embedder.h:2324
const char * country_code
Definition embedder.h:2319
ProcResolver gl_proc_resolver
Definition embedder.h:765
size_t struct_size
The size of this struct. Must be sizeof(FlutterOpenGLRendererConfig).
Definition embedder.h:726
TextureFrameCallback gl_external_texture_frame_callback
Definition embedder.h:770
BoolCallback make_resource_current
Definition embedder.h:748
UIntFrameInfoCallback fbo_with_frame_info_callback
Definition embedder.h:778
size_t struct_size
The size of this struct. Must be sizeof(FlutterPlatformMessage).
Definition embedder.h:1491
const FlutterPlatformMessageResponseHandle * response_handle
Definition embedder.h:1501
const char * channel
Definition embedder.h:1492
const uint8_t * message
Definition embedder.h:1493
size_t layers_count
The count of layers.
Definition embedder.h:2225
FlutterViewId view_id
The identifier of the target view.
Definition embedder.h:2219
const FlutterLayer ** layers
The layers that should be composited onto the view.
Definition embedder.h:2222
size_t struct_size
The size of this struct. Must be sizeof(FlutterProjectArgs).
Definition embedder.h:2513
FlutterRemoveViewCallback remove_view_callback
Definition embedder.h:1195
FlutterViewId view_id
Definition embedder.h:1178
FlutterSoftwareRendererConfig software
Definition embedder.h:1041
FlutterOpenGLRendererConfig open_gl
Definition embedder.h:1040
FlutterRendererType type
Definition embedder.h:1038
A batch of updates to semantics nodes and custom actions.
Definition embedder.h:1851
size_t node_count
The number of semantics node updates.
Definition embedder.h:1855
size_t custom_action_count
The number of semantics custom action updates.
Definition embedder.h:1859
FlutterSemanticsNode2 ** nodes
Definition embedder.h:1857
FlutterSemanticsCustomAction2 ** custom_actions
Definition embedder.h:1862
FlutterViewId view_id
Definition embedder.h:1864
size_t struct_size
The size of this struct. Must be sizeof(FlutterSoftwareRendererConfig).
Definition embedder.h:1029
SoftwareSurfacePresentCallback surface_present_callback
Definition embedder.h:1034
size_t struct_size
The size of this struct. Must be sizeof(FlutterTaskRunnerDescription).
Definition embedder.h:1919
BoolCallback runs_task_on_current_thread_callback
Definition embedder.h:1925
FlutterTaskRunnerPostTaskCallback post_task_callback
Definition embedder.h:1936
FlutterViewId view_id
The identifier of the view that received the focus event.
Definition embedder.h:1257
int64_t texture_id
#define BASE_DCHECK(condition)
Definition logging.h:63
LONG_PTR LRESULT
unsigned int UINT
LONG_PTR LPARAM
UINT_PTR WPARAM