|  | // 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/global.h> | 
|  | #include <lib/syslog/logger.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_LOGF(ERROR, "kLogTag", | 
|  | "Unable to connect to fuchsia_element::Presenter protocol: %s", | 
|  | graphical_client_end.status_string()); | 
|  | } | 
|  |  | 
|  | presenter_.Bind(std::move(*graphical_client_end), dispatcher_); | 
|  | FX_LOG(INFO, kLogTag, "Presenter Binded"); | 
|  |  | 
|  | auto flatland_client_end = | 
|  | component::Connect<fuchsia_ui_composition::Flatland>(); | 
|  | if (flatland_client_end.is_error()) { | 
|  | FX_LOGF( | 
|  | ERROR, kLogTag, | 
|  | "Unable to connect to fuchsia_ui_composition::Flatland protocol: %s", | 
|  | flatland_client_end.status_string()); | 
|  | } | 
|  |  | 
|  | flatland_.Bind(std::move(*flatland_client_end), dispatcher_); | 
|  | FX_LOG(INFO, kLogTag, "Connected to Flatland"); | 
|  | } | 
|  |  | 
|  | void GraphicalWindow::CreateView() { | 
|  | FX_LOG(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_LOG(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_LOGF(ERROR, kLogTag, "Unable to run Create View: %s", | 
|  | create.error_value().status_string()); | 
|  | } | 
|  | FX_LOG(INFO, kLogTag, "View Created"); | 
|  |  | 
|  | auto present_flatland = | 
|  | flatland_->Present(fuchsia_ui_composition::PresentArgs{}); | 
|  | if (present_flatland.is_error()) { | 
|  | FX_LOGF(ERROR, kLogTag, "Unable to present Flatland: %s", | 
|  | present_flatland.error_value().status_string()); | 
|  | } | 
|  |  | 
|  | // Attach View to Parent | 
|  | presenter_->PresentView({{.view_spec = std::move(view_spec)}}) | 
|  | .Then([](auto result) { | 
|  | if (result.is_error()) { | 
|  | FX_LOGF(ERROR, kLogTag, "PresentView failed:"); | 
|  | } | 
|  | }); | 
|  | FX_LOG(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_LOGF(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_LOGF(INFO, kLogTag, "Width: %d", windowWidth); | 
|  | FX_LOGF(INFO, kLogTag, "Height: %d", 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_LOGF(ERROR, kLogTag, "Unable to run Create Transform: %s", | 
|  | create_transform.error_value().status_string()); | 
|  | }; | 
|  |  | 
|  | auto root_transform = flatland_->SetRootTransform( | 
|  | fuchsia_ui_composition::TransformId({.value = kRootTransformId})); | 
|  | if (root_transform.is_error()) { | 
|  | FX_LOGF(ERROR, kLogTag, "Unable to run Root Transform: %s", | 
|  | root_transform.error_value().status_string()); | 
|  | }; | 
|  | FX_LOG(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_LOGF(ERROR, kLogTag, "Unable to Set Region"); | 
|  | }; | 
|  | FX_LOG(INFO, kLogTag, "Square Translation Set"); | 
|  |  | 
|  | // Create Square | 
|  | auto create_rect = flatland_->CreateFilledRect(kFilledRectId); | 
|  | if (create_rect.is_error()) { | 
|  | FX_LOGF(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_LOGF(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_LOGF(ERROR, kLogTag, "Unable to Set Content"); | 
|  | }; | 
|  | FX_LOG(INFO, kLogTag, "Content Created"); | 
|  |  | 
|  | auto present_flatland = | 
|  | flatland_->Present(fuchsia_ui_composition::PresentArgs{}); | 
|  | if (present_flatland.is_error()) { | 
|  | FX_LOGF(ERROR, kLogTag, "Unable to present Flatland: %s", | 
|  | present_flatland.error_value().status_string()); | 
|  | } | 
|  | FX_LOG(INFO, kLogTag, "View Presented!"); | 
|  | } |