Home | History | Annotate | Download | only in corewm
      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.
     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.
     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.
     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 
     65 TransientWindowStackingClient::TransientWindowStackingClient() {
     66 }
     67 
     68 TransientWindowStackingClient::~TransientWindowStackingClient() {
     69 }
     70 
     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