chromium/ash/wm/wm_shadow_controller_delegate.cc

// Copyright 2018 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/wm_shadow_controller_delegate.h"

#include "ash/root_window_controller.h"
#include "ash/shell.h"
#include "ash/wm/overview/overview_controller.h"
#include "ash/wm/overview/overview_item.h"
#include "ash/wm/overview/overview_session.h"
#include "ash/wm/splitview/split_view_controller.h"
#include "ash/wm/window_state.h"
#include "chromeos/ui/base/window_properties.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/window.h"
#include "ui/base/class_property.h"
#include "ui/color/color_provider_source_observer.h"
#include "ui/views/widget/widget.h"
#include "ui/wm/core/shadow_controller.h"
#include "ui/wm/core/shadow_types.h"

namespace {

//------------------------------------------------------------------------------
// ShadowColorizer:
// Observes the given color provider source and updates the shadow colors with
// the colors map generated by the color provider.
class ShadowColorizer : public ui::ColorProviderSourceObserver {
 public:
  ShadowColorizer(aura::Window* window,
                  ui::ColorProviderSource* color_provider_source)
      : window_(window) {
    Observe(color_provider_source);
  }

  ShadowColorizer(const ShadowColorizer&) = delete;
  ShadowColorizer& operator=(const ShadowColorizer&) = delete;
  ~ShadowColorizer() override = default;

  // ui::ColorProviderSourceObserver:
  void OnColorProviderChanged() override {
    // This function will also be called when color provider source is
    // destroying. We should guarantee the observed color provider source
    // exists.
    if (auto* color_provider_source = GetColorProviderSource()) {
      const auto* color_provider = color_provider_source->GetColorProvider();
      auto* shadow = wm::ShadowController::GetShadowForWindow(window_.get());
      shadow->SetElevationToColorsMap(
          wm::ShadowController::GenerateShadowColorsMap(color_provider));
    }
  }

 private:
  const raw_ptr<aura::Window> window_;
};

}  // namespace

DEFINE_UI_CLASS_PROPERTY_TYPE(ShadowColorizer*)
DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(ShadowColorizer,
                                   kShadowColorizerKey,
                                   nullptr)
namespace ash {

//------------------------------------------------------------------------------
// WmShadowControllerDelegate:
WmShadowControllerDelegate::WmShadowControllerDelegate() = default;

WmShadowControllerDelegate::~WmShadowControllerDelegate() = default;

bool WmShadowControllerDelegate::ShouldShowShadowForWindow(
    const aura::Window* window) {
  // Hide the shadow if it is one of the splitscreen snapped windows.
  if (window->GetRootWindow() && RootWindowController::ForWindow(window)) {
    SplitViewController* split_view_controller =
        SplitViewController::Get(window);
    if (split_view_controller &&
        split_view_controller->IsWindowInSplitView(window)) {
      return false;
    }
  }

  // Hide the shadow while we are in overview mode.
  OverviewController* overview_controller = Shell::Get()->overview_controller();
  if (overview_controller && overview_controller->InOverviewSession()) {
    OverviewSession* overview_session = overview_controller->overview_session();
    // InOverviewSession() being true implies |overview_session| exists.
    DCHECK(overview_session);
    // Windows in overview that are not moving out of the active desk should not
    // have shadows.
    auto* overview_item = overview_session->GetOverviewItemForWindow(window);
    if (overview_item && !overview_item->is_moving_to_another_desk()) {
      return false;
    }
  }

  // The shadow state will be updated when the window is added to a parent.
  if (!window->parent())
    return false;

  // Show the shadow if it's currently being dragged no matter of the window's
  // show state.
  auto* window_state = WindowState::Get(window);
  if (window_state && window_state->is_dragged())
    return ::wm::GetShadowElevationConvertDefault(window) > 0;

  // Hide the shadow if it's not being dragged and it's a maximized/fullscreen
  // window.
  ui::WindowShowState show_state =
      window->GetProperty(aura::client::kShowStateKey);
  if (show_state == ui::SHOW_STATE_FULLSCREEN ||
      show_state == ui::SHOW_STATE_MAXIMIZED) {
    return false;
  }

  return ::wm::GetShadowElevationConvertDefault(window) > 0;
}

bool WmShadowControllerDelegate::ShouldUpdateShadowOnWindowPropertyChange(
    const aura::Window* window,
    const void* key,
    intptr_t old) {
  return (key == chromeos::kIsShowingInOverviewKey &&
          window->GetProperty(chromeos::kIsShowingInOverviewKey) != old) ||
         (key == chromeos::kWindowStateTypeKey &&
          window->GetProperty(chromeos::kWindowStateTypeKey) !=
              static_cast<chromeos::WindowStateType>(old));
}

void WmShadowControllerDelegate::ApplyColorThemeToWindowShadow(
    aura::Window* window) {
  if (auto* color_provider_source =
          views::Widget::GetWidgetForNativeWindow(window)) {
    window->SetProperty(
        kShadowColorizerKey,
        std::make_unique<ShadowColorizer>(window, color_provider_source));
  }
}

}  // namespace ash