From 737a0867b76aac62ca4aa25a019157df6320cd49 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Thu, 17 Jan 2019 16:05:08 -0500 Subject: [PATCH 1/5] [linux/windows] Add FlutterWindowController Creates an initial C++ object as the primary intaction point for the embedder calls. This provides a simpler API surface than embedder.h, and folds in some common code (e.g., error logging). This also serves to insulate clients from the embedder.h API layer, so that future incremental changes done for #230 will cause less churn for embedders. --- example/linux_fde/flutter_embedder_example.cc | 35 +++---- .../windows_fde/flutter_embedder_example.cpp | 28 +++--- library/BUILD.gn | 2 + .../common/glfw/flutter_window_controller.cc | 68 ++++++++++++++ .../glfw/flutter_window_controller.h | 94 +++++++++++++++++++ 5 files changed, 193 insertions(+), 34 deletions(-) create mode 100644 library/common/glfw/flutter_window_controller.cc create mode 100644 library/include/flutter_desktop_embedding/glfw/flutter_window_controller.h diff --git a/example/linux_fde/flutter_embedder_example.cc b/example/linux_fde/flutter_embedder_example.cc index cfbd64f3e..2dc82fc99 100644 --- a/example/linux_fde/flutter_embedder_example.cc +++ b/example/linux_fde/flutter_embedder_example.cc @@ -24,9 +24,9 @@ #include #ifdef USE_FLATTENED_INCLUDES -#include +#include #else -#include +#include #endif namespace { @@ -53,11 +53,6 @@ std::string GetExecutableDirectory() { } // namespace int main(int argc, char **argv) { - if (!flutter_desktop_embedding::FlutterInit()) { - std::cerr << "Unable to init GLFW; exiting." << std::endl; - return EXIT_FAILURE; - } - // Resources are located relative to the executable. std::string base_directory = GetExecutableDirectory(); if (base_directory.empty()) { @@ -72,27 +67,27 @@ int main(int argc, char **argv) { #ifdef NDEBUG arguments.push_back("--disable-dart-asserts"); #endif + + flutter_desktop_embedding::FlutterWindowController flutter_controller( + icu_data_path); + // Start the engine. - auto window = flutter_desktop_embedding::CreateFlutterWindow( - 640, 480, assets_path, icu_data_path, arguments); - if (window == nullptr) { - flutter_desktop_embedding::FlutterTerminate(); - std::cerr << "Unable to create Flutter window; exiting." << std::endl; + if (!flutter_controller.CreateWindow(640, 480, assets_path, arguments)) { return EXIT_FAILURE; } // Register any native plugins. plugins_menubar::MenubarPlugin::RegisterWithRegistrar( - flutter_desktop_embedding::GetRegistrarForPlugin( - window, "plugins_menubar::MenubarPlugin")); + flutter_controller.GetRegistrarForPlugin( + "plugins_menubar::MenubarPlugin")); plugins_color_panel::ColorPanelPlugin::RegisterWithRegistrar( - flutter_desktop_embedding::GetRegistrarForPlugin( - window, "plugins_color_panel::ColorPanelPlugin")); + flutter_controller.GetRegistrarForPlugin( + "plugins_color_panel::ColorPanelPlugin")); plugins_file_chooser::FileChooserPlugin::RegisterWithRegistrar( - flutter_desktop_embedding::GetRegistrarForPlugin( - window, "plugins_file_chooser::FileChooserPlugin")); + flutter_controller.GetRegistrarForPlugin( + "plugins_file_chooser::FileChooserPlugin")); - flutter_desktop_embedding::FlutterWindowLoop(window); - glfwTerminate(); + // Run until the window is closed. + flutter_controller.RunEventLoop(); return EXIT_SUCCESS; } diff --git a/example/windows_fde/flutter_embedder_example.cpp b/example/windows_fde/flutter_embedder_example.cpp index 9ea8d70a7..664fd7a6b 100644 --- a/example/windows_fde/flutter_embedder_example.cpp +++ b/example/windows_fde/flutter_embedder_example.cpp @@ -13,32 +13,32 @@ // limitations under the License. #include +#include #include -#include "flutter_desktop_embedding/glfw/embedder.h" +#include "flutter_desktop_embedding/glfw/flutter_window_controller.h" int main(int argc, char **argv) { - if (!flutter_desktop_embedding::FlutterInit()) { - std::cerr << "Unable to init GLFW; exiting." << std::endl; - return EXIT_FAILURE; - } + // TODO: Make paths relative to the executable so it can be run from anywhere. + std::string assets_path = + "..\\..\\example\\flutter_app\\build\\flutter_assets"; + std::string icu_data_path = + "..\\..\\library\\windows\\dependencies\\engine\\icudtl.dat"; + // Arguments for the Flutter Engine. std::vector arguments; #ifndef _DEBUG arguments.push_back("--disable-dart-asserts"); #endif + flutter_desktop_embedding::FlutterWindowController flutter_controller( + icu_data_path); + // Start the engine. - // TODO: Make paths relative to the executable so it can be run from anywhere. - auto window = flutter_desktop_embedding::CreateFlutterWindow( - 640, 480, "..\\build\\flutter_assets", - "..\\..\\library\\windows\\dependencies\\engine\\icudtl.dat", arguments); - if (window == nullptr) { - flutter_desktop_embedding::FlutterTerminate(); - std::cerr << "Unable to create Flutter window; exiting." << std::endl; + if (!flutter_controller.CreateWindow(640, 480, assets_path, arguments)) { return EXIT_FAILURE; } - flutter_desktop_embedding::FlutterWindowLoop(window); - flutter_desktop_embedding::FlutterTerminate(); + // Run until the window is closed. + flutter_controller.RunEventLoop(); return EXIT_SUCCESS; } diff --git a/library/BUILD.gn b/library/BUILD.gn index 12aedfb09..e4d786eec 100644 --- a/library/BUILD.gn +++ b/library/BUILD.gn @@ -21,9 +21,11 @@ published_shared_library("flutter_embedder") { if (is_linux || is_win) { public = [ "include/flutter_desktop_embedding/glfw/embedder.h", + "include/flutter_desktop_embedding/glfw/flutter_window_controller.h", ] sources = [ "common/glfw/embedder.cc", + "common/glfw/flutter_window_controller.cc", "common/glfw/key_event_handler.cc", "common/glfw/key_event_handler.h", "common/glfw/keyboard_hook_handler.h", diff --git a/library/common/glfw/flutter_window_controller.cc b/library/common/glfw/flutter_window_controller.cc new file mode 100644 index 000000000..5e686130e --- /dev/null +++ b/library/common/glfw/flutter_window_controller.cc @@ -0,0 +1,68 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "library/include/flutter_desktop_embedding/glfw/flutter_window_controller.h" + +#include + +namespace flutter_desktop_embedding { + +FlutterWindowController::FlutterWindowController(std::string &icu_data_path) + : icu_data_path_(icu_data_path) { + init_succeeded_ = FlutterInit(); +} + +FlutterWindowController::~FlutterWindowController() { + if (init_succeeded_) { + FlutterTerminate(); + } +} + +bool FlutterWindowController::CreateWindow( + size_t width, size_t height, const std::string &assets_path, + const std::vector &arguments) { + if (!init_succeeded_) { + std::cerr << "Could not create window; FlutterInit failed." << std::endl; + return false; + } + + if (window_) { + std::cerr << "Only one Flutter window can exist at a time." << std::endl; + return false; + } + + window_ = CreateFlutterWindow(width, height, assets_path, icu_data_path_, + arguments); + if (!window_) { + std::cerr << "Failed to create window." << std::endl; + return false; + } + return true; +} + +PluginRegistrar *FlutterWindowController::GetRegistrarForPlugin( + const std::string &plugin_name) { + if (!window_) { + return nullptr; + } + return flutter_desktop_embedding::GetRegistrarForPlugin(window_, plugin_name); +} + +void FlutterWindowController::RunEventLoop() { + if (window_) { + FlutterWindowLoop(window_); + } +} + +} // namespace flutter_desktop_embedding diff --git a/library/include/flutter_desktop_embedding/glfw/flutter_window_controller.h b/library/include/flutter_desktop_embedding/glfw/flutter_window_controller.h new file mode 100644 index 000000000..732fc8c04 --- /dev/null +++ b/library/include/flutter_desktop_embedding/glfw/flutter_window_controller.h @@ -0,0 +1,94 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef LIBRARY_INCLUDE_FLUTTER_DESKTOP_EMBEDDING_GLFW_FLUTTER_WINDOW_CONTROLLER_H_ +#define LIBRARY_INCLUDE_FLUTTER_DESKTOP_EMBEDDING_GLFW_FLUTTER_WINDOW_CONTROLLER_H_ + +#include +#include + +#include "embedder.h" + +#ifdef USE_FLATTENED_INCLUDES +#include "fde_export.h" +#include "plugin_registrar.h" +#else +#include "../fde_export.h" +#include "../plugin_registrar.h" +#endif + +namespace flutter_desktop_embedding { + +// A controller for a window displaying Flutter content. +// +// This is the primary wrapper class for the desktop embedding C API. +// If you use this class, you should not call any of the setup or teardown +// methods in embedder.h directly, as this class will do that internally. +// +// This class is a singleton, as Flutter does not support multiple engines in +// one process, or multiple views in one engine. +// +// Note: This is an early implementation (using GLFW internally) which +// requires control of the application's event loop, and is thus useful +// primarily for building a simple one-window shell hosting a Flutter +// application. The final implementation and API will be very different. +class FDE_EXPORT FlutterWindowController { + public: + // There must be only one instance of this class in an application at any + // given time, as Flutter does not support multiple engines in one process, + // or multiple views in one engine. + explicit FlutterWindowController(std::string &icu_data_path); + + ~FlutterWindowController(); + + // Creates and displays a window for displaying Flutter content. + // + // The |assets_path| is the path to the flutter_assets folder for the Flutter + // application to be run. |icu_data_path| is the path to the icudtl.dat file + // for the version of Flutter you are using. + // + // The |arguments| are passed to the Flutter engine. See: + // https://github.com/flutter/engine/blob/master/shell/common/switches.h for + // for details. Not all arguments will apply to embedding mode. + // + // There must be only one instance of this class in an application at any + // given time, as Flutter does not support multiple engines in one process, + // or multiple views in one engine. + bool CreateWindow(size_t width, size_t height, const std::string &assets_path, + const std::vector &arguments); + + // Returns the PluginRegistrar to register a plugin with the given name. + // + // The name must be unique across the application, so the recommended approach + // is to use the fully namespace-qualified name of the plugin class. + PluginRegistrar *GetRegistrarForPlugin(const std::string &plugin_name); + + // Loops on Flutter window events until termination. + void RunEventLoop(); + + private: + // The path to the ICU data file. Set at creation time since it is the same + // for any window created. + std::string icu_data_path_; + + // Whether or not FlutterInit succeeded at creation time. + bool init_succeeded_ = false; + + // The curent Flutter window, if any. + GLFWwindow *window_ = nullptr; +}; + +} // namespace flutter_desktop_embedding + +#endif // LIBRARY_INCLUDE_FLUTTER_DESKTOP_EMBEDDING_GLFW_FLUTTER_WINDOW_CONTROLLER_H_ From 212798744b49167018587489b7828b8c4ce218de Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Mon, 28 Jan 2019 15:30:01 -0800 Subject: [PATCH 2/5] Fix Windows --- .../windows_fde/flutter_embedder_example.cpp | 3 +- library/windows/GLFW Library.vcxproj | 1 + library/windows/GLFW Library.vcxproj.filters | 99 ++++++++++--------- 3 files changed, 53 insertions(+), 50 deletions(-) diff --git a/example/windows_fde/flutter_embedder_example.cpp b/example/windows_fde/flutter_embedder_example.cpp index 664fd7a6b..34b8530eb 100644 --- a/example/windows_fde/flutter_embedder_example.cpp +++ b/example/windows_fde/flutter_embedder_example.cpp @@ -20,8 +20,7 @@ int main(int argc, char **argv) { // TODO: Make paths relative to the executable so it can be run from anywhere. - std::string assets_path = - "..\\..\\example\\flutter_app\\build\\flutter_assets"; + std::string assets_path = "..\\build\\flutter_assets"; std::string icu_data_path = "..\\..\\library\\windows\\dependencies\\engine\\icudtl.dat"; diff --git a/library/windows/GLFW Library.vcxproj b/library/windows/GLFW Library.vcxproj index d7dfa8a2f..c14747a6e 100644 --- a/library/windows/GLFW Library.vcxproj +++ b/library/windows/GLFW Library.vcxproj @@ -148,6 +148,7 @@ + diff --git a/library/windows/GLFW Library.vcxproj.filters b/library/windows/GLFW Library.vcxproj.filters index bf62d4890..ad4017e40 100644 --- a/library/windows/GLFW Library.vcxproj.filters +++ b/library/windows/GLFW Library.vcxproj.filters @@ -1,48 +1,51 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;ipp;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + \ No newline at end of file From b1dbc20597c03c42e0323e196aee6add169e606a Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Mon, 28 Jan 2019 15:34:00 -0800 Subject: [PATCH 3/5] Comment fix --- .../flutter_desktop_embedding/glfw/flutter_window_controller.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/library/include/flutter_desktop_embedding/glfw/flutter_window_controller.h b/library/include/flutter_desktop_embedding/glfw/flutter_window_controller.h index 732fc8c04..0211d527e 100644 --- a/library/include/flutter_desktop_embedding/glfw/flutter_window_controller.h +++ b/library/include/flutter_desktop_embedding/glfw/flutter_window_controller.h @@ -36,9 +36,6 @@ namespace flutter_desktop_embedding { // If you use this class, you should not call any of the setup or teardown // methods in embedder.h directly, as this class will do that internally. // -// This class is a singleton, as Flutter does not support multiple engines in -// one process, or multiple views in one engine. -// // Note: This is an early implementation (using GLFW internally) which // requires control of the application's event loop, and is thus useful // primarily for building a simple one-window shell hosting a Flutter From 8bbe97b35bb47380079c4227e3e306a33a735c64 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Mon, 28 Jan 2019 15:37:16 -0800 Subject: [PATCH 4/5] More comment fixes --- .../glfw/flutter_window_controller.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/library/include/flutter_desktop_embedding/glfw/flutter_window_controller.h b/library/include/flutter_desktop_embedding/glfw/flutter_window_controller.h index 0211d527e..01e0092a0 100644 --- a/library/include/flutter_desktop_embedding/glfw/flutter_window_controller.h +++ b/library/include/flutter_desktop_embedding/glfw/flutter_window_controller.h @@ -59,9 +59,7 @@ class FDE_EXPORT FlutterWindowController { // https://github.com/flutter/engine/blob/master/shell/common/switches.h for // for details. Not all arguments will apply to embedding mode. // - // There must be only one instance of this class in an application at any - // given time, as Flutter does not support multiple engines in one process, - // or multiple views in one engine. + // Only one Flutter window can exist at a time; see constructor comment. bool CreateWindow(size_t width, size_t height, const std::string &assets_path, const std::vector &arguments); @@ -71,7 +69,7 @@ class FDE_EXPORT FlutterWindowController { // is to use the fully namespace-qualified name of the plugin class. PluginRegistrar *GetRegistrarForPlugin(const std::string &plugin_name); - // Loops on Flutter window events until termination. + // Loops on Flutter window events until the window closes. void RunEventLoop(); private: From 213998627337bd10acc59a516879db01b8e77e30 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Mon, 28 Jan 2019 19:32:48 -0500 Subject: [PATCH 5/5] README update --- library/README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/library/README.md b/library/README.md index 98447350f..2cd62a2a9 100644 --- a/library/README.md +++ b/library/README.md @@ -55,7 +55,8 @@ $ sudo apt-get install libglfw3-dev libepoxy-dev libjsoncpp-dev libgtk-3-dev \ #### Using the Library Run `make` under `linux/`, then link `libflutter_embedder.so` into your -binary. See [embedder.h](include/flutter_desktop_embedding/glfw/embedder.h) +binary. See +[flutter_window_controller.h](include/flutter_desktop_embedding/glfw/flutter_window_controller.h) for details on calling into the library. You will also need to link `libflutter_engine.so` into your binary. @@ -96,8 +97,8 @@ You must have a copy of Visual Studio installed. Build the GLFW Library project under `windows/` in Visual Studio into a static or dynamic library, then link `flutter_embedder.lib` into your binary and make -sure `embedder.h` is in your include paths. Also ensure that the -`flutter_engine.dll`, and if using a dynamic library +sure `flutter_window_controller.h` is in your include paths. Also ensure that +the `flutter_engine.dll`, and if using a dynamic library `flutter_embedder.dll`, are in valid DLL include paths. The output files are located in `bin\x64\$(Configuration)\GLFW Library\`.