| // Copyright 2014 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 "ui/wm/core/easy_resize_window_targeter.h" |
| |
| #include <algorithm> |
| |
| #include "services/ui/public/interfaces/window_manager.mojom.h" |
| #include "ui/aura/client/aura_constants.h" |
| #include "ui/aura/client/transient_window_client.h" |
| #include "ui/aura/env.h" |
| #include "ui/aura/mus/window_port_mus.h" |
| #include "ui/aura/mus/window_tree_client.h" |
| #include "ui/aura/window.h" |
| #include "ui/events/event.h" |
| #include "ui/gfx/geometry/insets_f.h" |
| #include "ui/gfx/geometry/rect.h" |
| |
| namespace wm { |
| namespace { |
| |
| gfx::Insets InsetsWithOnlyPositiveValues(const gfx::Insets& insets) { |
| return gfx::Insets(std::max(0, insets.top()), std::max(0, insets.left()), |
| std::max(0, insets.bottom()), std::max(0, insets.right())); |
| } |
| |
| } // namespace |
| |
| // HitMaskSetter is responsible for setting the hit-test mask on a Window. |
| class EasyResizeWindowTargeter::HitMaskSetter : public aura::WindowObserver { |
| public: |
| explicit HitMaskSetter(aura::Window* window) : window_(window) { |
| window_->AddObserver(this); |
| } |
| ~HitMaskSetter() override { |
| if (window_) { |
| aura::WindowPortMus::Get(window_)->SetHitTestMask(base::nullopt); |
| window_->RemoveObserver(this); |
| } |
| } |
| |
| void SetHitMaskInsets(const gfx::Insets& insets) { |
| if (insets == insets_) |
| return; |
| |
| insets_ = insets; |
| ApplyHitTestMask(); |
| } |
| |
| private: |
| void ApplyHitTestMask() { |
| base::Optional<gfx::Rect> hit_test_mask( |
| gfx::Rect(window_->bounds().size())); |
| hit_test_mask->Inset(insets_); |
| aura::WindowPortMus::Get(window_)->SetHitTestMask(hit_test_mask); |
| } |
| |
| // aura::WindowObserver: |
| void OnWindowDestroying(aura::Window* window) override { |
| window_->RemoveObserver(this); |
| window_ = nullptr; |
| } |
| void OnWindowBoundsChanged(aura::Window* window, |
| const gfx::Rect& old_bounds, |
| const gfx::Rect& new_bounds, |
| ui::PropertyChangeReason reason) override { |
| ApplyHitTestMask(); |
| } |
| |
| private: |
| aura::Window* window_; |
| gfx::Insets insets_; |
| |
| DISALLOW_COPY_AND_ASSIGN(HitMaskSetter); |
| }; |
| |
| EasyResizeWindowTargeter::EasyResizeWindowTargeter( |
| aura::Window* container, |
| const gfx::Insets& mouse_extend, |
| const gfx::Insets& touch_extend) |
| : container_(container) { |
| DCHECK(container_); |
| SetInsets(mouse_extend, touch_extend); |
| } |
| |
| EasyResizeWindowTargeter::~EasyResizeWindowTargeter() {} |
| |
| void EasyResizeWindowTargeter::OnSetInsets( |
| const gfx::Insets& last_mouse_extend, |
| const gfx::Insets& last_touch_extend) { |
| if (aura::Env::GetInstance()->mode() != aura::Env::Mode::MUS) |
| return; |
| |
| // Positive values equate to a hit test mask. |
| const gfx::Insets positive_mouse_insets = |
| InsetsWithOnlyPositiveValues(mouse_extend()); |
| if (positive_mouse_insets.IsEmpty()) { |
| hit_mask_setter_.reset(); |
| } else { |
| if (!hit_mask_setter_) |
| hit_mask_setter_ = std::make_unique<HitMaskSetter>(container_); |
| hit_mask_setter_->SetHitMaskInsets(positive_mouse_insets); |
| } |
| } |
| |
| bool EasyResizeWindowTargeter::EventLocationInsideBounds( |
| aura::Window* target, |
| const ui::LocatedEvent& event) const { |
| return WindowTargeter::EventLocationInsideBounds(target, event); |
| } |
| |
| bool EasyResizeWindowTargeter::ShouldUseExtendedBounds( |
| const aura::Window* window) const { |
| // Use the extended bounds only for immediate child windows of |container_|. |
| // Use the default targeter otherwise. |
| if (window->parent() != container_) |
| return false; |
| |
| // Only resizable windows benefit from the extended hit-test region. |
| if ((window->GetProperty(aura::client::kResizeBehaviorKey) & |
| ui::mojom::kResizeBehaviorCanResize) == 0) { |
| return false; |
| } |
| |
| // For transient children use extended bounds if a transient parent or if |
| // transient parent's parent is a top level window in |container_|. |
| aura::client::TransientWindowClient* transient_window_client = |
| aura::client::GetTransientWindowClient(); |
| const aura::Window* transient_parent = |
| transient_window_client |
| ? transient_window_client->GetTransientParent(window) |
| : nullptr; |
| return !transient_parent || transient_parent == container_ || |
| transient_parent->parent() == container_; |
| } |
| |
| } // namespace wm |