| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/views/corewm/transient_window_stacking_client.h" | 5 #include "ui/views/corewm/transient_window_stacking_client.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "ui/views/corewm/transient_window_manager.h" |
| 10 |
| 9 using aura::Window; | 11 using aura::Window; |
| 10 | 12 |
| 11 namespace views { | 13 namespace views { |
| 12 namespace corewm { | 14 namespace corewm { |
| 13 | 15 |
| 14 namespace { | 16 namespace { |
| 15 | 17 |
| 16 // Populates |ancestors| with all transient ancestors of |window| that are | 18 // Populates |ancestors| with all transient ancestors of |window| that are |
| 17 // siblings of |window|. Returns true if any ancestors were found, false if not. | 19 // siblings of |window|. Returns true if any ancestors were found, false if not. |
| 18 bool GetAllTransientAncestors(Window* window, Window::Windows* ancestors) { | 20 bool GetAllTransientAncestors(Window* window, Window::Windows* ancestors) { |
| 19 Window* parent = window->parent(); | 21 Window* parent = window->parent(); |
| 20 for (; window; window = window->transient_parent()) { | 22 for (; window; window = GetTransientParent(window)) { |
| 21 if (window->parent() == parent) | 23 if (window->parent() == parent) |
| 22 ancestors->push_back(window); | 24 ancestors->push_back(window); |
| 23 } | 25 } |
| 24 return (!ancestors->empty()); | 26 return (!ancestors->empty()); |
| 25 } | 27 } |
| 26 | 28 |
| 27 // Replaces |window1| and |window2| with their possible transient ancestors that | 29 // Replaces |window1| and |window2| with their possible transient ancestors that |
| 28 // are still siblings (have a common transient parent). |window1| and |window2| | 30 // are still siblings (have a common transient parent). |window1| and |window2| |
| 29 // are not modified if such ancestors cannot be found. | 31 // are not modified if such ancestors cannot be found. |
| 30 void FindCommonTransientAncestor(Window** window1, Window** window2) { | 32 void FindCommonTransientAncestor(Window** window1, Window** window2) { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 44 Window::Windows::const_reverse_iterator it2 = ancestors2.rbegin(); | 46 Window::Windows::const_reverse_iterator it2 = ancestors2.rbegin(); |
| 45 for (; it1 != ancestors1.rend() && it2 != ancestors2.rend(); ++it1, ++it2) { | 47 for (; it1 != ancestors1.rend() && it2 != ancestors2.rend(); ++it1, ++it2) { |
| 46 if (*it1 != *it2) { | 48 if (*it1 != *it2) { |
| 47 *window1 = *it1; | 49 *window1 = *it1; |
| 48 *window2 = *it2; | 50 *window2 = *it2; |
| 49 break; | 51 break; |
| 50 } | 52 } |
| 51 } | 53 } |
| 52 } | 54 } |
| 53 | 55 |
| 54 // Returns true if |window| has |ancestor| as a transient ancestor. A transient | 56 // Adjusts |target| so that we don't attempt to stack on top of a window with a |
| 55 // ancestor is found by following the transient parent chain of the window. | 57 // NULL delegate. |
| 56 bool HasTransientAncestor(const Window* window, const Window* ancestor) { | 58 void SkipNullDelegates(Window::StackDirection direction, Window** target) { |
| 57 if (window->transient_parent() == ancestor) | 59 const Window::Windows& children((*target)->parent()->children()); |
| 58 return true; | 60 size_t target_i = |
| 59 return window->transient_parent() ? | 61 std::find(children.begin(), children.end(), *target) - |
| 60 HasTransientAncestor(window->transient_parent(), ancestor) : false; | 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]; |
| 61 } | 77 } |
| 62 | 78 |
| 63 } // namespace | 79 } // namespace |
| 64 | 80 |
| 81 // static |
| 82 TransientWindowStackingClient* TransientWindowStackingClient::instance_ = NULL; |
| 83 |
| 65 TransientWindowStackingClient::TransientWindowStackingClient() { | 84 TransientWindowStackingClient::TransientWindowStackingClient() { |
| 85 instance_ = this; |
| 66 } | 86 } |
| 67 | 87 |
| 68 TransientWindowStackingClient::~TransientWindowStackingClient() { | 88 TransientWindowStackingClient::~TransientWindowStackingClient() { |
| 89 if (instance_ == this) |
| 90 instance_ = NULL; |
| 69 } | 91 } |
| 70 | 92 |
| 71 void TransientWindowStackingClient::AdjustStacking( | 93 bool TransientWindowStackingClient::AdjustStacking( |
| 72 Window** child, | 94 Window** child, |
| 73 Window** target, | 95 Window** target, |
| 74 Window::StackDirection* direction) { | 96 Window::StackDirection* direction) { |
| 97 const TransientWindowManager* transient_manager = |
| 98 TransientWindowManager::Get((*child)->parent()); |
| 99 if (transient_manager && |
| 100 transient_manager->IsStackingTransient(*child, *target)) |
| 101 return true; |
| 102 |
| 75 // For windows that have transient children stack the transient ancestors that | 103 // For windows that have transient children stack the transient ancestors that |
| 76 // are siblings. This prevents one transient group from being inserted in the | 104 // are siblings. This prevents one transient group from being inserted in the |
| 77 // middle of another. | 105 // middle of another. |
| 78 FindCommonTransientAncestor(child, target); | 106 FindCommonTransientAncestor(child, target); |
| 79 | 107 |
| 80 // When stacking above skip to the topmost transient descendant of the target. | 108 // When stacking above skip to the topmost transient descendant of the target. |
| 81 if (*direction == Window::STACK_ABOVE && | 109 if (*direction == Window::STACK_ABOVE && |
| 82 !HasTransientAncestor(*child, *target)) { | 110 !HasTransientAncestor(*child, *target)) { |
| 83 const Window::Windows& siblings((*child)->parent()->children()); | 111 const Window::Windows& siblings((*child)->parent()->children()); |
| 84 size_t target_i = | 112 size_t target_i = |
| 85 std::find(siblings.begin(), siblings.end(), *target) - siblings.begin(); | 113 std::find(siblings.begin(), siblings.end(), *target) - siblings.begin(); |
| 86 while (target_i + 1 < siblings.size() && | 114 while (target_i + 1 < siblings.size() && |
| 87 HasTransientAncestor(siblings[target_i + 1], *target)) { | 115 HasTransientAncestor(siblings[target_i + 1], *target)) { |
| 88 ++target_i; | 116 ++target_i; |
| 89 } | 117 } |
| 90 *target = siblings[target_i]; | 118 *target = siblings[target_i]; |
| 91 } | 119 } |
| 120 |
| 121 SkipNullDelegates(*direction, target); |
| 122 |
| 123 // If we couldn't find a valid target position, don't move anything. |
| 124 if (*direction == Window::STACK_ABOVE && |
| 125 ((*target)->layer() && (*target)->layer()->delegate() == NULL)) { |
| 126 return false; |
| 127 } |
| 128 |
| 129 return *child != *target; |
| 92 } | 130 } |
| 93 | 131 |
| 94 } // namespace corewm | 132 } // namespace corewm |
| 95 } // namespace views | 133 } // namespace views |
| OLD | NEW |