mozart: Initial commit of the launcher. The launcher is a simple application which binds a ViewTree to a NativeViewport, thereby allowing Mozart based applications to be shown on screen. Note: This version does not support input yet. R=abarth@google.com, jamesr@chromium.org Review URL: https://codereview.chromium.org/1404423007 .
diff --git a/services/ui/BUILD.gn b/services/ui/BUILD.gn index bb93fba..9480d5e 100644 --- a/services/ui/BUILD.gn +++ b/services/ui/BUILD.gn
@@ -4,6 +4,7 @@ group("ui") { deps = [ + "//services/ui/launcher", "//services/ui/view_manager", ] }
diff --git a/services/ui/launcher/BUILD.gn b/services/ui/launcher/BUILD.gn new file mode 100644 index 0000000..e85fda3 --- /dev/null +++ b/services/ui/launcher/BUILD.gn
@@ -0,0 +1,28 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//mojo/public/mojo_application.gni") +import("//testing/test.gni") + +mojo_native_application("launcher") { + sources = [ + "launcher_app.cc", + "launcher_app.h", + "launcher_view_tree.cc", + "launcher_view_tree.h", + "main.cc", + ] + + deps = [ + "//base", + "//mojo/application", + "//mojo/common:tracing_impl", + "//mojo/environment:chromium", + "//mojo/public/cpp/bindings:bindings", + "//mojo/services/native_viewport/interfaces", + "//mojo/services/surfaces/cpp", + "//mojo/services/surfaces/interfaces", + "//mojo/services/ui/views/interfaces", + ] +}
diff --git a/services/ui/launcher/README.md b/services/ui/launcher/README.md new file mode 100644 index 0000000..eb4e776 --- /dev/null +++ b/services/ui/launcher/README.md
@@ -0,0 +1,11 @@ +# Mozart Launcher + +This directory contains the Launcher, a simple tool for hosting a View +inside of the NativeViewport. + +In other words, use this to run UI applications which implement the +ViewProvider interface and which register their views with the ViewManager. + +## USAGE + + out/Debug/mojo_shell "mojo:launcher <app url>"
diff --git a/services/ui/launcher/launcher_app.cc b/services/ui/launcher/launcher_app.cc new file mode 100644 index 0000000..07e796f --- /dev/null +++ b/services/ui/launcher/launcher_app.cc
@@ -0,0 +1,128 @@ +// Copyright 2015 The Chromium 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 "base/trace_event/trace_event.h" +#include "mojo/application/application_runner_chromium.h" +#include "mojo/common/tracing_impl.h" +#include "mojo/public/c/system/main.h" +#include "mojo/public/cpp/application/application_connection.h" +#include "mojo/public/cpp/application/application_impl.h" +#include "mojo/services/surfaces/cpp/surfaces_utils.h" +#include "mojo/services/surfaces/interfaces/quads.mojom.h" +#include "services/ui/launcher/launcher_app.h" +#include "services/ui/launcher/launcher_view_tree.h" + +namespace launcher { + +LauncherApp::LauncherApp() + : app_impl_(nullptr), viewport_event_dispatcher_binding_(this) {} + +LauncherApp::~LauncherApp() {} + +void LauncherApp::Initialize(mojo::ApplicationImpl* app) { + app_impl_ = app; + tracing_.Initialize(app); + TRACE_EVENT0("launcher", __func__); + + if (app->args().size() != 2) { + LOG(ERROR) << "Invalid arguments.\n\n" + "Usage: mojo_shell \"mojo:launcher <app url>\""; + app->Terminate(); + return; + } + + InitViewport(); + LaunchClient(app->args()[1]); +} + +void LauncherApp::InitViewport() { + app_impl_->ConnectToService("mojo:native_viewport_service", + &viewport_service_); + viewport_service_.set_connection_error_handler(base::Bind( + &LauncherApp::OnViewportConnectionError, base::Unretained(this))); + + mojo::NativeViewportEventDispatcherPtr dispatcher; + viewport_event_dispatcher_binding_.Bind(GetProxy(&dispatcher)); + viewport_service_->SetEventDispatcher(dispatcher.Pass()); + + // Match the Nexus 5 aspect ratio initially. + auto size = mojo::Size::New(); + size->width = 320; + size->height = 640; + + auto requested_configuration = mojo::SurfaceConfiguration::New(); + viewport_service_->Create( + size.Clone(), requested_configuration.Pass(), + base::Bind(&LauncherApp::OnViewportCreated, base::Unretained(this))); +} + +void LauncherApp::OnViewportConnectionError() { + LOG(ERROR) << "Exiting due to viewport connection error."; + app_impl_->Terminate(); +} + +void LauncherApp::OnViewportCreated(mojo::ViewportMetricsPtr metrics) { + viewport_service_->Show(); + mojo::ContextProviderPtr context_provider; + viewport_service_->GetContextProvider(GetProxy(&context_provider)); + + mojo::DisplayFactoryPtr display_factory; + app_impl_->ConnectToService("mojo:surfaces_service", &display_factory); + + mojo::DisplayPtr display; + display_factory->Create(context_provider.Pass(), nullptr, GetProxy(&display)); + + view_tree_.reset( + new LauncherViewTree(app_impl_, display.Pass(), metrics.Pass())); + UpdateClientView(); + RequestUpdatedViewportMetrics(); +} + +void LauncherApp::OnViewportMetricsChanged(mojo::ViewportMetricsPtr metrics) { + if (view_tree_) { + view_tree_->SetViewportMetrics(metrics.Pass()); + RequestUpdatedViewportMetrics(); + } +} + +void LauncherApp::RequestUpdatedViewportMetrics() { + viewport_service_->RequestMetrics(base::Bind( + &LauncherApp::OnViewportMetricsChanged, base::Unretained(this))); +} + +void LauncherApp::OnEvent(mojo::EventPtr event, + const mojo::Callback<void()>& callback) { + if (view_tree_) + view_tree_->DispatchEvent(event.Pass()); + callback.Run(); +} + +void LauncherApp::LaunchClient(std::string app_url) { + DVLOG(1) << "Launching " << app_url; + + app_impl_->ConnectToService(app_url, &client_view_provider_); + client_view_provider_.set_connection_error_handler(base::Bind( + &LauncherApp::OnClientConnectionError, base::Unretained(this))); + + client_view_provider_->CreateView( + nullptr, nullptr, + base::Bind(&LauncherApp::OnClientViewCreated, base::Unretained(this))); +} + +void LauncherApp::OnClientConnectionError() { + LOG(ERROR) << "Exiting due to client application connection error."; + app_impl_->Terminate(); +} + +void LauncherApp::OnClientViewCreated(mojo::ui::ViewTokenPtr view_token) { + client_view_token_ = view_token.Pass(); + UpdateClientView(); +} + +void LauncherApp::UpdateClientView() { + if (view_tree_) + view_tree_->SetRoot(client_view_token_.Clone()); +} + +} // namespace launcher
diff --git a/services/ui/launcher/launcher_app.h b/services/ui/launcher/launcher_app.h new file mode 100644 index 0000000..d614956 --- /dev/null +++ b/services/ui/launcher/launcher_app.h
@@ -0,0 +1,65 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SERVICES_UI_LAUNCHER_LAUNCHER_APP_H_ +#define SERVICES_UI_LAUNCHER_LAUNCHER_APP_H_ + +#include <memory> + +#include "mojo/common/tracing_impl.h" +#include "mojo/public/cpp/application/application_delegate.h" +#include "mojo/services/native_viewport/interfaces/native_viewport.mojom.h" +#include "mojo/services/surfaces/interfaces/display.mojom.h" +#include "mojo/services/ui/views/interfaces/view_provider.mojom.h" + +namespace launcher { + +class LauncherViewTree; + +class LauncherApp : public mojo::ApplicationDelegate, + public mojo::NativeViewportEventDispatcher { + public: + LauncherApp(); + ~LauncherApp() override; + + private: + // |ApplicationDelegate|: + void Initialize(mojo::ApplicationImpl* app) override; + + // |NativeViewportEventDispatcher|: + void OnEvent(mojo::EventPtr event, + const mojo::Callback<void()>& callback) override; + + void InitViewport(); + void OnViewportConnectionError(); + void OnViewportCreated(mojo::ViewportMetricsPtr metrics); + void OnViewportMetricsChanged(mojo::ViewportMetricsPtr metrics); + void RequestUpdatedViewportMetrics(); + + void OnViewManagerConnectionError(); + + void LaunchClient(std::string app_url); + void OnClientConnectionError(); + void OnClientViewCreated(mojo::ui::ViewTokenPtr view_token); + + void UpdateClientView(); + + mojo::ApplicationImpl* app_impl_; + mojo::TracingImpl tracing_; + + mojo::NativeViewportPtr viewport_service_; + mojo::Binding<NativeViewportEventDispatcher> + viewport_event_dispatcher_binding_; + + std::unique_ptr<LauncherViewTree> view_tree_; + + mojo::ui::ViewProviderPtr client_view_provider_; + mojo::ui::ViewTokenPtr client_view_token_; + + DISALLOW_COPY_AND_ASSIGN(LauncherApp); +}; + +} // namespace launcher + +#endif // SERVICES_UI_LAUNCHER_LAUNCHER_APP_H_
diff --git a/services/ui/launcher/launcher_view_tree.cc b/services/ui/launcher/launcher_view_tree.cc new file mode 100644 index 0000000..052b3c0 --- /dev/null +++ b/services/ui/launcher/launcher_view_tree.cc
@@ -0,0 +1,159 @@ +// Copyright 2015 The Chromium 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 "base/bind.h" +#include "services/ui/launcher/launcher_view_tree.h" + +namespace launcher { + +LauncherViewTree::LauncherViewTree(mojo::ApplicationImpl* app_impl, + mojo::DisplayPtr display, + mojo::ViewportMetricsPtr viewport_metrics) + : display_(display.Pass()), + viewport_metrics_(viewport_metrics.Pass()), + binding_(this), + root_key_(0), + frame_scheduled_(false), + frame_pending_(false) { + app_impl->ConnectToService("mojo:view_manager_service", &view_manager_); + view_manager_.set_connection_error_handler(base::Bind( + &LauncherViewTree::OnViewManagerConnectionError, base::Unretained(this))); + + mojo::ui::ViewTreePtr view_tree; + binding_.Bind(mojo::GetProxy(&view_tree)); + view_manager_->RegisterViewTree( + view_tree.Pass(), mojo::GetProxy(&view_tree_host_), + base::Bind(&LauncherViewTree::OnViewTreeRegistered, + base::Unretained(this))); + + ScheduleFrame(); +} + +LauncherViewTree::~LauncherViewTree() {} + +void LauncherViewTree::SetRoot(mojo::ui::ViewTokenPtr token) { + root_ = token.Pass(); + if (root_) + view_tree_host_->SetRoot(++root_key_, root_.Clone()); + else + view_tree_host_->ResetRoot(); + root_layout_info_.reset(); +} + +void LauncherViewTree::SetViewportMetrics( + mojo::ViewportMetricsPtr viewport_metrics) { + viewport_metrics_ = viewport_metrics.Pass(); + view_tree_host_->RequestLayout(); +} + +void LauncherViewTree::DispatchEvent(mojo::EventPtr event) { + // TODO(jeffbrown): Support input dispatch. +} + +void LauncherViewTree::OnViewManagerConnectionError() { + LOG(ERROR) << "View manager connection error."; +} + +void LauncherViewTree::OnViewTreeRegistered() {} + +void LauncherViewTree::OnLayout(const OnLayoutCallback& callback) { + LayoutRoot(); + callback.Run(); +} + +void LauncherViewTree::OnRootUnavailable( + uint32_t root_key, + const OnRootUnavailableCallback& callback) { + if (root_key_ == root_key) { + // TODO(jeffbrown): We should probably shut down the launcher. + LOG(ERROR) << "Root view terminated unexpectedly."; + SetRoot(mojo::ui::ViewTokenPtr()); + } + callback.Run(); +} + +void LauncherViewTree::LayoutRoot() { + if (!root_) + return; + + auto params = mojo::ui::ViewLayoutParams::New(); + params->constraints = mojo::ui::BoxConstraints::New(); + params->constraints->min_width = viewport_metrics_->size->width; + params->constraints->max_width = viewport_metrics_->size->width; + params->constraints->min_height = viewport_metrics_->size->height; + params->constraints->max_height = viewport_metrics_->size->height; + params->device_pixel_ratio = viewport_metrics_->device_pixel_ratio; + view_tree_host_->LayoutRoot( + params.Pass(), + base::Bind(&LauncherViewTree::OnLayoutResult, base::Unretained(this))); +} + +void LauncherViewTree::OnLayoutResult(mojo::ui::ViewLayoutInfoPtr info) { + if (!info) { + DVLOG(1) << "Root layout: <stale>"; + return; + } + + DVLOG(1) << "Root layout: size.width=" << info->size->width + << ", size.height=" << info->size->height + << ", surface_id.id_namespace=" << info->surface_id->id_namespace + << ", surface_id.local=" << info->surface_id->local; + + root_layout_info_ = info.Pass(); + ScheduleFrame(); +} + +void LauncherViewTree::ScheduleFrame() { + frame_scheduled_ = true; + FinishFrame(); +} + +void LauncherViewTree::FinishFrame() { + if (!frame_scheduled_ || frame_pending_) + return; + frame_scheduled_ = false; + + mojo::FramePtr frame = mojo::Frame::New(); + frame->resources.resize(0u); + + mojo::Rect bounds; + bounds.width = viewport_metrics_->size->width; + bounds.height = viewport_metrics_->size->height; + mojo::PassPtr pass = mojo::CreateDefaultPass(1, bounds); + pass->shared_quad_states.push_back( + mojo::CreateDefaultSQS(*viewport_metrics_->size)); + + mojo::QuadPtr quad = mojo::Quad::New(); + quad->rect = bounds.Clone(); + quad->opaque_rect = bounds.Clone(); + quad->visible_rect = bounds.Clone(); + quad->shared_quad_state_index = 0u; + + if (root_layout_info_) { + quad->material = mojo::Material::SURFACE_CONTENT; + quad->surface_quad_state = mojo::SurfaceQuadState::New(); + quad->surface_quad_state->surface = root_layout_info_->surface_id.Clone(); + } else { + quad->material = mojo::Material::SOLID_COLOR; + quad->solid_color_quad_state = mojo::SolidColorQuadState::New(); + quad->solid_color_quad_state->color = mojo::Color::New(); + quad->solid_color_quad_state->color->rgba = 0xffff0000; + } + + pass->quads.push_back(quad.Pass()); + frame->passes.push_back(pass.Pass()); + + frame_pending_ = true; + display_->SubmitFrame( + frame.Pass(), + base::Bind(&LauncherViewTree::OnFrameSubmitted, base::Unretained(this))); +} + +void LauncherViewTree::OnFrameSubmitted() { + DCHECK(frame_pending_); + frame_pending_ = false; + FinishFrame(); +} + +} // namespace launcher
diff --git a/services/ui/launcher/launcher_view_tree.h b/services/ui/launcher/launcher_view_tree.h new file mode 100644 index 0000000..58ab563 --- /dev/null +++ b/services/ui/launcher/launcher_view_tree.h
@@ -0,0 +1,67 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SERVICES_UI_LAUNCHER_VIEW_TREE_IMPL_H_ +#define SERVICES_UI_LAUNCHER_VIEW_TREE_IMPL_H_ + +#include "base/macros.h" +#include "mojo/public/cpp/application/application_impl.h" +#include "mojo/public/cpp/bindings/binding.h" +#include "mojo/services/native_viewport/interfaces/native_viewport.mojom.h" +#include "mojo/services/surfaces/cpp/surfaces_utils.h" +#include "mojo/services/surfaces/interfaces/display.mojom.h" +#include "mojo/services/surfaces/interfaces/quads.mojom.h" +#include "mojo/services/surfaces/interfaces/surfaces.mojom.h" +#include "mojo/services/ui/views/interfaces/view_manager.mojom.h" + +namespace launcher { + +class LauncherViewTree : public mojo::ui::ViewTree { + public: + LauncherViewTree(mojo::ApplicationImpl* app_impl, + mojo::DisplayPtr display, + mojo::ViewportMetricsPtr viewport_metrics); + + ~LauncherViewTree() override; + + void SetRoot(mojo::ui::ViewTokenPtr token); + void SetViewportMetrics(mojo::ViewportMetricsPtr viewport_metrics); + void DispatchEvent(mojo::EventPtr event); + + private: + // |ViewTree|: + void OnLayout(const OnLayoutCallback& callback) override; + void OnRootUnavailable(uint32_t root_key, + const OnRootUnavailableCallback& callback) override; + + void OnViewManagerConnectionError(); + void OnViewTreeRegistered(); + + void LayoutRoot(); + void OnLayoutResult(mojo::ui::ViewLayoutInfoPtr info); + + void ScheduleFrame(); + void FinishFrame(); + void OnFrameSubmitted(); + + mojo::ui::ViewManagerPtr view_manager_; + mojo::DisplayPtr display_; + mojo::ViewportMetricsPtr viewport_metrics_; + mojo::Binding<mojo::ui::ViewTree> binding_; + + mojo::ui::ViewTreeHostPtr view_tree_host_; + + mojo::ui::ViewTokenPtr root_; + uint32_t root_key_; + mojo::ui::ViewLayoutInfoPtr root_layout_info_; + + bool frame_scheduled_; + bool frame_pending_; + + DISALLOW_COPY_AND_ASSIGN(LauncherViewTree); +}; + +} // namespace launcher + +#endif // SERVICES_UI_LAUNCHER_VIEW_TREE_IMPL_H_
diff --git a/services/ui/launcher/main.cc b/services/ui/launcher/main.cc new file mode 100644 index 0000000..fa82e08 --- /dev/null +++ b/services/ui/launcher/main.cc
@@ -0,0 +1,12 @@ +// Copyright 2015 The Chromium 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 "mojo/application/application_runner_chromium.h" +#include "mojo/public/c/system/main.h" +#include "services/ui/launcher/launcher_app.h" + +MojoResult MojoMain(MojoHandle application_request) { + mojo::ApplicationRunnerChromium runner(new launcher::LauncherApp); + return runner.Run(application_request); +}