blob: 3ddd809f898de3e9f21755f8f949deb1eb42402d [file] [log] [blame]
// Copyright 2019 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/system/accessibility/autoclick_menu_bubble_controller.h"
#include "ash/public/cpp/app_list/app_list_features.h"
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/shell.h"
#include "ash/system/tray/tray_background_view.h"
#include "ash/system/tray/tray_constants.h"
#include "ash/system/unified/unified_system_tray_view.h"
#include "ash/wm/collision_detection/collision_detection_utils.h"
#include "ash/wm/work_area_insets.h"
#include "ui/aura/window_tree_host.h"
#include "ui/events/event_utils.h"
namespace ash {
namespace {
// Autoclick menu constants.
const int kAutoclickMenuWidth = 321;
} // namespace
AutoclickMenuBubbleController::AutoclickMenuBubbleController() {}
AutoclickMenuBubbleController::~AutoclickMenuBubbleController() {
if (bubble_widget_ && !bubble_widget_->IsClosed())
bubble_widget_->CloseNow();
}
void AutoclickMenuBubbleController::SetEventType(
mojom::AutoclickEventType type) {
if (menu_view_) {
menu_view_->UpdateEventType(type);
}
}
void AutoclickMenuBubbleController::SetPosition(
mojom::AutoclickMenuPosition position) {
if (!menu_view_ || !bubble_view_)
return;
menu_view_->UpdatePosition(position);
// TODO(katie): On first load it can display over top of the shelf on Chrome
// OS emulated on Linux (not reproduced on Eve). There must be a race
// condition with the user work area bounds loading.
// TODO(katie): Support multiple displays.
gfx::Rect work_area = WorkAreaInsets::ForWindow(Shell::GetPrimaryRootWindow())
->user_work_area_bounds();
gfx::Rect new_position;
switch (position) {
case mojom::AutoclickMenuPosition::kBottomRight:
new_position = gfx::Rect(work_area.width(), work_area.height(), 0, 0);
break;
case mojom::AutoclickMenuPosition::kBottomLeft:
new_position = gfx::Rect(work_area.x(), work_area.height(), 0, 0);
break;
case mojom::AutoclickMenuPosition::kTopLeft:
// Setting the top to 1 instead of 0 so that the view is drawn on screen.
new_position = gfx::Rect(work_area.x(), 1, 0, 0);
break;
case mojom::AutoclickMenuPosition::kTopRight:
// Setting the top to 1 instead of 0 so that the view is drawn on screen.
new_position = gfx::Rect(work_area.width(), 1, 0, 0);
break;
}
bubble_view_->MoveToPosition(new_position);
}
void AutoclickMenuBubbleController::ShowBubble(
mojom::AutoclickEventType type,
mojom::AutoclickMenuPosition position) {
// Ignore if bubble widget already exists.
if (bubble_widget_)
return;
DCHECK(!bubble_view_);
TrayBubbleView::InitParams init_params;
init_params.delegate = this;
// Anchor within the overlay container.
init_params.parent_window = Shell::GetContainer(
Shell::GetPrimaryRootWindow(), kShellWindowId_AutoclickContainer);
init_params.anchor_mode = TrayBubbleView::AnchorMode::kRect;
init_params.insets =
gfx::Insets(kUnifiedMenuPadding, kUnifiedMenuPadding,
kUnifiedMenuPadding - 1, kUnifiedMenuPadding - 1);
init_params.min_width = kAutoclickMenuWidth;
init_params.max_width = kAutoclickMenuWidth;
init_params.corner_radius = kUnifiedTrayCornerRadius;
init_params.has_shadow = false;
bubble_view_ = new AutoclickMenuBubbleView(init_params);
menu_view_ = new AutoclickMenuView(type, position);
menu_view_->SetBackground(UnifiedSystemTrayView::CreateBackground());
menu_view_->SetBorder(
views::CreateEmptyBorder(kUnifiedTopShortcutSpacing, 0, 0, 0));
bubble_view_->AddChildView(menu_view_);
bubble_view_->set_color(SK_ColorTRANSPARENT);
bubble_view_->layer()->SetFillsBoundsOpaquely(false);
bubble_widget_ = views::BubbleDialogDelegateView::CreateBubble(bubble_view_);
TrayBackgroundView::InitializeBubbleAnimations(bubble_widget_);
CollisionDetectionUtils::MarkWindowPriorityForCollisionDetection(
bubble_widget_->GetNativeWindow(),
CollisionDetectionUtils::RelativePriority::kAutomaticClicksMenu);
bubble_view_->InitializeAndShowBubble();
if (app_list_features::IsBackgroundBlurEnabled()) {
bubble_widget_->client_view()->layer()->SetBackgroundBlur(
kUnifiedMenuBackgroundBlur);
}
SetPosition(position);
}
void AutoclickMenuBubbleController::CloseBubble() {
if (!bubble_widget_ || bubble_widget_->IsClosed())
return;
bubble_widget_->Close();
}
void AutoclickMenuBubbleController::ClickOnBubble(gfx::Point location_in_dips,
int mouse_event_flags) {
if (!bubble_widget_)
return;
// Change the event location bounds to be relative to the menu bubble.
location_in_dips -= bubble_view_->GetBoundsInScreen().OffsetFromOrigin();
// Generate synthesized mouse events for the click.
const ui::MouseEvent press_event(ui::ET_MOUSE_PRESSED, location_in_dips,
location_in_dips, ui::EventTimeForNow(),
mouse_event_flags | ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON);
const ui::MouseEvent release_event(
ui::ET_MOUSE_RELEASED, location_in_dips, location_in_dips,
ui::EventTimeForNow(), mouse_event_flags | ui::EF_LEFT_MOUSE_BUTTON,
ui::EF_LEFT_MOUSE_BUTTON);
// Send the press/release events to the widget's root view for processing.
bubble_widget_->GetRootView()->OnMousePressed(press_event);
bubble_widget_->GetRootView()->OnMouseReleased(release_event);
}
bool AutoclickMenuBubbleController::ContainsPointInScreen(
const gfx::Point& point) {
return bubble_view_ && bubble_view_->GetBoundsInScreen().Contains(point);
}
void AutoclickMenuBubbleController::BubbleViewDestroyed() {
bubble_view_ = nullptr;
bubble_widget_ = nullptr;
menu_view_ = nullptr;
}
} // namespace ash