| Index: ui/views/corewm/transient_window_manager.cc
|
| diff --git a/ui/views/corewm/transient_window_manager.cc b/ui/views/corewm/transient_window_manager.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..0f716ff5ba0d20f0e99b5bb7eff1f95bbdaca2f4
|
| --- /dev/null
|
| +++ b/ui/views/corewm/transient_window_manager.cc
|
| @@ -0,0 +1,182 @@
|
| +// Copyright (c) 2013 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/views/corewm/transient_window_manager.h"
|
| +
|
| +#include <algorithm>
|
| +#include <functional>
|
| +
|
| +#include "base/auto_reset.h"
|
| +#include "base/stl_util.h"
|
| +#include "ui/aura/window.h"
|
| +#include "ui/aura/window_property.h"
|
| +#include "ui/views/corewm/transient_window_stacking_client.h"
|
| +
|
| +using aura::Window;
|
| +
|
| +namespace views {
|
| +namespace corewm {
|
| +
|
| +DEFINE_OWNED_WINDOW_PROPERTY_KEY(TransientWindowManager, kPropertyKey, NULL);
|
| +
|
| +Window* GetTransientParent(Window* window) {
|
| + return const_cast<Window*>(GetTransientParent(
|
| + const_cast<const Window*>(window)));
|
| +}
|
| +
|
| +const Window* GetTransientParent(const Window* window) {
|
| + const TransientWindowManager* manager = TransientWindowManager::Get(window);
|
| + return manager ? manager->transient_parent() : NULL;
|
| +}
|
| +
|
| +const std::vector<Window*>& GetTransientChildren(
|
| + const Window* window) {
|
| + const TransientWindowManager* manager = TransientWindowManager::Get(window);
|
| + if (manager)
|
| + return manager->transient_children();
|
| +
|
| + static std::vector<Window*>* shared = new std::vector<Window*>;
|
| + return *shared;
|
| +}
|
| +
|
| +void AddTransientChild(aura::Window* parent, aura::Window* child) {
|
| + TransientWindowManager::Get(parent)->AddTransientChild(child);
|
| +}
|
| +
|
| +void RemoveTransientChild(aura::Window* parent, aura::Window* child) {
|
| + TransientWindowManager::Get(parent)->RemoveTransientChild(child);
|
| +}
|
| +
|
| +bool HasTransientAncestor(const Window* window, const Window* ancestor) {
|
| + const Window* transient_parent = GetTransientParent(window);
|
| + if (transient_parent == ancestor)
|
| + return true;
|
| + return transient_parent ?
|
| + HasTransientAncestor(transient_parent, ancestor) : false;
|
| +}
|
| +
|
| +TransientWindowManager::~TransientWindowManager() {
|
| +}
|
| +
|
| +// static
|
| +TransientWindowManager* TransientWindowManager::Get(Window* window) {
|
| + TransientWindowManager* manager = window->GetProperty(kPropertyKey);
|
| + if (!manager) {
|
| + manager = new TransientWindowManager(window);
|
| + window->SetProperty(kPropertyKey, manager);
|
| + }
|
| + return manager;
|
| +}
|
| +
|
| +// static
|
| +const TransientWindowManager* TransientWindowManager::Get(
|
| + const Window* window) {
|
| + return window->GetProperty(kPropertyKey);
|
| +}
|
| +
|
| +void TransientWindowManager::AddTransientChild(Window* child) {
|
| + // TransientWindowStackingClient does the stacking of transient windows. If it
|
| + // isn't installed stacking is going to be wrong.
|
| + DCHECK(TransientWindowStackingClient::instance_);
|
| +
|
| + TransientWindowManager* child_manager = Get(child);
|
| + if (child_manager->transient_parent_)
|
| + Get(child_manager->transient_parent_)->RemoveTransientChild(child);
|
| + DCHECK(std::find(transient_children_.begin(), transient_children_.end(),
|
| + child) == transient_children_.end());
|
| + transient_children_.push_back(child);
|
| + child_manager->transient_parent_ = window_;
|
| + FOR_EACH_OBSERVER(WindowObserver, window_->observers_,
|
| + OnAddTransientChild(window_, child));
|
| +}
|
| +
|
| +void TransientWindowManager::RemoveTransientChild(Window* child) {
|
| + Windows::iterator i =
|
| + std::find(transient_children_.begin(), transient_children_.end(), child);
|
| + DCHECK(i != transient_children_.end());
|
| + transient_children_.erase(i);
|
| + TransientWindowManager* child_manager = Get(child);
|
| + DCHECK_EQ(window_, child_manager->transient_parent_);
|
| + child_manager->transient_parent_ = NULL;
|
| + FOR_EACH_OBSERVER(WindowObserver, window_->observers_,
|
| + OnRemoveTransientChild(window_, child));
|
| +}
|
| +
|
| +bool TransientWindowManager::IsStackingTransient(
|
| + const aura::Window* child,
|
| + const aura::Window* target) const {
|
| + return stacking_pair_ && stacking_pair_->child == child &&
|
| + stacking_pair_->target == target;
|
| +}
|
| +
|
| +void TransientWindowManager::OnWindowVisibilityChanging(Window* window,
|
| + bool visible) {
|
| + // TODO(sky): move handling of becoming visible here.
|
| + if (!visible) {
|
| + std::for_each(transient_children_.begin(), transient_children_.end(),
|
| + std::mem_fun(&Window::Hide));
|
| + }
|
| +}
|
| +
|
| +void TransientWindowManager::OnWindowStackingChanged(Window* window) {
|
| + TransientWindowManager* parent_manager = Get(window->parent());
|
| + parent_manager->OnChildStackingChanged(window);
|
| +}
|
| +
|
| +void TransientWindowManager::OnWindowDestroying(Window* window) {
|
| + // TODO(sky): remove notes after safely landing and baking.
|
| +
|
| + // Removes ourselves from our transient parent (if it hasn't been done by the
|
| + // RootWindow).
|
| + // NOTE: This use to be done after children where removed, now it is before.
|
| + if (transient_parent_) {
|
| + TransientWindowManager::Get(transient_parent_)->RemoveTransientChild(
|
| + window_);
|
| + }
|
| +
|
| + // Destroy transient children, only after we've removed ourselves from our
|
| + // parent, as destroying an active transient child may otherwise attempt to
|
| + // refocus us.
|
| + // NOTE: this use to be after removed from parent, now its before.
|
| + Windows transient_children(transient_children_);
|
| + STLDeleteElements(&transient_children);
|
| + DCHECK(transient_children_.empty());
|
| +}
|
| +
|
| +TransientWindowManager::TransientWindowManager(Window* window)
|
| + : window_(window),
|
| + transient_parent_(NULL),
|
| + stacking_pair_(NULL) {
|
| + window_->AddObserver(this);
|
| +}
|
| +
|
| +void TransientWindowManager::OnChildStackingChanged(aura::Window* child) {
|
| + // Do nothing if we initiated the stacking change.
|
| + // TODO(sky): change args to OnWindowStackingChanged() so that this lookup
|
| + // can be simpler.
|
| + if (stacking_pair_ && stacking_pair_->child == child) {
|
| + Windows::const_iterator child_i = std::find(
|
| + window_->children().begin(), window_->children().end(), child);
|
| + DCHECK(child_i != window_->children().end());
|
| + if (child_i != window_->children().begin() &&
|
| + (*(child_i - 1) == stacking_pair_->target))
|
| + return;
|
| + }
|
| +
|
| + // Stack any transient children that share the same parent to be in front of
|
| + // |child|. The existing stacking order is preserved by iterating backwards
|
| + // and always stacking on top.
|
| + Window::Windows children(window_->children());
|
| + for (Window::Windows::reverse_iterator it = children.rbegin();
|
| + it != children.rend(); ++it) {
|
| + if ((*it) != child && HasTransientAncestor(*it, child)) {
|
| + StackingPair pair(*it, child);
|
| + base::AutoReset<StackingPair*> resetter(&stacking_pair_, &pair);
|
| + window_->StackChildAbove((*it), child);
|
| + }
|
| + }
|
| +}
|
| +
|
| +} // namespace corewm
|
| +} // namespace views
|
|
|