| // 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!"); |
| } |