#include "ash/wm/overview/overview_grid_event_handler.h"
#include "ash/app_list/app_list_controller_impl.h"
#include "ash/root_window_controller.h"
#include "ash/shell.h"
#include "ash/wallpaper/views/wallpaper_view.h"
#include "ash/wallpaper/views/wallpaper_widget_controller.h"
#include "ash/wm/gestures/wm_fling_handler.h"
#include "ash/wm/overview/overview_controller.h"
#include "ash/wm/overview/overview_grid.h"
#include "ash/wm/overview/overview_utils.h"
#include "ash/wm/splitview/split_view_controller.h"
#include "base/functional/bind.h"
#include "ui/display/screen.h"
#include "ui/events/event.h"
#include "ui/gfx/geometry/vector2d_f.h"
#include "ui/views/widget/widget.h"
namespace ash {
namespace {
constexpr float kScrollOffsetThresholdDp = 1.f;
WallpaperView* GetWallpaperViewForRoot(const aura::Window* root_window) {
auto* wallpaper_widget_controller =
RootWindowController::ForWindow(root_window)
->wallpaper_widget_controller();
if (!wallpaper_widget_controller)
return nullptr;
return wallpaper_widget_controller->wallpaper_view();
}
}
OverviewGridEventHandler::OverviewGridEventHandler(OverviewGrid* grid)
: grid_(grid), overview_session_(grid_->overview_session()) {
DCHECK(overview_session_);
auto* wallpaper_view = GetWallpaperViewForRoot(grid_->root_window());
if (wallpaper_view)
wallpaper_view->AddPreTargetHandler(this);
}
OverviewGridEventHandler::~OverviewGridEventHandler() {
OnFlingEnd();
grid_->EndScroll();
auto* wallpaper_view = GetWallpaperViewForRoot(grid_->root_window());
if (wallpaper_view)
wallpaper_view->RemovePreTargetHandler(this);
}
void OverviewGridEventHandler::OnMouseEvent(ui::MouseEvent* event) {
if (event->type() == ui::EventType::kMousePressed &&
!overview_session_->CanProcessEvent()) {
OverviewController::Get()->EndOverview(
OverviewEndAction::kClickingOutsideWindowsInOverview);
event->StopPropagation();
event->SetHandled();
return;
}
if (event->type() == ui::EventType::kMouseReleased) {
HandleClickOrTap(event);
}
}
void OverviewGridEventHandler::OnGestureEvent(ui::GestureEvent* event) {
if (!overview_session_->CanProcessEvent()) {
event->StopPropagation();
event->SetHandled();
return;
}
if (grid_->IsShowingSavedDeskLibrary()) {
return;
}
if (event->type() == ui::EventType::kGestureTap) {
HandleClickOrTap(event);
return;
}
if (!display::Screen::Get()->InTabletMode()) {
return;
}
switch (event->type()) {
case ui::EventType::kScrollFlingStart: {
HandleFlingScroll(event);
event->SetHandled();
break;
}
case ui::EventType::kGestureScrollBegin: {
scroll_offset_x_cumulative_ = 0.f;
OnFlingEnd();
grid_->StartScroll();
event->SetHandled();
break;
}
case ui::EventType::kGestureScrollUpdate: {
const float scroll_offset_x = event->details().scroll_x();
scroll_offset_x_cumulative_ += scroll_offset_x;
if (std::abs(scroll_offset_x_cumulative_) > kScrollOffsetThresholdDp) {
grid_->UpdateScrollOffset(scroll_offset_x_cumulative_);
scroll_offset_x_cumulative_ = 0.f;
}
event->SetHandled();
break;
}
case ui::EventType::kGestureScrollEnd: {
grid_->EndScroll();
event->SetHandled();
break;
}
default:
break;
}
}
void OverviewGridEventHandler::HandleClickOrTap(ui::Event* event) {
CHECK_EQ(ui::EP_PRETARGET, event->phase());
if (grid_->IsDeskNameBeingModified() ||
grid_->IsSavedDeskNameBeingModified()) {
grid_->CommitNameChanges();
event->StopPropagation();
return;
}
if (display::Screen::Get()->InTabletMode()) {
aura::Window* window = static_cast<views::View*>(event->target())
->GetWidget()
->GetNativeWindow();
if (!SplitViewController::Get(window)->InSplitViewMode()) {
int64_t display_id =
display::Screen::Get()->GetDisplayNearestWindow(window).id();
Shell::Get()->app_list_controller()->GoHome(display_id);
}
} else {
OverviewController::Get()->EndOverview(
OverviewEndAction::kClickingOutsideWindowsInOverview);
}
event->StopPropagation();
}
void OverviewGridEventHandler::HandleFlingScroll(ui::GestureEvent* event) {
const gfx::Vector2dF initial_fling_velocity(event->details().velocity_x(),
event->details().velocity_y());
fling_handler_ = std::make_unique<WmFlingHandler>(
initial_fling_velocity, grid_->root_window(),
base::BindRepeating(&OverviewGridEventHandler::OnFlingStep,
base::Unretained(this)),
base::BindRepeating(&OverviewGridEventHandler::OnFlingEnd,
base::Unretained(this)));
}
bool OverviewGridEventHandler::OnFlingStep(float offset) {
DCHECK(fling_handler_);
return grid_->UpdateScrollOffset(offset);
}
void OverviewGridEventHandler::OnFlingEnd() {
if (!fling_handler_)
return;
fling_handler_.reset();
grid_->EndScroll();
}
}