blob: b0262dec4cc9005d291c4914324c51daff547e09 [file] [log] [blame]
// Copyright 2018 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 "components/exo/fullscreen_shell_surface.h"
#include "components/exo/shell_surface_util.h"
#include "components/exo/surface.h"
#include "components/exo/wm_helper.h"
#include "third_party/skia/include/core/SkPath.h"
#include "ui/aura/window.h"
#include "ui/aura/window_observer.h"
#include "ui/aura/window_targeter.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/dip_util.h"
#include "ui/views/widget/widget.h"
#include "ui/wm/core/window_util.h"
namespace exo {
FullscreenShellSurface::FullscreenShellSurface(Surface* surface)
: SurfaceTreeHost("FullscreenShellSurfaceHost") {
surface->AddSurfaceObserver(this);
SetRootSurface(surface);
host_window()->Show();
set_owned_by_client();
CreateFullscreenShellSurfaceWidget(ui::SHOW_STATE_FULLSCREEN);
widget_->SetFullscreen(true);
}
FullscreenShellSurface::~FullscreenShellSurface() {
if (widget_) {
widget_->GetNativeWindow()->RemoveObserver(this);
// Remove transient children so they are not automatically destroyed.
for (auto* child : wm::GetTransientChildren(widget_->GetNativeWindow()))
wm::RemoveTransientChild(widget_->GetNativeWindow(), child);
if (widget_->IsVisible())
widget_->Hide();
widget_->CloseNow();
}
if (parent_)
parent_->RemoveObserver(this);
if (root_surface())
root_surface()->RemoveSurfaceObserver(this);
}
void FullscreenShellSurface::SetApplicationId(const char* application_id) {
// Store the value in |application_id_| in case the window does not exist yet.
if (application_id)
application_id_ = std::string(application_id);
else
application_id_.reset();
if (widget_ && widget_->GetNativeWindow())
SetShellApplicationId(widget_->GetNativeWindow(), application_id_);
}
void FullscreenShellSurface::SetStartupId(const char* startup_id) {
// Store the value in |startup_id_| in case the window does not exist yet.
if (startup_id)
startup_id_ = std::string(startup_id);
else
startup_id_.reset();
if (widget_ && widget_->GetNativeWindow())
SetShellStartupId(widget_->GetNativeWindow(), startup_id_);
}
void FullscreenShellSurface::Maximize() {
if (!widget_)
return;
widget_->Maximize();
}
void FullscreenShellSurface::Minimize() {
if (!widget_)
return;
widget_->Minimize();
}
void FullscreenShellSurface::Close() {
if (!close_callback_.is_null())
close_callback_.Run();
}
void FullscreenShellSurface::OnSurfaceCommit() {
SurfaceTreeHost::OnSurfaceCommit();
if (!OnPreWidgetCommit())
return;
CommitWidget();
SubmitCompositorFrame();
}
bool FullscreenShellSurface::IsInputEnabled(Surface*) const {
return true;
}
void FullscreenShellSurface::OnSetFrame(SurfaceFrameType frame_type) {}
void FullscreenShellSurface::OnSetFrameColors(SkColor active_color,
SkColor inactive_color) {}
void FullscreenShellSurface::OnSetStartupId(const char* startup_id) {
SetStartupId(startup_id);
}
void FullscreenShellSurface::OnSetApplicationId(const char* application_id) {
SetApplicationId(application_id);
}
void FullscreenShellSurface::OnSurfaceDestroying(Surface* surface) {
DCHECK_EQ(root_surface(), surface);
surface->RemoveSurfaceObserver(this);
SetRootSurface(nullptr);
if (widget_)
SetShellMainSurface(widget_->GetNativeWindow(), nullptr);
// Hide widget before surface is destroyed. This allows hide animations to
// run using the current surface contents.
if (widget_) {
// Remove transient children so they are not automatically hidden.
for (auto* child : wm::GetTransientChildren(widget_->GetNativeWindow()))
wm::RemoveTransientChild(widget_->GetNativeWindow(), child);
widget_->Hide();
}
// Note: In its use in the Wayland server implementation, the surface
// destroyed callback may destroy the ShellSurface instance. This call needs
// to be last so that the instance can be destroyed.
std::move(surface_destroyed_callback_).Run();
}
bool FullscreenShellSurface::CanResize() const {
return false;
}
bool FullscreenShellSurface::CanMaximize() const {
return true;
}
bool FullscreenShellSurface::CanMinimize() const {
return true;
}
bool FullscreenShellSurface::ShouldShowWindowTitle() const {
return false;
}
void FullscreenShellSurface::WindowClosing() {
SetEnabled(false);
widget_ = nullptr;
}
views::Widget* FullscreenShellSurface::GetWidget() {
return widget_;
}
const views::Widget* FullscreenShellSurface::GetWidget() const {
return widget_;
}
views::View* FullscreenShellSurface::GetContentsView() {
return this;
}
bool FullscreenShellSurface::WidgetHasHitTestMask() const {
return true;
}
void FullscreenShellSurface::GetWidgetHitTestMask(SkPath* mask) const {
GetHitTestMask(mask);
gfx::Point origin = host_window()->bounds().origin();
SkMatrix matrix;
// TODO (sagallea) acquire scale from display
float scale = 1.f;
matrix.setScaleTranslate(
SkFloatToScalar(1.0f / scale), SkFloatToScalar(1.0f / scale),
SkIntToScalar(origin.x()), SkIntToScalar(origin.y()));
mask->transform(matrix);
}
void FullscreenShellSurface::OnWindowDestroying(aura::Window* window) {
if (window == parent_) {
parent_ = nullptr;
// |parent_| being set to null effects the ability to maximize the window.
if (widget_)
widget_->OnSizeConstraintsChanged();
}
window->RemoveObserver(this);
}
void FullscreenShellSurface::CreateFullscreenShellSurfaceWidget(
ui::WindowShowState show_state) {
DCHECK(enabled());
DCHECK(!widget_);
views::Widget::InitParams params;
params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS;
params.ownership = views::Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET;
params.delegate = this;
params.shadow_type = views::Widget::InitParams::SHADOW_TYPE_NONE;
params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
params.show_state = show_state;
params.activatable = views::Widget::InitParams::ACTIVATABLE_YES;
params.parent = WMHelper::GetInstance()->GetRootWindowForNewWindows();
params.bounds = gfx::Rect(params.parent->bounds().size());
widget_ = new views::Widget();
widget_->Init(params);
aura::Window* window = widget_->GetNativeWindow();
window->SetName("FullscreenShellSurface");
window->AddChild(host_window());
SetShellApplicationId(window, application_id_);
SetShellStartupId(window, startup_id_);
SetShellMainSurface(window, root_surface());
window->AddObserver(this);
}
void FullscreenShellSurface::CommitWidget() {
if (!widget_)
return;
// Show widget if needed.
if (!widget_->IsVisible()) {
DCHECK(!widget_->IsClosed());
widget_->Show();
}
}
bool FullscreenShellSurface::OnPreWidgetCommit() {
if (!widget_ && enabled() && host_window()->bounds().IsEmpty())
return false;
return true;
}
} // namespace exo