| Index: ash/wm/pinned_controller.cc
|
| diff --git a/ash/wm/pinned_controller.cc b/ash/wm/pinned_controller.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..dacb2ba58831a008ca1bca752472fff008eb643d
|
| --- /dev/null
|
| +++ b/ash/wm/pinned_controller.cc
|
| @@ -0,0 +1,239 @@
|
| +// 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 <algorithm>
|
| +#include <vector>
|
| +
|
| +#include "ash/aura/wm_window_aura.h"
|
| +#include "ash/common/shell_window_ids.h"
|
| +#include "ash/common/wm/window_state.h"
|
| +#include "ash/common/wm_window.h"
|
| +#include "ash/shell.h"
|
| +#include "ash/wm/dim_window.h"
|
| +#include "ash/wm/pinned_controller.h"
|
| +#include "base/auto_reset.h"
|
| +#include "base/logging.h"
|
| +
|
| +namespace ash {
|
| +namespace wm {
|
| +namespace {
|
| +
|
| +WmWindow* CreateDimWindow(WmWindow* container) {
|
| + DimWindow* dim_window = new DimWindow(WmWindowAura::GetAuraWindow(container));
|
| + dim_window->SetDimOpacity(1); // Set whole black.
|
| + dim_window->Show();
|
| + WmWindow* result = WmWindowAura::Get(dim_window);
|
| + result->SetFullscreen();
|
| + return result;
|
| +}
|
| +
|
| +// Returns a list of WmWindows corresponding to SystemModalContainers,
|
| +// except ones whose root is shared with |pinned_window|.
|
| +std::vector<WmWindow*> GetSystemModalWindowsExceptPinned(
|
| + WmWindow* pinned_window) {
|
| + WmWindow* pinned_root = pinned_window->GetRootWindow();
|
| +
|
| + ash::Shell* shell = ash::Shell::GetInstance();
|
| + std::vector<WmWindow*> result;
|
| + for (WmWindow* system_modal :
|
| + WmWindowAura::FromAuraWindows(shell->GetContainersFromAllRootWindows(
|
| + kShellWindowId_SystemModalContainer, nullptr))) {
|
| + if (system_modal->GetRootWindow() == pinned_root)
|
| + continue;
|
| + result.push_back(system_modal);
|
| + }
|
| + return result;
|
| +}
|
| +
|
| +template <typename T>
|
| +bool Contains(const std::vector<T>& container, const T& target) {
|
| + return std::find(container.begin(), container.end(), target) !=
|
| + container.end();
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +PinnedController::PinnedController() = default;
|
| +PinnedController::~PinnedController() = default;
|
| +
|
| +bool PinnedController::IsPinned() const {
|
| + return pinned_window_ != nullptr;
|
| +}
|
| +
|
| +void PinnedController::OnPinnedStateChanged(WmWindow* pinned_window) {
|
| + if (pinned_window->GetWindowState()->IsPinned()) {
|
| + if (pinned_window_) {
|
| + LOG(ERROR) << "Pinned mode is enabled, while it is already in "
|
| + << "the pinned mode";
|
| + return;
|
| + }
|
| +
|
| + WmWindow* container = pinned_window->GetParent();
|
| + std::vector<WmWindow*> system_modal_containers =
|
| + GetSystemModalWindowsExceptPinned(pinned_window);
|
| +
|
| + // Set up the container which has the pinned window.
|
| + pinned_window_ = pinned_window;
|
| + background_window_ = CreateDimWindow(container);
|
| + container->StackChildAtTop(pinned_window);
|
| + container->StackChildBelow(background_window_, pinned_window);
|
| +
|
| + // Set the dim windows to the system containers, other than the one which
|
| + // the root window of the pinned window holds.
|
| + for (WmWindow* system_modal : system_modal_containers) {
|
| + WmWindow* dim_window = CreateDimWindow(system_modal);
|
| + system_modal->StackChildAtTop(dim_window);
|
| + dim_windows_.push_back(dim_window);
|
| + }
|
| +
|
| + // Set observers.
|
| + container->AddObserver(this);
|
| + for (WmWindow* child : container->GetChildren())
|
| + child->AddObserver(this);
|
| + for (WmWindow* dim_window : dim_windows_)
|
| + dim_window->AddObserver(this);
|
| + for (WmWindow* system_modal : system_modal_containers)
|
| + system_modal->AddObserver(this);
|
| + } else {
|
| + if (pinned_window != pinned_window_) {
|
| + LOG(ERROR) << "Pinned mode is being disabled, but for the different "
|
| + << "target window.";
|
| + return;
|
| + }
|
| +
|
| + WmWindow* container = pinned_window->GetParent();
|
| + std::vector<WmWindow*> system_modal_containers =
|
| + GetSystemModalWindowsExceptPinned(pinned_window_);
|
| +
|
| + // Unset observers.
|
| + for (WmWindow* system_modal : system_modal_containers)
|
| + system_modal->RemoveObserver(this);
|
| + for (WmWindow* dim_window : dim_windows_)
|
| + dim_window->RemoveObserver(this);
|
| + for (WmWindow* child : container->GetChildren())
|
| + child->RemoveObserver(this);
|
| + container->RemoveObserver(this);
|
| +
|
| + // Delete the dim windows. This works, but do not use RAII, because
|
| + // the window is owned by the parent.
|
| + for (WmWindow* dim_window : dim_windows_) {
|
| + dim_window->RemoveObserver(this);
|
| + delete WmWindowAura::GetAuraWindow(dim_window);
|
| + }
|
| + dim_windows_.clear();
|
| + delete WmWindowAura::GetAuraWindow(background_window_);
|
| + background_window_ = nullptr;
|
| +
|
| + pinned_window_ = nullptr;
|
| + }
|
| +}
|
| +
|
| +void PinnedController::OnWindowTreeChanging(WmWindow* window,
|
| + const TreeChangeParams& params) {
|
| + DCHECK(IsPinned());
|
| + DCHECK(params.target != pinned_window_);
|
| + DCHECK(params.target != background_window_);
|
| + DCHECK(!Contains(dim_windows_, params.target));
|
| +
|
| + // Here, only events to remove a window directly from a container should be
|
| + // handled.
|
| + if ((window != pinned_window_->GetParent() &&
|
| + window->GetShellWindowId() != kShellWindowId_SystemModalContainer) ||
|
| + window != params.old_parent)
|
| + return;
|
| +
|
| + // If a window is being removed from the parent, stop observing it.
|
| + params.target->RemoveObserver(this);
|
| +}
|
| +
|
| +void PinnedController::OnWindowTreeChanged(WmWindow* window,
|
| + const TreeChangeParams& params) {
|
| + DCHECK(IsPinned());
|
| + DCHECK(params.target != pinned_window_);
|
| + DCHECK(params.target != background_window_);
|
| + DCHECK(!Contains(dim_windows_, params.target));
|
| +
|
| + // Here, only events to add a window directly into a container should be
|
| + // handled.
|
| + if ((window != pinned_window_->GetParent() &&
|
| + window->GetShellWindowId() != kShellWindowId_SystemModalContainer) ||
|
| + window != params.new_parent)
|
| + return;
|
| +
|
| + // Observe the window to see the stacking change.
|
| + // Also, keep the pinned window at the top.
|
| + params.target->AddObserver(this);
|
| + if (window == pinned_window_->GetParent())
|
| + KeepPinnedWindowOnTop();
|
| + else
|
| + KeepDimWindowOnTop(window);
|
| +}
|
| +
|
| +void PinnedController::OnWindowStackingChanged(WmWindow* window) {
|
| + DCHECK(IsPinned());
|
| +
|
| + if (in_restacking_)
|
| + return;
|
| +
|
| + if (window->GetParent() == pinned_window_->GetParent())
|
| + KeepPinnedWindowOnTop();
|
| + else if (window->GetParent()->GetShellWindowId() ==
|
| + kShellWindowId_SystemModalContainer)
|
| + KeepDimWindowOnTop(window->GetParent());
|
| +}
|
| +
|
| +void PinnedController::OnWindowDestroying(WmWindow* window) {
|
| + DCHECK(IsPinned());
|
| +
|
| + if (window == pinned_window_) {
|
| + pinned_window_->GetWindowState()->Restore();
|
| + } else if (window == background_window_) {
|
| + background_window_ = nullptr;
|
| + } else if (Contains(dim_windows_, window)) {
|
| + dim_windows_.erase(
|
| + std::find(dim_windows_.begin(), dim_windows_.end(), window));
|
| + }
|
| +}
|
| +
|
| +void PinnedController::OnDisplayConfigurationChanged() {
|
| + // Note: this is called on display attached or detached.
|
| + if (!IsPinned())
|
| + return;
|
| +
|
| + std::vector<WmWindow*> system_modal_containers =
|
| + GetSystemModalWindowsExceptPinned(pinned_window_);
|
| + for (WmWindow* system_modal : system_modal_containers) {
|
| + if (Contains(dim_windows_, system_modal->GetChildren().back()))
|
| + continue;
|
| + WmWindow* dim_window = CreateDimWindow(system_modal);
|
| + system_modal->StackChildAtTop(dim_window);
|
| + dim_windows_.push_back(dim_window);
|
| + system_modal->AddObserver(this);
|
| + dim_window->AddObserver(this);
|
| + }
|
| +}
|
| +
|
| +void PinnedController::KeepPinnedWindowOnTop() {
|
| + DCHECK(!in_restacking_);
|
| +
|
| + base::AutoReset<bool> auto_reset(&in_restacking_, true);
|
| + WmWindow* container = pinned_window_->GetParent();
|
| + container->StackChildAtTop(pinned_window_);
|
| + container->StackChildBelow(background_window_, pinned_window_);
|
| +}
|
| +
|
| +void PinnedController::KeepDimWindowOnTop(WmWindow* container) {
|
| + DCHECK(!in_restacking_);
|
| +
|
| + base::AutoReset<bool> auto_reset(&in_restacking_, true);
|
| + for (WmWindow* dim_window : dim_windows_) {
|
| + if (dim_window->GetParent() == container) {
|
| + container->StackChildAtTop(dim_window);
|
| + break;
|
| + }
|
| + }
|
| +}
|
| +
|
| +} // namespace wm
|
| +} // namespace ash
|
|
|