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.
5 #include "ui/wm/core/transient_window_stacking_client.h"
9 #include "ui/wm/core/transient_window_manager.h"
10 #include "ui/wm/core/window_util.h"
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
);
26 return (!ancestors
->empty());
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
) {
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
)) {
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
) {
56 // Adjusts |target| so that we don't attempt to stack on top of a window with a
58 void SkipNullDelegates(Window::StackDirection direction
, Window
** target
) {
59 const Window::Windows
& children((*target
)->parent()->children());
61 std::find(children
.begin(), children
.end(), *target
) -
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
)
76 *target
= children
[target_i
];
82 TransientWindowStackingClient
* TransientWindowStackingClient::instance_
= NULL
;
84 TransientWindowStackingClient::TransientWindowStackingClient() {
88 TransientWindowStackingClient::~TransientWindowStackingClient() {
89 if (instance_
== this)
93 bool TransientWindowStackingClient::AdjustStacking(
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
))
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
);
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());
112 std::find(siblings
.begin(), siblings
.end(), *target
) - siblings
.begin();
113 while (target_i
+ 1 < siblings
.size() &&
114 HasTransientAncestor(siblings
[target_i
+ 1], *target
)) {
117 *target
= siblings
[target_i
];
120 SkipNullDelegates(*direction
, target
);
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
)) {
128 return *child
!= *target
;