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