| // Copyright 2012 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ash/wm/resize_shadow_controller.h" |
| |
| #include <memory> |
| |
| #include "ash/public/cpp/window_properties.h" |
| #include "ash/shell.h" |
| #include "ash/wm/overview/overview_controller.h" |
| #include "ash/wm/resize_shadow.h" |
| #include "chromeos/constants/chromeos_features.h" |
| #include "chromeos/ui/base/window_state_type.h" |
| #include "chromeos/ui/frame/frame_utils.h" |
| #include "ui/aura/client/aura_constants.h" |
| |
| namespace ash { |
| |
| namespace { |
| |
| // Lock shadow params |
| constexpr ResizeShadow::InitParams kLockParams{ |
| .thickness = 6, |
| .shadow_corner_radius = 6, |
| .window_corner_radius = 2, |
| .opacity = 0.3f, |
| .color = gfx::kGoogleGrey900, |
| .hit_test_enabled = false, |
| .hide_duration_ms = 0, |
| }; |
| |
| } // namespace |
| |
| ResizeShadowController::ResizeShadowController() = default; |
| |
| ResizeShadowController::~ResizeShadowController() { |
| RemoveAllShadows(); |
| } |
| |
| void ResizeShadowController::ShowShadow(aura::Window* window, int hit_test) { |
| RecreateShadowIfNeeded(window); |
| if (ShouldShowShadowForWindow(window) && window->IsVisible()) |
| GetShadowForWindow(window)->ShowForHitTest(hit_test); |
| } |
| |
| void ResizeShadowController::TryShowAllShadows() { |
| for (const auto& shadow : window_shadows_) |
| UpdateShadowVisibility(shadow.first, shadow.first->IsVisible()); |
| } |
| |
| void ResizeShadowController::HideShadow(aura::Window* window) { |
| ResizeShadow* shadow = GetShadowForWindow(window); |
| if (!shadow) |
| return; |
| UpdateShadowVisibility(window, false); |
| } |
| |
| void ResizeShadowController::HideAllShadows() { |
| for (auto& shadow : window_shadows_) { |
| if (!shadow.second) |
| continue; |
| |
| switch (shadow.second->type_) { |
| case ResizeShadowType::kLock: { // Hides lock style of shadow |
| UpdateShadowVisibility(shadow.first, false); |
| break; |
| } |
| case ResizeShadowType::kUnlock: { // Deletes unlock style of shadow |
| shadow.second.reset(); |
| break; |
| } |
| } |
| } |
| } |
| |
| void ResizeShadowController::OnCrossFadeAnimationCompleted( |
| aura::Window* window) { |
| if (auto* shadow = GetShadowForWindow(window)) { |
| shadow->ReparentLayer(); |
| } |
| } |
| |
| void ResizeShadowController::RemoveAllShadows() { |
| windows_observation_.RemoveAllObservations(); |
| window_shadows_.clear(); |
| } |
| |
| void ResizeShadowController::OnWindowHierarchyChanged( |
| const aura::WindowObserver::HierarchyChangeParams& params) { |
| ResizeShadow* shadow = GetShadowForWindow(params.target); |
| if (shadow) |
| shadow->ReparentLayer(); |
| } |
| |
| void ResizeShadowController::OnWindowVisibilityChanging(aura::Window* window, |
| bool visible) { |
| UpdateShadowVisibility(window, visible); |
| } |
| |
| void ResizeShadowController::OnWindowBoundsChanged( |
| aura::Window* window, |
| const gfx::Rect& old_bounds, |
| const gfx::Rect& new_bounds, |
| ui::PropertyChangeReason reason) { |
| ResizeShadow* shadow = GetShadowForWindow(window); |
| if (shadow && window->GetProperty(aura::client::kUseWindowBoundsForShadow)) |
| shadow->UpdateBoundsAndVisibility(); |
| } |
| |
| void ResizeShadowController::OnWindowStackingChanged(aura::Window* window) { |
| ResizeShadow* shadow = GetShadowForWindow(window); |
| if (shadow) |
| shadow->ReparentLayer(); |
| } |
| |
| void ResizeShadowController::OnWindowDestroying(aura::Window* window) { |
| windows_observation_.RemoveObservation(window); |
| window_shadows_.erase(window); |
| } |
| |
| void ResizeShadowController::OnWindowPropertyChanged(aura::Window* window, |
| const void* key, |
| intptr_t old) { |
| if (key == aura::client::kShowStateKey) { |
| UpdateShadowVisibility(window, window->IsVisible()); |
| return; |
| } |
| |
| // If the resize shadow is being shown, ensure that shadow is configured |
| // correctly for either a rounded window or squared window. |
| if (ShouldShowShadowForWindow(window) && |
| chromeos::CanPropertyEffectFrameRadius(key)) { |
| RecreateShadowIfNeeded(window); |
| UpdateShadowVisibility(window, window->IsVisible()); |
| return; |
| } |
| } |
| |
| void ResizeShadowController::OnWindowAddedToRootWindow(aura::Window* window) { |
| ResizeShadow* shadow = GetShadowForWindow(window); |
| if (shadow) { |
| shadow->OnWindowParentToRootWindow(); |
| } |
| } |
| |
| void ResizeShadowController::UpdateResizeShadowBoundsOfWindow( |
| aura::Window* window, |
| const gfx::Rect& bounds) { |
| ResizeShadow* shadow = GetShadowForWindow(window); |
| if (shadow) |
| shadow->UpdateBounds(bounds); |
| } |
| |
| ResizeShadow* ResizeShadowController::GetShadowForWindowForTest( |
| aura::Window* window) { |
| return GetShadowForWindow(window); |
| } |
| |
| void ResizeShadowController::RecreateShadowIfNeeded(aura::Window* window) { |
| if (!windows_observation_.IsObservingSource(window)) |
| windows_observation_.AddObservation(window); |
| ResizeShadow* shadow = GetShadowForWindow(window); |
| const ash::ResizeShadowType type = |
| window->GetProperty(ash::kResizeShadowTypeKey); |
| const bool has_rounded_window = |
| chromeos::features::IsRoundedWindowsEnabled() && |
| chromeos::ShouldWindowHaveRoundedCorners(window); |
| |
| // If the `window` has a resize shadow with the requested type and the shadow |
| // is configured for a rounded window, no need to recreate it. |
| if (shadow && shadow->type_ == type && |
| shadow->is_for_rounded_window() == has_rounded_window) { |
| return; |
| } |
| |
| ResizeShadow::InitParams params; |
| if (type == ResizeShadowType::kLock) { |
| params = kLockParams; |
| } |
| |
| // Configure window and shadow corner radius when `window` has rounded |
| // corners. |
| if (has_rounded_window) { |
| params.thickness = 6; |
| params.window_corner_radius = chromeos::features::RoundedWindowsRadius(); |
| params.shadow_corner_radius = 16; |
| params.is_for_rounded_window = true; |
| } |
| |
| auto new_shadow = std::make_unique<ResizeShadow>(window, params, type); |
| |
| auto it = window_shadows_.find(window); |
| if (it == window_shadows_.end()) |
| window_shadows_.insert(std::make_pair(window, std::move(new_shadow))); |
| else |
| it->second = std::move(new_shadow); |
| } |
| |
| ResizeShadow* ResizeShadowController::GetShadowForWindow( |
| aura::Window* window) const { |
| auto it = window_shadows_.find(window); |
| return it != window_shadows_.end() ? it->second.get() : nullptr; |
| } |
| |
| void ResizeShadowController::UpdateShadowVisibility(aura::Window* window, |
| bool visible) const { |
| ResizeShadow* shadow = GetShadowForWindow(window); |
| if (!shadow) |
| return; |
| |
| if (shadow->type_ == ResizeShadowType::kLock) { |
| visible &= ShouldShowShadowForWindow(window); |
| if (visible) |
| shadow->ShowForHitTest(); |
| } |
| |
| if (!visible) |
| shadow->Hide(); |
| } |
| |
| bool ResizeShadowController::ShouldShowShadowForWindow( |
| aura::Window* window) const { |
| // Hide the shadow if it's a maximized/fullscreen/minimized window or the |
| // overview mode is active. |
| ui::WindowShowState show_state = |
| window->GetProperty(aura::client::kShowStateKey); |
| return show_state != ui::SHOW_STATE_FULLSCREEN && |
| show_state != ui::SHOW_STATE_MAXIMIZED && |
| show_state != ui::SHOW_STATE_MINIMIZED && |
| !Shell::Get()->overview_controller()->InOverviewSession(); |
| } |
| |
| } // namespace ash |