blob: b88e2ac9dc97bc2f4f3665bd068a64ea3de6d494 [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 "ash/frame/wide_frame_view.h"
#include "ash/frame/header_view.h"
#include "ash/frame/non_client_frame_view_ash.h"
#include "ash/public/cpp/caption_buttons/frame_caption_button_container_view.h"
#include "ash/public/cpp/immersive/immersive_fullscreen_controller.h"
#include "ash/public/cpp/window_properties.h"
#include "ash/shell.h"
#include "ash/wm/overview/overview_controller.h"
#include "ash/wm/window_state.h"
#include "ash/wm/wm_event.h"
#include "base/metrics/user_metrics.h"
#include "ui/aura/window.h"
#include "ui/aura/window_targeter.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/views/widget/widget.h"
#include "ui/views/window/caption_button_layout_constants.h"
namespace ash {
namespace {
class WideFrameTargeter : public aura::WindowTargeter {
public:
explicit WideFrameTargeter(HeaderView* header_view)
: header_view_(header_view) {}
~WideFrameTargeter() override = default;
// aura::WindowTargeter:
bool GetHitTestRects(aura::Window* target,
gfx::Rect* hit_test_rect_mouse,
gfx::Rect* hit_test_rect_touch) const override {
if (header_view_->in_immersive_mode() && !header_view_->is_revealed()) {
aura::Window* source = header_view_->GetWidget()->GetNativeWindow();
*hit_test_rect_mouse = source->bounds();
aura::Window::ConvertRectToTarget(source, target->parent(),
hit_test_rect_mouse);
hit_test_rect_mouse->set_y(target->bounds().y());
hit_test_rect_mouse->set_height(1);
hit_test_rect_touch->SetRect(0, 0, 0, 0);
return true;
}
return aura::WindowTargeter::GetHitTestRects(target, hit_test_rect_mouse,
hit_test_rect_touch);
}
private:
HeaderView* header_view_;
DISALLOW_COPY_AND_ASSIGN(WideFrameTargeter);
};
} // namespace
// static
gfx::Rect WideFrameView::GetFrameBounds(views::Widget* target) {
static const int kFrameHeight =
views::GetCaptionButtonLayoutSize(
views::CaptionButtonLayoutSize::kNonBrowserCaption)
.height();
display::Screen* screen = display::Screen::GetScreen();
aura::Window* target_window = target->GetNativeWindow();
gfx::Rect bounds =
target->IsFullscreen()
? screen->GetDisplayNearestWindow(target_window).bounds()
: screen->GetDisplayNearestWindow(target_window).work_area();
bounds.set_height(kFrameHeight);
return bounds;
}
void WideFrameView::Init(ImmersiveFullscreenController* controller) {
DCHECK(target_);
controller->Init(this, target_, header_view_);
}
void WideFrameView::SetCaptionButtonModel(
std::unique_ptr<CaptionButtonModel> model) {
header_view_->caption_button_container()->SetModel(std::move(model));
header_view_->UpdateCaptionButtons();
}
WideFrameView::WideFrameView(views::Widget* target)
: target_(target), widget_(std::make_unique<views::Widget>()) {
Shell::Get()->overview_controller()->AddObserver(this);
display::Screen::GetScreen()->AddObserver(this);
aura::Window* target_window = target->GetNativeWindow();
target_window->AddObserver(this);
header_view_ = new HeaderView(target);
AddChildView(header_view_);
GetTargetHeaderView()->SetShouldPaintHeader(false);
views::Widget::InitParams params;
params.type = views::Widget::InitParams::TYPE_POPUP;
params.delegate = this;
params.bounds = GetFrameBounds(target);
params.name = "WideFrameView";
params.parent = target->GetNativeWindow();
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
widget_->Init(params);
aura::Window* window = widget_->GetNativeWindow();
window->SetEventTargeter(std::make_unique<WideFrameTargeter>(header_view()));
set_owned_by_client();
}
WideFrameView::~WideFrameView() {
if (widget_)
widget_->CloseNow();
if (Shell::Get()->overview_controller())
Shell::Get()->overview_controller()->RemoveObserver(this);
display::Screen::GetScreen()->RemoveObserver(this);
if (target_) {
GetTargetHeaderView()->SetShouldPaintHeader(true);
target_->GetNativeWindow()->RemoveObserver(this);
}
}
void WideFrameView::DeleteDelegate() {
// WideFrameView is owned by a client, not its widget, so don't delete
// here.
}
void WideFrameView::Layout() {
int onscreen_height = header_view_->GetPreferredOnScreenHeight();
if (onscreen_height == 0 || !visible()) {
header_view_->SetVisible(false);
} else {
const int height = header_view_->GetPreferredHeight();
header_view_->SetBounds(0, onscreen_height - height, width(), height);
header_view_->SetVisible(true);
}
}
void WideFrameView::OnMouseEvent(ui::MouseEvent* event) {
if (event->IsOnlyLeftMouseButton()) {
if ((event->flags() & ui::EF_IS_DOUBLE_CLICK)) {
base::RecordAction(
base::UserMetricsAction("Caption_ClickTogglesMaximize"));
const wm::WMEvent wm_event(wm::WM_EVENT_TOGGLE_MAXIMIZE_CAPTION);
wm::GetWindowState(target_->GetNativeWindow())->OnWMEvent(&wm_event);
}
event->SetHandled();
}
}
void WideFrameView::OnWindowDestroying(aura::Window* window) {
window->RemoveObserver(this);
target_ = nullptr;
}
void WideFrameView::OnDisplayMetricsChanged(const display::Display& display,
uint32_t changed_metrics) {
display::Screen* screen = display::Screen::GetScreen();
if (screen->GetDisplayNearestWindow(target_->GetNativeWindow()).id() !=
display.id()) {
return;
}
DCHECK(target_);
GetWidget()->SetBounds(GetFrameBounds(target_));
}
void WideFrameView::OnImmersiveRevealStarted() {
header_view_->OnImmersiveRevealStarted();
}
void WideFrameView::OnImmersiveRevealEnded() {
header_view_->OnImmersiveRevealEnded();
}
void WideFrameView::OnImmersiveFullscreenEntered() {
header_view_->OnImmersiveFullscreenEntered();
if (target_)
GetTargetHeaderView()->OnImmersiveFullscreenEntered();
}
void WideFrameView::OnImmersiveFullscreenExited() {
header_view_->OnImmersiveFullscreenExited();
if (target_)
GetTargetHeaderView()->OnImmersiveFullscreenExited();
Layout();
}
void WideFrameView::SetVisibleFraction(double visible_fraction) {
header_view_->SetVisibleFraction(visible_fraction);
}
std::vector<gfx::Rect> WideFrameView::GetVisibleBoundsInScreen() const {
return header_view_->GetVisibleBoundsInScreen();
}
void WideFrameView::OnOverviewModeStarting() {
header_view_->SetShouldPaintHeader(false);
}
void WideFrameView::OnOverviewModeEnded() {
header_view_->SetShouldPaintHeader(true);
}
HeaderView* WideFrameView::GetTargetHeaderView() {
auto* frame_view = static_cast<NonClientFrameViewAsh*>(
target_->non_client_view()->frame_view());
return frame_view->GetHeaderView();
}
} // namespace ash