15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright (c) 2013 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_stacking_client.h" 65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <algorithm> 85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 9a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/wm/core/transient_window_manager.h" 10a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/wm/core/window_util.h" 115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using aura::Window; 135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 14a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace wm { 155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace { 175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Populates |ancestors| with all transient ancestors of |window| that are 195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// siblings of |window|. Returns true if any ancestors were found, false if not. 205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool GetAllTransientAncestors(Window* window, Window::Windows* ancestors) { 215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Window* parent = window->parent(); 225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (; window; window = GetTransientParent(window)) { 235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (window->parent() == parent) 245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ancestors->push_back(window); 255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return (!ancestors->empty()); 275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Replaces |window1| and |window2| with their possible transient ancestors that 305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// are still siblings (have a common transient parent). |window1| and |window2| 315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// are not modified if such ancestors cannot be found. 325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void FindCommonTransientAncestor(Window** window1, Window** window2) { 335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(window1); 345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(window2); 355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(*window1); 365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(*window2); 375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Assemble chains of ancestors of both windows. 385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Window::Windows ancestors1; 395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Window::Windows ancestors2; 405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!GetAllTransientAncestors(*window1, &ancestors1) || 415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) !GetAllTransientAncestors(*window2, &ancestors2)) { 425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Walk the two chains backwards and look for the first difference. 455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Window::Windows::reverse_iterator it1 = ancestors1.rbegin(); 465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Window::Windows::reverse_iterator it2 = ancestors2.rbegin(); 475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (; it1 != ancestors1.rend() && it2 != ancestors2.rend(); ++it1, ++it2) { 485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (*it1 != *it2) { 495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) *window1 = *it1; 505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) *window2 = *it2; 515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Adjusts |target| so that we don't attempt to stack on top of a window with a 575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// NULL delegate. 585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void SkipNullDelegates(Window::StackDirection direction, Window** target) { 595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const Window::Windows& children((*target)->parent()->children()); 605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) size_t target_i = 615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::find(children.begin(), children.end(), *target) - 625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) children.begin(); 635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // By convention we don't stack on top of windows with layers with NULL 655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // delegates. Walk backward to find a valid target window. See tests 665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // TransientWindowManagerTest.StackingMadrigal and StackOverClosingTransient 675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // for an explanation of this. 685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) while (target_i > 0) { 695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const size_t index = direction == Window::STACK_ABOVE ? 705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) target_i : target_i - 1; 715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!children[index]->layer() || 725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) children[index]->layer()->delegate() != NULL) 735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) break; 745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) --target_i; 755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) *target = children[target_i]; 775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} // namespace 805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// static 825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TransientWindowStackingClient* TransientWindowStackingClient::instance_ = NULL; 835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TransientWindowStackingClient::TransientWindowStackingClient() { 855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) instance_ = this; 865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TransientWindowStackingClient::~TransientWindowStackingClient() { 895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (instance_ == this) 905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) instance_ = NULL; 915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool TransientWindowStackingClient::AdjustStacking( 945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Window** child, 955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Window** target, 965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Window::StackDirection* direction) { 975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const TransientWindowManager* transient_manager = 98a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch TransientWindowManager::Get(static_cast<const Window*>(*child)); 99a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (transient_manager && transient_manager->IsStackingTransient(*target)) 1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return true; 1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // For windows that have transient children stack the transient ancestors that 1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // are siblings. This prevents one transient group from being inserted in the 1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // middle of another. 1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) FindCommonTransientAncestor(child, target); 1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // When stacking above skip to the topmost transient descendant of the target. 1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (*direction == Window::STACK_ABOVE && 1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) !HasTransientAncestor(*child, *target)) { 1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const Window::Windows& siblings((*child)->parent()->children()); 1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) size_t target_i = 1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::find(siblings.begin(), siblings.end(), *target) - siblings.begin(); 1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) while (target_i + 1 < siblings.size() && 1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) HasTransientAncestor(siblings[target_i + 1], *target)) { 1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ++target_i; 1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) *target = siblings[target_i]; 1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SkipNullDelegates(*direction, target); 1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // If we couldn't find a valid target position, don't move anything. 1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (*direction == Window::STACK_ABOVE && 1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ((*target)->layer() && (*target)->layer()->delegate() == NULL)) { 1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return false; 1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return *child != *target; 1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} // namespace wm 132