blob: 12fd0b8fbf6c878c6b8459673ea063e11066db68 [file] [log] [blame]
// Copyright 2021 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 "ui/ozone/platform/flatland/flatland_window.h"
#include <fuchsia/sys/cpp/fidl.h>
#include <lib/sys/cpp/component_context.h>
#include <lib/ui/scenic/cpp/view_identity.h>
#include <algorithm>
#include <cstdint>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/fuchsia/process_context.h"
#include "base/memory/scoped_refptr.h"
#include "flatland_connection.h"
#include "ui/base/cursor/platform_cursor.h"
#include "ui/events/event.h"
#include "ui/events/ozone/events_ozone.h"
#include "ui/events/platform/platform_event_source.h"
#include "ui/ozone/platform/flatland/flatland_window_manager.h"
namespace ui {
FlatlandWindow::FlatlandWindow(FlatlandWindowManager* window_manager,
PlatformWindowDelegate* delegate,
PlatformWindowInitProperties properties)
: manager_(window_manager),
window_delegate_(delegate),
window_id_(manager_->AddWindow(this)),
view_ref_(std::move(properties.view_ref_pair.view_ref)),
view_controller_(std::move(properties.view_controller)),
flatland_("Chromium FlatlandWindow"),
bounds_(properties.bounds) {
if (view_controller_) {
view_controller_.set_error_handler(
fit::bind_member(this, &FlatlandWindow::OnViewControllerDisconnected));
}
fuchsia::ui::views::ViewIdentityOnCreation view_identity = {
.view_ref = CloneViewRef(),
.view_ref_control = std::move(properties.view_ref_pair.control_ref)};
fuchsia::ui::composition::ViewBoundProtocols view_bound_protocols;
view_bound_protocols.set_view_ref_focused(view_ref_focused_.NewRequest());
fuchsia::ui::pointer::TouchSourceHandle touch_source;
view_bound_protocols.set_touch_source(touch_source.NewRequest());
fuchsia::ui::pointer::MouseSourceHandle mouse_source;
view_bound_protocols.set_mouse_source(mouse_source.NewRequest());
pointer_handler_ = std::make_unique<PointerEventsHandler>(
std::move(touch_source), std::move(mouse_source));
pointer_handler_->StartWatching(base::BindRepeating(
&FlatlandWindow::DispatchEvent,
// This is safe since |pointer_handler_| is a class member.
base::Unretained(this)));
flatland_.flatland()->CreateView2(
std::move(properties.view_creation_token), std::move(view_identity),
std::move(view_bound_protocols), parent_viewport_watcher_.NewRequest());
parent_viewport_watcher_->GetLayout(
fit::bind_member(this, &FlatlandWindow::OnGetLayout));
parent_viewport_watcher_->GetStatus(
fit::bind_member(this, &FlatlandWindow::OnGetStatus));
view_ref_focused_->Watch(
fit::bind_member(this, &FlatlandWindow::OnViewRefFocusedWatchResult));
root_transform_id_ = flatland_.NextTransformId();
flatland_.flatland()->CreateTransform(root_transform_id_);
window_delegate_->OnAcceleratedWidgetAvailable(window_id_);
if (properties.enable_keyboard) {
is_virtual_keyboard_enabled_ = properties.enable_virtual_keyboard;
keyboard_service_ = base::ComponentContextForProcess()
->svc()
->Connect<fuchsia::ui::input3::Keyboard>();
keyboard_service_.set_error_handler([](zx_status_t status) {
ZX_LOG(ERROR, status) << "input3.Keyboard service disconnected.";
});
keyboard_client_ = std::make_unique<KeyboardClient>(keyboard_service_.get(),
CloneViewRef(), this);
} else {
DCHECK(!properties.enable_virtual_keyboard);
}
}
FlatlandWindow::~FlatlandWindow() {
manager_->RemoveWindow(window_id_, this);
}
void FlatlandWindow::AttachSurfaceContent(
fuchsia::ui::views::ViewportCreationToken token) {
if (surface_content_id_.value) {
flatland_.flatland()->ReleaseViewport(surface_content_id_, [](auto) {});
flatland_.flatland()->ReleaseTransform(surface_transform_id_);
}
surface_transform_id_ = flatland_.NextTransformId();
flatland_.flatland()->CreateTransform(surface_transform_id_);
flatland_.flatland()->AddChild(root_transform_id_, surface_transform_id_);
fuchsia::ui::composition::ViewportProperties properties;
properties.set_logical_size({static_cast<uint32_t>(bounds_.width()),
static_cast<uint32_t>(bounds_.height())});
surface_content_id_ = flatland_.NextContentId();
fuchsia::ui::composition::ChildViewWatcherPtr content_link;
flatland_.flatland()->CreateViewport(surface_content_id_, std::move(token),
std::move(properties),
content_link.NewRequest());
flatland_.flatland()->SetContent(surface_transform_id_, surface_content_id_);
flatland_.Present();
// View is actually not attached but without it we dont get OutputPresenter
// updates.
OnViewAttachedChanged(true);
}
fuchsia::ui::views::ViewRef FlatlandWindow::CloneViewRef() {
fuchsia::ui::views::ViewRef dup;
zx_status_t status =
view_ref_.reference.duplicate(ZX_RIGHT_SAME_RIGHTS, &dup.reference);
ZX_CHECK(status == ZX_OK, status) << "zx_object_duplicate";
return dup;
}
gfx::Rect FlatlandWindow::GetBoundsInPixels() const {
return bounds_;
}
void FlatlandWindow::SetBoundsInPixels(const gfx::Rect& bounds) {
// This path should only be reached in tests.
bounds_ = bounds;
}
gfx::Rect FlatlandWindow::GetBoundsInDIP() const {
return window_delegate_->ConvertRectToDIP(bounds_);
}
void FlatlandWindow::SetBoundsInDIP(const gfx::Rect& bounds) {
// This path should only be reached in tests.
bounds_ = window_delegate_->ConvertRectToPixels(bounds);
}
void FlatlandWindow::SetTitle(const std::u16string& title) {
NOTIMPLEMENTED();
}
void FlatlandWindow::Show(bool inactive) {
if (is_visible_)
return;
is_visible_ = true;
flatland_.flatland()->SetRootTransform(root_transform_id_);
flatland_.Present();
}
void FlatlandWindow::Hide() {
if (!is_visible_)
return;
is_visible_ = false;
flatland_.flatland()->SetRootTransform({0});
flatland_.Present();
}
void FlatlandWindow::Close() {
if (view_controller_) {
view_controller_->Dismiss();
view_controller_ = nullptr;
}
Hide();
window_delegate_->OnClosed();
}
bool FlatlandWindow::IsVisible() const {
return is_visible_;
}
void FlatlandWindow::PrepareForShutdown() {
NOTIMPLEMENTED();
}
void FlatlandWindow::SetCapture() {
has_capture_ = true;
}
void FlatlandWindow::ReleaseCapture() {
has_capture_ = false;
}
bool FlatlandWindow::HasCapture() const {
return has_capture_;
}
void FlatlandWindow::ToggleFullscreen() {
NOTIMPLEMENTED_LOG_ONCE();
is_fullscreen_ = !is_fullscreen_;
}
void FlatlandWindow::Maximize() {
NOTIMPLEMENTED();
}
void FlatlandWindow::Minimize() {
NOTIMPLEMENTED();
}
void FlatlandWindow::Restore() {
NOTIMPLEMENTED();
}
PlatformWindowState FlatlandWindow::GetPlatformWindowState() const {
NOTIMPLEMENTED_LOG_ONCE();
if (is_fullscreen_)
return PlatformWindowState::kFullScreen;
if (!is_view_attached_)
return PlatformWindowState::kMinimized;
// TODO(crbug.com/1241868): We cannot tell what portion of the screen is
// occupied by the View, so report is as maximized to reduce the space used
// by any browser chrome.
return PlatformWindowState::kMaximized;
}
void FlatlandWindow::Activate() {
NOTIMPLEMENTED_LOG_ONCE();
}
void FlatlandWindow::Deactivate() {
NOTIMPLEMENTED_LOG_ONCE();
}
void FlatlandWindow::SetUseNativeFrame(bool use_native_frame) {}
bool FlatlandWindow::ShouldUseNativeFrame() const {
NOTIMPLEMENTED_LOG_ONCE();
return false;
}
void FlatlandWindow::SetCursor(scoped_refptr<PlatformCursor> cursor) {
NOTIMPLEMENTED_LOG_ONCE();
}
void FlatlandWindow::MoveCursorTo(const gfx::Point& location) {
NOTIMPLEMENTED_LOG_ONCE();
}
void FlatlandWindow::ConfineCursorToBounds(const gfx::Rect& bounds) {
NOTIMPLEMENTED();
}
void FlatlandWindow::SetRestoredBoundsInDIP(const gfx::Rect& bounds) {
NOTIMPLEMENTED();
}
gfx::Rect FlatlandWindow::GetRestoredBoundsInDIP() const {
NOTIMPLEMENTED();
return gfx::Rect();
}
void FlatlandWindow::SetWindowIcons(const gfx::ImageSkia& window_icon,
const gfx::ImageSkia& app_icon) {
NOTIMPLEMENTED();
}
void FlatlandWindow::SizeConstraintsChanged() {
NOTIMPLEMENTED();
}
void FlatlandWindow::OnGetLayout(fuchsia::ui::composition::LayoutInfo info) {
// TODO(https://fxbug.dev/99312): Read device pixel ratio from LayoutInfo when
// available.
view_properties_ = info.logical_size();
if (view_properties_ || device_pixel_ratio_ > 0.0)
UpdateSize();
// Size update is sent via |delegate_| and SetViewportProperties().
if (surface_content_id_.value) {
fuchsia::ui::composition::ViewportProperties properties;
properties.set_logical_size(info.logical_size());
flatland_.flatland()->SetViewportProperties(surface_content_id_,
std::move(properties));
flatland_.Present();
}
parent_viewport_watcher_->GetLayout(
fit::bind_member(this, &FlatlandWindow::OnGetLayout));
}
void FlatlandWindow::OnGetStatus(
fuchsia::ui::composition::ParentViewportStatus status) {
switch (status) {
case fuchsia::ui::composition::ParentViewportStatus::CONNECTED_TO_DISPLAY:
OnViewAttachedChanged(true);
break;
case fuchsia::ui::composition::ParentViewportStatus::
DISCONNECTED_FROM_DISPLAY:
OnViewAttachedChanged(false);
break;
default:
NOTIMPLEMENTED();
break;
}
parent_viewport_watcher_->GetStatus(
fit::bind_member(this, &FlatlandWindow::OnGetStatus));
}
void FlatlandWindow::OnViewRefFocusedWatchResult(
fuchsia::ui::views::FocusState focus_state) {
window_delegate_->OnActivationChanged(focus_state.focused());
view_ref_focused_->Watch(
fit::bind_member(this, &FlatlandWindow::OnViewRefFocusedWatchResult));
}
void FlatlandWindow::UpdateSize() {
DCHECK_GT(device_pixel_ratio_, 0.0);
DCHECK(view_properties_);
const uint32_t width = view_properties_->width;
const uint32_t height = view_properties_->height;
const gfx::Point old_origin = bounds_.origin();
bounds_ = gfx::Rect(ceilf(width * device_pixel_ratio_),
ceilf(height * device_pixel_ratio_));
PlatformWindowDelegate::BoundsChange bounds(old_origin != bounds_.origin());
// TODO(fxbug.dev/93998): Calculate insets and update.
window_delegate_->OnBoundsChanged(bounds);
}
void FlatlandWindow::OnViewAttachedChanged(bool is_view_attached) {
PlatformWindowState old_state = GetPlatformWindowState();
is_view_attached_ = is_view_attached;
PlatformWindowState new_state = GetPlatformWindowState();
if (old_state != new_state) {
window_delegate_->OnWindowStateChanged(old_state, new_state);
}
}
void FlatlandWindow::DispatchEvent(ui::Event* event) {
if (event->IsLocatedEvent()) {
ui::LocatedEvent* located_event = event->AsLocatedEvent();
gfx::PointF location = located_event->location_f();
location.Scale(device_pixel_ratio_);
located_event->set_location_f(location);
}
window_delegate_->DispatchEvent(event);
}
void FlatlandWindow::OnViewControllerDisconnected(zx_status_t status) {
view_controller_ = nullptr;
window_delegate_->OnCloseRequest();
}
} // namespace ui