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