1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "ui/views/corewm/transient_window_stacking_client.h" 6 7 #include <algorithm> 8 9 using aura::Window; 10 11 namespace views { 12 namespace corewm { 13 14 namespace { 15 16 // Populates |ancestors| with all transient ancestors of |window| that are 17 // siblings of |window|. Returns true if any ancestors were found, false if not. 18 bool GetAllTransientAncestors(Window* window, Window::Windows* ancestors) { 19 Window* parent = window->parent(); 20 for (; window; window = window->transient_parent()) { 21 if (window->parent() == parent) 22 ancestors->push_back(window); 23 } 24 return (!ancestors->empty()); 25 } 26 27 // Replaces |window1| and |window2| with their possible transient ancestors that 28 // are still siblings (have a common transient parent). |window1| and |window2| 29 // are not modified if such ancestors cannot be found. 30 void FindCommonTransientAncestor(Window** window1, Window** window2) { 31 DCHECK(window1); 32 DCHECK(window2); 33 DCHECK(*window1); 34 DCHECK(*window2); 35 // Assemble chains of ancestors of both windows. 36 Window::Windows ancestors1; 37 Window::Windows ancestors2; 38 if (!GetAllTransientAncestors(*window1, &ancestors1) || 39 !GetAllTransientAncestors(*window2, &ancestors2)) { 40 return; 41 } 42 // Walk the two chains backwards and look for the first difference. 43 Window::Windows::const_reverse_iterator it1 = ancestors1.rbegin(); 44 Window::Windows::const_reverse_iterator it2 = ancestors2.rbegin(); 45 for (; it1 != ancestors1.rend() && it2 != ancestors2.rend(); ++it1, ++it2) { 46 if (*it1 != *it2) { 47 *window1 = *it1; 48 *window2 = *it2; 49 break; 50 } 51 } 52 } 53 54 // Returns true if |window| has |ancestor| as a transient ancestor. A transient 55 // ancestor is found by following the transient parent chain of the window. 56 bool HasTransientAncestor(const Window* window, const Window* ancestor) { 57 if (window->transient_parent() == ancestor) 58 return true; 59 return window->transient_parent() ? 60 HasTransientAncestor(window->transient_parent(), ancestor) : false; 61 } 62 63 } // namespace 64 65 TransientWindowStackingClient::TransientWindowStackingClient() { 66 } 67 68 TransientWindowStackingClient::~TransientWindowStackingClient() { 69 } 70 71 void TransientWindowStackingClient::AdjustStacking( 72 Window** child, 73 Window** target, 74 Window::StackDirection* direction) { 75 // For windows that have transient children stack the transient ancestors that 76 // are siblings. This prevents one transient group from being inserted in the 77 // middle of another. 78 FindCommonTransientAncestor(child, target); 79 80 // When stacking above skip to the topmost transient descendant of the target. 81 if (*direction == Window::STACK_ABOVE && 82 !HasTransientAncestor(*child, *target)) { 83 const Window::Windows& siblings((*child)->parent()->children()); 84 size_t target_i = 85 std::find(siblings.begin(), siblings.end(), *target) - siblings.begin(); 86 while (target_i + 1 < siblings.size() && 87 HasTransientAncestor(siblings[target_i + 1], *target)) { 88 ++target_i; 89 } 90 *target = siblings[target_i]; 91 } 92 } 93 94 } // namespace corewm 95 } // namespace views 96