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