• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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