| // Copyright 2018 The Fuchsia Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include <lib/async-loop/cpp/loop.h> | |
| #include <lib/async-loop/default.h> | |
| #include <lib/syslog/cpp/macros.h> | |
| #include <lib/sys/cpp/component_context.h> | |
| #include <lib/ui/scenic/cpp/view_token_pair.h> | |
| #include <zircon/system/ulib/zircon/include/zircon/status.h> | |
| #include <memory> | |
| #include "src/lib/fxl/command_line.h" | |
| #include "src/lib/fxl/log_settings_command_line.h" | |
| #include "src/lib/ui/base_view/view_provider_component.h" | |
| #include "src/ui/examples/simplest_embedder/example_presenter.h" | |
| #include "src/ui/examples/simplest_embedder/view.h" | |
| using namespace simplest_embedder; | |
| int main(int argc, const char** argv) { | |
| async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread); | |
| auto command_line = fxl::CommandLineFromArgcArgv(argc, argv); | |
| if (!fxl::SetLogSettingsFromCommandLine(command_line)) | |
| return 1; | |
| const bool kUseRootPresenter = command_line.HasOption("use_root_presenter"); | |
| const bool kUseExamplePresenter = command_line.HasOption("use_example_presenter"); | |
| if (kUseRootPresenter && kUseExamplePresenter) { | |
| FX_LOGS(ERROR) << "Cannot set both --use_root_presenter and --use_example_presenter"; | |
| return 1; | |
| } | |
| // If the user asked us to use a Presenter, then do so. Otherwise, just | |
| // provide our view as a service. | |
| if (kUseRootPresenter) { | |
| FX_LOGS(INFO) << "Using root presenter."; | |
| FX_LOGS(INFO) << "To quit: Tap the background and hit the ESC key."; | |
| // We need to attach ourselves to a Presenter. To do this, we create a | |
| // pair of tokens, and use one to create a View locally (which we attach | |
| // the rest of our UI to), and one which we pass to a Presenter to create | |
| // a ViewHolder to embed us. | |
| // | |
| // In the Peridot layer of Fuchsia, the device_runner both launches the | |
| // device shell, and connects it to the root presenter. Here, we create | |
| // two eventpair handles, one of which will be passed to the root presenter | |
| // and the other to the View. | |
| auto [view_token, view_holder_token] = scenic::ViewTokenPair::New(); | |
| // Create a startup context for ourselves and use it to connect to | |
| // environment services. | |
| auto component_context = sys::ComponentContext::CreateAndServeOutgoingDirectory(); | |
| fuchsia::ui::scenic::ScenicPtr scenic = | |
| component_context->svc()->Connect<fuchsia::ui::scenic::Scenic>(); | |
| scenic.set_error_handler([&loop](zx_status_t status) { | |
| FX_LOGS(ERROR) << "Lost connection to Scenic with error " << zx_status_get_string(status) | |
| << "."; | |
| loop.Quit(); | |
| }); | |
| // Create a View which will launch shadertoy and attach shadertoy's View to | |
| // itself. | |
| scenic::ViewContext view_context = { | |
| .session_and_listener_request = | |
| scenic::CreateScenicSessionPtrAndListenerRequest(scenic.get()), | |
| .view_token = std::move(view_token), | |
| .component_context = component_context.get(), | |
| }; | |
| auto view = std::make_unique<ShadertoyEmbedderView>(std::move(view_context), &loop); | |
| view->LaunchShadertoyClient(); | |
| // Display the newly-created view using root_presenter. | |
| fidl::InterfacePtr<fuchsia::ui::policy::Presentation> presentation; | |
| fuchsia::ui::policy::PresenterPtr root_presenter = | |
| component_context->svc()->Connect<fuchsia::ui::policy::Presenter>(); | |
| root_presenter->PresentView(std::move(view_holder_token), presentation.NewRequest()); | |
| loop.Run(); | |
| } else if (kUseExamplePresenter) { | |
| FX_LOGS(INFO) << "Using example presenter."; | |
| // We need to attach ourselves to a Presenter. To do this, we create a | |
| // pair of tokens, and use one to create a View locally (which we attach | |
| // the rest of our UI to), and one which we pass to a Presenter to create | |
| // a ViewHolder to embed us. | |
| // | |
| // In the Peridot layer of Fuchsia, the device_runner both launches the | |
| // device shell, and connects it to the root presenter. Here, we create | |
| // two eventpair handles, one of which will be passed to our example | |
| // Presenter and the other to the View. | |
| // | |
| // For simplicity, both the presenter and the view run in-process, and the | |
| // tokens are passed to them via C++ methods. However, it would work just | |
| // as well if the presenter/view lived in two other processes, and we | |
| // passed the tokens to them via FIDL messages. In Peridot, this is | |
| // exactly what the device_runner does. | |
| auto [view_token, view_holder_token] = scenic::ViewTokenPair::New(); | |
| // Create a startup context for ourselves and use it to connect to | |
| // environment services. | |
| auto component_context = sys::ComponentContext::CreateAndServeOutgoingDirectory(); | |
| fuchsia::ui::scenic::ScenicPtr scenic = | |
| component_context->svc()->Connect<fuchsia::ui::scenic::Scenic>(); | |
| scenic.set_error_handler([&loop](zx_status_t status) { | |
| FX_LOGS(INFO) << "Lost connection to Scenic with error code " << status << "."; | |
| loop.Quit(); | |
| }); | |
| // Create a View which will launch shadertoy and attach shadertoy's View to | |
| // itself. | |
| scenic::ViewContext view_context = { | |
| .session_and_listener_request = | |
| scenic::CreateScenicSessionPtrAndListenerRequest(scenic.get()), | |
| .view_token = std::move(view_token), | |
| .component_context = component_context.get(), | |
| }; | |
| auto view = std::make_unique<ShadertoyEmbedderView>(std::move(view_context), &loop); | |
| view->LaunchShadertoyClient(); | |
| // Display the newly created View using our in-process presenter, which | |
| // creates a DisplayCompositor directly for screen output. | |
| // NOTE: The example presenter has an independent session to Scenic even | |
| // though it resides in the same process as the view. | |
| auto example_presenter = std::make_unique<ExamplePresenter>(scenic.get()); | |
| example_presenter->PresentView(std::move(view_holder_token), nullptr); | |
| loop.Run(); | |
| } else { | |
| // Instead of creating a View directly, provide a component that will do so | |
| // when asked via FIDL. | |
| FX_LOGS(INFO) << "Launching view provider service."; | |
| scenic::ViewProviderComponent component( | |
| [&loop](scenic::ViewContext context) { | |
| // Create a View which will launch shadertoy and attach shadertoy's | |
| // View to itself. | |
| auto view = std::make_unique<ShadertoyEmbedderView>(std::move(context), &loop); | |
| view->LaunchShadertoyClient(); | |
| return view; | |
| }, | |
| &loop); | |
| loop.Run(); | |
| } | |
| return 0; | |
| } |