Allow creating views from an external engine (#54080)

While only one view works at this point in the future this will allow a runner to create multiple views.
diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc
index 55cd0c7..9d5022a 100644
--- a/shell/platform/linux/fl_engine.cc
+++ b/shell/platform/linux/fl_engine.cc
@@ -19,6 +19,7 @@
 #include "flutter/shell/platform/linux/fl_pixel_buffer_texture_private.h"
 #include "flutter/shell/platform/linux/fl_plugin_registrar_private.h"
 #include "flutter/shell/platform/linux/fl_renderer.h"
+#include "flutter/shell/platform/linux/fl_renderer_gdk.h"
 #include "flutter/shell/platform/linux/fl_renderer_headless.h"
 #include "flutter/shell/platform/linux/fl_settings_handler.h"
 #include "flutter/shell/platform/linux/fl_texture_gl_private.h"
@@ -461,7 +462,8 @@
   self->texture_registrar = fl_texture_registrar_new(self);
 }
 
-FlEngine* fl_engine_new(FlDartProject* project, FlRenderer* renderer) {
+FlEngine* fl_engine_new_with_renderer(FlDartProject* project,
+                                      FlRenderer* renderer) {
   g_return_val_if_fail(FL_IS_DART_PROJECT(project), nullptr);
   g_return_val_if_fail(FL_IS_RENDERER(renderer), nullptr);
 
@@ -475,9 +477,19 @@
   return self;
 }
 
+G_MODULE_EXPORT FlEngine* fl_engine_new(FlDartProject* project) {
+  g_autoptr(FlRendererGdk) renderer = fl_renderer_gdk_new();
+  return fl_engine_new_with_renderer(project, FL_RENDERER(renderer));
+}
+
 G_MODULE_EXPORT FlEngine* fl_engine_new_headless(FlDartProject* project) {
   g_autoptr(FlRendererHeadless) renderer = fl_renderer_headless_new();
-  return fl_engine_new(project, FL_RENDERER(renderer));
+  return fl_engine_new_with_renderer(project, FL_RENDERER(renderer));
+}
+
+FlRenderer* fl_engine_get_renderer(FlEngine* self) {
+  g_return_val_if_fail(FL_IS_ENGINE(self), nullptr);
+  return self->renderer;
 }
 
 gboolean fl_engine_start(FlEngine* self, GError** error) {
diff --git a/shell/platform/linux/fl_engine_private.h b/shell/platform/linux/fl_engine_private.h
index 855485a..9c3ef70 100644
--- a/shell/platform/linux/fl_engine_private.h
+++ b/shell/platform/linux/fl_engine_private.h
@@ -71,7 +71,7 @@
                                                   gpointer user_data);
 
 /**
- * fl_engine_new:
+ * fl_engine_new_with_renderer:
  * @project: an #FlDartProject.
  * @renderer: an #FlRenderer.
  *
@@ -79,7 +79,18 @@
  *
  * Returns: a new #FlEngine.
  */
-FlEngine* fl_engine_new(FlDartProject* project, FlRenderer* renderer);
+FlEngine* fl_engine_new_with_renderer(FlDartProject* project,
+                                      FlRenderer* renderer);
+
+/**
+ * fl_engine_get_renderer:
+ * @engine: an #FlEngine.
+ *
+ * Gets the renderer used by this engine.
+ *
+ * Returns: an #FlRenderer.
+ */
+FlRenderer* fl_engine_get_renderer(FlEngine* engine);
 
 /**
  * fl_engine_start:
diff --git a/shell/platform/linux/fl_event_channel_test.cc b/shell/platform/linux/fl_event_channel_test.cc
index 7d33881..934a374 100644
--- a/shell/platform/linux/fl_event_channel_test.cc
+++ b/shell/platform/linux/fl_event_channel_test.cc
@@ -24,7 +24,8 @@
 static FlEngine* make_mock_engine() {
   g_autoptr(FlDartProject) project = fl_dart_project_new();
   g_autoptr(FlMockRenderer) renderer = fl_mock_renderer_new();
-  g_autoptr(FlEngine) engine = fl_engine_new(project, FL_RENDERER(renderer));
+  g_autoptr(FlEngine) engine =
+      fl_engine_new_with_renderer(project, FL_RENDERER(renderer));
   g_autoptr(GError) engine_error = nullptr;
   EXPECT_TRUE(fl_engine_start(engine, &engine_error));
   EXPECT_EQ(engine_error, nullptr);
diff --git a/shell/platform/linux/fl_view.cc b/shell/platform/linux/fl_view.cc
index 088de80..77414b0 100644
--- a/shell/platform/linux/fl_view.cc
+++ b/shell/platform/linux/fl_view.cc
@@ -37,8 +37,8 @@
 struct _FlView {
   GtkBox parent_instance;
 
-  // Project being run.
-  FlDartProject* project;
+  // Engine this view is showing.
+  FlEngine* engine;
 
   // ID for this view.
   FlutterViewId view_id;
@@ -46,9 +46,6 @@
   // Rendering output.
   FlRendererGdk* renderer;
 
-  // Engine running @project.
-  FlEngine* engine;
-
   // Pointer button state recorded for sending status updates.
   int64_t button_state;
 
@@ -633,50 +630,6 @@
   handle_geometry_changed(self);
 }
 
-static void fl_view_constructed(GObject* object) {
-  FlView* self = FL_VIEW(object);
-
-  self->renderer = fl_renderer_gdk_new();
-  self->engine = fl_engine_new(self->project, FL_RENDERER(self->renderer));
-  fl_engine_set_update_semantics_handler(self->engine, update_semantics_cb,
-                                         self, nullptr);
-  fl_engine_set_on_pre_engine_restart_handler(
-      self->engine, on_pre_engine_restart_cb, self, nullptr);
-}
-
-static void fl_view_set_property(GObject* object,
-                                 guint prop_id,
-                                 const GValue* value,
-                                 GParamSpec* pspec) {
-  FlView* self = FL_VIEW(object);
-
-  switch (prop_id) {
-    case kPropFlutterProject:
-      g_set_object(&self->project,
-                   static_cast<FlDartProject*>(g_value_get_object(value)));
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
-      break;
-  }
-}
-
-static void fl_view_get_property(GObject* object,
-                                 guint prop_id,
-                                 GValue* value,
-                                 GParamSpec* pspec) {
-  FlView* self = FL_VIEW(object);
-
-  switch (prop_id) {
-    case kPropFlutterProject:
-      g_value_set_object(value, self->project);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
-      break;
-  }
-}
-
 static void fl_view_notify(GObject* object, GParamSpec* pspec) {
   FlView* self = FL_VIEW(object);
 
@@ -699,9 +652,8 @@
                                                 nullptr);
   }
 
-  g_clear_object(&self->project);
-  g_clear_object(&self->renderer);
   g_clear_object(&self->engine);
+  g_clear_object(&self->renderer);
   g_clear_object(&self->window_state_monitor);
   g_clear_object(&self->scrolling_manager);
   g_clear_object(&self->keyboard_handler);
@@ -736,9 +688,6 @@
 
 static void fl_view_class_init(FlViewClass* klass) {
   GObjectClass* object_class = G_OBJECT_CLASS(klass);
-  object_class->constructed = fl_view_constructed;
-  object_class->set_property = fl_view_set_property;
-  object_class->get_property = fl_view_get_property;
   object_class->notify = fl_view_notify;
   object_class->dispose = fl_view_dispose;
 
@@ -746,14 +695,6 @@
   widget_class->key_press_event = fl_view_key_press_event;
   widget_class->key_release_event = fl_view_key_release_event;
 
-  g_object_class_install_property(
-      G_OBJECT_CLASS(klass), kPropFlutterProject,
-      g_param_spec_object(
-          "flutter-project", "flutter-project", "Flutter project in use",
-          fl_dart_project_get_type(),
-          static_cast<GParamFlags>(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
-                                   G_PARAM_STATIC_STRINGS)));
-
   gtk_widget_class_set_accessible_type(GTK_WIDGET_CLASS(klass),
                                        fl_socket_accessible_get_type());
 }
@@ -819,8 +760,24 @@
 }
 
 G_MODULE_EXPORT FlView* fl_view_new(FlDartProject* project) {
-  return static_cast<FlView*>(
-      g_object_new(fl_view_get_type(), "flutter-project", project, nullptr));
+  g_autoptr(FlEngine) engine = fl_engine_new(project);
+  return fl_view_new_for_engine(engine);
+}
+
+G_MODULE_EXPORT FlView* fl_view_new_for_engine(FlEngine* engine) {
+  FlView* self = FL_VIEW(g_object_new(fl_view_get_type(), nullptr));
+
+  self->engine = FL_ENGINE(g_object_ref(engine));
+  FlRenderer* renderer = fl_engine_get_renderer(engine);
+  g_assert(FL_IS_RENDERER_GDK(renderer));
+  self->renderer = FL_RENDERER_GDK(g_object_ref(renderer));
+
+  fl_engine_set_update_semantics_handler(self->engine, update_semantics_cb,
+                                         self, nullptr);
+  fl_engine_set_on_pre_engine_restart_handler(
+      self->engine, on_pre_engine_restart_cb, self, nullptr);
+
+  return self;
 }
 
 G_MODULE_EXPORT FlEngine* fl_view_get_engine(FlView* self) {
diff --git a/shell/platform/linux/public/flutter_linux/fl_engine.h b/shell/platform/linux/public/flutter_linux/fl_engine.h
index f5ba7ca..94e13e2 100644
--- a/shell/platform/linux/public/flutter_linux/fl_engine.h
+++ b/shell/platform/linux/public/flutter_linux/fl_engine.h
@@ -28,6 +28,16 @@
  */
 
 /**
+ * fl_engine_new:
+ * @project: an #FlDartProject.
+ *
+ * Creates new Flutter engine.
+ *
+ * Returns: a new #FlEngine.
+ */
+FlEngine* fl_engine_new(FlDartProject* project);
+
+/**
  * fl_engine_new_headless:
  * @project: an #FlDartProject.
  *
diff --git a/shell/platform/linux/public/flutter_linux/fl_view.h b/shell/platform/linux/public/flutter_linux/fl_view.h
index 34e9acf..663e3d1 100644
--- a/shell/platform/linux/public/flutter_linux/fl_view.h
+++ b/shell/platform/linux/public/flutter_linux/fl_view.h
@@ -42,13 +42,24 @@
  * fl_view_new:
  * @project: The project to show.
  *
- * Creates a widget to show Flutter application.
+ * Creates a widget to show a Flutter application.
  *
  * Returns: a new #FlView.
  */
 FlView* fl_view_new(FlDartProject* project);
 
 /**
+ * fl_view_new_for_engine:
+ * @engine: an #FlEngine.
+ *
+ * Creates a widget to show a window in a Flutter application.
+ * The engine must be not be headless.
+ *
+ * Returns: a new #FlView.
+ */
+FlView* fl_view_new_for_engine(FlEngine* engine);
+
+/**
  * fl_view_get_engine:
  * @view: an #FlView.
  *
diff --git a/shell/platform/linux/testing/fl_test.cc b/shell/platform/linux/testing/fl_test.cc
index c6a48d8..6d0888f 100644
--- a/shell/platform/linux/testing/fl_test.cc
+++ b/shell/platform/linux/testing/fl_test.cc
@@ -67,7 +67,8 @@
 
 FlEngine* make_mock_engine_with_project(FlDartProject* project) {
   g_autoptr(FlMockRenderer) renderer = fl_mock_renderer_new();
-  g_autoptr(FlEngine) engine = fl_engine_new(project, FL_RENDERER(renderer));
+  g_autoptr(FlEngine) engine =
+      fl_engine_new_with_renderer(project, FL_RENDERER(renderer));
   g_autoptr(GError) engine_error = nullptr;
   EXPECT_TRUE(fl_engine_start(engine, &engine_error));
   EXPECT_EQ(engine_error, nullptr);