1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139

ash / user_education / welcome_tour / welcome_tour_window_minimizer.cc [blame]

// Copyright 2023 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/user_education/welcome_tour/welcome_tour_window_minimizer.h"

#include "ash/public/cpp/shell_window_ids.h"
#include "ash/shell.h"
#include "ash/wm/desks/desks_util.h"
#include "ash/wm/window_state.h"
#include "base/check.h"
#include "base/task/sequenced_task_runner.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tracker.h"
#include "ui/wm/core/scoped_animation_disabler.h"

namespace ash {
namespace {

// Helpers ---------------------------------------------------------------------

// Returns whether a window's children should be minimized while
// `WelcomeTourWindowMinimizer` exists.
bool ShouldMinimizeChildren(aura::Window* window) {
  return window && (desks_util::IsDeskContainer(window) ||
                    window->GetId() == kShellWindowId_FloatContainer);
}

// Minimizes a window, if it is possible to do so.
void Minimize(aura::Window* window) {
  auto* state = WindowState::Get(window);
  if (state && !state->IsMinimized()) {
    state->Minimize();
  }
}

// Minimizes all windows in a `aura::WindowTracker`, if they are in containers
// that should have their windows minimized. Can be called asynchronously.
void MaybeMinimize(aura::WindowTracker* window_tracker) {
  for (aura::Window* window : window_tracker->windows()) {
    if (ShouldMinimizeChildren(window->parent())) {
      wm::ScopedAnimationDisabler animation_disabler(window);
      Minimize(window);
    }
  }
}

}  // namespace

// WelcomeTourWindowMinimizer --------------------------------------------------

WelcomeTourWindowMinimizer::WelcomeTourWindowMinimizer() {
  for (aura::Window* root_window : Shell::GetAllRootWindows()) {
    OnRootWindowAdded(root_window);
  }

  shell_observation_.Observe(Shell::Get());
}

WelcomeTourWindowMinimizer::~WelcomeTourWindowMinimizer() = default;

void WelcomeTourWindowMinimizer::OnWindowDestroying(aura::Window* window) {
  root_window_observations_.RemoveObservation(window);
}

void WelcomeTourWindowMinimizer::OnWindowHierarchyChanged(
    const HierarchyChangeParams& params) {
  // If the relevant window is entering a container that should be minimized,
  // begin keeping it minimized.
  if (ShouldMinimizeChildren(params.new_parent)) {
    app_window_minimizer_.AddWindow(params.target);
  } else if (ShouldMinimizeChildren(params.old_parent)) {
    // If the window is leaving a should-minimize container and not entering
    // another one, stop keeping it minimized.
    app_window_minimizer_.RemoveWindow(params.target);
  }
}

void WelcomeTourWindowMinimizer::OnRootWindowAdded(aura::Window* root_window) {
  root_window_observations_.AddObservation(root_window);

  std::vector<aura::Window*> containers =
      desks_util::GetDesksContainers(root_window);

  auto* float_container =
      root_window->GetChildById(kShellWindowId_FloatContainer);
  CHECK(float_container);
  containers.push_back(float_container);

  for (auto* container : containers) {
    if (ShouldMinimizeChildren(container)) {
      for (aura::Window* child : container->children()) {
        app_window_minimizer_.AddWindow(child);
      }
    }
  }
}

// WelcomeTourMinimized::AppWindowMinimizer ------------------------------------

WelcomeTourWindowMinimizer::AppWindowMinimizer::AppWindowMinimizer() = default;

WelcomeTourWindowMinimizer::AppWindowMinimizer::~AppWindowMinimizer() = default;

void WelcomeTourWindowMinimizer::AppWindowMinimizer::AddWindow(
    aura::Window* window) {
  Minimize(window);
  if (!app_window_observations_.IsObservingSource(window)) {
    app_window_observations_.AddObservation(window);
  }
}

void WelcomeTourWindowMinimizer::AppWindowMinimizer::RemoveWindow(
    aura::Window* window) {
  if (app_window_observations_.IsObservingSource(window)) {
    app_window_observations_.RemoveObservation(window);
  }
}

void WelcomeTourWindowMinimizer::AppWindowMinimizer::OnWindowDestroying(
    aura::Window* window) {
  app_window_observations_.RemoveObservation(window);
}

void WelcomeTourWindowMinimizer::AppWindowMinimizer::OnWindowVisibilityChanged(
    aura::Window* window,
    bool visible) {
  if (visible) {
    // Minimize the window asynchronously to avoid changing visibility directly
    // from within a visibility event.
    base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
        FROM_HERE,
        base::BindOnce(&MaybeMinimize,
                       base::Owned(std::make_unique<aura::WindowTracker>(
                           aura::WindowTracker::WindowList{window}))));
  }
}

}  // namespace ash