summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-12 22:13:27 +0000
committersky@chromium.org <sky@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-12 22:13:27 +0000
commit9661035442518ea3fc5cefe2e9439fee8b735fc4 (patch)
tree5b64e8c05556aaa061742f3ed7117477221edba1
parent75746b4b91172882cdaf1cc956147317627ad231 (diff)
downloadchromium_src-9661035442518ea3fc5cefe2e9439fee8b735fc4.zip
chromium_src-9661035442518ea3fc5cefe2e9439fee8b735fc4.tar.gz
chromium_src-9661035442518ea3fc5cefe2e9439fee8b735fc4.tar.bz2
Moves transient stacking logic into WindowStackingClient
This is part of moving transient window logic out of Window. BUG=none TEST=covered by tests R=ben@chromium.org Review URL: https://codereview.chromium.org/103813006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@240440 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--ash/shell/shell_main.cc15
-rw-r--r--ash/test/ash_test_helper.cc7
-rw-r--r--chrome/browser/ui/views/chrome_browser_main_extra_parts_views.cc10
-rw-r--r--ui/aura/aura.gyp2
-rw-r--r--ui/aura/client/window_stacking_client.cc26
-rw-r--r--ui/aura/client/window_stacking_client.h34
-rw-r--r--ui/aura/window.cc97
-rw-r--r--ui/aura/window.h28
-rw-r--r--ui/aura/window_unittest.cc137
-rw-r--r--ui/views/corewm/transient_window_stacking_client.cc95
-rw-r--r--ui/views/corewm/transient_window_stacking_client.h32
-rw-r--r--ui/views/corewm/transient_window_stacking_client_unittest.cc175
-rw-r--r--ui/views/test/views_test_base.cc5
-rw-r--r--ui/views/views.gyp3
14 files changed, 445 insertions, 221 deletions
diff --git a/ash/shell/shell_main.cc b/ash/shell/shell_main.cc
index 5648c81..b45ca5e 100644
--- a/ash/shell/shell_main.cc
+++ b/ash/shell/shell_main.cc
@@ -2,24 +2,37 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "ash/shell/content_client/shell_main_delegate.h"
#include "content/public/app/content_main.h"
#include "sandbox/win/src/sandbox_types.h"
-#include "ash/shell/content_client/shell_main_delegate.h"
+#include "ui/views/corewm/transient_window_stacking_client.h"
#if defined(OS_WIN)
#include "content/public/app/startup_helper_win.h"
#endif
+namespace {
+
+void CommonInit() {
+ // SetWindowStackingClient() takes ownership of TransientWindowStackingClient.
+ aura::client::SetWindowStackingClient(
+ new views::corewm::TransientWindowStackingClient);
+}
+
+} // namespace
+
#if defined(OS_WIN)
int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t*, int) {
sandbox::SandboxInterfaceInfo sandbox_info = {0};
content::InitializeSandboxInfo(&sandbox_info);
ash::shell::ShellMainDelegate delegate;
+ CommonInit();
return content::ContentMain(instance, &sandbox_info, &delegate);
}
#else
int main(int argc, const char** argv) {
ash::shell::ShellMainDelegate delegate;
+ CommonInit();
return content::ContentMain(argc, argv, &delegate);
}
#endif
diff --git a/ash/test/ash_test_helper.cc b/ash/test/ash_test_helper.cc
index 10ed2a2..6cff6ba 100644
--- a/ash/test/ash_test_helper.cc
+++ b/ash/test/ash_test_helper.cc
@@ -22,6 +22,7 @@
#include "ui/compositor/test/context_factories_for_test.h"
#include "ui/message_center/message_center.h"
#include "ui/views/corewm/capture_controller.h"
+#include "ui/views/corewm/transient_window_stacking_client.h"
#if defined(OS_CHROMEOS)
#include "chromeos/audio/cras_audio_handler.h"
@@ -87,6 +88,10 @@ void AshTestHelper::SetUp(bool start_session) {
test_screenshot_delegate_ = new TestScreenshotDelegate();
shell->accelerator_controller()->SetScreenshotDelegate(
scoped_ptr<ScreenshotDelegate>(test_screenshot_delegate_));
+
+ // SetWindowStackingClient() takes ownership of TransientWindowStackingClient.
+ aura::client::SetWindowStackingClient(
+ new views::corewm::TransientWindowStackingClient);
}
void AshTestHelper::TearDown() {
@@ -111,6 +116,8 @@ void AshTestHelper::TearDown() {
zero_duration_mode_.reset();
CHECK(!views::corewm::ScopedCaptureClient::IsActive());
+
+ aura::client::SetWindowStackingClient(NULL);
}
void AshTestHelper::RunAllPendingInMessageLoop() {
diff --git a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views.cc b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views.cc
index 3bf186f..b6ecac4 100644
--- a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views.cc
+++ b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views.cc
@@ -9,6 +9,10 @@
#include "chrome/common/chrome_switches.h"
#include "ui/base/ui_base_switches.h"
+#if defined(USE_AURA)
+#include "ui/views/corewm/transient_window_stacking_client.h"
+#endif
+
ChromeBrowserMainExtraPartsViews::ChromeBrowserMainExtraPartsViews() {
}
@@ -17,4 +21,10 @@ void ChromeBrowserMainExtraPartsViews::ToolkitInitialized() {
// display the correct icon.
if (!views::ViewsDelegate::views_delegate)
views::ViewsDelegate::views_delegate = new ChromeViewsDelegate;
+
+#if defined(USE_AURA)
+ // SetWindowStackingClient() takes ownership of TransientWindowStackingClient.
+ aura::client::SetWindowStackingClient(
+ new views::corewm::TransientWindowStackingClient);
+#endif
}
diff --git a/ui/aura/aura.gyp b/ui/aura/aura.gyp
index 5cd9922..68164d4 100644
--- a/ui/aura/aura.gyp
+++ b/ui/aura/aura.gyp
@@ -71,6 +71,8 @@
'client/visibility_client.h',
'client/window_move_client.cc',
'client/window_move_client.h',
+ 'client/window_stacking_client.cc',
+ 'client/window_stacking_client.h',
'client/window_tree_client.cc',
'client/window_tree_client.h',
'client/window_types.h',
diff --git a/ui/aura/client/window_stacking_client.cc b/ui/aura/client/window_stacking_client.cc
new file mode 100644
index 0000000..81da8d1
--- /dev/null
+++ b/ui/aura/client/window_stacking_client.cc
@@ -0,0 +1,26 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/aura/client/window_stacking_client.h"
+
+namespace aura {
+namespace client {
+
+namespace {
+
+WindowStackingClient* instance = NULL;
+
+} // namespace
+
+void SetWindowStackingClient(WindowStackingClient* client) {
+ delete instance;
+ instance = client;
+}
+
+AURA_EXPORT WindowStackingClient* GetWindowStackingClient() {
+ return instance;
+}
+
+} // namespace client
+} // namespace aura
diff --git a/ui/aura/client/window_stacking_client.h b/ui/aura/client/window_stacking_client.h
new file mode 100644
index 0000000..35772ed
--- /dev/null
+++ b/ui/aura/client/window_stacking_client.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_AURA_CLIENT_WINDOW_STACKING_DELEGATE_H_
+#define UI_AURA_CLIENT_WINDOW_STACKING_DELEGATE_H_
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/aura/aura_export.h"
+#include "ui/aura/window.h"
+
+namespace aura {
+namespace client {
+
+class AURA_EXPORT WindowStackingClient {
+ public:
+ virtual ~WindowStackingClient() {}
+
+ // Invoked from the various Window stacking functions. Allows the
+ // WindowStackingClient to alter the source, target and/or direction to stack.
+ virtual void AdjustStacking(Window** child,
+ Window** target,
+ Window::StackDirection* direction) = 0;
+};
+
+// Sets/gets the WindowStackingClient. The setter takes ownership of |client|.
+AURA_EXPORT void SetWindowStackingClient(WindowStackingClient* client);
+AURA_EXPORT WindowStackingClient* GetWindowStackingClient();
+
+} // namespace client
+} // namespace aura
+
+#endif // UI_AURA_CLIENT_WINDOW_STACKING_DELEGATE_H_
diff --git a/ui/aura/window.cc b/ui/aura/window.cc
index 5f70c0d..4836a15 100644
--- a/ui/aura/window.cc
+++ b/ui/aura/window.cc
@@ -20,6 +20,7 @@
#include "ui/aura/client/focus_client.h"
#include "ui/aura/client/screen_position_client.h"
#include "ui/aura/client/visibility_client.h"
+#include "ui/aura/client/window_stacking_client.h"
#include "ui/aura/env.h"
#include "ui/aura/layout_manager.h"
#include "ui/aura/root_window.h"
@@ -1159,39 +1160,6 @@ void Window::OnParentChanged() {
WindowObserver, observers_, OnWindowParentChanged(this, parent_));
}
-bool Window::GetAllTransientAncestors(Window* window,
- Windows* ancestors) const {
- for (; window; window = window->transient_parent()) {
- if (window->parent() == this)
- ancestors->push_back(window);
- }
- return (!ancestors->empty());
-}
-
-void Window::FindCommonSiblings(Window** window1, Window** window2) const {
- DCHECK(window1);
- DCHECK(window2);
- DCHECK(*window1);
- DCHECK(*window2);
- // Assemble chains of ancestors of both windows.
- Windows ancestors1;
- Windows ancestors2;
- if (!GetAllTransientAncestors(*window1, &ancestors1) ||
- !GetAllTransientAncestors(*window2, &ancestors2)) {
- return;
- }
- // Walk the two chains backwards and look for the first difference.
- Windows::const_reverse_iterator it1 = ancestors1.rbegin();
- Windows::const_reverse_iterator it2 = ancestors2.rbegin();
- for (; it1 != ancestors1.rend() && it2 != ancestors2.rend(); ++it1, ++it2) {
- if (*it1 != *it2) {
- *window1 = *it1;
- *window2 = *it2;
- break;
- }
- }
-}
-
bool Window::HasTransientAncestor(const Window* ancestor) const {
if (transient_parent_ == ancestor)
return true;
@@ -1199,59 +1167,54 @@ bool Window::HasTransientAncestor(const Window* ancestor) const {
transient_parent_->HasTransientAncestor(ancestor) : false;
}
-void Window::StackChildRelativeTo(Window* child,
- Window* target,
- StackDirection direction) {
- DCHECK_NE(child, target);
- DCHECK(child);
- DCHECK(target);
- DCHECK_EQ(this, child->parent());
- DCHECK_EQ(this, target->parent());
-
- // Consider all transient children of both child's and target's ancestors
- // up to the common ancestor if such exists and stack them as a unit.
- // This prevents one transient group from being inserted in the middle of
- // another.
- FindCommonSiblings(&child, &target);
-
- const size_t target_i =
- std::find(children_.begin(), children_.end(), target) - children_.begin();
-
- // When stacking above skip to the topmost transient descendant of the target.
- size_t final_target_i = target_i;
- if (direction == STACK_ABOVE && !child->HasTransientAncestor(target)) {
- while (final_target_i + 1 < children_.size() &&
- children_[final_target_i + 1]->HasTransientAncestor(target)) {
- ++final_target_i;
- }
- }
+void Window::SkipNullDelegatesForStacking(StackDirection direction,
+ Window** target) const {
+ DCHECK_EQ(this, (*target)->parent());
+ size_t target_i =
+ std::find(children_.begin(), children_.end(), *target) -
+ children_.begin();
// By convention we don't stack on top of windows with layers with NULL
// delegates. Walk backward to find a valid target window.
// See tests WindowTest.StackingMadrigal and StackOverClosingTransient
// for an explanation of this.
- while (final_target_i > 0) {
- const size_t index = direction == STACK_ABOVE ?
- final_target_i : final_target_i - 1;
+ while (target_i > 0) {
+ const size_t index = direction == STACK_ABOVE ? target_i : target_i - 1;
if (!children_[index]->layer_ ||
children_[index]->layer_->delegate() != NULL)
break;
- --final_target_i;
+ --target_i;
}
+ *target = children_[target_i];
+}
+
+void Window::StackChildRelativeTo(Window* child,
+ Window* target,
+ StackDirection direction) {
+ DCHECK_NE(child, target);
+ DCHECK(child);
+ DCHECK(target);
+ DCHECK_EQ(this, child->parent());
+ DCHECK_EQ(this, target->parent());
+
+ client::WindowStackingClient* stacking_client =
+ client::GetWindowStackingClient();
+ if (stacking_client)
+ stacking_client->AdjustStacking(&child, &target, &direction);
- Window* final_target = children_[final_target_i];
+ SkipNullDelegatesForStacking(direction, &target);
// If we couldn't find a valid target position, don't move anything.
if (direction == STACK_ABOVE &&
- (final_target->layer_ && final_target->layer_->delegate() == NULL))
+ (target->layer_ && target->layer_->delegate() == NULL))
return;
// Don't try to stack a child above itself.
- if (child == final_target)
+ if (child == target)
return;
// Move the child.
- StackChildRelativeToImpl(child, final_target, direction);
+ StackChildRelativeToImpl(child, target, direction);
// Stack any transient children that share the same parent to be in front of
// 'child'. Preserve the existing stacking order by iterating in the order
diff --git a/ui/aura/window.h b/ui/aura/window.h
index 5ed3ea4..d69d88e 100644
--- a/ui/aura/window.h
+++ b/ui/aura/window.h
@@ -68,6 +68,12 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
public ui::EventTarget,
public ui::GestureConsumer {
public:
+ // Used when stacking windows.
+ enum StackDirection {
+ STACK_ABOVE,
+ STACK_BELOW
+ };
+
typedef std::vector<Window*> Windows;
explicit Window(WindowDelegate* delegate);
@@ -378,14 +384,8 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
private:
friend class test::WindowTestApi;
friend class LayoutManager;
- friend class WindowTargeter;
friend class RootWindow;
-
- // Used when stacking windows.
- enum StackDirection {
- STACK_ABOVE,
- STACK_BELOW
- };
+ friend class WindowTargeter;
// Called by the public {Set,Get,Clear}Property functions.
int64 SetPropertyInternal(const void* key,
@@ -445,18 +445,14 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
// Called when this window's parent has changed.
void OnParentChanged();
- // Populates |ancestors| with all transient ancestors of |window| that are
- // children of |this|. Returns true if any ancestors were found, false if not.
- bool GetAllTransientAncestors(Window* window, Windows* ancestors) const;
-
- // Replaces two windows |window1| and |window2| with their possible transient
- // ancestors that are still siblings (have a common transient parent).
- // |window1| and |window2| are not modified if such ancestors cannot be found.
- void FindCommonSiblings(Window** window1, Window** window2) const;
-
// Returns true when |ancestor| is a transient ancestor of |this|.
bool HasTransientAncestor(const Window* ancestor) const;
+ // Adjusts |target| so that we don't attempt to stack on top of a window with
+ // a NULL delegate. See implementation for details.
+ void SkipNullDelegatesForStacking(StackDirection direction,
+ Window** target) const;
+
// Determines the real location for stacking |child| and invokes
// StackChildRelativeToImpl().
void StackChildRelativeTo(Window* child,
diff --git a/ui/aura/window_unittest.cc b/ui/aura/window_unittest.cc
index dfce60b..b791431 100644
--- a/ui/aura/window_unittest.cc
+++ b/ui/aura/window_unittest.cc
@@ -1618,143 +1618,6 @@ TEST_F(WindowTest, TransientChildren) {
EXPECT_FALSE(w2->IsVisible());
}
-// Tests that transient children are stacked as a unit when using stack above.
-TEST_F(WindowTest, TransientChildrenGroupAbove) {
- scoped_ptr<Window> parent(CreateTestWindowWithId(0, root_window()));
- scoped_ptr<Window> w1(CreateTestWindowWithId(1, parent.get()));
- Window* w11 = CreateTestWindowWithId(11, parent.get());
- scoped_ptr<Window> w2(CreateTestWindowWithId(2, parent.get()));
- Window* w21 = CreateTestWindowWithId(21, parent.get());
- Window* w211 = CreateTestWindowWithId(211, parent.get());
- Window* w212 = CreateTestWindowWithId(212, parent.get());
- Window* w213 = CreateTestWindowWithId(213, parent.get());
- Window* w22 = CreateTestWindowWithId(22, parent.get());
- ASSERT_EQ(8u, parent->children().size());
-
- w1->AddTransientChild(w11); // w11 is now owned by w1.
- w2->AddTransientChild(w21); // w21 is now owned by w2.
- w2->AddTransientChild(w22); // w22 is now owned by w2.
- w21->AddTransientChild(w211); // w211 is now owned by w21.
- w21->AddTransientChild(w212); // w212 is now owned by w21.
- w21->AddTransientChild(w213); // w213 is now owned by w21.
- EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
-
- // Stack w1 at the top (end), this should force w11 to be last (on top of w1).
- parent->StackChildAtTop(w1.get());
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
-
- // This tests that the order in children_ array rather than in
- // transient_children_ array is used when reinserting transient children.
- // If transient_children_ array was used '22' would be following '21'.
- parent->StackChildAtTop(w2.get());
- EXPECT_EQ(w22, parent->children().back());
- EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
-
- parent->StackChildAbove(w11, w2.get());
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
-
- parent->StackChildAbove(w21, w1.get());
- EXPECT_EQ(w22, parent->children().back());
- EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
-
- parent->StackChildAbove(w21, w22);
- EXPECT_EQ(w213, parent->children().back());
- EXPECT_EQ("1 11 2 22 21 211 212 213", ChildWindowIDsAsString(parent.get()));
-
- parent->StackChildAbove(w11, w21);
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 22 21 211 212 213 1 11", ChildWindowIDsAsString(parent.get()));
-
- parent->StackChildAbove(w213, w21);
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
-
- // No change when stacking a transient parent above its transient child.
- parent->StackChildAbove(w21, w211);
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
-
- // This tests that the order in children_ array rather than in
- // transient_children_ array is used when reinserting transient children.
- // If transient_children_ array was used '22' would be following '21'.
- parent->StackChildAbove(w2.get(), w1.get());
- EXPECT_EQ(w212, parent->children().back());
- EXPECT_EQ("1 11 2 22 21 213 211 212", ChildWindowIDsAsString(parent.get()));
-
- parent->StackChildAbove(w11, w213);
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
-}
-
-// Tests that transient children are stacked as a unit when using stack below.
-TEST_F(WindowTest, TransientChildrenGroupBelow) {
- scoped_ptr<Window> parent(CreateTestWindowWithId(0, root_window()));
- scoped_ptr<Window> w1(CreateTestWindowWithId(1, parent.get()));
- Window* w11 = CreateTestWindowWithId(11, parent.get());
- scoped_ptr<Window> w2(CreateTestWindowWithId(2, parent.get()));
- Window* w21 = CreateTestWindowWithId(21, parent.get());
- Window* w211 = CreateTestWindowWithId(211, parent.get());
- Window* w212 = CreateTestWindowWithId(212, parent.get());
- Window* w213 = CreateTestWindowWithId(213, parent.get());
- Window* w22 = CreateTestWindowWithId(22, parent.get());
- ASSERT_EQ(8u, parent->children().size());
-
- w1->AddTransientChild(w11); // w11 is now owned by w1.
- w2->AddTransientChild(w21); // w21 is now owned by w2.
- w2->AddTransientChild(w22); // w22 is now owned by w2.
- w21->AddTransientChild(w211); // w211 is now owned by w21.
- w21->AddTransientChild(w212); // w212 is now owned by w21.
- w21->AddTransientChild(w213); // w213 is now owned by w21.
- EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
-
- // Stack w2 at the bottom, this should force w11 to be last (on top of w1).
- // This also tests that the order in children_ array rather than in
- // transient_children_ array is used when reinserting transient children.
- // If transient_children_ array was used '22' would be following '21'.
- parent->StackChildAtBottom(w2.get());
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
-
- parent->StackChildAtBottom(w1.get());
- EXPECT_EQ(w22, parent->children().back());
- EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
-
- parent->StackChildBelow(w21, w1.get());
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
-
- parent->StackChildBelow(w11, w2.get());
- EXPECT_EQ(w22, parent->children().back());
- EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
-
- parent->StackChildBelow(w22, w21);
- EXPECT_EQ(w213, parent->children().back());
- EXPECT_EQ("1 11 2 22 21 211 212 213", ChildWindowIDsAsString(parent.get()));
-
- parent->StackChildBelow(w21, w11);
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 22 21 211 212 213 1 11", ChildWindowIDsAsString(parent.get()));
-
- parent->StackChildBelow(w213, w211);
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
-
- // No change when stacking a transient parent below its transient child.
- parent->StackChildBelow(w21, w211);
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
-
- parent->StackChildBelow(w1.get(), w2.get());
- EXPECT_EQ(w212, parent->children().back());
- EXPECT_EQ("1 11 2 22 21 213 211 212", ChildWindowIDsAsString(parent.get()));
-
- parent->StackChildBelow(w213, w11);
- EXPECT_EQ(w11, parent->children().back());
- EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
-}
-
namespace {
DEFINE_WINDOW_PROPERTY_KEY(int, kIntKey, -2);
DEFINE_WINDOW_PROPERTY_KEY(const char*, kStringKey, "squeamish");
diff --git a/ui/views/corewm/transient_window_stacking_client.cc b/ui/views/corewm/transient_window_stacking_client.cc
new file mode 100644
index 0000000..6a4f8ab
--- /dev/null
+++ b/ui/views/corewm/transient_window_stacking_client.cc
@@ -0,0 +1,95 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/corewm/transient_window_stacking_client.h"
+
+#include <algorithm>
+
+using aura::Window;
+
+namespace views {
+namespace corewm {
+
+namespace {
+
+// Populates |ancestors| with all transient ancestors of |window| that are
+// siblings of |window|. Returns true if any ancestors were found, false if not.
+bool GetAllTransientAncestors(Window* window, Window::Windows* ancestors) {
+ Window* parent = window->parent();
+ for (; window; window = window->transient_parent()) {
+ if (window->parent() == parent)
+ ancestors->push_back(window);
+ }
+ return (!ancestors->empty());
+}
+
+// Replaces |window1| and |window2| with their possible transient ancestors that
+// are still siblings (have a common transient parent). |window1| and |window2|
+// are not modified if such ancestors cannot be found.
+void FindCommonTransientAncestor(Window** window1, Window** window2) {
+ DCHECK(window1);
+ DCHECK(window2);
+ DCHECK(*window1);
+ DCHECK(*window2);
+ // Assemble chains of ancestors of both windows.
+ Window::Windows ancestors1;
+ Window::Windows ancestors2;
+ if (!GetAllTransientAncestors(*window1, &ancestors1) ||
+ !GetAllTransientAncestors(*window2, &ancestors2)) {
+ return;
+ }
+ // Walk the two chains backwards and look for the first difference.
+ Window::Windows::const_reverse_iterator it1 = ancestors1.rbegin();
+ Window::Windows::const_reverse_iterator it2 = ancestors2.rbegin();
+ for (; it1 != ancestors1.rend() && it2 != ancestors2.rend(); ++it1, ++it2) {
+ if (*it1 != *it2) {
+ *window1 = *it1;
+ *window2 = *it2;
+ break;
+ }
+ }
+}
+
+// Returns true if |window| has |ancestor| as a transient ancestor. A transient
+// ancestor is found by following the transient parent chain of the window.
+bool HasTransientAncestor(const Window* window, const Window* ancestor) {
+ if (window->transient_parent() == ancestor)
+ return true;
+ return window->transient_parent() ?
+ HasTransientAncestor(window->transient_parent(), ancestor) : false;
+}
+
+} // namespace
+
+TransientWindowStackingClient::TransientWindowStackingClient() {
+}
+
+TransientWindowStackingClient::~TransientWindowStackingClient() {
+}
+
+void TransientWindowStackingClient::AdjustStacking(
+ Window** child,
+ Window** target,
+ Window::StackDirection* direction) {
+ // For windows that have transient children stack the transient ancestors that
+ // are siblings. This prevents one transient group from being inserted in the
+ // middle of another.
+ FindCommonTransientAncestor(child, target);
+
+ // When stacking above skip to the topmost transient descendant of the target.
+ if (*direction == Window::STACK_ABOVE &&
+ !HasTransientAncestor(*child, *target)) {
+ const Window::Windows& siblings((*child)->parent()->children());
+ size_t target_i =
+ std::find(siblings.begin(), siblings.end(), *target) - siblings.begin();
+ while (target_i + 1 < siblings.size() &&
+ HasTransientAncestor(siblings[target_i + 1], *target)) {
+ ++target_i;
+ }
+ *target = siblings[target_i];
+ }
+}
+
+} // namespace corewm
+} // namespace views
diff --git a/ui/views/corewm/transient_window_stacking_client.h b/ui/views/corewm/transient_window_stacking_client.h
new file mode 100644
index 0000000..1935836
--- /dev/null
+++ b/ui/views/corewm/transient_window_stacking_client.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_COREWM_TRANSIENT_WINDOW_STACKING_CLIENT_H_
+#define UI_VIEWS_COREWM_TRANSIENT_WINDOW_STACKING_CLIENT_H_
+
+#include "ui/aura/client/window_stacking_client.h"
+#include "ui/views/views_export.h"
+
+namespace views {
+namespace corewm {
+
+class VIEWS_EXPORT TransientWindowStackingClient
+ : public aura::client::WindowStackingClient {
+ public:
+ TransientWindowStackingClient();
+ virtual ~TransientWindowStackingClient();
+
+ // WindowStackingClient:
+ virtual void AdjustStacking(aura::Window** child,
+ aura::Window** target,
+ aura::Window::StackDirection* direction) OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TransientWindowStackingClient);
+};
+
+} // namespace corewm
+} // namespace views
+
+#endif // UI_VIEWS_COREWM_TRANSIENT_WINDOW_STACKING_CLIENT_H_
diff --git a/ui/views/corewm/transient_window_stacking_client_unittest.cc b/ui/views/corewm/transient_window_stacking_client_unittest.cc
new file mode 100644
index 0000000..a84b832
--- /dev/null
+++ b/ui/views/corewm/transient_window_stacking_client_unittest.cc
@@ -0,0 +1,175 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/corewm/transient_window_stacking_client.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "ui/aura/test/aura_test_base.h"
+#include "ui/aura/test/test_windows.h"
+
+using aura::test::ChildWindowIDsAsString;
+using aura::test::CreateTestWindowWithId;
+using aura::Window;
+
+namespace views {
+namespace corewm {
+
+class TransientWindowStackingClientTest : public aura::test::AuraTestBase {
+ public:
+ TransientWindowStackingClientTest() {}
+ virtual ~TransientWindowStackingClientTest() {}
+
+ virtual void SetUp() OVERRIDE {
+ AuraTestBase::SetUp();
+ aura::client::SetWindowStackingClient(new TransientWindowStackingClient);
+ }
+
+ virtual void TearDown() OVERRIDE {
+ aura::client::SetWindowStackingClient(NULL);
+ AuraTestBase::TearDown();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TransientWindowStackingClientTest);
+};
+
+// Tests that transient children are stacked as a unit when using stack above.
+TEST_F(TransientWindowStackingClientTest, TransientChildrenGroupAbove) {
+ scoped_ptr<Window> parent(CreateTestWindowWithId(0, root_window()));
+ scoped_ptr<Window> w1(CreateTestWindowWithId(1, parent.get()));
+ Window* w11 = CreateTestWindowWithId(11, parent.get());
+ scoped_ptr<Window> w2(CreateTestWindowWithId(2, parent.get()));
+ Window* w21 = CreateTestWindowWithId(21, parent.get());
+ Window* w211 = CreateTestWindowWithId(211, parent.get());
+ Window* w212 = CreateTestWindowWithId(212, parent.get());
+ Window* w213 = CreateTestWindowWithId(213, parent.get());
+ Window* w22 = CreateTestWindowWithId(22, parent.get());
+ ASSERT_EQ(8u, parent->children().size());
+
+ w1->AddTransientChild(w11); // w11 is now owned by w1.
+ w2->AddTransientChild(w21); // w21 is now owned by w2.
+ w2->AddTransientChild(w22); // w22 is now owned by w2.
+ w21->AddTransientChild(w211); // w211 is now owned by w21.
+ w21->AddTransientChild(w212); // w212 is now owned by w21.
+ w21->AddTransientChild(w213); // w213 is now owned by w21.
+ EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
+
+ // Stack w1 at the top (end), this should force w11 to be last (on top of w1).
+ parent->StackChildAtTop(w1.get());
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
+
+ // This tests that the order in children_ array rather than in
+ // transient_children_ array is used when reinserting transient children.
+ // If transient_children_ array was used '22' would be following '21'.
+ parent->StackChildAtTop(w2.get());
+ EXPECT_EQ(w22, parent->children().back());
+ EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildAbove(w11, w2.get());
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildAbove(w21, w1.get());
+ EXPECT_EQ(w22, parent->children().back());
+ EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildAbove(w21, w22);
+ EXPECT_EQ(w213, parent->children().back());
+ EXPECT_EQ("1 11 2 22 21 211 212 213", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildAbove(w11, w21);
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 22 21 211 212 213 1 11", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildAbove(w213, w21);
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
+
+ // No change when stacking a transient parent above its transient child.
+ parent->StackChildAbove(w21, w211);
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
+
+ // This tests that the order in children_ array rather than in
+ // transient_children_ array is used when reinserting transient children.
+ // If transient_children_ array was used '22' would be following '21'.
+ parent->StackChildAbove(w2.get(), w1.get());
+ EXPECT_EQ(w212, parent->children().back());
+ EXPECT_EQ("1 11 2 22 21 213 211 212", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildAbove(w11, w213);
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
+}
+
+// Tests that transient children are stacked as a unit when using stack below.
+TEST_F(TransientWindowStackingClientTest, TransientChildrenGroupBelow) {
+ scoped_ptr<Window> parent(CreateTestWindowWithId(0, root_window()));
+ scoped_ptr<Window> w1(CreateTestWindowWithId(1, parent.get()));
+ Window* w11 = CreateTestWindowWithId(11, parent.get());
+ scoped_ptr<Window> w2(CreateTestWindowWithId(2, parent.get()));
+ Window* w21 = CreateTestWindowWithId(21, parent.get());
+ Window* w211 = CreateTestWindowWithId(211, parent.get());
+ Window* w212 = CreateTestWindowWithId(212, parent.get());
+ Window* w213 = CreateTestWindowWithId(213, parent.get());
+ Window* w22 = CreateTestWindowWithId(22, parent.get());
+ ASSERT_EQ(8u, parent->children().size());
+
+ w1->AddTransientChild(w11); // w11 is now owned by w1.
+ w2->AddTransientChild(w21); // w21 is now owned by w2.
+ w2->AddTransientChild(w22); // w22 is now owned by w2.
+ w21->AddTransientChild(w211); // w211 is now owned by w21.
+ w21->AddTransientChild(w212); // w212 is now owned by w21.
+ w21->AddTransientChild(w213); // w213 is now owned by w21.
+ EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
+
+ // Stack w2 at the bottom, this should force w11 to be last (on top of w1).
+ // This also tests that the order in children_ array rather than in
+ // transient_children_ array is used when reinserting transient children.
+ // If transient_children_ array was used '22' would be following '21'.
+ parent->StackChildAtBottom(w2.get());
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildAtBottom(w1.get());
+ EXPECT_EQ(w22, parent->children().back());
+ EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildBelow(w21, w1.get());
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildBelow(w11, w2.get());
+ EXPECT_EQ(w22, parent->children().back());
+ EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildBelow(w22, w21);
+ EXPECT_EQ(w213, parent->children().back());
+ EXPECT_EQ("1 11 2 22 21 211 212 213", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildBelow(w21, w11);
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 22 21 211 212 213 1 11", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildBelow(w213, w211);
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
+
+ // No change when stacking a transient parent below its transient child.
+ parent->StackChildBelow(w21, w211);
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildBelow(w1.get(), w2.get());
+ EXPECT_EQ(w212, parent->children().back());
+ EXPECT_EQ("1 11 2 22 21 213 211 212", ChildWindowIDsAsString(parent.get()));
+
+ parent->StackChildBelow(w213, w11);
+ EXPECT_EQ(w11, parent->children().back());
+ EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
+}
+
+} // namespace corewm
+} // namespace views
diff --git a/ui/views/test/views_test_base.cc b/ui/views/test/views_test_base.cc
index 1a6f5c9..cff7e9a 100644
--- a/ui/views/test/views_test_base.cc
+++ b/ui/views/test/views_test_base.cc
@@ -13,6 +13,7 @@
#include "ui/aura/root_window.h"
#include "ui/aura/test/aura_test_helper.h"
#include "ui/views/corewm/capture_controller.h"
+#include "ui/views/corewm/transient_window_stacking_client.h"
#endif
namespace views {
@@ -37,6 +38,9 @@ void ViewsTestBase::SetUp() {
#if defined(USE_AURA)
aura_test_helper_.reset(new aura::test::AuraTestHelper(&message_loop_));
aura_test_helper_->SetUp();
+ // SetWindowStackingClient() takes ownership of TransientWindowStackingClient.
+ aura::client::SetWindowStackingClient(
+ new corewm::TransientWindowStackingClient);
#endif // USE_AURA
ui::InitializeInputMethodForTesting();
}
@@ -53,6 +57,7 @@ void ViewsTestBase::TearDown() {
ui::ShutdownInputMethodForTesting();
#if defined(USE_AURA)
aura_test_helper_->TearDown();
+ aura::client::SetWindowStackingClient(NULL);
CHECK(!corewm::ScopedCaptureClient::IsActive());
#endif // USE_AURA
}
diff --git a/ui/views/views.gyp b/ui/views/views.gyp
index e853e76..af835c22 100644
--- a/ui/views/views.gyp
+++ b/ui/views/views.gyp
@@ -262,6 +262,8 @@
'corewm/tooltip_controller.h',
'corewm/tooltip_win.cc',
'corewm/tooltip_win.h',
+ 'corewm/transient_window_stacking_client.cc',
+ 'corewm/transient_window_stacking_client.h',
'corewm/visibility_controller.cc',
'corewm/visibility_controller.h',
'corewm/window_animations.cc',
@@ -759,6 +761,7 @@
'corewm/shadow_controller_unittest.cc',
'corewm/tooltip_aura_unittest.cc',
'corewm/tooltip_controller_unittest.cc',
+ 'corewm/transient_window_stacking_client_unittest.cc',
'corewm/visibility_controller_unittest.cc',
'corewm/window_animations_unittest.cc',
'corewm/window_util_unittest.cc',