15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file.
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/wm/core/transient_window_stacking_client.h"
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <algorithm>
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
9a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/wm/core/transient_window_manager.h"
10a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/wm/core/window_util.h"
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using aura::Window;
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
14a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace wm {
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Populates |ancestors| with all transient ancestors of |window| that are
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// siblings of |window|. Returns true if any ancestors were found, false if not.
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool GetAllTransientAncestors(Window* window, Window::Windows* ancestors) {
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Window* parent = window->parent();
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (; window; window = GetTransientParent(window)) {
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (window->parent() == parent)
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ancestors->push_back(window);
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return (!ancestors->empty());
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Replaces |window1| and |window2| with their possible transient ancestors that
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// are still siblings (have a common transient parent).  |window1| and |window2|
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// are not modified if such ancestors cannot be found.
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void FindCommonTransientAncestor(Window** window1, Window** window2) {
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(window1);
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(window2);
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(*window1);
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(*window2);
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Assemble chains of ancestors of both windows.
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Window::Windows ancestors1;
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Window::Windows ancestors2;
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!GetAllTransientAncestors(*window1, &ancestors1) ||
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      !GetAllTransientAncestors(*window2, &ancestors2)) {
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Walk the two chains backwards and look for the first difference.
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Window::Windows::reverse_iterator it1 = ancestors1.rbegin();
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Window::Windows::reverse_iterator it2 = ancestors2.rbegin();
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (; it1  != ancestors1.rend() && it2  != ancestors2.rend(); ++it1, ++it2) {
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (*it1 != *it2) {
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      *window1 = *it1;
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      *window2 = *it2;
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Adjusts |target| so that we don't attempt to stack on top of a window with a
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// NULL delegate.
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void SkipNullDelegates(Window::StackDirection direction, Window** target) {
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const Window::Windows& children((*target)->parent()->children());
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  size_t target_i =
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      std::find(children.begin(), children.end(), *target) -
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      children.begin();
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // By convention we don't stack on top of windows with layers with NULL
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // delegates.  Walk backward to find a valid target window.  See tests
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // TransientWindowManagerTest.StackingMadrigal and StackOverClosingTransient
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // for an explanation of this.
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  while (target_i > 0) {
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const size_t index = direction == Window::STACK_ABOVE ?
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        target_i : target_i - 1;
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!children[index]->layer() ||
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        children[index]->layer()->delegate() != NULL)
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    --target_i;
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  *target = children[target_i];
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// static
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TransientWindowStackingClient* TransientWindowStackingClient::instance_ = NULL;
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TransientWindowStackingClient::TransientWindowStackingClient() {
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  instance_ = this;
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TransientWindowStackingClient::~TransientWindowStackingClient() {
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (instance_ == this)
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    instance_ = NULL;
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool TransientWindowStackingClient::AdjustStacking(
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Window** child,
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Window** target,
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Window::StackDirection* direction) {
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const TransientWindowManager* transient_manager =
98a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch      TransientWindowManager::Get(static_cast<const Window*>(*child));
99a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (transient_manager && transient_manager->IsStackingTransient(*target))
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return true;
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // For windows that have transient children stack the transient ancestors that
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // are siblings. This prevents one transient group from being inserted in the
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // middle of another.
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FindCommonTransientAncestor(child, target);
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // When stacking above skip to the topmost transient descendant of the target.
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (*direction == Window::STACK_ABOVE &&
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      !HasTransientAncestor(*child, *target)) {
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const Window::Windows& siblings((*child)->parent()->children());
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    size_t target_i =
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        std::find(siblings.begin(), siblings.end(), *target) - siblings.begin();
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    while (target_i + 1 < siblings.size() &&
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           HasTransientAncestor(siblings[target_i + 1], *target)) {
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ++target_i;
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    *target = siblings[target_i];
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SkipNullDelegates(*direction, target);
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // If we couldn't find a valid target position, don't move anything.
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (*direction == Window::STACK_ABOVE &&
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ((*target)->layer() && (*target)->layer()->delegate() == NULL)) {
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return *child != *target;
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}  // namespace wm
132