Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 112 additions & 8 deletions shell/platform/linux/fl_engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ struct _FlEngine {
FLUTTER_API_SYMBOL(FlutterEngine) engine;
FlutterEngineProcTable embedder_api;

// Next ID to use for a view.
FlutterViewId next_view_id;

// Function to call when a platform message is received.
FlEnginePlatformMessageHandler platform_message_handler;
gpointer platform_message_handler_data;
Expand Down Expand Up @@ -127,6 +130,28 @@ static void parse_locale(const gchar* locale,
}
}

static void view_added_cb(const FlutterAddViewResult* result) {
g_autoptr(GTask) task = G_TASK(result->user_data);

if (result->added) {
g_task_return_boolean(task, TRUE);
} else {
g_task_return_new_error(task, fl_engine_error_quark(),
FL_ENGINE_ERROR_FAILED, "Failed to add view");
}
}

static void view_removed_cb(const FlutterRemoveViewResult* result) {
g_autoptr(GTask) task = G_TASK(result->user_data);

if (result->removed) {
g_task_return_boolean(task, TRUE);
} else {
g_task_return_new_error(task, fl_engine_error_quark(),
FL_ENGINE_ERROR_FAILED, "Failed to remove view");
}
}

static void set_app_lifecycle_state(FlEngine* self,
const flutter::AppLifecycleState state) {
FlBinaryMessenger* binary_messenger = fl_engine_get_binary_messenger(self);
Expand Down Expand Up @@ -200,12 +225,11 @@ static bool compositor_collect_backing_store_callback(
}

// Called when embedder should composite contents of each layer onto the screen.
static bool compositor_present_layers_callback(const FlutterLayer** layers,
size_t layers_count,
void* user_data) {
g_return_val_if_fail(FL_IS_RENDERER(user_data), false);
return fl_renderer_present_layers(FL_RENDERER(user_data), layers,
layers_count);
static bool compositor_present_view_callback(
const FlutterPresentViewInfo* info) {
g_return_val_if_fail(FL_IS_RENDERER(info->user_data), false);
return fl_renderer_present_layers(FL_RENDERER(info->user_data), info->layers,
info->layers_count);
}

// Flutter engine rendering callbacks.
Expand Down Expand Up @@ -234,7 +258,7 @@ static uint32_t fl_engine_gl_get_fbo(void* user_data) {

static bool fl_engine_gl_present(void* user_data) {
// No action required, as this is handled in
// compositor_present_layers_callback.
// compositor_present_view_callback.
return true;
}

Expand Down Expand Up @@ -452,6 +476,9 @@ static void fl_engine_init(FlEngine* self) {
self->embedder_api.struct_size = sizeof(FlutterEngineProcTable);
FlutterEngineGetProcAddresses(&self->embedder_api);

// Implicit view is 0, so start at 1.
self->next_view_id = 1;

self->texture_registrar = fl_texture_registrar_new(self);
}

Expand Down Expand Up @@ -534,7 +561,7 @@ gboolean fl_engine_start(FlEngine* self, GError** error) {
compositor_create_backing_store_callback;
compositor.collect_backing_store_callback =
compositor_collect_backing_store_callback;
compositor.present_layers_callback = compositor_present_layers_callback;
compositor.present_view_callback = compositor_present_view_callback;
args.compositor = &compositor;

if (self->embedder_api.RunsAOTCompiledDartCode()) {
Expand Down Expand Up @@ -603,6 +630,83 @@ FlutterEngineProcTable* fl_engine_get_embedder_api(FlEngine* self) {
return &(self->embedder_api);
}

FlutterViewId fl_engine_add_view(FlEngine* self,
size_t width,
size_t height,
double pixel_ratio,
GCancellable* cancellable,
GAsyncReadyCallback callback,
gpointer user_data) {
Comment thread
robert-ancell marked this conversation as resolved.
Outdated
g_return_val_if_fail(FL_IS_ENGINE(self), 0);

g_autoptr(GTask) task = g_task_new(self, cancellable, callback, user_data);

FlutterViewId view_id = self->next_view_id;
self->next_view_id++;

FlutterWindowMetricsEvent metrics;
metrics.struct_size = sizeof(FlutterWindowMetricsEvent);
metrics.width = width;
metrics.height = height;
metrics.pixel_ratio = pixel_ratio;
metrics.view_id = view_id;
FlutterAddViewInfo info;
info.struct_size = sizeof(FlutterAddViewInfo);
info.view_id = view_id;
info.view_metrics = &metrics;
info.user_data = g_object_ref(task);
info.add_view_callback = view_added_cb;
FlutterEngineResult result = self->embedder_api.AddView(self->engine, &info);
if (result != kSuccess) {
g_task_return_new_error(task, fl_engine_error_quark(),
FL_ENGINE_ERROR_FAILED, "AddView returned %d",
result);
// This would have been done in the callback, but that won't occur now.
g_object_unref(task);
}

return view_id;
}

gboolean fl_engine_add_view_finish(FlEngine* self,
GAsyncResult* result,
GError** error) {
g_return_val_if_fail(FL_IS_ENGINE(self), FALSE);
return g_task_propagate_boolean(G_TASK(result), error);
}

void fl_engine_remove_view(FlEngine* self,
FlutterViewId view_id,
GCancellable* cancellable,
GAsyncReadyCallback callback,
gpointer user_data) {
g_return_if_fail(FL_IS_ENGINE(self));

g_autoptr(GTask) task = g_task_new(self, cancellable, callback, user_data);

FlutterRemoveViewInfo info;
info.struct_size = sizeof(FlutterRemoveViewInfo);
info.view_id = view_id;
info.user_data = g_object_ref(task);
info.remove_view_callback = view_removed_cb;
FlutterEngineResult result =
self->embedder_api.RemoveView(self->engine, &info);
if (result != kSuccess) {
g_task_return_new_error(task, fl_engine_error_quark(),
FL_ENGINE_ERROR_FAILED, "RemoveView returned %d",
result);
// This would have been done in the callback, but that won't occur now.
g_object_unref(task);
}
}

gboolean fl_engine_remove_view_finish(FlEngine* self,
GAsyncResult* result,
GError** error) {
g_return_val_if_fail(FL_IS_ENGINE(self), FALSE);
return g_task_propagate_boolean(G_TASK(result), error);
}

void fl_engine_set_platform_message_handler(
FlEngine* self,
FlEnginePlatformMessageHandler handler,
Expand Down
95 changes: 83 additions & 12 deletions shell/platform/linux/fl_engine_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,18 @@ typedef void (*FlEngineOnPreEngineRestartHandler)(FlEngine* engine,
*/
FlEngine* fl_engine_new(FlDartProject* project, FlRenderer* renderer);

/**
* fl_engine_start:
* @engine: an #FlEngine.
* @error: (allow-none): #GError location to store the error occurring, or %NULL
* to ignore.
*
* Starts the Flutter engine.
*
* Returns: %TRUE on success.
*/
gboolean fl_engine_start(FlEngine* engine, GError** error);

/**
* fl_engine_get_embedder_api:
* @engine: an #FlEngine.
Expand All @@ -91,6 +103,77 @@ FlEngine* fl_engine_new(FlDartProject* project, FlRenderer* renderer);
*/
FlutterEngineProcTable* fl_engine_get_embedder_api(FlEngine* engine);

/**
* fl_engine_add_view:
* @engine: an #FlEngine.
* @width: width of view in pixels.
* @height: height of view in pixels.
* @pixel_ratio: scale factor for view.
* @cancellable: (allow-none): a #GCancellable or %NULL.
* @callback: (scope async): a #GAsyncReadyCallback to call when the view is
* added.
* @user_data: (closure): user data to pass to @callback.
*
* Adds a new view.
*
* Returns: the ID for the new view.
*
*/
FlutterViewId fl_engine_add_view(FlEngine* engine,
size_t width,
size_t height,
double pixel_ratio,
GCancellable* cancellable,
GAsyncReadyCallback callback,
gpointer user_data);

/**
* fl_engine_add_view_finish:
* @engine: an #FlEngine.
* @result: a #GAsyncResult.
* @error: (allow-none): #GError location to store the error occurring, or %NULL
* to ignore.
*
* Completes request started with fl_engine_add_view().
*
* Returns: TRUE on succcess.
*/
gboolean fl_engine_add_view_finish(FlEngine* engine,
GAsyncResult* result,
GError** error);

/**
* fl_engine_remove_view:
* @engine: an #FlEngine.
* @view_id: ID to remove.
* @cancellable: (allow-none): a #GCancellable or %NULL.
* @callback: (scope async): a #GAsyncReadyCallback to call when the view is
* added.
* @user_data: (closure): user data to pass to @callback.
*
* Removes a view previously added with fl_engine_add_view().
*/
void fl_engine_remove_view(FlEngine* engine,
FlutterViewId view_id,
GCancellable* cancellable,
GAsyncReadyCallback callback,
gpointer user_data);

/**
* fl_engine_remove_view_finish:
* @engine: an #FlEngine.
* @result: a #GAsyncResult.
* @error: (allow-none): #GError location to store the error occurring, or %NULL
* to ignore.
*
* Completes request started with fl_engine_remove_view().
*
* Returns: TRUE on succcess.
*/
gboolean fl_engine_remove_view_finish(FlEngine* engine,
GAsyncResult* result,
GError** error);

/**
* fl_engine_set_platform_message_handler:
* @engine: an #FlEngine.
Expand Down Expand Up @@ -143,18 +226,6 @@ void fl_engine_set_on_pre_engine_restart_handler(
gpointer user_data,
GDestroyNotify destroy_notify);

/**
* fl_engine_start:
* @engine: an #FlEngine.
* @error: (allow-none): #GError location to store the error occurring, or %NULL
* to ignore.
*
* Starts the Flutter engine.
*
* Returns: %TRUE on success.
*/
gboolean fl_engine_start(FlEngine* engine, GError** error);

/**
* fl_engine_send_window_metrics_event:
* @engine: an #FlEngine.
Expand Down
Loading