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.
GetAllTransientAncestors(Window * window,Window::Windows * ancestors)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.
FindCommonTransientAncestor(Window ** window1,Window ** window2)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.
HasTransientAncestor(const Window * window,const Window * ancestor)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
TransientWindowStackingClient()65 TransientWindowStackingClient::TransientWindowStackingClient() {
66 }
67
~TransientWindowStackingClient()68 TransientWindowStackingClient::~TransientWindowStackingClient() {
69 }
70
AdjustStacking(Window ** child,Window ** target,Window::StackDirection * direction)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