| // Copyright 2024 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 <fidl/fuchsia.ui.composition/cpp/fidl.h> |
| #include <fidl/fuchsia.ui.views/cpp/fidl.h> |
| #include <lib/async-loop/cpp/loop.h> |
| #include <lib/async-loop/default.h> |
| #include <lib/component/incoming/cpp/protocol.h> |
| #include <lib/fidl/cpp/interface_ptr.h> |
| #include <lib/fidl/cpp/wire/internal/thenable.h> |
| #include <lib/sys/cpp/component_context.h> |
| #include <lib/syslog/cpp/macros.h> |
| #include <lib/ui/scenic/cpp/view_creation_tokens.h> |
| #include <lib/ui/scenic/cpp/view_identity.h> |
| #include <zircon/rights.h> |
| #include <zircon/status.h> |
| |
| #include <cstdint> |
| #include <iostream> |
| |
| #include "graphical_window.h" |
| |
| namespace { |
| // Tag for logging errors |
| constexpr char kLogTag[] = "reference_session"; |
| |
| // ID for transform |
| static constexpr uint64_t kRootTransformId = 1; |
| } // namespace |
| |
| GraphicalWindow::GraphicalWindow(async_dispatcher_t *dispatcher) |
| : dispatcher_(dispatcher) { |
| auto graphical_client_end = |
| component::Connect<fuchsia_element::GraphicalPresenter>(); |
| if (graphical_client_end.is_error()) { |
| FX_LOGST(ERROR, kLogTag) |
| << "Unable to connect to fuchsia_element::Presenter protocol: " |
| << graphical_client_end.status_string(); |
| } |
| |
| presenter_.Bind(std::move(*graphical_client_end), dispatcher_); |
| FX_LOGST(INFO, kLogTag) << "Presenter Binded"; |
| |
| auto flatland_client_end = |
| component::Connect<fuchsia_ui_composition::Flatland>(); |
| if (flatland_client_end.is_error()) { |
| FX_LOGST(ERROR, kLogTag) |
| << "Unable to connect to fuchsia_ui_composition::Flatland protocol: " |
| << flatland_client_end.status_string(); |
| } |
| |
| flatland_.Bind(std::move(*flatland_client_end), dispatcher_); |
| FX_LOGST(INFO, kLogTag) << "Connected to Flatland"; |
| } |
| |
| void GraphicalWindow::CreateView() { |
| FX_LOGST(INFO, kLogTag) << "Creating View..."; |
| |
| // Creating Flatland View |
| auto [view_token, parent_viewport_token] = |
| scenic::ViewCreationTokenPair::New(); |
| |
| fuchsia_element::ViewSpec view_spec; |
| view_spec.viewport_creation_token(fuchsia_ui_views::ViewportCreationToken( |
| std::move(parent_viewport_token.value))); |
| |
| FX_LOGST(INFO, kLogTag) << "View Creation Token Created"; |
| |
| auto parent_viewport_watcher_endpoints = |
| fidl::CreateEndpoints<fuchsia_ui_composition::ParentViewportWatcher>(); |
| |
| auto [parent_viewport_watcher_client_end, |
| parent_viewport_watcher_server_end] = |
| std::move(parent_viewport_watcher_endpoints.value()); |
| parent_viewport_watcher_.Bind(std::move(parent_viewport_watcher_client_end), |
| dispatcher_); |
| |
| auto create = |
| flatland_->CreateView({{.token = std::move(view_token.value), |
| .parent_viewport_watcher = std::move( |
| parent_viewport_watcher_server_end)}}); |
| if (create.is_error()) { |
| FX_LOGST(ERROR, kLogTag) |
| << "Unable to run Create View: " << create.error_value(); |
| } |
| FX_LOGST(INFO, kLogTag) << "View Created"; |
| |
| auto present_flatland = |
| flatland_->Present(fuchsia_ui_composition::PresentArgs{}); |
| if (present_flatland.is_error()) { |
| FX_LOGST(ERROR, kLogTag) |
| << "Unable to present Flatland: " << present_flatland.error_value(); |
| } |
| |
| // Attach View to Parent |
| presenter_->PresentView({{.view_spec = std::move(view_spec)}}) |
| .Then([](auto result) { |
| if (result.is_error()) { |
| FX_LOGST(ERROR, kLogTag) |
| << "PresentView failed: " << result.error_value(); |
| } |
| }); |
| FX_LOGST(INFO, kLogTag) << "View Presented!"; |
| |
| // Gets size of emulator window and draws square |
| GetLayout(); |
| } |
| |
| void GraphicalWindow::GetLayout() { |
| parent_viewport_watcher_->GetLayout().ThenExactlyOnce( |
| [&](fidl::Result<fuchsia_ui_composition::ParentViewportWatcher::GetLayout> |
| &result) { OnGetLayout(result); }); |
| } |
| |
| void GraphicalWindow::OnGetLayout( |
| fidl::Result<fuchsia_ui_composition::ParentViewportWatcher::GetLayout> |
| &result) { |
| // Get terminal window size |
| if (result.is_ok()) { |
| FX_LOGST(INFO, kLogTag) << "Layout Received: "; |
| int32_t windowWidth = |
| static_cast<int32_t>(result->info().logical_size()->width()); |
| int32_t windowHeight = |
| static_cast<int32_t>(result->info().logical_size()->height()); |
| FX_LOGST(INFO, kLogTag) << "Width: " << windowWidth; |
| FX_LOGST(INFO, kLogTag) << "Height: " << windowHeight; |
| |
| DrawSquare(windowWidth, windowHeight, |
| static_cast<uint32_t>(windowWidth / 5)); |
| } |
| } |
| |
| void GraphicalWindow::DrawSquare(int32_t window_width, int32_t window_height, |
| uint32_t square_size) { |
| // Create ID for square |
| const fuchsia_ui_composition::ContentId kFilledRectId = {1}; |
| |
| // Create Transform and set to root transform |
| auto create_transform = flatland_->CreateTransform( |
| fuchsia_ui_composition::TransformId({.value = kRootTransformId})); |
| if (create_transform.is_error()) { |
| FX_LOGST(ERROR, kLogTag) |
| << "Unable to run Create Transform: " << create_transform.error_value(); |
| }; |
| |
| auto root_transform = flatland_->SetRootTransform( |
| fuchsia_ui_composition::TransformId({.value = kRootTransformId})); |
| if (root_transform.is_error()) { |
| FX_LOGST(ERROR, kLogTag) |
| << "Unable to run Root Transform: " << root_transform.error_value(); |
| }; |
| FX_LOGST(INFO, kLogTag) << "Transform Created"; |
| |
| // Move square towards middle of terminal window |
| auto set_region = flatland_->SetTranslation( |
| {fuchsia_ui_composition::TransformId({.value = kRootTransformId}), |
| {static_cast<int32_t>((window_width / 2) - (square_size / 2)), |
| static_cast<int32_t>((window_height / 2) - (square_size / 2))}}); |
| |
| if (set_region.is_error()) { |
| FX_LOGST(ERROR, kLogTag) << "Unable to Set Region"; |
| }; |
| FX_LOGST(INFO, kLogTag) << "Square Translation Set"; |
| |
| // Create Square |
| auto create_rect = flatland_->CreateFilledRect(kFilledRectId); |
| if (create_rect.is_error()) { |
| FX_LOGST(ERROR, kLogTag) << "Unable to Create Rectangle"; |
| }; |
| |
| // Here, you can change the color of the rectangle! Change the color of the |
| // rectangle and run the session again to see the change of your color. |
| |
| // R G B Alpha |
| // {x, y, z, a} |
| |
| // {0.28, 0.46, 1, 1} will give you blue! |
| |
| auto set_fill = |
| flatland_->SetSolidFill({{kFilledRectId, |
| {1, 0, 1, 1} /* The color fuchsia*/, |
| {square_size, square_size} /* size */}}); |
| if (set_fill.is_error()) { |
| FX_LOGST(ERROR, kLogTag) << "Unable to Set Solid Fill"; |
| }; |
| |
| // Set Content and Present |
| auto set_content = flatland_->SetContent( |
| {{fuchsia_ui_composition::TransformId({.value = kRootTransformId}), |
| kFilledRectId}}); |
| if (set_content.is_error()) { |
| FX_LOGST(ERROR, kLogTag) << "Unable to Set Content"; |
| }; |
| FX_LOGST(INFO, kLogTag) << "Content Created"; |
| |
| auto present_flatland = |
| flatland_->Present(fuchsia_ui_composition::PresentArgs{}); |
| if (present_flatland.is_error()) { |
| FX_LOGST(ERROR, kLogTag) |
| << "Unable to present Flatland: " << present_flatland.error_value(); |
| } |
| FX_LOGST(INFO, kLogTag) << "View Presented!"; |
| } |