transient_window_manager.cc revision a02191e04bc25c4935f804f2c080ae28663d096d
15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file.
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/wm/core/transient_window_manager.h"
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <algorithm>
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <functional>
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/auto_reset.h"
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/stl_util.h"
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/aura/window.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/aura/window_property.h"
14a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/wm/core/transient_window_observer.h"
15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/wm/core/transient_window_stacking_client.h"
16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/wm/core/window_util.h"
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using aura::Window;
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
20a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace wm {
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)DEFINE_OWNED_WINDOW_PROPERTY_KEY(TransientWindowManager, kPropertyKey, NULL);
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TransientWindowManager::~TransientWindowManager() {
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// static
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TransientWindowManager* TransientWindowManager::Get(Window* window) {
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  TransientWindowManager* manager = window->GetProperty(kPropertyKey);
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!manager) {
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    manager = new TransientWindowManager(window);
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    window->SetProperty(kPropertyKey, manager);
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return manager;
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// static
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const TransientWindowManager* TransientWindowManager::Get(
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const Window* window) {
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return window->GetProperty(kPropertyKey);
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void TransientWindowManager::AddObserver(TransientWindowObserver* observer) {
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  observers_.AddObserver(observer);
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void TransientWindowManager::RemoveObserver(TransientWindowObserver* observer) {
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  observers_.RemoveObserver(observer);
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void TransientWindowManager::AddTransientChild(Window* child) {
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // TransientWindowStackingClient does the stacking of transient windows. If it
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // isn't installed stacking is going to be wrong.
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(TransientWindowStackingClient::instance_);
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  TransientWindowManager* child_manager = Get(child);
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (child_manager->transient_parent_)
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Get(child_manager->transient_parent_)->RemoveTransientChild(child);
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(std::find(transient_children_.begin(), transient_children_.end(),
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   child) == transient_children_.end());
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  transient_children_.push_back(child);
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  child_manager->transient_parent_ = window_;
63a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
64a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // Restack |child| properly above its transient parent, if they share the same
65a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // parent.
66a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (child->parent() == window_->parent())
67a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    RestackTransientDescendants();
68a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FOR_EACH_OBSERVER(TransientWindowObserver, observers_,
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    OnTransientChildAdded(window_, child));
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void TransientWindowManager::RemoveTransientChild(Window* child) {
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Windows::iterator i =
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      std::find(transient_children_.begin(), transient_children_.end(), child);
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(i != transient_children_.end());
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  transient_children_.erase(i);
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  TransientWindowManager* child_manager = Get(child);
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_EQ(window_, child_manager->transient_parent_);
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  child_manager->transient_parent_ = NULL;
81a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
82a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // If |child| and its former transient parent share the same parent, |child|
83a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // should be restacked properly so it is not among transient children of its
84a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // former parent, anymore.
85a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (window_->parent() == child->parent())
86a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    RestackTransientDescendants();
87a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FOR_EACH_OBSERVER(TransientWindowObserver, observers_,
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    OnTransientChildRemoved(window_, child));
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool TransientWindowManager::IsStackingTransient(
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const aura::Window* target) const {
94a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  return stacking_target_ == target;
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TransientWindowManager::TransientWindowManager(Window* window)
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : window_(window),
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      transient_parent_(NULL),
100a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      stacking_target_(NULL) {
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  window_->AddObserver(this);
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
104a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochvoid TransientWindowManager::RestackTransientDescendants() {
105a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  Window* parent = window_->parent();
106a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (!parent)
107a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    return;
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Stack any transient children that share the same parent to be in front of
110a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // |window_|. The existing stacking order is preserved by iterating backwards
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // and always stacking on top.
112a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  Window::Windows children(parent->children());
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (Window::Windows::reverse_iterator it = children.rbegin();
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       it != children.rend(); ++it) {
115a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    if ((*it) != window_ && HasTransientAncestor(*it, window_)) {
116a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      TransientWindowManager* descendant_manager = Get(*it);
117a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      base::AutoReset<Window*> resetter(
118a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch          &descendant_manager->stacking_target_,
119a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch          window_);
120a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      parent->StackChildAbove((*it), window_);
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
125a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochvoid TransientWindowManager::OnWindowParentChanged(aura::Window* window,
126a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch                                                   aura::Window* parent) {
127a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  DCHECK_EQ(window_, window);
128a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // Stack |window| properly if it is transient child of a sibling.
129a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  Window* transient_parent = wm::GetTransientParent(window);
130a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (transient_parent && transient_parent->parent() == parent) {
131a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    TransientWindowManager* transient_parent_manager =
132a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        Get(transient_parent);
133a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    transient_parent_manager->RestackTransientDescendants();
134a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  }
135a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
136a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void TransientWindowManager::OnWindowVisibilityChanging(Window* window,
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                        bool visible) {
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // TODO(sky): move handling of becoming visible here.
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!visible) {
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::for_each(transient_children_.begin(), transient_children_.end(),
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  std::mem_fun(&Window::Hide));
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void TransientWindowManager::OnWindowStackingChanged(Window* window) {
147a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  DCHECK_EQ(window_, window);
148a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
149a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // Do nothing if we initiated the stacking change.
150a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  const TransientWindowManager* transient_manager =
151a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      Get(static_cast<const Window*>(window));
152a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (transient_manager && transient_manager->stacking_target_) {
153a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    Windows::const_iterator window_i = std::find(
154a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        window->parent()->children().begin(),
155a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        window->parent()->children().end(),
156a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        window);
157a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    DCHECK(window_i != window->parent()->children().end());
158a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch    if (window_i != window->parent()->children().begin() &&
159a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        (*(window_i - 1) == transient_manager->stacking_target_))
160a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      return;
161a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  }
162a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
163a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  RestackTransientDescendants();
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void TransientWindowManager::OnWindowDestroying(Window* window) {
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Removes ourselves from our transient parent (if it hasn't been done by the
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // RootWindow).
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (transient_parent_) {
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    TransientWindowManager::Get(transient_parent_)->RemoveTransientChild(
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        window_);
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Destroy transient children, only after we've removed ourselves from our
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // parent, as destroying an active transient child may otherwise attempt to
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // refocus us.
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Windows transient_children(transient_children_);
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  STLDeleteElements(&transient_children);
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(transient_children_.empty());
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
182a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}  // namespace wm
183