// Copyright 2016 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/shelf/shelf_window_targeter.h" #include "ash/public/cpp/session/session_types.h" #include "ash/public/cpp/shelf_config.h" #include "ash/public/cpp/shelf_types.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/session/session_controller_impl.h" #include "ash/shelf/shelf.h" #include "ash/shelf/shelf_widget.h" #include "ash/shell.h" #include "ui/aura/window.h" namespace ash { namespace { gfx::Insets GetInsetsForAlignment(int distance, ShelfAlignment alignment) { if (alignment == ShelfAlignment::kLeft) return gfx::Insets::TLBR(0, 0, 0, distance); if (alignment == ShelfAlignment::kRight) return gfx::Insets::TLBR(0, distance, 0, 0); return gfx::Insets::TLBR(distance, 0, 0, 0); } } // namespace ShelfWindowTargeter::ShelfWindowTargeter(aura::Window* container, Shelf* shelf) : ::wm::EasyResizeWindowTargeter(gfx::Insets(), gfx::Insets()), shelf_(shelf) { WillChangeVisibilityState(shelf_->GetVisibilityState()); container->AddObserver(this); shelf_->AddObserver(this); } ShelfWindowTargeter::~ShelfWindowTargeter() { // Ensure that the observers were removed and the shelf pointer was cleared. DCHECK(!shelf_); } bool ShelfWindowTargeter::ShouldUseExtendedBounds(const aura::Window* w) const { // Use extended bounds only for direct child of the container. return window() == w->parent(); } bool ShelfWindowTargeter::GetHitTestRects( aura::Window* target, gfx::Rect* hit_test_rect_mouse, gfx::Rect* hit_test_rect_touch) const { // We only want to special case a very specific situation where we are not // currently in an active session (or unknown session state) and change only // the behavior of the login shelf. On secondary displays, the login shelf // will not be visible. // TODO(https://crbug.com/1343114): remove this code block after the login // shelf widget is in use. bool target_is_shelf_widget = target == shelf_->shelf_widget()->GetNativeWindow(); if (target_is_shelf_widget && Shell::Get()->session_controller()->GetSessionState() != session_manager::SessionState::ACTIVE && Shell::Get()->session_controller()->GetSessionState() != session_manager::SessionState::UNKNOWN && !features::IsUseLoginShelfWidgetEnabled()) { // When this is the case, let events pass through the "empty" part of // the shelf. return shelf_->shelf_widget()->GetHitTestRects(target, hit_test_rect_mouse, hit_test_rect_touch); } *hit_test_rect_mouse = *hit_test_rect_touch = target->bounds(); if (ShouldUseExtendedBounds(target)) { hit_test_rect_mouse->Inset(mouse_extend()); // Whether the touch hit area should be extended beyond the window top when // the shelf is in auto-hide state (to make targeting hidden shelf easier). // This should be applied for shelf widget only, to prevent other widgets // positioned below display bounds (e.g. hidden hotseat widget) from // handling touch events instead of the shelf. if (target_is_shelf_widget) hit_test_rect_touch->Inset(touch_extend()); } return true; } void ShelfWindowTargeter::OnWindowDestroying(aura::Window* window) { window->RemoveObserver(this); shelf_->RemoveObserver(this); shelf_ = nullptr; } void ShelfWindowTargeter::WillChangeVisibilityState( ShelfVisibilityState new_state) { // Do not use |new_state| as it can be a shelf on other displays. auto visibility_state = shelf_->GetVisibilityState(); gfx::Insets mouse_insets; gfx::Insets touch_insets; if (visibility_state == SHELF_VISIBLE) { // Let clicks at the very top of the shelf through so windows can be // resized with the bottom-right corner and bottom edge. mouse_insets = GetInsetsForAlignment( ShelfConfig::Get()->workspace_area_visible_inset(), shelf_->alignment()); } else if (visibility_state == SHELF_AUTO_HIDE) { // Extend the touch hit target out a bit to allow users to drag shelf out // while hidden. touch_insets = GetInsetsForAlignment( -ShelfConfig::Get()->workspace_area_auto_hide_inset(), shelf_->alignment()); } // Remember the insets. See GetHitTestsRects when they're actually used. SetInsets(mouse_insets, touch_insets); } } // namespace ash