transient_window_manager.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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_;
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FOR_EACH_OBSERVER(TransientWindowObserver, observers_,
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    OnTransientChildAdded(window_, child));
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void TransientWindowManager::RemoveTransientChild(Window* child) {
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Windows::iterator i =
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      std::find(transient_children_.begin(), transient_children_.end(), child);
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(i != transient_children_.end());
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  transient_children_.erase(i);
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  TransientWindowManager* child_manager = Get(child);
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_EQ(window_, child_manager->transient_parent_);
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  child_manager->transient_parent_ = NULL;
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FOR_EACH_OBSERVER(TransientWindowObserver, observers_,
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                    OnTransientChildRemoved(window_, child));
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool TransientWindowManager::IsStackingTransient(
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const aura::Window* child,
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const aura::Window* target) const {
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return stacking_pair_ && stacking_pair_->child == child &&
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      stacking_pair_->target == target;
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TransientWindowManager::TransientWindowManager(Window* window)
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : window_(window),
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      transient_parent_(NULL),
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      stacking_pair_(NULL) {
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  window_->AddObserver(this);
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void TransientWindowManager::OnChildStackingChanged(aura::Window* child) {
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Do nothing if we initiated the stacking change.
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // TODO(sky): change args to OnWindowStackingChanged() so that this lookup
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // can be simpler.
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (stacking_pair_ && stacking_pair_->child == child) {
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Windows::const_iterator child_i = std::find(
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        window_->children().begin(), window_->children().end(), child);
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DCHECK(child_i != window_->children().end());
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (child_i != window_->children().begin() &&
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        (*(child_i - 1) == stacking_pair_->target))
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return;
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Stack any transient children that share the same parent to be in front of
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // |child|. The existing stacking order is preserved by iterating backwards
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // and always stacking on top.
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Window::Windows children(window_->children());
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (Window::Windows::reverse_iterator it = children.rbegin();
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       it != children.rend(); ++it) {
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if ((*it) != child && HasTransientAncestor(*it, child)) {
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      StackingPair pair(*it, child);
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::AutoReset<StackingPair*> resetter(&stacking_pair_, &pair);
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      window_->StackChildAbove((*it), child);
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void TransientWindowManager::OnWindowVisibilityChanging(Window* window,
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                                        bool visible) {
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // TODO(sky): move handling of becoming visible here.
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!visible) {
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::for_each(transient_children_.begin(), transient_children_.end(),
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  std::mem_fun(&Window::Hide));
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void TransientWindowManager::OnWindowStackingChanged(Window* window) {
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  TransientWindowManager* parent_manager = Get(window->parent());
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  parent_manager->OnChildStackingChanged(window);
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void TransientWindowManager::OnWindowDestroying(Window* window) {
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // TODO(sky): remove notes after safely landing and baking.
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Removes ourselves from our transient parent (if it hasn't been done by the
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // RootWindow).
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // NOTE: This use to be done after children where removed, now it is before.
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (transient_parent_) {
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    TransientWindowManager::Get(transient_parent_)->RemoveTransientChild(
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        window_);
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Destroy transient children, only after we've removed ourselves from our
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // parent, as destroying an active transient child may otherwise attempt to
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // refocus us.
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // NOTE: this use to be after removed from parent, now its before.
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Windows transient_children(transient_children_);
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  STLDeleteElements(&transient_children);
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(transient_children_.empty());
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
154a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}  // namespace wm
155