blob: ecdf7052a185db3b67a237e4954d612492caa3a4 [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/wm/overview/overview_utils.h"
#include "ash/public/cpp/ash_features.h"
#include "ash/public/cpp/ash_switches.h"
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/shell.h"
#include "ash/wm/overview/cleanup_animation_observer.h"
#include "ash/wm/overview/scoped_overview_animation_settings.h"
#include "ash/wm/overview/window_selector_controller.h"
#include "ash/wm/splitview/split_view_controller.h"
#include "ash/wm/window_state.h"
#include "base/optional.h"
#include "third_party/skia/include/pathops/SkPathOps.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/window.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/scoped_canvas.h"
#include "ui/views/background.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
#include "ui/wm/core/window_animations.h"
namespace ash {
namespace {
// BackgroundWith1PxBorder renders a solid background color, with a one pixel
// border with rounded corners. This accounts for the scaling of the canvas, so
// that the border is 1 pixel thick regardless of display scaling.
class BackgroundWith1PxBorder : public views::Background {
public:
BackgroundWith1PxBorder(SkColor background,
SkColor border_color,
int border_thickness,
int corner_radius)
: border_color_(border_color),
border_thickness_(border_thickness),
corner_radius_(corner_radius) {
SetNativeControlColor(background);
}
// views::Background:
void Paint(gfx::Canvas* canvas, views::View* view) const override {
gfx::RectF border_rect_f(view->GetContentsBounds());
gfx::ScopedCanvas scoped_canvas(canvas);
const float scale = canvas->UndoDeviceScaleFactor();
border_rect_f.Inset(border_thickness_, border_thickness_);
border_rect_f = gfx::ScaleRect(border_rect_f, scale);
SkPath path;
const SkScalar scaled_corner_radius =
SkIntToScalar(gfx::ToCeiledInt(corner_radius_ * scale));
path.addRoundRect(gfx::RectFToSkRect(border_rect_f), scaled_corner_radius,
scaled_corner_radius);
cc::PaintFlags flags;
flags.setStyle(cc::PaintFlags::kStroke_Style);
flags.setStrokeWidth(1);
flags.setAntiAlias(true);
SkPath stroke_path;
flags.getFillPath(path, &stroke_path);
SkPath fill_path;
Op(path, stroke_path, kDifference_SkPathOp, &fill_path);
flags.setStyle(cc::PaintFlags::kFill_Style);
flags.setColor(get_color());
canvas->sk_canvas()->drawPath(fill_path, flags);
if (border_thickness_ > 0) {
flags.setColor(border_color_);
canvas->sk_canvas()->drawPath(stroke_path, flags);
}
}
private:
// Color for the one pixel border.
const SkColor border_color_;
// Thickness of border inset.
const int border_thickness_;
// Corner radius of the inside edge of the roundrect border stroke.
const int corner_radius_;
DISALLOW_COPY_AND_ASSIGN(BackgroundWith1PxBorder);
};
} // namespace
bool CanCoverAvailableWorkspace(aura::Window* window) {
SplitViewController* split_view_controller =
Shell::Get()->split_view_controller();
if (split_view_controller->IsSplitViewModeActive())
return split_view_controller->CanSnap(window);
return wm::GetWindowState(window)->IsMaximizedOrFullscreenOrPinned();
}
bool IsNewOverviewAnimationsEnabled() {
return base::FeatureList::IsEnabled(features::kNewOverviewAnimations);
}
bool IsOverviewSwipeToCloseEnabled() {
return base::FeatureList::IsEnabled(features::kOverviewSwipeToClose);
}
void FadeOutWidgetOnExit(std::unique_ptr<views::Widget> widget,
OverviewAnimationType animation_type) {
// The window selector controller may be nullptr on shutdown.
WindowSelectorController* controller =
Shell::Get()->window_selector_controller();
if (!controller) {
widget->SetOpacity(0.f);
return;
}
widget->SetOpacity(1.f);
// Fade out the widget. This animation continues past the lifetime of overview
// mode items.
ScopedOverviewAnimationSettings animation_settings(animation_type,
widget->GetNativeWindow());
// CleanupAnimationObserver will delete itself (and the widget) when the
// opacity animation is complete.
// Ownership over the observer is passed to the window selector controller
// which has longer lifetime so that animations can continue even after the
// overview mode is shut down.
views::Widget* widget_ptr = widget.get();
std::unique_ptr<CleanupAnimationObserver> observer(
new CleanupAnimationObserver(std::move(widget)));
animation_settings.AddObserver(observer.get());
controller->AddDelayedAnimationObserver(std::move(observer));
widget_ptr->SetOpacity(0.f);
}
std::unique_ptr<views::Widget> CreateBackgroundWidget(aura::Window* root_window,
ui::LayerType layer_type,
SkColor background_color,
int border_thickness,
int border_radius,
SkColor border_color,
float initial_opacity,
aura::Window* parent,
bool stack_on_top) {
std::unique_ptr<views::Widget> widget(new views::Widget());
views::Widget::InitParams params;
params.type = views::Widget::InitParams::TYPE_POPUP;
params.keep_on_top = false;
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
params.layer_type = layer_type;
params.accept_events = false;
widget->set_focus_on_creation(false);
// Parenting in kShellWindowId_WallpaperContainer allows proper layering of
// the shield and selection widgets. Since that container is created with
// USE_LOCAL_COORDINATES BoundsInScreenBehavior local bounds in |root_window_|
// need to be provided.
params.parent =
parent ? parent
: root_window->GetChildById(kShellWindowId_WallpaperContainer);
widget->Init(params);
aura::Window* widget_window = widget->GetNativeWindow();
// Disable the "bounce in" animation when showing the window.
::wm::SetWindowVisibilityAnimationTransition(widget_window,
::wm::ANIMATE_NONE);
// The background widget should not activate the shelf when passing under it.
wm::GetWindowState(widget_window)->set_ignored_by_shelf(true);
if (params.layer_type == ui::LAYER_SOLID_COLOR) {
widget_window->layer()->SetColor(background_color);
} else {
views::View* content_view = new views::View();
content_view->SetBackground(std::make_unique<BackgroundWith1PxBorder>(
background_color, border_color, border_thickness, border_radius));
widget->SetContentsView(content_view);
}
if (stack_on_top) {
widget_window->parent()->StackChildAtTop(widget_window);
} else {
widget_window->parent()->StackChildAtBottom(widget_window);
}
widget->Show();
widget_window->layer()->SetOpacity(initial_opacity);
return widget;
}
} // namespace ash