| OLD | NEW |
| (Empty) |
| 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/wm/core/transient_window_stacking_client.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 | |
| 9 #include "ui/wm/core/transient_window_manager.h" | |
| 10 #include "ui/wm/core/window_util.h" | |
| 11 | |
| 12 using aura::Window; | |
| 13 | |
| 14 namespace wm { | |
| 15 | |
| 16 namespace { | |
| 17 | |
| 18 // Populates |ancestors| with all transient ancestors of |window| that are | |
| 19 // siblings of |window|. Returns true if any ancestors were found, false if not. | |
| 20 bool GetAllTransientAncestors(Window* window, Window::Windows* ancestors) { | |
| 21 Window* parent = window->parent(); | |
| 22 for (; window; window = GetTransientParent(window)) { | |
| 23 if (window->parent() == parent) | |
| 24 ancestors->push_back(window); | |
| 25 } | |
| 26 return (!ancestors->empty()); | |
| 27 } | |
| 28 | |
| 29 // Replaces |window1| and |window2| with their possible transient ancestors that | |
| 30 // are still siblings (have a common transient parent). |window1| and |window2| | |
| 31 // are not modified if such ancestors cannot be found. | |
| 32 void FindCommonTransientAncestor(Window** window1, Window** window2) { | |
| 33 DCHECK(window1); | |
| 34 DCHECK(window2); | |
| 35 DCHECK(*window1); | |
| 36 DCHECK(*window2); | |
| 37 // Assemble chains of ancestors of both windows. | |
| 38 Window::Windows ancestors1; | |
| 39 Window::Windows ancestors2; | |
| 40 if (!GetAllTransientAncestors(*window1, &ancestors1) || | |
| 41 !GetAllTransientAncestors(*window2, &ancestors2)) { | |
| 42 return; | |
| 43 } | |
| 44 // Walk the two chains backwards and look for the first difference. | |
| 45 Window::Windows::reverse_iterator it1 = ancestors1.rbegin(); | |
| 46 Window::Windows::reverse_iterator it2 = ancestors2.rbegin(); | |
| 47 for (; it1 != ancestors1.rend() && it2 != ancestors2.rend(); ++it1, ++it2) { | |
| 48 if (*it1 != *it2) { | |
| 49 *window1 = *it1; | |
| 50 *window2 = *it2; | |
| 51 break; | |
| 52 } | |
| 53 } | |
| 54 } | |
| 55 | |
| 56 // Adjusts |target| so that we don't attempt to stack on top of a window with a | |
| 57 // NULL delegate. | |
| 58 void SkipNullDelegates(Window::StackDirection direction, Window** target) { | |
| 59 const Window::Windows& children((*target)->parent()->children()); | |
| 60 size_t target_i = | |
| 61 std::find(children.begin(), children.end(), *target) - | |
| 62 children.begin(); | |
| 63 | |
| 64 // By convention we don't stack on top of windows with layers with NULL | |
| 65 // delegates. Walk backward to find a valid target window. See tests | |
| 66 // TransientWindowManagerTest.StackingMadrigal and StackOverClosingTransient | |
| 67 // for an explanation of this. | |
| 68 while (target_i > 0) { | |
| 69 const size_t index = direction == Window::STACK_ABOVE ? | |
| 70 target_i : target_i - 1; | |
| 71 if (!children[index]->layer() || | |
| 72 children[index]->layer()->delegate() != NULL) | |
| 73 break; | |
| 74 --target_i; | |
| 75 } | |
| 76 *target = children[target_i]; | |
| 77 } | |
| 78 | |
| 79 } // namespace | |
| 80 | |
| 81 // static | |
| 82 TransientWindowStackingClient* TransientWindowStackingClient::instance_ = NULL; | |
| 83 | |
| 84 TransientWindowStackingClient::TransientWindowStackingClient() { | |
| 85 instance_ = this; | |
| 86 } | |
| 87 | |
| 88 TransientWindowStackingClient::~TransientWindowStackingClient() { | |
| 89 if (instance_ == this) | |
| 90 instance_ = NULL; | |
| 91 } | |
| 92 | |
| 93 bool TransientWindowStackingClient::AdjustStacking( | |
| 94 Window** child, | |
| 95 Window** target, | |
| 96 Window::StackDirection* direction) { | |
| 97 const TransientWindowManager* transient_manager = | |
| 98 TransientWindowManager::Get(static_cast<const Window*>(*child)); | |
| 99 if (transient_manager && transient_manager->IsStackingTransient(*target)) | |
| 100 return true; | |
| 101 | |
| 102 // For windows that have transient children stack the transient ancestors that | |
| 103 // are siblings. This prevents one transient group from being inserted in the | |
| 104 // middle of another. | |
| 105 FindCommonTransientAncestor(child, target); | |
| 106 | |
| 107 // When stacking above skip to the topmost transient descendant of the target. | |
| 108 if (*direction == Window::STACK_ABOVE && | |
| 109 !HasTransientAncestor(*child, *target)) { | |
| 110 const Window::Windows& siblings((*child)->parent()->children()); | |
| 111 size_t target_i = | |
| 112 std::find(siblings.begin(), siblings.end(), *target) - siblings.begin(); | |
| 113 while (target_i + 1 < siblings.size() && | |
| 114 HasTransientAncestor(siblings[target_i + 1], *target)) { | |
| 115 ++target_i; | |
| 116 } | |
| 117 *target = siblings[target_i]; | |
| 118 } | |
| 119 | |
| 120 SkipNullDelegates(*direction, target); | |
| 121 | |
| 122 // If we couldn't find a valid target position, don't move anything. | |
| 123 if (*direction == Window::STACK_ABOVE && | |
| 124 ((*target)->layer() && (*target)->layer()->delegate() == NULL)) { | |
| 125 return false; | |
| 126 } | |
| 127 | |
| 128 return *child != *target; | |
| 129 } | |
| 130 | |
| 131 } // namespace wm | |
| OLD | NEW |