blob: f67ae84e629e795903667d689ab9030fba263c10 [file] [log] [blame]
// Copyright 2015 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 "garnet/bin/ui/root_presenter/app.h"
#include <algorithm>
#include <cstdlib>
#include <string>
#include <fuchsia/ui/input/cpp/fidl.h>
#include "lib/component/cpp/connect.h"
#include "lib/fidl/cpp/clone.h"
#include "lib/fxl/files/file.h"
#include "lib/fxl/logging.h"
#include "lib/ui/input/cpp/formatting.h"
namespace root_presenter {
App::App(const fxl::CommandLine& command_line)
: startup_context_(component::StartupContext::CreateFromStartupInfo()),
input_reader_(this) {
FXL_DCHECK(startup_context_);
input_reader_.Start();
startup_context_->outgoing().AddPublicService(
presenter_bindings_.GetHandler(this));
startup_context_->outgoing().AddPublicService(
presenter2_bindings_.GetHandler(this));
startup_context_->outgoing().AddPublicService(
input_receiver_bindings_.GetHandler(this));
}
App::~App() {}
Presentation::YieldCallback App::GetYieldCallback() {
return [this](bool yield_to_next) {
if (yield_to_next) {
SwitchToNextPresentation();
} else {
SwitchToPreviousPresentation();
}
};
}
Presentation::ShutdownCallback App::GetShutdownCallback(
Presentation* presentation) {
return [this, presentation] {
size_t idx;
for (idx = 0; idx < presentations_.size(); ++idx) {
if (presentations_[idx].get() == presentation) {
break;
}
}
FXL_DCHECK(idx != presentations_.size());
if (idx == active_presentation_idx_) {
// This works fine when idx == 0, because the previous idx chosen will
// also be 0, and it will be an no-op within SwitchToPreviousPresentation.
// Finally, at the end of the callback, everything will be cleaned up.
SwitchToPreviousPresentation();
}
presentations_.erase(presentations_.begin() + idx);
if (idx < active_presentation_idx_) {
// Adjust index into presentations_.
active_presentation_idx_--;
}
if (presentations_.empty()) {
layer_stack_->RemoveAllLayers();
active_presentation_idx_ = std::numeric_limits<size_t>::max();
}
};
}
void App::Present2(zx::eventpair view_holder_token,
fidl::InterfaceRequest<fuchsia::ui::policy::Presentation>
presentation_request) {
InitializeServices();
// Duplication intentional, this copy will go away soon.
int32_t display_startup_rotation_adjustment = 0;
{
std::string rotation_value;
if (files::ReadFileToString("/system/data/root_presenter/display_rotation",
&rotation_value)) {
display_startup_rotation_adjustment = atoi(rotation_value.c_str());
FXL_LOG(INFO) << "Display rotation adjustment applied: "
<< display_startup_rotation_adjustment << " degrees.";
}
}
auto presentation = std::make_unique<Presentation1>(
scenic_.get(), session_.get(), compositor_->id(),
std::move(view_holder_token), renderer_params_,
display_startup_rotation_adjustment, startup_context_.get());
presentation->Present(std::move(presentation_request), GetYieldCallback(),
GetShutdownCallback(presentation.get()));
AddPresentation(std::move(presentation));
}
void App::PresentView(
zx::eventpair view_holder_token,
::fidl::InterfaceRequest<fuchsia::ui::policy::Presentation>
presentation_request) {
InitializeServices();
int32_t display_startup_rotation_adjustment = 0;
{
std::string rotation_value;
if (files::ReadFileToString("/system/data/root_presenter/display_rotation",
&rotation_value)) {
display_startup_rotation_adjustment = atoi(rotation_value.c_str());
FXL_LOG(INFO) << "Display rotation adjustment applied: "
<< display_startup_rotation_adjustment << " degrees.";
}
}
auto presentation = std::make_unique<Presentation2>(
scenic_.get(), session_.get(), compositor_->id(),
std::move(view_holder_token), renderer_params_,
display_startup_rotation_adjustment);
presentation->PresentView(std::move(presentation_request), GetYieldCallback(),
GetShutdownCallback(presentation.get()));
AddPresentation(std::move(presentation));
}
void App::AddPresentation(std::unique_ptr<Presentation> presentation) {
for (auto& it : devices_by_id_) {
presentation->OnDeviceAdded(it.second.get());
}
presentations_.push_back(std::move(presentation));
SwitchToPresentation(presentations_.size() - 1);
}
void App::HACK_SetRendererParams(
bool enable_clipping,
::std::vector<fuchsia::ui::gfx::RendererParam> params) {
renderer_params_.clipping_enabled = enable_clipping;
FXL_LOG(INFO)
<< "Presenter::HACK_SetRendererParams: Setting clipping enabled to "
<< (enable_clipping ? "true" : "false");
for (auto& param : params) {
switch (param.Which()) {
case ::fuchsia::ui::gfx::RendererParam::Tag::kShadowTechnique:
renderer_params_.shadow_technique = param.shadow_technique();
FXL_LOG(INFO)
<< "Presenter::HACK_SetRendererParams: Setting shadow technique to "
<< fidl::ToUnderlying(param.shadow_technique());
continue;
case fuchsia::ui::gfx::RendererParam::Tag::kRenderFrequency:
renderer_params_.render_frequency = param.render_frequency();
FXL_LOG(INFO)
<< "Presenter::HACK_SetRendererParams: Setting render frequency to "
<< fidl::ToUnderlying(param.render_frequency());
continue;
case fuchsia::ui::gfx::RendererParam::Tag::Invalid:
continue;
}
}
for (const auto& presentation : presentations_) {
presentation->OverrideRendererParams(renderer_params_);
}
}
void App::SwitchToPresentation(const size_t presentation_idx) {
FXL_DCHECK(presentation_idx < presentations_.size());
if (presentation_idx == active_presentation_idx_) {
return;
}
active_presentation_idx_ = presentation_idx;
layer_stack_->RemoveAllLayers();
layer_stack_->AddLayer(presentations_[presentation_idx]->layer());
session_->Present(0, [](fuchsia::images::PresentationInfo info) {});
}
void App::SwitchToNextPresentation() {
SwitchToPresentation((active_presentation_idx_ + 1) % presentations_.size());
}
void App::SwitchToPreviousPresentation() {
SwitchToPresentation((active_presentation_idx_ + presentations_.size() - 1) %
presentations_.size());
}
void App::RegisterDevice(fuchsia::ui::input::DeviceDescriptor descriptor,
fidl::InterfaceRequest<fuchsia::ui::input::InputDevice>
input_device_request) {
uint32_t device_id = ++next_device_token_;
FXL_VLOG(1) << "RegisterDevice " << device_id << " " << descriptor;
std::unique_ptr<mozart::InputDeviceImpl> input_device =
std::make_unique<mozart::InputDeviceImpl>(
device_id, std::move(descriptor), std::move(input_device_request),
this);
for (auto& presentation : presentations_) {
presentation->OnDeviceAdded(input_device.get());
}
devices_by_id_.emplace(device_id, std::move(input_device));
}
void App::OnDeviceDisconnected(mozart::InputDeviceImpl* input_device) {
if (devices_by_id_.count(input_device->id()) == 0)
return;
FXL_VLOG(1) << "UnregisterDevice " << input_device->id();
for (auto& presentation : presentations_) {
presentation->OnDeviceRemoved(input_device->id());
}
devices_by_id_.erase(input_device->id());
}
void App::OnReport(mozart::InputDeviceImpl* input_device,
fuchsia::ui::input::InputReport report) {
FXL_VLOG(3) << "OnReport from " << input_device->id() << " " << report;
if (devices_by_id_.count(input_device->id()) == 0 ||
presentations_.size() == 0)
return;
FXL_DCHECK(active_presentation_idx_ < presentations_.size());
FXL_VLOG(3) << "OnReport to " << active_presentation_idx_;
// Input events are only reported to the active presentation.
presentations_[active_presentation_idx_]->OnReport(input_device->id(),
std::move(report));
}
void App::InitializeServices() {
if (!scenic_) {
startup_context_->ConnectToEnvironmentService(scenic_.NewRequest());
scenic_.set_error_handler([this](zx_status_t error) {
FXL_LOG(ERROR) << "Scenic died, destroying all presentations.";
Reset();
});
session_ = std::make_unique<scenic::Session>(scenic_.get());
session_->set_error_handler([this](zx_status_t error) {
FXL_LOG(ERROR) << "Session died, destroying all presentations.";
Reset();
});
// Globally disable parallel dispatch of input events.
// TODO(SCN-1047): Enable parallel dispatch.
{
fuchsia::ui::input::SetParallelDispatchCmd cmd;
cmd.parallel_dispatch = false;
fuchsia::ui::input::Command input_cmd;
input_cmd.set_set_parallel_dispatch(std::move(cmd));
session_->Enqueue(std::move(input_cmd));
}
compositor_ = std::make_unique<scenic::DisplayCompositor>(session_.get());
layer_stack_ = std::make_unique<scenic::LayerStack>(session_.get());
compositor_->SetLayerStack(*layer_stack_.get());
session_->Present(0, [](fuchsia::images::PresentationInfo info) {});
scenic_->GetDisplayOwnershipEvent([this](zx::event event) {
input_reader_.SetOwnershipEvent(std::move(event));
});
}
}
void App::Reset() {
presentations_.clear(); // must be first, holds pointers to services
active_presentation_idx_ = std::numeric_limits<size_t>::max();
layer_stack_ = nullptr;
compositor_ = nullptr;
session_ = nullptr;
scenic_.Unbind();
}
} // namespace root_presenter