summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ash/display/screen_position_controller.cc6
-rw-r--r--ash/root_window_controller.cc3
-rw-r--r--ash/wm/dock/docked_window_layout_manager.cc3
-rw-r--r--ash/wm/dock/docked_window_resizer_unittest.cc11
-rw-r--r--ash/wm/drag_window_resizer.cc9
-rw-r--r--ash/wm/drag_window_resizer_unittest.cc3
-rw-r--r--ash/wm/immersive_fullscreen_controller.cc10
-rw-r--r--ash/wm/mru_window_tracker.cc5
-rw-r--r--ash/wm/mru_window_tracker.h2
-rw-r--r--ash/wm/overview/scoped_transform_overview_window.cc10
-rw-r--r--ash/wm/overview/window_selector.cc3
-rw-r--r--ash/wm/overview/window_selector_unittest.cc7
-rw-r--r--ash/wm/panels/panel_window_resizer_unittest.cc5
-rw-r--r--ash/wm/stacking_controller.cc20
-rw-r--r--ash/wm/stacking_controller_unittest.cc3
-rw-r--r--ash/wm/system_modal_container_layout_manager_unittest.cc11
-rw-r--r--ash/wm/window_modality_controller_unittest.cc23
-rw-r--r--ash/wm/window_state.cc2
-rw-r--r--ash/wm/window_util.cc11
-rw-r--r--ash/wm/workspace/workspace_layout_manager_unittest.cc3
-rw-r--r--ash/wm/workspace/workspace_window_resizer.cc3
-rw-r--r--ash/wm/workspace_controller_unittest.cc6
-rw-r--r--chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc17
-rw-r--r--chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc29
-rw-r--r--chrome/browser/ui/views/extensions/extension_popup.cc3
-rw-r--r--content/browser/renderer_host/render_widget_host_view_aura.cc14
-rw-r--r--ui/aura/aura.gyp2
-rw-r--r--ui/aura/client/transient_window_client.cc25
-rw-r--r--ui/aura/client/transient_window_client.h47
-rw-r--r--ui/aura/test/aura_test_base.cc10
-rw-r--r--ui/aura/test/aura_test_base.h3
-rw-r--r--ui/aura/window.cc110
-rw-r--r--ui/aura/window.h47
-rw-r--r--ui/aura/window_unittest.cc374
-rw-r--r--ui/oak/oak_aura_window_display.cc8
-rw-r--r--ui/views/corewm/base_focus_rules.cc7
-rw-r--r--ui/views/corewm/focus_controller.cc7
-rw-r--r--ui/views/corewm/shadow_controller.cc7
-rw-r--r--ui/views/corewm/shadow_controller_unittest.cc3
-rw-r--r--ui/views/corewm/transient_window_controller.cc42
-rw-r--r--ui/views/corewm/transient_window_controller.h38
-rw-r--r--ui/views/corewm/transient_window_manager.cc147
-rw-r--r--ui/views/corewm/transient_window_manager.h96
-rw-r--r--ui/views/corewm/transient_window_manager_unittest.cc577
-rw-r--r--ui/views/corewm/transient_window_stacking_client.cc56
-rw-r--r--ui/views/corewm/transient_window_stacking_client.h7
-rw-r--r--ui/views/corewm/transient_window_stacking_client_unittest.cc64
-rw-r--r--ui/views/corewm/window_modality_controller.cc16
-rw-r--r--ui/views/corewm/window_util.cc38
-rw-r--r--ui/views/corewm/window_util.h18
-rw-r--r--ui/views/corewm/wm_state.cc10
-rw-r--r--ui/views/corewm/wm_state.h2
-rw-r--r--ui/views/views.gyp5
-rw-r--r--ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc10
-rw-r--r--ui/views/widget/native_widget_aura.cc11
-rw-r--r--ui/wm/core/easy_resize_window_targeter.cc20
-rw-r--r--ui/wm/public/easy_resize_window_targeter.h4
57 files changed, 1356 insertions, 677 deletions
diff --git a/ash/display/screen_position_controller.cc b/ash/display/screen_position_controller.cc
index 624a0cd..5b45b7c 100644
--- a/ash/display/screen_position_controller.cc
+++ b/ash/display/screen_position_controller.cc
@@ -19,6 +19,7 @@
#include "ui/compositor/dip_util.h"
#include "ui/gfx/display.h"
#include "ui/gfx/screen.h"
+#include "ui/views/corewm/window_util.h"
namespace ash {
namespace {
@@ -37,7 +38,8 @@ void MoveAllTransientChildrenToNewRoot(const gfx::Display& display,
aura::Window* window) {
aura::Window* dst_root = Shell::GetInstance()->display_controller()->
GetRootWindowForDisplayId(display.id());
- aura::Window::Windows transient_children = window->transient_children();
+ aura::Window::Windows transient_children =
+ views::corewm::GetTransientChildren(window);
for (aura::Window::Windows::iterator iter = transient_children.begin();
iter != transient_children.end(); ++iter) {
aura::Window* transient_child = *iter;
@@ -162,7 +164,7 @@ void ScreenPositionController::SetBounds(aura::Window* window,
// b) if the window or its ancestor has kStayInSameRootWindowkey. It's
// intentionally kept in the same root window even if the bounds is
// outside of the display.
- if (!window->transient_parent() &&
+ if (!views::corewm::GetTransientParent(window) &&
!ShouldStayInSameRootWindow(window)) {
aura::Window* dst_root =
Shell::GetInstance()->display_controller()->GetRootWindowForDisplayId(
diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc
index 1af782d..330b8d4 100644
--- a/ash/root_window_controller.cc
+++ b/ash/root_window_controller.cc
@@ -65,6 +65,7 @@
#include "ui/views/controls/menu/menu_runner.h"
#include "ui/views/corewm/capture_controller.h"
#include "ui/views/corewm/visibility_controller.h"
+#include "ui/views/corewm/window_util.h"
#include "ui/views/view_model.h"
#include "ui/views/view_model_utils.h"
#include "ui/wm/public/easy_resize_window_targeter.h"
@@ -589,7 +590,7 @@ const aura::Window* RootWindowController::GetWindowForFullscreenMode() const {
while (topmost_window) {
if (wm::GetWindowState(topmost_window)->IsFullscreen())
return topmost_window;
- topmost_window = topmost_window->transient_parent();
+ topmost_window = views::corewm::GetTransientParent(topmost_window);
}
return NULL;
}
diff --git a/ash/wm/dock/docked_window_layout_manager.cc b/ash/wm/dock/docked_window_layout_manager.cc
index 40088a4..0a648a0 100644
--- a/ash/wm/dock/docked_window_layout_manager.cc
+++ b/ash/wm/dock/docked_window_layout_manager.cc
@@ -37,6 +37,7 @@
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/gfx/rect.h"
#include "ui/views/background.h"
+#include "ui/views/corewm/window_util.h"
namespace ash {
namespace internal {
@@ -189,7 +190,7 @@ namespace {
// Returns true if a window is a popup or a transient child.
bool IsPopupOrTransient(const aura::Window* window) {
return (window->type() == ui::wm::WINDOW_TYPE_POPUP ||
- window->transient_parent());
+ views::corewm::GetTransientParent(window));
}
// Certain windows (minimized, hidden or popups) do not matter to docking.
diff --git a/ash/wm/dock/docked_window_resizer_unittest.cc b/ash/wm/dock/docked_window_resizer_unittest.cc
index b15117d..05cb9b3 100644
--- a/ash/wm/dock/docked_window_resizer_unittest.cc
+++ b/ash/wm/dock/docked_window_resizer_unittest.cc
@@ -32,6 +32,7 @@
#include "ui/aura/test/test_window_delegate.h"
#include "ui/base/hit_test.h"
#include "ui/base/ui_base_types.h"
+#include "ui/views/corewm/window_util.h"
#include "ui/views/widget/widget.h"
namespace ash {
@@ -1295,10 +1296,10 @@ TEST_P(DockedWindowResizerTest, DragWindowWithTransientChild) {
scoped_ptr<aura::Window> window(CreateTestWindow(gfx::Rect(0, 0, 201, 201)));
scoped_ptr<aura::Window> child(CreateTestWindowInShellWithDelegateAndType(
NULL, ui::wm::WINDOW_TYPE_NORMAL, 0, gfx::Rect(20, 20, 150, 20)));
- window->AddTransientChild(child.get());
+ views::corewm::AddTransientChild(window.get(), child.get());
if (window->parent() != child->parent())
window->parent()->AddChild(child.get());
- EXPECT_EQ(window.get(), child->transient_parent());
+ EXPECT_EQ(window.get(), views::corewm::GetTransientParent(child.get()));
DragToVerticalPositionAndToEdge(DOCKED_EDGE_RIGHT, window.get(), 20);
@@ -1345,8 +1346,8 @@ TEST_P(DockedWindowResizerTest, DragWindowWithModalTransientChild) {
// While still dragging create a modal window and make it a transient child of
// the |window|.
scoped_ptr<aura::Window> child(CreateModalWindow(gfx::Rect(20, 20, 150, 20)));
- window->AddTransientChild(child.get());
- EXPECT_EQ(window.get(), child->transient_parent());
+ views::corewm::AddTransientChild(window.get(), child.get());
+ EXPECT_EQ(window.get(), views::corewm::GetTransientParent(child.get()));
EXPECT_EQ(internal::kShellWindowId_SystemModalContainer,
child->parent()->id());
@@ -1366,7 +1367,7 @@ TEST_P(DockedWindowResizerTest, DragWindowWithModalTransientChild) {
EXPECT_EQ(gfx::Point(20, 20).ToString(),
child->GetBoundsInScreen().origin().ToString());
// The |child| should still be a transient child of |window|.
- EXPECT_EQ(window.get(), child->transient_parent());
+ EXPECT_EQ(window.get(), views::corewm::GetTransientParent(child.get()));
}
// Tests that side snapping a window undocks it, closes the dock and then snaps.
diff --git a/ash/wm/drag_window_resizer.cc b/ash/wm/drag_window_resizer.cc
index 5b74fcb..2a859cf 100644
--- a/ash/wm/drag_window_resizer.cc
+++ b/ash/wm/drag_window_resizer.cc
@@ -22,6 +22,7 @@
#include "ui/base/hit_test.h"
#include "ui/base/ui_base_types.h"
#include "ui/gfx/screen.h"
+#include "ui/views/corewm/window_util.h"
namespace ash {
namespace internal {
@@ -232,9 +233,9 @@ void DragWindowResizer::UpdateDragWindow(const gfx::Rect& bounds,
bool DragWindowResizer::ShouldAllowMouseWarp() {
return (details_.window_component == HTCAPTION) &&
- !GetTarget()->transient_parent() &&
- (GetTarget()->type() == ui::wm::WINDOW_TYPE_NORMAL ||
- GetTarget()->type() == ui::wm::WINDOW_TYPE_PANEL);
+ !views::corewm::GetTransientParent(GetTarget()) &&
+ (GetTarget()->type() == ui::wm::WINDOW_TYPE_NORMAL ||
+ GetTarget()->type() == ui::wm::WINDOW_TYPE_PANEL);
}
TrayUser* DragWindowResizer::GetTrayUserItemAtPoint(
@@ -245,7 +246,7 @@ TrayUser* DragWindowResizer::GetTrayUserItemAtPoint(
// Check that this is a drag move operation from a suitable window.
if (details_.window_component != HTCAPTION ||
- GetTarget()->transient_parent() ||
+ views::corewm::GetTransientParent(GetTarget()) ||
(GetTarget()->type() != ui::wm::WINDOW_TYPE_NORMAL &&
GetTarget()->type() != ui::wm::WINDOW_TYPE_PANEL &&
GetTarget()->type() != ui::wm::WINDOW_TYPE_POPUP))
diff --git a/ash/wm/drag_window_resizer_unittest.cc b/ash/wm/drag_window_resizer_unittest.cc
index c2bd1df..0514ad5 100644
--- a/ash/wm/drag_window_resizer_unittest.cc
+++ b/ash/wm/drag_window_resizer_unittest.cc
@@ -22,6 +22,7 @@
#include "ui/base/ui_base_types.h"
#include "ui/gfx/insets.h"
#include "ui/gfx/screen.h"
+#include "ui/views/corewm/window_util.h"
#include "ui/views/widget/widget.h"
#if defined(OS_CHROMEOS)
@@ -84,7 +85,7 @@ class DragWindowResizerTest : public test::AshTestBase {
transient_parent_->SetType(ui::wm::WINDOW_TYPE_NORMAL);
transient_parent_->Init(ui::LAYER_NOT_DRAWN);
ParentWindowInPrimaryRootWindow(transient_parent_.get());
- transient_parent_->AddTransientChild(transient_child_);
+ views::corewm::AddTransientChild(transient_parent_.get(), transient_child_);
transient_parent_->set_id(5);
panel_window_.reset(new aura::Window(&delegate6_));
diff --git a/ash/wm/immersive_fullscreen_controller.cc b/ash/wm/immersive_fullscreen_controller.cc
index 701096e..14eee9d 100644
--- a/ash/wm/immersive_fullscreen_controller.cc
+++ b/ash/wm/immersive_fullscreen_controller.cc
@@ -23,6 +23,7 @@
#include "ui/gfx/rect.h"
#include "ui/gfx/screen.h"
#include "ui/views/bubble/bubble_delegate.h"
+#include "ui/views/corewm/window_util.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
@@ -88,7 +89,7 @@ bool IsWindowTransientChildOf(aura::Window* maybe_transient,
return false;
for (aura::Window* window = maybe_transient; window;
- window = window->transient_parent()) {
+ window = views::corewm::GetTransientParent(window)) {
if (window == toplevel)
return true;
}
@@ -472,8 +473,9 @@ void ImmersiveFullscreenController::AnimationProgressed(
////////////////////////////////////////////////////////////////////////////////
// aura::WindowObserver overrides:
-void ImmersiveFullscreenController::OnAddTransientChild(aura::Window* window,
- aura::Window* transient) {
+void ImmersiveFullscreenController::OnAddTransientChild(
+ aura::Window* window,
+ aura::Window* transient) {
views::BubbleDelegateView* bubble_delegate = AsBubbleDelegate(transient);
if (bubble_delegate &&
bubble_delegate->GetAnchorView() &&
@@ -915,7 +917,7 @@ bool ImmersiveFullscreenController::ShouldHandleGestureEvent(
void ImmersiveFullscreenController::RecreateBubbleManager() {
bubble_manager_.reset(new BubbleManager(this));
const std::vector<aura::Window*> transient_children =
- native_window_->transient_children();
+ views::corewm::GetTransientChildren(native_window_);
for (size_t i = 0; i < transient_children.size(); ++i) {
aura::Window* transient_child = transient_children[i];
views::BubbleDelegateView* bubble_delegate =
diff --git a/ash/wm/mru_window_tracker.cc b/ash/wm/mru_window_tracker.cc
index 4ed9a1d..af703e9 100644
--- a/ash/wm/mru_window_tracker.cc
+++ b/ash/wm/mru_window_tracker.cc
@@ -190,7 +190,10 @@ void MruWindowTracker::OnWindowActivated(aura::Window* gained_active,
SetActiveWindow(gained_active);
}
-void MruWindowTracker::OnWindowDestroying(aura::Window* window) {
+void MruWindowTracker::OnWindowDestroyed(aura::Window* window) {
+ // It's possible for OnWindowActivated() to be called after
+ // OnWindowDestroying(). This means we need to override OnWindowDestroyed()
+ // else we may end up with a deleted window in |mru_windows_|.
mru_windows_.remove(window);
window->RemoveObserver(this);
}
diff --git a/ash/wm/mru_window_tracker.h b/ash/wm/mru_window_tracker.h
index 1569a98..3f8740d 100644
--- a/ash/wm/mru_window_tracker.h
+++ b/ash/wm/mru_window_tracker.h
@@ -71,7 +71,7 @@ class ASH_EXPORT MruWindowTracker
aura::Window* lost_active) OVERRIDE;
// Overridden from WindowObserver:
- virtual void OnWindowDestroying(aura::Window* window) OVERRIDE;
+ virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE;
// List of windows that have been activated in containers that we cycle
// through, sorted by most recently used.
diff --git a/ash/wm/overview/scoped_transform_overview_window.cc b/ash/wm/overview/scoped_transform_overview_window.cc
index 507df0c..12b7c0c6 100644
--- a/ash/wm/overview/scoped_transform_overview_window.cc
+++ b/ash/wm/overview/scoped_transform_overview_window.cc
@@ -14,6 +14,7 @@
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/gfx/animation/tween.h"
#include "ui/views/corewm/window_animations.h"
+#include "ui/views/corewm/window_util.h"
#include "ui/views/widget/widget.h"
namespace ash {
@@ -63,7 +64,8 @@ void SetTransformOnWindowAndAllTransientChildren(
bool animate) {
SetTransformOnWindow(window, transform, animate);
- aura::Window::Windows transient_children = window->transient_children();
+ aura::Window::Windows transient_children =
+ views::corewm::GetTransientChildren(window);
for (aura::Window::Windows::iterator iter = transient_children.begin();
iter != transient_children.end(); ++iter) {
aura::Window* transient_child = *iter;
@@ -78,7 +80,7 @@ void SetTransformOnWindowAndAllTransientChildren(
aura::Window* GetModalTransientParent(aura::Window* window) {
if (window->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_WINDOW)
- return window->transient_parent();
+ return views::corewm::GetTransientParent(window);
return NULL;
}
@@ -237,8 +239,8 @@ void ScopedTransformOverviewWindow::SetTransformOnWindowAndTransientChildren(
bool animate) {
gfx::Point origin(GetBoundsInScreen().origin());
aura::Window* window = window_;
- while (window->transient_parent())
- window = window->transient_parent();
+ while (views::corewm::GetTransientParent(window))
+ window = views::corewm::GetTransientParent(window);
for (ScopedVector<ScopedWindowCopy>::const_iterator iter =
window_copies_.begin(); iter != window_copies_.end(); ++iter) {
SetTransformOnWindow(
diff --git a/ash/wm/overview/window_selector.cc b/ash/wm/overview/window_selector.cc
index 56ea455..aa35185 100644
--- a/ash/wm/overview/window_selector.cc
+++ b/ash/wm/overview/window_selector.cc
@@ -27,6 +27,7 @@
#include "ui/aura/window_observer.h"
#include "ui/events/event.h"
#include "ui/events/event_handler.h"
+#include "ui/views/corewm/window_util.h"
namespace ash {
@@ -400,7 +401,7 @@ void WindowSelector::OnWindowAdded(aura::Window* new_window) {
for (size_t i = 0; i < kSwitchableWindowContainerIdsLength; ++i) {
if (new_window->parent()->id() == kSwitchableWindowContainerIds[i] &&
- !new_window->transient_parent()) {
+ !views::corewm::GetTransientParent(new_window)) {
// The new window is in one of the switchable containers, abort overview.
CancelSelection();
return;
diff --git a/ash/wm/overview/window_selector_unittest.cc b/ash/wm/overview/window_selector_unittest.cc
index 86c0742..52bca15 100644
--- a/ash/wm/overview/window_selector_unittest.cc
+++ b/ash/wm/overview/window_selector_unittest.cc
@@ -33,6 +33,7 @@
#include "ui/compositor/scoped_animation_duration_scale_mode.h"
#include "ui/gfx/rect_conversions.h"
#include "ui/gfx/transform.h"
+#include "ui/views/corewm/window_util.h"
namespace ash {
namespace internal {
@@ -692,7 +693,7 @@ TEST_F(WindowSelectorTest, ModalChild) {
scoped_ptr<aura::Window> window1(CreateWindow(bounds));
scoped_ptr<aura::Window> child1(CreateWindow(bounds));
child1->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
- window1->AddTransientChild(child1.get());
+ views::corewm::AddTransientChild(window1.get(), child1.get());
EXPECT_EQ(window1->parent(), child1->parent());
ToggleOverview();
EXPECT_TRUE(window1->IsVisible());
@@ -708,7 +709,7 @@ TEST_F(WindowSelectorTest, ClickModalWindowParent) {
scoped_ptr<aura::Window> window1(CreateWindow(gfx::Rect(0, 0, 180, 180)));
scoped_ptr<aura::Window> child1(CreateWindow(gfx::Rect(200, 0, 180, 180)));
child1->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
- window1->AddTransientChild(child1.get());
+ views::corewm::AddTransientChild(window1.get(), child1.get());
EXPECT_FALSE(WindowsOverlapping(window1.get(), child1.get()));
EXPECT_EQ(window1->parent(), child1->parent());
ToggleOverview();
@@ -829,7 +830,7 @@ TEST_F(WindowSelectorTest, CycleMultipleDisplaysCopiesWindows) {
unmoved2->SetName("unmoved2");
moved1->SetName("moved1");
moved1->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
- moved1_trans_parent->AddTransientChild(moved1.get());
+ views::corewm::AddTransientChild(moved1_trans_parent.get(), moved1.get());
moved1_trans_parent->SetName("moved1_trans_parent");
EXPECT_EQ(root_windows[0], moved1->GetRootWindow());
diff --git a/ash/wm/panels/panel_window_resizer_unittest.cc b/ash/wm/panels/panel_window_resizer_unittest.cc
index 68477ab..3fdddf1 100644
--- a/ash/wm/panels/panel_window_resizer_unittest.cc
+++ b/ash/wm/panels/panel_window_resizer_unittest.cc
@@ -26,6 +26,7 @@
#include "ui/base/hit_test.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/ui_base_types.h"
+#include "ui/views/corewm/window_util.h"
#include "ui/views/widget/widget.h"
namespace ash {
@@ -470,10 +471,10 @@ TEST_P(PanelWindowResizerTransientTest, PanelWithTransientChild) {
scoped_ptr<aura::Window> window(CreatePanelWindow(gfx::Point(0, 0)));
scoped_ptr<aura::Window> child(CreateTestWindowInShellWithDelegateAndType(
NULL, transient_window_type_, 0, gfx::Rect(20, 20, 150, 40)));
- window->AddTransientChild(child.get());
+ views::corewm::AddTransientChild(window.get(), child.get());
if (window->parent() != child->parent())
window->parent()->AddChild(child.get());
- EXPECT_EQ(window.get(), child->transient_parent());
+ EXPECT_EQ(window.get(), views::corewm::GetTransientParent(child.get()));
// Drag the child to the shelf. Its new position should not be overridden.
const gfx::Rect attached_bounds(window->GetBoundsInScreen());
diff --git a/ash/wm/stacking_controller.cc b/ash/wm/stacking_controller.cc
index 570c8f3..6603181 100644
--- a/ash/wm/stacking_controller.cc
+++ b/ash/wm/stacking_controller.cc
@@ -15,6 +15,7 @@
#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
#include "ui/base/ui_base_types.h"
+#include "ui/views/corewm/window_util.h"
namespace ash {
namespace {
@@ -37,9 +38,10 @@ bool IsSystemModal(aura::Window* window) {
return window->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_SYSTEM;
}
-bool HasTransientParentWindow(aura::Window* window) {
- return window->transient_parent() &&
- window->transient_parent()->type() != ui::wm::WINDOW_TYPE_UNKNOWN;
+bool HasTransientParentWindow(const aura::Window* window) {
+ return views::corewm::GetTransientParent(window) &&
+ views::corewm::GetTransientParent(window)->type() !=
+ ui::wm::WINDOW_TYPE_UNKNOWN;
}
internal::AlwaysOnTopController*
@@ -66,9 +68,10 @@ aura::Window* StackingController::GetDefaultParent(aura::Window* context,
aura::Window* window,
const gfx::Rect& bounds) {
aura::Window* target_root = NULL;
- if (window->transient_parent()) {
+ aura::Window* transient_parent = views::corewm::GetTransientParent(window);
+ if (transient_parent) {
// Transient window should use the same root as its transient parent.
- target_root = window->transient_parent()->GetRootWindow();
+ target_root = transient_parent->GetRootWindow();
} else {
target_root = FindContainerRoot(bounds);
}
@@ -80,7 +83,7 @@ aura::Window* StackingController::GetDefaultParent(aura::Window* context,
return GetSystemModalContainer(target_root, window);
else if (HasTransientParentWindow(window))
return internal::RootWindowController::GetContainerForWindow(
- window->transient_parent());
+ views::corewm::GetTransientParent(window));
return GetAlwaysOnTopController(target_root)->GetContainer(window);
case ui::wm::WINDOW_TYPE_CONTROL:
return GetContainerById(
@@ -120,14 +123,15 @@ aura::Window* StackingController::GetSystemModalContainer(
SessionStateDelegate* session_state_delegate =
Shell::GetInstance()->session_state_delegate();
if (!session_state_delegate->IsUserSessionBlocked() ||
- !window->transient_parent()) {
+ !views::corewm::GetTransientParent(window)) {
return GetContainerById(root,
internal::kShellWindowId_SystemModalContainer);
}
// Otherwise those that originate from LockScreen container and above are
// placed in the screen lock modal container.
- int window_container_id = window->transient_parent()->parent()->id();
+ int window_container_id =
+ views::corewm::GetTransientParent(window)->parent()->id();
aura::Window* container = NULL;
if (window_container_id < internal::kShellWindowId_LockScreenContainer) {
container = GetContainerById(
diff --git a/ash/wm/stacking_controller_unittest.cc b/ash/wm/stacking_controller_unittest.cc
index 31ec8ff..6f7b35d 100644
--- a/ash/wm/stacking_controller_unittest.cc
+++ b/ash/wm/stacking_controller_unittest.cc
@@ -10,6 +10,7 @@
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
+#include "ui/views/corewm/window_util.h"
using aura::Window;
@@ -48,7 +49,7 @@ TEST_F(StackingControllerTest, TransientParent) {
// Window with a transient parent.
scoped_ptr<Window> w1(CreateTestWindow());
- w2->AddTransientChild(w1.get());
+ views::corewm::AddTransientChild(w2.get(), w1.get());
w1->SetBounds(gfx::Rect(10, 11, 250, 251));
ParentWindowInPrimaryRootWindow(w1.get());
w1->Show();
diff --git a/ash/wm/system_modal_container_layout_manager_unittest.cc b/ash/wm/system_modal_container_layout_manager_unittest.cc
index 6ae3369..e66678a 100644
--- a/ash/wm/system_modal_container_layout_manager_unittest.cc
+++ b/ash/wm/system_modal_container_layout_manager_unittest.cc
@@ -17,6 +17,7 @@
#include "ui/aura/window.h"
#include "ui/compositor/layer.h"
#include "ui/gfx/screen.h"
+#include "ui/views/corewm/window_util.h"
#include "ui/views/test/capture_tracking_view.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
@@ -161,7 +162,7 @@ TEST_F(SystemModalContainerLayoutManagerTest, NonModalTransient) {
TransientWindowObserver destruction_observer;
transient->AddObserver(&destruction_observer);
- EXPECT_EQ(parent.get(), transient->transient_parent());
+ EXPECT_EQ(parent.get(), views::corewm::GetTransientParent(transient));
EXPECT_EQ(parent->parent(), transient->parent());
// The transient should be destroyed with its parent.
@@ -178,7 +179,7 @@ TEST_F(SystemModalContainerLayoutManagerTest, ModalTransient) {
TransientWindowObserver do1;
t1->AddObserver(&do1);
- EXPECT_EQ(parent.get(), t1->transient_parent());
+ EXPECT_EQ(parent.get(), views::corewm::GetTransientParent(t1));
EXPECT_EQ(GetModalContainer(), t1->parent());
// t1 should now be active.
@@ -196,7 +197,7 @@ TEST_F(SystemModalContainerLayoutManagerTest, ModalTransient) {
EXPECT_TRUE(wm::IsActiveWindow(t2));
- EXPECT_EQ(t1, t2->transient_parent());
+ EXPECT_EQ(t1, views::corewm::GetTransientParent(t2));
EXPECT_EQ(GetModalContainer(), t2->parent());
// t2 should still be active, even after clicking on t1.
@@ -217,7 +218,7 @@ TEST_F(SystemModalContainerLayoutManagerTest, ModalNonTransient) {
TransientWindowObserver do1;
t1->AddObserver(&do1);
- EXPECT_EQ(NULL, t1->transient_parent());
+ EXPECT_EQ(NULL, views::corewm::GetTransientParent(t1.get()));
EXPECT_EQ(GetModalContainer(), t1->parent());
// t1 should now be active.
@@ -236,7 +237,7 @@ TEST_F(SystemModalContainerLayoutManagerTest, ModalNonTransient) {
EXPECT_TRUE(wm::IsActiveWindow(t2));
- EXPECT_EQ(t1, t2->transient_parent());
+ EXPECT_EQ(t1, views::corewm::GetTransientParent(t2));
EXPECT_EQ(GetModalContainer(), t2->parent());
// t2 should still be active, even after clicking on t1.
diff --git a/ash/wm/window_modality_controller_unittest.cc b/ash/wm/window_modality_controller_unittest.cc
index 7e36669..388a7cd 100644
--- a/ash/wm/window_modality_controller_unittest.cc
+++ b/ash/wm/window_modality_controller_unittest.cc
@@ -14,6 +14,7 @@
#include "ui/aura/test/test_windows.h"
#include "ui/aura/window.h"
#include "ui/base/ui_base_types.h"
+#include "ui/views/corewm/window_util.h"
#include "ui/views/test/capture_tracking_view.h"
#include "ui/views/test/child_modal_window.h"
#include "ui/views/widget/widget.h"
@@ -50,14 +51,14 @@ TEST_F(WindowModalityControllerTest, BasicActivation) {
scoped_ptr<aura::Window> w12(
CreateTestWindowInShellWithDelegate(&d, -12, gfx::Rect()));
- w1->AddTransientChild(w11.get());
+ views::corewm::AddTransientChild(w1.get(), w11.get());
wm::ActivateWindow(w1.get());
EXPECT_TRUE(wm::IsActiveWindow(w1.get()));
wm::ActivateWindow(w11.get());
EXPECT_TRUE(wm::IsActiveWindow(w11.get()));
w12->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
- w1->AddTransientChild(w12.get());
+ views::corewm::AddTransientChild(w1.get(), w12.get());
wm::ActivateWindow(w12.get());
EXPECT_TRUE(wm::IsActiveWindow(w12.get()));
@@ -97,8 +98,8 @@ TEST_F(WindowModalityControllerTest, NestedModals) {
scoped_ptr<aura::Window> w2(
CreateTestWindowInShellWithDelegate(&d, -2, gfx::Rect()));
- w1->AddTransientChild(w11.get());
- w11->AddTransientChild(w111.get());
+ views::corewm::AddTransientChild(w1.get(), w11.get());
+ views::corewm::AddTransientChild(w11.get(), w111.get());
wm::ActivateWindow(w1.get());
EXPECT_TRUE(wm::IsActiveWindow(w1.get()));
@@ -151,8 +152,8 @@ TEST_F(WindowModalityControllerTest, NestedModalsOuterClosed) {
scoped_ptr<aura::Window> w2(
CreateTestWindowInShellWithDelegate(&d, -2, gfx::Rect()));
- w1->AddTransientChild(w11.get());
- w11->AddTransientChild(w111);
+ views::corewm::AddTransientChild(w1.get(), w11.get());
+ views::corewm::AddTransientChild(w11.get(), w111);
wm::ActivateWindow(w1.get());
EXPECT_TRUE(wm::IsActiveWindow(w1.get()));
@@ -185,7 +186,7 @@ TEST_F(WindowModalityControllerTest, Events) {
scoped_ptr<aura::Window> w11(CreateTestWindowInShellWithDelegate(&d, -11,
gfx::Rect(20, 20, 50, 50)));
- w1->AddTransientChild(w11.get());
+ views::corewm::AddTransientChild(w1.get(), w11.get());
{
// Clicking a point within w1 should activate that window.
@@ -224,7 +225,7 @@ TEST_F(WindowModalityControllerTest, GetModalTransient) {
ASSERT_EQ(static_cast<aura::Window*>(NULL), wt);
// Parent w2 to w1. It should get parented to the parent of w1.
- w1->AddTransientChild(w2.get());
+ views::corewm::AddTransientChild(w1.get(), w2.get());
ASSERT_EQ(2U, w1->parent()->children().size());
EXPECT_EQ(-2, w1->parent()->children().at(1)->id());
@@ -326,7 +327,7 @@ TEST_F(WindowModalityControllerTest, TouchEvent) {
aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow(),
gfx::Point(10, 10));
- w1->AddTransientChild(w11.get());
+ views::corewm::AddTransientChild(w1.get(), w11.get());
d1.reset();
d11.reset();
@@ -515,7 +516,7 @@ TEST_F(WindowModalityControllerTest, WindowModalAncestor) {
scoped_ptr<aura::Window> w4(
CreateTestWindowInShellWithDelegate(&d, -2, gfx::Rect()));
w4->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
- w1->AddTransientChild(w4.get());
+ views::corewm::AddTransientChild(w1.get(), w4.get());
wm::ActivateWindow(w1.get());
EXPECT_TRUE(wm::IsActiveWindow(w4.get()));
@@ -544,7 +545,7 @@ TEST_F(WindowModalityControllerTest, ChildModalAncestor) {
CreateTestWindowInShellWithDelegate(&d, -2, gfx::Rect()));
w4->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_CHILD);
views::corewm::SetModalParent(w4.get(), w2.get());
- w1->AddTransientChild(w4.get());
+ views::corewm::AddTransientChild(w1.get(), w4.get());
wm::ActivateWindow(w1.get());
EXPECT_TRUE(wm::IsActiveWindow(w1.get()));
diff --git a/ash/wm/window_state.cc b/ash/wm/window_state.cc
index 548117ea..0c86e28 100644
--- a/ash/wm/window_state.cc
+++ b/ash/wm/window_state.cc
@@ -133,7 +133,7 @@ bool WindowState::CanActivate() const {
bool WindowState::CanSnap() const {
if (!CanResize() || window_->type() == ui::wm::WINDOW_TYPE_PANEL ||
- window_->transient_parent())
+ views::corewm::GetTransientParent(window_))
return false;
// If a window has a maximum size defined, snapping may make it too big.
return window_->delegate() ? window_->delegate()->GetMaximumSize().IsEmpty() :
diff --git a/ash/wm/window_util.cc b/ash/wm/window_util.cc
index def4b6d..2985f66 100644
--- a/ash/wm/window_util.cc
+++ b/ash/wm/window_util.cc
@@ -134,10 +134,13 @@ void ReparentChildWithTransientChildren(aura::Window* child,
void ReparentTransientChildrenOfChild(aura::Window* child,
aura::Window* old_parent,
aura::Window* new_parent) {
- for (size_t i = 0; i < child->transient_children().size(); ++i) {
- ReparentChildWithTransientChildren(child->transient_children()[i],
- old_parent,
- new_parent);
+ for (size_t i = 0;
+ i < views::corewm::GetTransientChildren(child).size();
+ ++i) {
+ ReparentChildWithTransientChildren(
+ views::corewm::GetTransientChildren(child)[i],
+ old_parent,
+ new_parent);
}
}
diff --git a/ash/wm/workspace/workspace_layout_manager_unittest.cc b/ash/wm/workspace/workspace_layout_manager_unittest.cc
index 0040a6c..49aaaa7 100644
--- a/ash/wm/workspace/workspace_layout_manager_unittest.cc
+++ b/ash/wm/workspace/workspace_layout_manager_unittest.cc
@@ -20,6 +20,7 @@
#include "ui/aura/test/test_windows.h"
#include "ui/aura/window.h"
#include "ui/gfx/insets.h"
+#include "ui/views/corewm/window_util.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
@@ -329,7 +330,7 @@ TEST_F(WorkspaceLayoutManagerTest, DontClobberRestoreBounds) {
scoped_ptr<aura::Window> window2(
CreateTestWindowInShellWithBounds(gfx::Rect(12, 20, 30, 40)));
- window->AddTransientChild(window2.get());
+ views::corewm::AddTransientChild(window.get(), window2.get());
window2->Show();
window_observer.set_window(window2.get());
diff --git a/ash/wm/workspace/workspace_window_resizer.cc b/ash/wm/workspace/workspace_window_resizer.cc
index 9d64fb2..eea0811 100644
--- a/ash/wm/workspace/workspace_window_resizer.cc
+++ b/ash/wm/workspace/workspace_window_resizer.cc
@@ -36,6 +36,7 @@
#include "ui/compositor/layer.h"
#include "ui/gfx/screen.h"
#include "ui/gfx/transform.h"
+#include "ui/views/corewm/window_util.h"
#include "ui/wm/public/window_types.h"
namespace ash {
@@ -97,7 +98,7 @@ scoped_ptr<WindowResizer> CreateWindowResizer(
}
if (switches::UseDockedWindows() &&
window_resizer && window->parent() &&
- !window->transient_parent() &&
+ !views::corewm::GetTransientParent(window) &&
(window->parent()->id() == internal::kShellWindowId_DefaultContainer ||
window->parent()->id() == internal::kShellWindowId_DockedContainer ||
window->parent()->id() == internal::kShellWindowId_PanelContainer)) {
diff --git a/ash/wm/workspace_controller_unittest.cc b/ash/wm/workspace_controller_unittest.cc
index 4b5fd926..e25a3d3 100644
--- a/ash/wm/workspace_controller_unittest.cc
+++ b/ash/wm/workspace_controller_unittest.cc
@@ -33,6 +33,7 @@
#include "ui/events/event_utils.h"
#include "ui/gfx/screen.h"
#include "ui/views/corewm/window_animations.h"
+#include "ui/views/corewm/window_util.h"
#include "ui/views/widget/widget.h"
using aura::Window;
@@ -677,7 +678,8 @@ TEST_F(WorkspaceControllerTest, TransientParent) {
// Window with a transient parent. We set the transient parent to the root,
// which would never happen but is enough to exercise the bug.
scoped_ptr<Window> w1(CreateTestWindowUnparented());
- Shell::GetInstance()->GetPrimaryRootWindow()->AddTransientChild(w1.get());
+ views::corewm::AddTransientChild(
+ Shell::GetInstance()->GetPrimaryRootWindow(), w1.get());
w1->SetBounds(gfx::Rect(10, 11, 250, 251));
ParentWindowInPrimaryRootWindow(w1.get());
w1->Show();
@@ -1132,7 +1134,7 @@ TEST_F(WorkspaceControllerTest, VerifyLayerOrdering) {
ui::wm::WINDOW_TYPE_POPUP,
gfx::Rect(5, 6, 7, 8),
NULL);
- browser->AddTransientChild(status_bubble);
+ views::corewm::AddTransientChild(browser.get(), status_bubble);
ParentWindowInPrimaryRootWindow(status_bubble);
status_bubble->SetName("status_bubble");
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc
index 3e3d98c..43c69d3 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc
@@ -36,6 +36,7 @@
#include "ui/aura/window.h"
#include "ui/base/ui_base_types.h"
#include "ui/events/event.h"
+#include "ui/views/corewm/window_util.h"
namespace {
@@ -562,8 +563,8 @@ void MultiUserWindowManagerChromeOS::SetWindowVisibility(
void MultiUserWindowManagerChromeOS::ShowWithTransientChildrenRecursive(
aura::Window* window) {
aura::Window::Windows::const_iterator it =
- window->transient_children().begin();
- for (; it != window->transient_children().end(); ++it)
+ views::corewm::GetTransientChildren(window).begin();
+ for (; it != views::corewm::GetTransientChildren(window).end(); ++it)
ShowWithTransientChildrenRecursive(*it);
// We show all children which were not explicitly hidden.
@@ -577,11 +578,11 @@ aura::Window* MultiUserWindowManagerChromeOS::GetOwningWindowInTransientChain(
aura::Window* window) {
if (!GetWindowOwner(window).empty())
return NULL;
- aura::Window* parent = window->transient_parent();
+ aura::Window* parent = views::corewm::GetTransientParent(window);
while (parent) {
if (!GetWindowOwner(parent).empty())
return parent;
- parent = parent->transient_parent();
+ parent = views::corewm::GetTransientParent(parent);
}
return NULL;
}
@@ -591,8 +592,8 @@ void MultiUserWindowManagerChromeOS::AddTransientOwnerRecursive(
aura::Window* owned_parent) {
// First add all child windows.
aura::Window::Windows::const_iterator it =
- window->transient_children().begin();
- for (; it != window->transient_children().end(); ++it)
+ views::corewm::GetTransientChildren(window).begin();
+ for (; it != views::corewm::GetTransientChildren(window).end(); ++it)
AddTransientOwnerRecursive(*it, owned_parent);
// If this window is the owned window, we do not have to handle it again.
@@ -618,8 +619,8 @@ void MultiUserWindowManagerChromeOS::RemoveTransientOwnerRecursive(
aura::Window* window) {
// First remove all child windows.
aura::Window::Windows::const_iterator it =
- window->transient_children().begin();
- for (; it != window->transient_children().end(); ++it)
+ views::corewm::GetTransientChildren(window).begin();
+ for (; it != views::corewm::GetTransientChildren(window).end(); ++it)
RemoveTransientOwnerRecursive(*it);
// Find from transient window storage the visibility for the given window,
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc
index 0af57e4..6d0e8e4 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc
@@ -19,6 +19,7 @@
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/root_window.h"
#include "ui/base/ui_base_types.h"
+#include "ui/views/corewm/window_util.h"
namespace ash {
namespace test {
@@ -465,15 +466,15 @@ TEST_F(MultiUserWindowManagerChromeOSTest, TransientWindows) {
// 3 - ..
multi_user_window_manager()->SetWindowOwner(window(0), "A");
multi_user_window_manager()->SetWindowOwner(window(4), "B");
- window(0)->AddTransientChild(window(1));
+ views::corewm::AddTransientChild(window(0), window(1));
// We first attach 2->3 and then 1->2 to see that the ownership gets
// properly propagated through the sub tree upon assigning.
- window(2)->AddTransientChild(window(3));
- window(1)->AddTransientChild(window(2));
- window(4)->AddTransientChild(window(5));
- window(4)->AddTransientChild(window(6));
- window(7)->AddTransientChild(window(8));
- window(7)->AddTransientChild(window(9));
+ views::corewm::AddTransientChild(window(2), window(3));
+ views::corewm::AddTransientChild(window(1), window(2));
+ views::corewm::AddTransientChild(window(4), window(5));
+ views::corewm::AddTransientChild(window(4), window(6));
+ views::corewm::AddTransientChild(window(7), window(8));
+ views::corewm::AddTransientChild(window(7), window(9));
// By now the hierarchy should have updated itself to show all windows of A
// and hide all windows of B. Unowned windows should remain in what ever state
@@ -510,15 +511,15 @@ TEST_F(MultiUserWindowManagerChromeOSTest, TransientWindows) {
// 1 5 8
// |
// 9
- window(2)->RemoveTransientChild(window(3));
- window(4)->RemoveTransientChild(window(6));
+ views::corewm::RemoveTransientChild(window(2), window(3));
+ views::corewm::RemoveTransientChild(window(4), window(6));
EXPECT_EQ("S[A], S[], H[], H[], H[B], H[], S[], S[], S[], H[]", GetStatus());
// Before we leave we need to reverse all transient window ownerships.
- window(0)->RemoveTransientChild(window(1));
- window(1)->RemoveTransientChild(window(2));
- window(4)->RemoveTransientChild(window(5));
- window(7)->RemoveTransientChild(window(8));
- window(7)->RemoveTransientChild(window(9));
+ views::corewm::RemoveTransientChild(window(0), window(1));
+ views::corewm::RemoveTransientChild(window(1), window(2));
+ views::corewm::RemoveTransientChild(window(4), window(5));
+ views::corewm::RemoveTransientChild(window(7), window(8));
+ views::corewm::RemoveTransientChild(window(7), window(9));
}
// Test that the initial visibility state gets remembered.
diff --git a/chrome/browser/ui/views/extensions/extension_popup.cc b/chrome/browser/ui/views/extensions/extension_popup.cc
index 3afafb1..ea57e3d 100644
--- a/chrome/browser/ui/views/extensions/extension_popup.cc
+++ b/chrome/browser/ui/views/extensions/extension_popup.cc
@@ -32,6 +32,7 @@
#include "ui/aura/client/activation_client.h"
#include "ui/aura/window.h"
#include "ui/views/corewm/window_animations.h"
+#include "ui/views/corewm/window_util.h"
#endif
#if defined(OS_WIN)
@@ -197,7 +198,7 @@ void ExtensionPopup::OnWindowActivated(aura::Window* gained_active,
if (!inspect_with_devtools_ && anchor_window == gained_active &&
host_desktop_type != chrome::HOST_DESKTOP_TYPE_ASH &&
this_window->GetRootWindow() == anchor_window->GetRootWindow() &&
- gained_active->transient_parent() != this_window)
+ views::corewm::GetTransientParent(gained_active) != this_window)
GetWidget()->Close();
}
#endif
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index 7558818..9a38126 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -56,6 +56,7 @@
#include "ui/aura/client/scoped_tooltip_disabler.h"
#include "ui/aura/client/screen_position_client.h"
#include "ui/aura/client/tooltip_client.h"
+#include "ui/aura/client/transient_window_client.h"
#include "ui/aura/client/window_tree_client.h"
#include "ui/aura/env.h"
#include "ui/aura/root_window.h"
@@ -505,6 +506,9 @@ void RenderWidgetHostViewAura::InitAsPopup(
popup_parent_host_view_ =
static_cast<RenderWidgetHostViewAura*>(parent_host_view);
+ // TransientWindowClient may be NULL during tests.
+ aura::client::TransientWindowClient* transient_window_client =
+ aura::client::GetTransientWindowClient();
RenderWidgetHostViewAura* old_child =
popup_parent_host_view_->popup_child_host_view_;
if (old_child) {
@@ -512,7 +516,10 @@ void RenderWidgetHostViewAura::InitAsPopup(
// similar mechanism to ensure a second popup doesn't cause the first one
// to never get a chance to filter events. See crbug.com/160589.
DCHECK(old_child->popup_parent_host_view_ == popup_parent_host_view_);
- popup_parent_host_view_->window_->RemoveTransientChild(old_child->window_);
+ if (transient_window_client) {
+ transient_window_client->RemoveTransientChild(
+ popup_parent_host_view_->window_, old_child->window_);
+ }
old_child->popup_parent_host_view_ = NULL;
}
popup_parent_host_view_->popup_child_host_view_ = this;
@@ -525,7 +532,10 @@ void RenderWidgetHostViewAura::InitAsPopup(
// Setting the transient child allows for the popup to get mouse events when
// in a system modal dialog.
// This fixes crbug.com/328593.
- popup_parent_host_view_->window_->AddTransientChild(window_);
+ if (transient_window_client) {
+ transient_window_client->AddTransientChild(
+ popup_parent_host_view_->window_, window_);
+ }
SetBounds(bounds_in_screen);
Show();
diff --git a/ui/aura/aura.gyp b/ui/aura/aura.gyp
index c10a3ed..ded1112 100644
--- a/ui/aura/aura.gyp
+++ b/ui/aura/aura.gyp
@@ -67,6 +67,8 @@
'client/screen_position_client.h',
'client/tooltip_client.cc',
'client/tooltip_client.h',
+ 'client/transient_window_client.cc',
+ 'client/transient_window_client.h',
'client/user_action_client.cc',
'client/user_action_client.h',
'client/visibility_client.cc',
diff --git a/ui/aura/client/transient_window_client.cc b/ui/aura/client/transient_window_client.cc
new file mode 100644
index 0000000..47b50b9
--- /dev/null
+++ b/ui/aura/client/transient_window_client.cc
@@ -0,0 +1,25 @@
+// Copyright 2014 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/transient_window_client.h"
+
+namespace aura {
+namespace client {
+
+namespace {
+
+TransientWindowClient* instance = NULL;
+
+} // namespace
+
+void SetTransientWindowClient(TransientWindowClient* client) {
+ instance = client;
+}
+
+TransientWindowClient* GetTransientWindowClient() {
+ return instance;
+}
+
+} // namespace client
+} // namespace aura
diff --git a/ui/aura/client/transient_window_client.h b/ui/aura/client/transient_window_client.h
new file mode 100644
index 0000000..96434d7
--- /dev/null
+++ b/ui/aura/client/transient_window_client.h
@@ -0,0 +1,47 @@
+// Copyright 2014 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_TRANSIENT_WINDOW_CLIENT_H_
+#define UI_AURA_CLIENT_TRANSIENT_WINDOW_CLIENT_H_
+
+#include "base/basictypes.h"
+#include "ui/aura/aura_export.h"
+
+namespace aura {
+
+class Window;
+
+namespace client {
+
+// TransientWindowClient is used to add or remove transient windows. Transient
+// children get the following behavior:
+// . The transient parent destroys any transient children when it is
+// destroyed. This means a transient child is destroyed if either its parent
+// or transient parent is destroyed.
+// . If a transient child and its transient parent share the same parent, then
+// transient children are always ordered above the transient parent.
+// Transient windows are typically used for popups and menus.
+// TODO(sky): nuke this class and replace with calls to TransientWindowManager.
+// This is temporary until we start moving to ui/wm.
+class AURA_EXPORT TransientWindowClient {
+ public:
+ virtual void AddTransientChild(Window* parent, Window* child) = 0;
+ virtual void RemoveTransientChild(Window* parent, Window* child) = 0;
+ virtual Window* GetTransientParent(Window* window) = 0;
+ virtual const Window* GetTransientParent(const Window* window) = 0;
+
+ protected:
+ virtual ~TransientWindowClient() {}
+};
+
+// Sets/gets the TransientWindowClient. This does *not* take ownership of
+// |client|. It is assumed the caller will invoke SetTransientWindowClient(NULL)
+// before deleting |client|.
+AURA_EXPORT void SetTransientWindowClient(TransientWindowClient* client);
+AURA_EXPORT TransientWindowClient* GetTransientWindowClient();
+
+} // namespace client
+} // namespace aura
+
+#endif // UI_AURA_CLIENT_TRANSIENT_WINDOW_CLIENT_H_
diff --git a/ui/aura/test/aura_test_base.cc b/ui/aura/test/aura_test_base.cc
index 4522c98..3b2d1b0 100644
--- a/ui/aura/test/aura_test_base.cc
+++ b/ui/aura/test/aura_test_base.cc
@@ -97,16 +97,6 @@ Window* AuraTestBase::CreateNormalWindow(int id, Window* parent,
return window;
}
-Window* AuraTestBase::CreateTransientChild(int id, Window* parent) {
- Window* window = new Window(NULL);
- window->set_id(id);
- window->SetType(ui::wm::WINDOW_TYPE_NORMAL);
- window->Init(ui::LAYER_TEXTURED);
- aura::client::ParentWindowWithContext(window, root_window(), gfx::Rect());
- parent->AddTransientChild(window);
- return window;
-}
-
void AuraTestBase::RunAllPendingInMessageLoop() {
helper_->RunAllPendingInMessageLoop();
}
diff --git a/ui/aura/test/aura_test_base.h b/ui/aura/test/aura_test_base.h
index 52cccf0..971fdba 100644
--- a/ui/aura/test/aura_test_base.h
+++ b/ui/aura/test/aura_test_base.h
@@ -32,9 +32,6 @@ class AuraTestBase : public testing::Test {
aura::Window* CreateNormalWindow(int id, Window* parent,
aura::WindowDelegate* delegate);
- // Creates a transient window that is transient to |parent|.
- aura::Window* CreateTransientChild(int id, aura::Window* parent);
-
protected:
void RunAllPendingInMessageLoop();
diff --git a/ui/aura/window.cc b/ui/aura/window.cc
index 404ad15..1936089 100644
--- a/ui/aura/window.cc
+++ b/ui/aura/window.cc
@@ -10,7 +10,6 @@
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/logging.h"
-#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
@@ -218,7 +217,6 @@ Window::Window(WindowDelegate* delegate)
owned_by_parent_(true),
delegate_(delegate),
parent_(NULL),
- transient_parent_(NULL),
visible_(false),
id_(-1),
transparent_(false),
@@ -249,24 +247,11 @@ Window::~Window() {
// Then destroy the children.
RemoveOrDestroyChildren();
- // Removes ourselves from our transient parent (if it hasn't been done by the
- // RootWindow).
- if (transient_parent_)
- transient_parent_->RemoveTransientChild(this);
-
// The window needs to be removed from the parent before calling the
// WindowDestroyed callbacks of delegate and the observers.
if (parent_)
parent_->RemoveChild(this);
- // Destroy transient children, only after we've removed ourselves from our
- // parent, as destroying an active transient child may otherwise attempt to
- // refocus us.
- Windows transient_children(transient_children_);
- STLDeleteElements(&transient_children);
- DCHECK(transient_children_.empty());
-
- // Delegate and observers need to be notified after transients are deleted.
if (delegate_)
delegate_->OnWindowDestroyed();
ObserverListBase<WindowObserver>::Iterator iter(observers_);
@@ -391,10 +376,6 @@ void Window::Show() {
}
void Window::Hide() {
- for (Windows::iterator it = transient_children_.begin();
- it != transient_children_.end(); ++it) {
- (*it)->Hide();
- }
SetVisible(false);
ReleaseCapture();
}
@@ -605,28 +586,6 @@ bool Window::Contains(const Window* other) const {
return false;
}
-void Window::AddTransientChild(Window* child) {
- if (child->transient_parent_)
- child->transient_parent_->RemoveTransientChild(child);
- DCHECK(std::find(transient_children_.begin(), transient_children_.end(),
- child) == transient_children_.end());
- transient_children_.push_back(child);
- child->transient_parent_ = this;
- FOR_EACH_OBSERVER(WindowObserver, observers_,
- OnAddTransientChild(this, child));
-}
-
-void Window::RemoveTransientChild(Window* child) {
- Windows::iterator i =
- std::find(transient_children_.begin(), transient_children_.end(), child);
- DCHECK(i != transient_children_.end());
- transient_children_.erase(i);
- if (child->transient_parent_ == this)
- child->transient_parent_ = NULL;
- FOR_EACH_OBSERVER(WindowObserver, observers_,
- OnRemoveTransientChild(this, child));
-}
-
Window* Window::GetChildById(int id) {
return const_cast<Window*>(const_cast<const Window*>(this)->GetChildById(id));
}
@@ -1160,34 +1119,6 @@ void Window::OnParentChanged() {
WindowObserver, observers_, OnWindowParentChanged(this, parent_));
}
-bool Window::HasTransientAncestor(const Window* ancestor) const {
- if (transient_parent_ == ancestor)
- return true;
- return transient_parent_ ?
- transient_parent_->HasTransientAncestor(ancestor) : false;
-}
-
-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 (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;
- --target_i;
- }
- *target = children_[target_i];
-}
-
void Window::StackChildRelativeTo(Window* child,
Window* target,
StackDirection direction) {
@@ -1199,47 +1130,10 @@ void Window::StackChildRelativeTo(Window* child,
client::WindowStackingClient* stacking_client =
client::GetWindowStackingClient();
- if (stacking_client)
- stacking_client->AdjustStacking(&child, &target, &direction);
-
- SkipNullDelegatesForStacking(direction, &target);
-
- // If we couldn't find a valid target position, don't move anything.
- if (direction == STACK_ABOVE &&
- (target->layer_ && target->layer_->delegate() == NULL))
- return;
-
- // Don't try to stack a child above itself.
- if (child == target)
+ if (stacking_client &&
+ !stacking_client->AdjustStacking(&child, &target, &direction))
return;
- // Move the child.
- 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
- // those children appear in children_ array.
- Window* last_transient = child;
- Windows children(children_);
- for (Windows::iterator it = children.begin(); it != children.end(); ++it) {
- Window* transient_child = *it;
- if (transient_child != last_transient &&
- transient_child->HasTransientAncestor(child)) {
- StackChildRelativeToImpl(transient_child, last_transient, STACK_ABOVE);
- last_transient = transient_child;
- }
- }
-}
-
-void Window::StackChildRelativeToImpl(Window* child,
- Window* target,
- StackDirection direction) {
- DCHECK_NE(child, target);
- DCHECK(child);
- DCHECK(target);
- DCHECK_EQ(this, child->parent());
- DCHECK_EQ(this, target->parent());
-
const size_t child_i =
std::find(children_.begin(), children_.end(), child) - children_.begin();
const size_t target_i =
diff --git a/ui/aura/window.h b/ui/aura/window.h
index 6b65be4..6f71f09 100644
--- a/ui/aura/window.h
+++ b/ui/aura/window.h
@@ -42,6 +42,12 @@ class Layer;
class Texture;
}
+// TODO(sky): nuke. Temporary while moving transients out of Window.
+namespace views {
+namespace corewm {
+class TransientWindowManager;
+}
+}
namespace aura {
class LayoutManager;
@@ -211,22 +217,6 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
// Returns true if this Window contains |other| somewhere in its children.
bool Contains(const Window* other) const;
- // Adds or removes |child| as a transient child of this window. Transient
- // children get the following behavior:
- // . The transient parent destroys any transient children when it is
- // destroyed. This means a transient child is destroyed if either its parent
- // or transient parent is destroyed.
- // . If a transient child and its transient parent share the same parent, then
- // transient children are always ordered above the transient parent.
- // Transient windows are typically used for popups and menus.
- void AddTransientChild(Window* child);
- void RemoveTransientChild(Window* child);
-
- const Windows& transient_children() const { return transient_children_; }
-
- Window* transient_parent() { return transient_parent_; }
- const Window* transient_parent() const { return transient_parent_; }
-
// Retrieves the first-level child with the specified id, or NULL if no first-
// level child is found matching |id|.
Window* GetChildById(int id);
@@ -383,6 +373,8 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
private:
friend class test::WindowTestApi;
+ // TODO(sky): temporary until TransientWindowManager gets its own observer.
+ friend class views::corewm::TransientWindowManager;
friend class LayoutManager;
friend class RootWindow;
friend class WindowTargeter;
@@ -445,26 +437,12 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
// Called when this window's parent has changed.
void OnParentChanged();
- // 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().
+ // The various stacking functions call into this to do the actual stacking.
void StackChildRelativeTo(Window* child,
Window* target,
StackDirection direction);
- // Implementation of StackChildRelativeTo().
- void StackChildRelativeToImpl(Window* child,
- Window* target,
- StackDirection direction);
-
- // Invoked from StackChildRelativeToImpl() to stack the layers appropriately
+ // Invoked from StackChildRelativeTo() to stack the layers appropriately
// when stacking |child| relative to |target|.
void StackChildLayerRelativeTo(Window* child,
Window* target,
@@ -562,11 +540,6 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
// Child windows. Topmost is last.
Windows children_;
- // Transient windows.
- Windows transient_children_;
-
- Window* transient_parent_;
-
// The visibility state of the window as set by Show()/Hide(). This may differ
// from the visibility of the underlying layer, which may remain visible after
// the window is hidden (e.g. to animate its disappearance).
diff --git a/ui/aura/window_unittest.cc b/ui/aura/window_unittest.cc
index ce1021e..6117489 100644
--- a/ui/aura/window_unittest.cc
+++ b/ui/aura/window_unittest.cc
@@ -18,7 +18,6 @@
#include "ui/aura/client/focus_change_observer.h"
#include "ui/aura/client/visibility_client.h"
#include "ui/aura/client/window_tree_client.h"
-#include "ui/aura/layout_manager.h"
#include "ui/aura/root_window.h"
#include "ui/aura/root_window_observer.h"
#include "ui/aura/test/aura_test_base.h"
@@ -1583,41 +1582,6 @@ TEST_F(WindowTest, TransformGesture) {
EXPECT_EQ(gfx::Point(10, 10).ToString(), delegate->position().ToString());
}
-// Various assertions for transient children.
-TEST_F(WindowTest, TransientChildren) {
- scoped_ptr<Window> parent(CreateTestWindowWithId(0, root_window()));
- scoped_ptr<Window> w1(CreateTestWindowWithId(1, parent.get()));
- scoped_ptr<Window> w3(CreateTestWindowWithId(3, parent.get()));
- Window* w2 = CreateTestWindowWithId(2, parent.get());
- w1->AddTransientChild(w2); // w2 is now owned by w1.
- // Stack w1 at the top (end), this should force w2 to be last (on top of w1).
- parent->StackChildAtTop(w1.get());
- ASSERT_EQ(3u, parent->children().size());
- EXPECT_EQ(w2, parent->children().back());
-
- // Destroy w1, which should also destroy w3 (since it's a transient child).
- w1.reset();
- w2 = NULL;
- ASSERT_EQ(1u, parent->children().size());
- EXPECT_EQ(w3.get(), parent->children()[0]);
-
- w1.reset(CreateTestWindowWithId(4, parent.get()));
- w2 = CreateTestWindowWithId(5, w3.get());
- w1->AddTransientChild(w2);
- parent->StackChildAtTop(w3.get());
- // Stack w1 at the top (end), this shouldn't affect w2 since it has a
- // different parent.
- parent->StackChildAtTop(w1.get());
- ASSERT_EQ(2u, parent->children().size());
- EXPECT_EQ(w3.get(), parent->children()[0]);
- EXPECT_EQ(w1.get(), parent->children()[1]);
-
- // Hiding parent should hide transient children.
- EXPECT_TRUE(w2->IsVisible());
- w1->Hide();
- EXPECT_FALSE(w2->IsVisible());
-}
-
namespace {
DEFINE_WINDOW_PROPERTY_KEY(int, kIntKey, -2);
DEFINE_WINDOW_PROPERTY_KEY(const char*, kStringKey, "squeamish");
@@ -2056,66 +2020,6 @@ TEST_F(WindowTest, StackWindowAtBottomBelowWindowWhoseLayerHasNoDelegate) {
ui::test::ChildLayerNamesAsString(*root_window()->layer()));
}
-TEST_F(WindowTest, StackWindowsWhoseLayersHaveNoDelegate) {
- scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window()));
- window1->layer()->set_name("1");
- scoped_ptr<Window> window2(CreateTestWindowWithId(2, root_window()));
- window2->layer()->set_name("2");
- scoped_ptr<Window> window3(CreateTestWindowWithId(3, root_window()));
- window3->layer()->set_name("3");
-
- // This brings |window1| (and its layer) to the front.
- root_window()->StackChildAbove(window1.get(), window3.get());
- EXPECT_EQ("2 3 1", ChildWindowIDsAsString(root_window()));
- EXPECT_EQ("2 3 1",
- ui::test::ChildLayerNamesAsString(*root_window()->layer()));
-
- // Since |window1| does not have a delegate, |window2| should not move in
- // front of it, nor should its layer.
- window1->layer()->set_delegate(NULL);
- root_window()->StackChildAbove(window2.get(), window1.get());
- EXPECT_EQ("3 2 1", ChildWindowIDsAsString(root_window()));
- EXPECT_EQ("3 2 1",
- ui::test::ChildLayerNamesAsString(*root_window()->layer()));
-
- // It should still be possible to stack |window3| immediately below |window1|.
- root_window()->StackChildBelow(window3.get(), window1.get());
- EXPECT_EQ("2 3 1", ChildWindowIDsAsString(root_window()));
- EXPECT_EQ("2 3 1",
- ui::test::ChildLayerNamesAsString(*root_window()->layer()));
-
- // Since neither |window3| nor |window1| have a delegate, |window2| should
- // not move in front of either.
- window3->layer()->set_delegate(NULL);
- root_window()->StackChildBelow(window2.get(), window1.get());
- EXPECT_EQ("2 3 1", ChildWindowIDsAsString(root_window()));
- EXPECT_EQ("2 3 1",
- ui::test::ChildLayerNamesAsString(*root_window()->layer()));
-}
-
-TEST_F(WindowTest, StackTransientsWhoseLayersHaveNoDelegate) {
- // Create a window with several transients, then a couple windows on top.
- scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window()));
- scoped_ptr<Window> window11(CreateTransientChild(11, window1.get()));
- scoped_ptr<Window> window12(CreateTransientChild(12, window1.get()));
- scoped_ptr<Window> window13(CreateTransientChild(13, window1.get()));
- scoped_ptr<Window> window2(CreateTestWindowWithId(2, root_window()));
- scoped_ptr<Window> window3(CreateTestWindowWithId(3, root_window()));
-
- EXPECT_EQ("1 11 12 13 2 3", ChildWindowIDsAsString(root_window()));
-
- // Remove the delegates of a couple of transients, as if they are closing
- // and animating out.
- window11->layer()->set_delegate(NULL);
- window13->layer()->set_delegate(NULL);
-
- // Move window1 to the front. All transients should move with it, and their
- // order should be preserved.
- root_window()->StackChildAtTop(window1.get());
-
- EXPECT_EQ("2 3 1 11 12 13", ChildWindowIDsAsString(root_window()));
-}
-
class TestVisibilityClient : public client::VisibilityClient {
public:
explicit TestVisibilityClient(Window* root_window)
@@ -2253,240 +2157,6 @@ TEST_F(WindowTest, MouseEventsOnWindowChange) {
EXPECT_EQ("0 0 0", d11.GetMouseMotionCountsAndReset());
}
-class StackingMadrigalLayoutManager : public LayoutManager {
- public:
- explicit StackingMadrigalLayoutManager(Window* root_window)
- : root_window_(root_window) {
- root_window_->SetLayoutManager(this);
- }
- virtual ~StackingMadrigalLayoutManager() {
- }
-
- private:
- // Overridden from LayoutManager:
- virtual void OnWindowResized() OVERRIDE {}
- virtual void OnWindowAddedToLayout(Window* child) OVERRIDE {}
- virtual void OnWillRemoveWindowFromLayout(Window* child) OVERRIDE {}
- virtual void OnWindowRemovedFromLayout(Window* child) OVERRIDE {}
- virtual void OnChildWindowVisibilityChanged(Window* child,
- bool visible) OVERRIDE {
- Window::Windows::const_iterator it = root_window_->children().begin();
- Window* last_window = NULL;
- for (; it != root_window_->children().end(); ++it) {
- if (*it == child && last_window) {
- if (!visible)
- root_window_->StackChildAbove(last_window, *it);
- else
- root_window_->StackChildAbove(*it, last_window);
- break;
- }
- last_window = *it;
- }
- }
- virtual void SetChildBounds(Window* child,
- const gfx::Rect& requested_bounds) OVERRIDE {
- SetChildBoundsDirect(child, requested_bounds);
- }
-
- Window* root_window_;
-
- DISALLOW_COPY_AND_ASSIGN(StackingMadrigalLayoutManager);
-};
-
-class StackingMadrigalVisibilityClient : public client::VisibilityClient {
- public:
- explicit StackingMadrigalVisibilityClient(Window* root_window)
- : ignored_window_(NULL) {
- client::SetVisibilityClient(root_window, this);
- }
- virtual ~StackingMadrigalVisibilityClient() {
- }
-
- void set_ignored_window(Window* ignored_window) {
- ignored_window_ = ignored_window;
- }
-
- private:
- // Overridden from client::VisibilityClient:
- virtual void UpdateLayerVisibility(Window* window, bool visible) OVERRIDE {
- if (!visible) {
- if (window == ignored_window_)
- window->layer()->set_delegate(NULL);
- else
- window->layer()->SetVisible(visible);
- } else {
- window->layer()->SetVisible(visible);
- }
- }
-
- Window* ignored_window_;
-
- DISALLOW_COPY_AND_ASSIGN(StackingMadrigalVisibilityClient);
-};
-
-// This test attempts to reconstruct a circumstance that can happen when the
-// aura client attempts to manipulate the visibility and delegate of a layer
-// independent of window visibility.
-// A use case is where the client attempts to keep a window visible onscreen
-// even after code has called Hide() on the window. The use case for this would
-// be that window hides are animated (e.g. the window fades out). To prevent
-// spurious updating the client code may also clear window's layer's delegate,
-// so that the window cannot attempt to paint or update it further. The window
-// uses the presence of a NULL layer delegate as a signal in stacking to note
-// that the window is being manipulated by such a use case and its stacking
-// should not be adjusted.
-// One issue that can arise when a window opens two transient children, and the
-// first is hidden. Subsequent attempts to activate the transient parent can
-// result in the transient parent being stacked above the second transient
-// child. A fix is made to Window::StackAbove to prevent this, and this test
-// verifies this fix.
-TEST_F(WindowTest, StackingMadrigal) {
- new StackingMadrigalLayoutManager(root_window());
- StackingMadrigalVisibilityClient visibility_client(root_window());
-
- scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window()));
- scoped_ptr<Window> window11(CreateTransientChild(11, window1.get()));
-
- visibility_client.set_ignored_window(window11.get());
-
- window11->Show();
- window11->Hide();
-
- // As a transient, window11 should still be stacked above window1, even when
- // hidden.
- EXPECT_TRUE(WindowIsAbove(window11.get(), window1.get()));
- EXPECT_TRUE(LayerIsAbove(window11.get(), window1.get()));
-
- // A new transient should still be above window1. It will appear behind
- // window11 because we don't stack windows on top of targets with NULL
- // delegates.
- scoped_ptr<Window> window12(CreateTransientChild(12, window1.get()));
- window12->Show();
-
- EXPECT_TRUE(WindowIsAbove(window12.get(), window1.get()));
- EXPECT_TRUE(LayerIsAbove(window12.get(), window1.get()));
-
- // In earlier versions of the StackChildAbove() method, attempting to stack
- // window1 above window12 at this point would actually restack the layers
- // resulting in window12's layer being below window1's layer (though the
- // windows themselves would still be correctly stacked, so events would pass
- // through.)
- root_window()->StackChildAbove(window1.get(), window12.get());
-
- // Both window12 and its layer should be stacked above window1.
- EXPECT_TRUE(WindowIsAbove(window12.get(), window1.get()));
- EXPECT_TRUE(LayerIsAbove(window12.get(), window1.get()));
-}
-
-// Test for an issue where attempting to stack a primary window on top of a
-// transient with a NULL layer delegate causes that primary window to be moved,
-// but the layer order not changed to match. http://crbug.com/112562
-TEST_F(WindowTest, StackOverClosingTransient) {
- scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window()));
- scoped_ptr<Window> transient1(CreateTransientChild(11, window1.get()));
- scoped_ptr<Window> window2(CreateTestWindowWithId(2, root_window()));
- scoped_ptr<Window> transient2(CreateTransientChild(21, window2.get()));
-
- // Both windows and layers are stacked in creation order.
- Window* root = root_window();
- ASSERT_EQ(4u, root->children().size());
- EXPECT_EQ(root->children()[0], window1.get());
- EXPECT_EQ(root->children()[1], transient1.get());
- EXPECT_EQ(root->children()[2], window2.get());
- EXPECT_EQ(root->children()[3], transient2.get());
- ASSERT_EQ(4u, root->layer()->children().size());
- EXPECT_EQ(root->layer()->children()[0], window1->layer());
- EXPECT_EQ(root->layer()->children()[1], transient1->layer());
- EXPECT_EQ(root->layer()->children()[2], window2->layer());
- EXPECT_EQ(root->layer()->children()[3], transient2->layer());
- EXPECT_EQ("1 11 2 21", ChildWindowIDsAsString(root_window()));
-
- // This brings window1 and its transient to the front.
- root->StackChildAtTop(window1.get());
- EXPECT_EQ("2 21 1 11", ChildWindowIDsAsString(root_window()));
-
- EXPECT_EQ(root->children()[0], window2.get());
- EXPECT_EQ(root->children()[1], transient2.get());
- EXPECT_EQ(root->children()[2], window1.get());
- EXPECT_EQ(root->children()[3], transient1.get());
- EXPECT_EQ(root->layer()->children()[0], window2->layer());
- EXPECT_EQ(root->layer()->children()[1], transient2->layer());
- EXPECT_EQ(root->layer()->children()[2], window1->layer());
- EXPECT_EQ(root->layer()->children()[3], transient1->layer());
-
- // Pretend we're closing the top-most transient, then bring window2 to the
- // front. This mimics activating a browser window while the status bubble
- // is fading out. The transient should stay topmost.
- transient1->layer()->set_delegate(NULL);
- root->StackChildAtTop(window2.get());
-
- EXPECT_EQ(root->children()[0], window1.get());
- EXPECT_EQ(root->children()[1], window2.get());
- EXPECT_EQ(root->children()[2], transient2.get());
- EXPECT_EQ(root->children()[3], transient1.get());
- EXPECT_EQ(root->layer()->children()[0], window1->layer());
- EXPECT_EQ(root->layer()->children()[1], window2->layer());
- EXPECT_EQ(root->layer()->children()[2], transient2->layer());
- EXPECT_EQ(root->layer()->children()[3], transient1->layer());
-
- // Close the transient. Remaining windows are stable.
- transient1.reset();
-
- ASSERT_EQ(3u, root->children().size());
- EXPECT_EQ(root->children()[0], window1.get());
- EXPECT_EQ(root->children()[1], window2.get());
- EXPECT_EQ(root->children()[2], transient2.get());
- ASSERT_EQ(3u, root->layer()->children().size());
- EXPECT_EQ(root->layer()->children()[0], window1->layer());
- EXPECT_EQ(root->layer()->children()[1], window2->layer());
- EXPECT_EQ(root->layer()->children()[2], transient2->layer());
-
- // Open another window on top.
- scoped_ptr<Window> window3(CreateTestWindowWithId(3, root_window()));
-
- ASSERT_EQ(4u, root->children().size());
- EXPECT_EQ(root->children()[0], window1.get());
- EXPECT_EQ(root->children()[1], window2.get());
- EXPECT_EQ(root->children()[2], transient2.get());
- EXPECT_EQ(root->children()[3], window3.get());
- ASSERT_EQ(4u, root->layer()->children().size());
- EXPECT_EQ(root->layer()->children()[0], window1->layer());
- EXPECT_EQ(root->layer()->children()[1], window2->layer());
- EXPECT_EQ(root->layer()->children()[2], transient2->layer());
- EXPECT_EQ(root->layer()->children()[3], window3->layer());
-
- // Pretend we're closing the topmost non-transient window, then bring
- // window2 to the top. It should not move.
- window3->layer()->set_delegate(NULL);
- root->StackChildAtTop(window2.get());
-
- ASSERT_EQ(4u, root->children().size());
- EXPECT_EQ(root->children()[0], window1.get());
- EXPECT_EQ(root->children()[1], window2.get());
- EXPECT_EQ(root->children()[2], transient2.get());
- EXPECT_EQ(root->children()[3], window3.get());
- ASSERT_EQ(4u, root->layer()->children().size());
- EXPECT_EQ(root->layer()->children()[0], window1->layer());
- EXPECT_EQ(root->layer()->children()[1], window2->layer());
- EXPECT_EQ(root->layer()->children()[2], transient2->layer());
- EXPECT_EQ(root->layer()->children()[3], window3->layer());
-
- // Bring window1 to the top. It should move ahead of window2, but not
- // ahead of window3 (with NULL delegate).
- root->StackChildAtTop(window1.get());
-
- ASSERT_EQ(4u, root->children().size());
- EXPECT_EQ(root->children()[0], window2.get());
- EXPECT_EQ(root->children()[1], transient2.get());
- EXPECT_EQ(root->children()[2], window1.get());
- EXPECT_EQ(root->children()[3], window3.get());
- ASSERT_EQ(4u, root->layer()->children().size());
- EXPECT_EQ(root->layer()->children()[0], window2->layer());
- EXPECT_EQ(root->layer()->children()[1], transient2->layer());
- EXPECT_EQ(root->layer()->children()[2], window1->layer());
- EXPECT_EQ(root->layer()->children()[3], window3->layer());
-}
-
class RootWindowAttachmentObserver : public WindowObserver {
public:
RootWindowAttachmentObserver() : added_count_(0), removed_count_(0) {}
@@ -3007,50 +2677,6 @@ TEST_F(WindowTest, OnWindowHierarchyChange) {
}
-namespace {
-
-// Used by NotifyDelegateAfterDeletingTransients. Adds a string to a vector when
-// OnWindowDestroyed() is invoked so that destruction order can be verified.
-class DestroyedTrackingDelegate : public TestWindowDelegate {
- public:
- explicit DestroyedTrackingDelegate(const std::string& name,
- std::vector<std::string>* results)
- : name_(name),
- results_(results) {}
-
- virtual void OnWindowDestroyed() OVERRIDE {
- results_->push_back(name_);
- }
-
- private:
- const std::string name_;
- std::vector<std::string>* results_;
-
- DISALLOW_COPY_AND_ASSIGN(DestroyedTrackingDelegate);
-};
-
-} // namespace
-
-// Verifies the delegate is notified of destruction after transients are
-// destroyed.
-TEST_F(WindowTest, NotifyDelegateAfterDeletingTransients) {
- std::vector<std::string> destruction_order;
-
- DestroyedTrackingDelegate parent_delegate("parent", &destruction_order);
- scoped_ptr<Window> parent(new Window(&parent_delegate));
- parent->Init(ui::LAYER_NOT_DRAWN);
-
- DestroyedTrackingDelegate transient_delegate("transient", &destruction_order);
- Window* transient = new Window(&transient_delegate); // Owned by |parent|.
- transient->Init(ui::LAYER_NOT_DRAWN);
- parent->AddTransientChild(transient);
- parent.reset();
-
- ASSERT_EQ(2u, destruction_order.size());
- EXPECT_EQ("transient", destruction_order[0]);
- EXPECT_EQ("parent", destruction_order[1]);
-}
-
// Verifies SchedulePaint() on a layerless window results in damaging the right
// thing.
TEST_F(WindowTest, LayerlessWindowSchedulePaint) {
diff --git a/ui/oak/oak_aura_window_display.cc b/ui/oak/oak_aura_window_display.cc
index 51e83c4..41ee3d3 100644
--- a/ui/oak/oak_aura_window_display.cc
+++ b/ui/oak/oak_aura_window_display.cc
@@ -11,6 +11,7 @@
#include "ui/aura/window.h"
#include "ui/base/models/table_model_observer.h"
#include "ui/oak/oak_pretty_print.h"
+#include "ui/views/corewm/window_util.h"
namespace oak {
namespace internal {
@@ -131,11 +132,12 @@ base::string16 OakAuraWindowDisplay::GetText(int row, int column_id) {
case ROW_ROOTWINDOW:
return PropertyWithVoidStar("Root Window: ", window_->GetRootWindow());
case ROW_TRANSIENTCHILDREN:
- return PropertyWithInteger("Transient Children: ",
- window_->transient_children().size());
+ return PropertyWithInteger(
+ "Transient Children: ",
+ views::corewm::GetTransientChildren(window_).size());
case ROW_TRANSIENTPARENT:
return PropertyWithVoidStar("Transient Parent: ",
- window_->transient_parent());
+ views::corewm::GetTransientParent(window_));
case ROW_USERDATA:
return PropertyWithVoidStar("User Data: ", window_->user_data());
case ROW_IGNOREEVENTS:
diff --git a/ui/views/corewm/base_focus_rules.cc b/ui/views/corewm/base_focus_rules.cc
index 9520c74..066627d 100644
--- a/ui/views/corewm/base_focus_rules.cc
+++ b/ui/views/corewm/base_focus_rules.cc
@@ -9,6 +9,7 @@
#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
#include "ui/views/corewm/window_modality_controller.h"
+#include "ui/views/corewm/window_util.h"
namespace views {
namespace corewm {
@@ -120,15 +121,15 @@ aura::Window* BaseFocusRules::GetActivatableWindow(aura::Window* window) const {
if (modal_transient)
return GetActivatableWindow(modal_transient);
- if (child->transient_parent()) {
+ if (views::corewm::GetTransientParent(child)) {
// To avoid infinite recursion, if |child| has a transient parent
// whose own modal transient is |child| itself, just return |child|.
aura::Window* parent_modal_transient =
- GetModalTransient(child->transient_parent());
+ GetModalTransient(views::corewm::GetTransientParent(child));
if (parent_modal_transient == child)
return child;
- return GetActivatableWindow(child->transient_parent());
+ return GetActivatableWindow(views::corewm::GetTransientParent(child));
}
parent = parent->parent();
diff --git a/ui/views/corewm/focus_controller.cc b/ui/views/corewm/focus_controller.cc
index bf77b03..a3107a1 100644
--- a/ui/views/corewm/focus_controller.cc
+++ b/ui/views/corewm/focus_controller.cc
@@ -13,6 +13,7 @@
#include "ui/aura/window_tracker.h"
#include "ui/events/event.h"
#include "ui/views/corewm/focus_rules.h"
+#include "ui/views/corewm/window_util.h"
namespace views {
namespace corewm {
@@ -25,10 +26,10 @@ void StackTransientParentsBelowModalWindow(aura::Window* window) {
if (window->GetProperty(aura::client::kModalKey) != ui::MODAL_TYPE_WINDOW)
return;
- aura::Window* transient_parent = window->transient_parent();
+ aura::Window* transient_parent = views::corewm::GetTransientParent(window);
while (transient_parent) {
transient_parent->parent()->StackChildAtTop(transient_parent);
- transient_parent = transient_parent->transient_parent();
+ transient_parent = views::corewm::GetTransientParent(transient_parent);
}
}
@@ -37,7 +38,7 @@ void StackWindowLayerAbove(aura::Window* window, aura::Window* relative_to) {
// Stack |window| above the last transient child of |relative_to| that shares
// the same parent.
const aura::Window::Windows& window_transients(
- relative_to->transient_children());
+ GetTransientChildren(relative_to));
for (aura::Window::Windows::const_iterator i = window_transients.begin();
i != window_transients.end(); ++i) {
aura::Window* transient = *i;
diff --git a/ui/views/corewm/shadow_controller.cc b/ui/views/corewm/shadow_controller.cc
index eb09616..7327f92 100644
--- a/ui/views/corewm/shadow_controller.cc
+++ b/ui/views/corewm/shadow_controller.cc
@@ -19,6 +19,7 @@
#include "ui/compositor/layer.h"
#include "ui/views/corewm/shadow.h"
#include "ui/views/corewm/shadow_types.h"
+#include "ui/views/corewm/window_util.h"
using std::make_pair;
@@ -59,10 +60,10 @@ Shadow::Style GetShadowStyleForWindowLosingActive(
aura::Window* gaining_active) {
if (gaining_active && aura::client::GetHideOnDeactivate(gaining_active)) {
aura::Window::Windows::const_iterator it =
- std::find(losing_active->transient_children().begin(),
- losing_active->transient_children().end(),
+ std::find(GetTransientChildren(losing_active).begin(),
+ GetTransientChildren(losing_active).end(),
gaining_active);
- if (it != losing_active->transient_children().end())
+ if (it != GetTransientChildren(losing_active).end())
return Shadow::STYLE_ACTIVE;
}
return Shadow::STYLE_INACTIVE;
diff --git a/ui/views/corewm/shadow_controller_unittest.cc b/ui/views/corewm/shadow_controller_unittest.cc
index fb2c1d9..a01237a 100644
--- a/ui/views/corewm/shadow_controller_unittest.cc
+++ b/ui/views/corewm/shadow_controller_unittest.cc
@@ -16,6 +16,7 @@
#include "ui/compositor/layer.h"
#include "ui/views/corewm/shadow.h"
#include "ui/views/corewm/shadow_types.h"
+#include "ui/views/corewm/window_util.h"
#include "ui/views/corewm/wm_state.h"
namespace views {
@@ -205,7 +206,7 @@ TEST_F(ShadowControllerTest, TransientParentKeepsActiveShadow) {
window2->Init(ui::LAYER_TEXTURED);
ParentWindow(window2.get());
window2->SetBounds(gfx::Rect(11, 21, 301, 401));
- window1->AddTransientChild(window2.get());
+ AddTransientChild(window1.get(), window2.get());
aura::client::SetHideOnDeactivate(window2.get(), true);
window2->Show();
ActivateWindow(window2.get());
diff --git a/ui/views/corewm/transient_window_controller.cc b/ui/views/corewm/transient_window_controller.cc
new file mode 100644
index 0000000..13a5b1f
--- /dev/null
+++ b/ui/views/corewm/transient_window_controller.cc
@@ -0,0 +1,42 @@
+// Copyright 2014 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_controller.h"
+
+#include "ui/views/corewm/transient_window_manager.h"
+
+namespace views {
+namespace corewm {
+
+TransientWindowController::TransientWindowController() {
+}
+
+TransientWindowController::~TransientWindowController() {
+}
+
+void TransientWindowController::AddTransientChild(aura::Window* parent,
+ aura::Window* child) {
+ TransientWindowManager::Get(parent)->AddTransientChild(child);
+}
+
+void TransientWindowController::RemoveTransientChild(aura::Window* parent,
+ aura::Window* child) {
+ TransientWindowManager::Get(parent)->RemoveTransientChild(child);
+}
+
+aura::Window* TransientWindowController::GetTransientParent(
+ aura::Window* window) {
+ return const_cast<aura::Window*>(GetTransientParent(
+ const_cast<const aura::Window*>(window)));
+}
+
+const aura::Window* TransientWindowController::GetTransientParent(
+ const aura::Window* window) {
+ const TransientWindowManager* window_manager =
+ TransientWindowManager::Get(window);
+ return window_manager ? window_manager->transient_parent() : NULL;
+}
+
+} // namespace corewm
+} // namespace views
diff --git a/ui/views/corewm/transient_window_controller.h b/ui/views/corewm/transient_window_controller.h
new file mode 100644
index 0000000..88d473d
--- /dev/null
+++ b/ui/views/corewm/transient_window_controller.h
@@ -0,0 +1,38 @@
+// Copyright 2014 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_CONTROLLER_H_
+#define UI_VIEWS_COREWM_TRANSIENT_WINDOW_CONTROLLER_H_
+
+#include "ui/aura/client/transient_window_client.h"
+#include "ui/views/views_export.h"
+
+namespace views {
+namespace corewm {
+
+// TransientWindowClient implementation. Uses TransientWindowManager to handle
+// tracking transient per window.
+class VIEWS_EXPORT TransientWindowController
+ : public aura::client::TransientWindowClient {
+ public:
+ TransientWindowController();
+ virtual ~TransientWindowController();
+
+ // TransientWindowClient:
+ virtual void AddTransientChild(aura::Window* parent,
+ aura::Window* child) OVERRIDE;
+ virtual void RemoveTransientChild(aura::Window* parent,
+ aura::Window* child) OVERRIDE;
+ virtual aura::Window* GetTransientParent(aura::Window* window) OVERRIDE;
+ virtual const aura::Window* GetTransientParent(
+ const aura::Window* window) OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TransientWindowController);
+};
+
+} // namespace corewm
+} // namespace views
+
+#endif // UI_VIEWS_COREWM_TRANSIENT_WINDOW_CONTROLLER_H_
diff --git a/ui/views/corewm/transient_window_manager.cc b/ui/views/corewm/transient_window_manager.cc
new file mode 100644
index 0000000..35ee95d
--- /dev/null
+++ b/ui/views/corewm/transient_window_manager.cc
@@ -0,0 +1,147 @@
+// Copyright 2014 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_manager.h"
+
+#include <algorithm>
+#include <functional>
+
+#include "base/auto_reset.h"
+#include "base/stl_util.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_property.h"
+#include "ui/views/corewm/transient_window_stacking_client.h"
+#include "ui/views/corewm/window_util.h"
+
+using aura::Window;
+
+namespace views {
+namespace corewm {
+
+DEFINE_OWNED_WINDOW_PROPERTY_KEY(TransientWindowManager, kPropertyKey, NULL);
+
+TransientWindowManager::~TransientWindowManager() {
+}
+
+// static
+TransientWindowManager* TransientWindowManager::Get(Window* window) {
+ TransientWindowManager* manager = window->GetProperty(kPropertyKey);
+ if (!manager) {
+ manager = new TransientWindowManager(window);
+ window->SetProperty(kPropertyKey, manager);
+ }
+ return manager;
+}
+
+// static
+const TransientWindowManager* TransientWindowManager::Get(
+ const Window* window) {
+ return window->GetProperty(kPropertyKey);
+}
+
+void TransientWindowManager::AddTransientChild(Window* child) {
+ // TransientWindowStackingClient does the stacking of transient windows. If it
+ // isn't installed stacking is going to be wrong.
+ DCHECK(TransientWindowStackingClient::instance_);
+
+ TransientWindowManager* child_manager = Get(child);
+ if (child_manager->transient_parent_)
+ Get(child_manager->transient_parent_)->RemoveTransientChild(child);
+ DCHECK(std::find(transient_children_.begin(), transient_children_.end(),
+ child) == transient_children_.end());
+ transient_children_.push_back(child);
+ child_manager->transient_parent_ = window_;
+ FOR_EACH_OBSERVER(WindowObserver, window_->observers_,
+ OnAddTransientChild(window_, child));
+}
+
+void TransientWindowManager::RemoveTransientChild(Window* child) {
+ Windows::iterator i =
+ std::find(transient_children_.begin(), transient_children_.end(), child);
+ DCHECK(i != transient_children_.end());
+ transient_children_.erase(i);
+ TransientWindowManager* child_manager = Get(child);
+ DCHECK_EQ(window_, child_manager->transient_parent_);
+ child_manager->transient_parent_ = NULL;
+ FOR_EACH_OBSERVER(WindowObserver, window_->observers_,
+ OnRemoveTransientChild(window_, child));
+}
+
+bool TransientWindowManager::IsStackingTransient(
+ const aura::Window* child,
+ const aura::Window* target) const {
+ return stacking_pair_ && stacking_pair_->child == child &&
+ stacking_pair_->target == target;
+}
+
+TransientWindowManager::TransientWindowManager(Window* window)
+ : window_(window),
+ transient_parent_(NULL),
+ stacking_pair_(NULL) {
+ window_->AddObserver(this);
+}
+
+void TransientWindowManager::OnChildStackingChanged(aura::Window* child) {
+ // Do nothing if we initiated the stacking change.
+ // TODO(sky): change args to OnWindowStackingChanged() so that this lookup
+ // can be simpler.
+ if (stacking_pair_ && stacking_pair_->child == child) {
+ Windows::const_iterator child_i = std::find(
+ window_->children().begin(), window_->children().end(), child);
+ DCHECK(child_i != window_->children().end());
+ if (child_i != window_->children().begin() &&
+ (*(child_i - 1) == stacking_pair_->target))
+ return;
+ }
+
+ // Stack any transient children that share the same parent to be in front of
+ // |child|. The existing stacking order is preserved by iterating backwards
+ // and always stacking on top.
+ Window::Windows children(window_->children());
+ for (Window::Windows::reverse_iterator it = children.rbegin();
+ it != children.rend(); ++it) {
+ if ((*it) != child && HasTransientAncestor(*it, child)) {
+ StackingPair pair(*it, child);
+ base::AutoReset<StackingPair*> resetter(&stacking_pair_, &pair);
+ window_->StackChildAbove((*it), child);
+ }
+ }
+}
+
+void TransientWindowManager::OnWindowVisibilityChanging(Window* window,
+ bool visible) {
+ // TODO(sky): move handling of becoming visible here.
+ if (!visible) {
+ std::for_each(transient_children_.begin(), transient_children_.end(),
+ std::mem_fun(&Window::Hide));
+ }
+}
+
+void TransientWindowManager::OnWindowStackingChanged(Window* window) {
+ TransientWindowManager* parent_manager = Get(window->parent());
+ parent_manager->OnChildStackingChanged(window);
+}
+
+void TransientWindowManager::OnWindowDestroying(Window* window) {
+ // TODO(sky): remove notes after safely landing and baking.
+
+ // Removes ourselves from our transient parent (if it hasn't been done by the
+ // RootWindow).
+ // NOTE: This use to be done after children where removed, now it is before.
+ if (transient_parent_) {
+ TransientWindowManager::Get(transient_parent_)->RemoveTransientChild(
+ window_);
+ }
+
+ // Destroy transient children, only after we've removed ourselves from our
+ // parent, as destroying an active transient child may otherwise attempt to
+ // refocus us.
+ // NOTE: this use to be after removed from parent, now its before.
+ Windows transient_children(transient_children_);
+ STLDeleteElements(&transient_children);
+ DCHECK(transient_children_.empty());
+}
+
+} // namespace corewm
+} // namespace views
diff --git a/ui/views/corewm/transient_window_manager.h b/ui/views/corewm/transient_window_manager.h
new file mode 100644
index 0000000..72c9f99
--- /dev/null
+++ b/ui/views/corewm/transient_window_manager.h
@@ -0,0 +1,96 @@
+// Copyright 2014 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_MANAGER_H_
+#define UI_VIEWS_COREWM_TRANSIENT_WINDOW_MANAGER_H_
+
+#include <vector>
+
+#include "ui/aura/window_observer.h"
+#include "ui/views/views_export.h"
+
+namespace views {
+namespace corewm {
+
+// TransientWindowManager manages the set of transient children for a window
+// along with the transient parent. Transient children get the following
+// behavior:
+// . The transient parent destroys any transient children when it is
+// destroyed. This means a transient child is destroyed if either its parent
+// or transient parent is destroyed.
+// . If a transient child and its transient parent share the same parent, then
+// transient children are always ordered above the transient parent.
+// Transient windows are typically used for popups and menus.
+// TODO(sky): when we nuke TransientWindowClient rename this to
+// TransientWindowController.
+class VIEWS_EXPORT TransientWindowManager : public aura::WindowObserver {
+ public:
+ typedef std::vector<aura::Window*> Windows;
+
+ virtual ~TransientWindowManager();
+
+ // Returns the TransientWindowManager for |window|. This never returns NULL.
+ static TransientWindowManager* Get(aura::Window* window);
+
+ // Returns the TransientWindowManager for |window| only if it already exists.
+ // WARNING: this may return NULL.
+ static const TransientWindowManager* Get(const aura::Window* window);
+
+ // Adds or removes a transient child.
+ void AddTransientChild(aura::Window* child);
+ void RemoveTransientChild(aura::Window* child);
+
+ const Windows& transient_children() const { return transient_children_; }
+
+ aura::Window* transient_parent() { return transient_parent_; }
+ const aura::Window* transient_parent() const { return transient_parent_; }
+
+ // Returns true if in the process of stacking |child| on top of |target|. That
+ // is, when the stacking order of a window changes (OnWindowStackingChanged())
+ // the transients may get restacked as well. This function can be used to
+ // detect if TransientWindowManager is in the process of stacking a transient
+ // as the result of window stacking changing.
+ bool IsStackingTransient(const aura::Window* child,
+ const aura::Window* target) const;
+
+ private:
+ // Used to identify when a stacking change needs to restack transients.
+ struct StackingPair {
+ StackingPair(const aura::Window* child, const aura::Window* target)
+ : child(child),
+ target(target) {}
+
+ // The window being moved.
+ const aura::Window* child;
+
+ // |child| is being stacked on top of this.
+ const aura::Window* target;
+ };
+
+ explicit TransientWindowManager(aura::Window* window);
+
+ // Invoked whne |child|'s stacking order changes.
+ void OnChildStackingChanged(aura::Window* child);
+
+ // WindowObserver:
+ virtual void OnWindowVisibilityChanging(aura::Window* window,
+ bool visible) OVERRIDE;
+ virtual void OnWindowStackingChanged(aura::Window* window) OVERRIDE;
+ virtual void OnWindowDestroying(aura::Window* window) OVERRIDE;
+
+ aura::Window* window_;
+ aura::Window* transient_parent_;
+ Windows transient_children_;
+
+ // If non-null we're actively restacking transient as the result of a
+ // transient ancestor changing. This is a pointer to a value on the stack.
+ StackingPair* stacking_pair_;
+
+ DISALLOW_COPY_AND_ASSIGN(TransientWindowManager);
+};
+
+} // namespace corewm
+} // namespace views
+
+#endif // UI_VIEWS_COREWM_TRANSIENT_WINDOW_MANAGER_H_
diff --git a/ui/views/corewm/transient_window_manager_unittest.cc b/ui/views/corewm/transient_window_manager_unittest.cc
new file mode 100644
index 0000000..b942eb1
--- /dev/null
+++ b/ui/views/corewm/transient_window_manager_unittest.cc
@@ -0,0 +1,577 @@
+// Copyright 2014 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_manager.h"
+
+#include "ui/aura/client/visibility_client.h"
+#include "ui/aura/client/window_tree_client.h"
+#include "ui/aura/layout_manager.h"
+#include "ui/aura/test/test_windows.h"
+#include "ui/aura/window.h"
+#include "ui/views/corewm/window_util.h"
+#include "ui/views/test/views_test_base.h"
+
+using aura::Window;
+
+using aura::test::ChildWindowIDsAsString;
+using aura::test::CreateTestWindowWithId;
+
+namespace views {
+namespace corewm {
+
+class TransientWindowManagerTest : public views::ViewsTestBase {
+ public:
+ TransientWindowManagerTest() {}
+ virtual ~TransientWindowManagerTest() {}
+
+ protected:
+ // Creates a transient window that is transient to |parent|.
+ Window* CreateTransientChild(int id, Window* parent) {
+ Window* window = new Window(NULL);
+ window->set_id(id);
+ window->SetType(ui::wm::WINDOW_TYPE_NORMAL);
+ window->Init(ui::LAYER_TEXTURED);
+ aura::client::ParentWindowWithContext(window, GetContext(), gfx::Rect());
+ AddTransientChild(parent, window);
+ return window;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TransientWindowManagerTest);
+};
+
+// Various assertions for transient children.
+TEST_F(TransientWindowManagerTest, TransientChildren) {
+ scoped_ptr<Window> parent(CreateTestWindowWithId(0, GetContext()));
+ scoped_ptr<Window> w1(CreateTestWindowWithId(1, parent.get()));
+ scoped_ptr<Window> w3(CreateTestWindowWithId(3, parent.get()));
+ Window* w2 = CreateTestWindowWithId(2, parent.get());
+ // w2 is now owned by w1.
+ AddTransientChild(w1.get(), w2);
+ // Stack w1 at the top (end), this should force w2 to be last (on top of w1).
+ parent->StackChildAtTop(w1.get());
+ ASSERT_EQ(3u, parent->children().size());
+ EXPECT_EQ(w2, parent->children().back());
+
+ // Destroy w1, which should also destroy w3 (since it's a transient child).
+ w1.reset();
+ w2 = NULL;
+ ASSERT_EQ(1u, parent->children().size());
+ EXPECT_EQ(w3.get(), parent->children()[0]);
+
+ w1.reset(CreateTestWindowWithId(4, parent.get()));
+ w2 = CreateTestWindowWithId(5, w3.get());
+ AddTransientChild(w1.get(), w2);
+ parent->StackChildAtTop(w3.get());
+ // Stack w1 at the top (end), this shouldn't affect w2 since it has a
+ // different parent.
+ parent->StackChildAtTop(w1.get());
+ ASSERT_EQ(2u, parent->children().size());
+ EXPECT_EQ(w3.get(), parent->children()[0]);
+ EXPECT_EQ(w1.get(), parent->children()[1]);
+
+ // Hiding parent should hide transient children.
+ EXPECT_TRUE(w2->IsVisible());
+ w1->Hide();
+ EXPECT_FALSE(w2->IsVisible());
+}
+
+// Tests that transient children are stacked as a unit when using stack above.
+TEST_F(TransientWindowManagerTest, TransientChildrenGroupAbove) {
+ scoped_ptr<Window> parent(CreateTestWindowWithId(0, GetContext()));
+ 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());
+
+ // w11 is now owned by w1.
+ AddTransientChild(w1.get(), w11);
+ // w21 is now owned by w2.
+ AddTransientChild(w2.get(), w21);
+ // w22 is now owned by w2.
+ AddTransientChild(w2.get(), w22);
+ // w211 is now owned by w21.
+ AddTransientChild(w21, w211);
+ // w212 is now owned by w21.
+ AddTransientChild(w21, w212);
+ // w213 is now owned by w21.
+ AddTransientChild(w21, w213);
+ 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(TransientWindowManagerTest, TransientChildrenGroupBelow) {
+ scoped_ptr<Window> parent(CreateTestWindowWithId(0, GetContext()));
+ 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());
+
+ // w11 is now owned by w1.
+ AddTransientChild(w1.get(), w11);
+ // w21 is now owned by w2.
+ AddTransientChild(w2.get(), w21);
+ // w22 is now owned by w2.
+ AddTransientChild(w2.get(), w22);
+ // w211 is now owned by w21.
+ AddTransientChild(w21, w211);
+ // w212 is now owned by w21.
+ AddTransientChild(w21, w212);
+ // w213 is now owned by w21.
+ AddTransientChild(w21, w213);
+ 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 {
+
+// Used by NotifyDelegateAfterDeletingTransients. Adds a string to a vector when
+// OnWindowDestroyed() is invoked so that destruction order can be verified.
+class DestroyedTrackingDelegate : public aura::test::TestWindowDelegate {
+ public:
+ explicit DestroyedTrackingDelegate(const std::string& name,
+ std::vector<std::string>* results)
+ : name_(name),
+ results_(results) {}
+
+ virtual void OnWindowDestroyed() OVERRIDE {
+ results_->push_back(name_);
+ }
+
+ private:
+ const std::string name_;
+ std::vector<std::string>* results_;
+
+ DISALLOW_COPY_AND_ASSIGN(DestroyedTrackingDelegate);
+};
+
+} // namespace
+
+// Verifies the delegate is notified of destruction after transients are
+// destroyed.
+TEST_F(TransientWindowManagerTest, NotifyDelegateAfterDeletingTransients) {
+ std::vector<std::string> destruction_order;
+
+ DestroyedTrackingDelegate parent_delegate("parent", &destruction_order);
+ scoped_ptr<Window> parent(new Window(&parent_delegate));
+ parent->Init(ui::LAYER_NOT_DRAWN);
+
+ DestroyedTrackingDelegate transient_delegate("transient", &destruction_order);
+ Window* transient = new Window(&transient_delegate); // Owned by |parent|.
+ transient->Init(ui::LAYER_NOT_DRAWN);
+ AddTransientChild(parent.get(), transient);
+ parent.reset();
+
+ ASSERT_EQ(2u, destruction_order.size());
+ EXPECT_EQ("transient", destruction_order[0]);
+ EXPECT_EQ("parent", destruction_order[1]);
+}
+
+TEST_F(TransientWindowManagerTest, StackTransientsWhoseLayersHaveNoDelegate) {
+ // Create a window with several transients, then a couple windows on top.
+ scoped_ptr<Window> window1(CreateTestWindowWithId(1, GetContext()));
+ scoped_ptr<Window> window11(CreateTransientChild(11, window1.get()));
+ scoped_ptr<Window> window12(CreateTransientChild(12, window1.get()));
+ scoped_ptr<Window> window13(CreateTransientChild(13, window1.get()));
+ scoped_ptr<Window> window2(CreateTestWindowWithId(2, GetContext()));
+ scoped_ptr<Window> window3(CreateTestWindowWithId(3, GetContext()));
+
+ EXPECT_EQ("1 11 12 13 2 3", ChildWindowIDsAsString(GetContext()));
+
+ // Remove the delegates of a couple of transients, as if they are closing
+ // and animating out.
+ window11->layer()->set_delegate(NULL);
+ window13->layer()->set_delegate(NULL);
+
+ // Move window1 to the front. All transients should move with it, and their
+ // order should be preserved.
+ GetContext()->StackChildAtTop(window1.get());
+
+ EXPECT_EQ("2 3 1 11 12 13", ChildWindowIDsAsString(GetContext()));
+}
+
+TEST_F(TransientWindowManagerTest,
+ StackTransientsLayersRelativeToOtherTransients) {
+ // Create a window with several transients, then a couple windows on top.
+ scoped_ptr<Window> window1(CreateTestWindowWithId(1, GetContext()));
+ scoped_ptr<Window> window11(CreateTransientChild(11, window1.get()));
+ scoped_ptr<Window> window12(CreateTransientChild(12, window1.get()));
+ scoped_ptr<Window> window13(CreateTransientChild(13, window1.get()));
+
+ EXPECT_EQ("1 11 12 13", ChildWindowIDsAsString(GetContext()));
+
+ // Stack 11 above 12.
+ GetContext()->StackChildAbove(window11.get(), window12.get());
+ EXPECT_EQ("1 12 11 13", ChildWindowIDsAsString(GetContext()));
+
+ // Stack 13 below 12.
+ GetContext()->StackChildBelow(window13.get(), window12.get());
+ EXPECT_EQ("1 13 12 11", ChildWindowIDsAsString(GetContext()));
+
+ // Stack 11 above 1.
+ GetContext()->StackChildAbove(window11.get(), window1.get());
+ EXPECT_EQ("1 11 13 12", ChildWindowIDsAsString(GetContext()));
+
+ // Stack 12 below 13.
+ GetContext()->StackChildBelow(window12.get(), window13.get());
+ EXPECT_EQ("1 11 12 13", ChildWindowIDsAsString(GetContext()));
+}
+
+TEST_F(TransientWindowManagerTest,
+ StackTransientsLayersRelativeToOtherTransientsNoLayerDelegate) {
+ // Create a window with several transients, then a couple windows on top.
+ scoped_ptr<Window> window1(CreateTestWindowWithId(1, GetContext()));
+ scoped_ptr<Window> window11(CreateTransientChild(11, window1.get()));
+ scoped_ptr<Window> window12(CreateTransientChild(12, window1.get()));
+ scoped_ptr<Window> window13(CreateTransientChild(13, window1.get()));
+ scoped_ptr<Window> window2(CreateTestWindowWithId(2, GetContext()));
+ scoped_ptr<Window> window3(CreateTestWindowWithId(3, GetContext()));
+
+ EXPECT_EQ("1 11 12 13 2 3", ChildWindowIDsAsString(GetContext()));
+
+ window1->layer()->set_delegate(NULL);
+
+ // Stack 1 at top.
+ GetContext()->StackChildAtTop(window1.get());
+ EXPECT_EQ("2 3 1 11 12 13", ChildWindowIDsAsString(GetContext()));
+}
+
+class StackingMadrigalLayoutManager : public aura::LayoutManager {
+ public:
+ explicit StackingMadrigalLayoutManager(Window* root_window)
+ : root_window_(root_window) {
+ root_window_->SetLayoutManager(this);
+ }
+ virtual ~StackingMadrigalLayoutManager() {
+ }
+
+ private:
+ // Overridden from LayoutManager:
+ virtual void OnWindowResized() OVERRIDE {}
+ virtual void OnWindowAddedToLayout(Window* child) OVERRIDE {}
+ virtual void OnWillRemoveWindowFromLayout(Window* child) OVERRIDE {}
+ virtual void OnWindowRemovedFromLayout(Window* child) OVERRIDE {}
+ virtual void OnChildWindowVisibilityChanged(Window* child,
+ bool visible) OVERRIDE {
+ Window::Windows::const_iterator it = root_window_->children().begin();
+ Window* last_window = NULL;
+ for (; it != root_window_->children().end(); ++it) {
+ if (*it == child && last_window) {
+ if (!visible)
+ root_window_->StackChildAbove(last_window, *it);
+ else
+ root_window_->StackChildAbove(*it, last_window);
+ break;
+ }
+ last_window = *it;
+ }
+ }
+ virtual void SetChildBounds(Window* child,
+ const gfx::Rect& requested_bounds) OVERRIDE {
+ SetChildBoundsDirect(child, requested_bounds);
+ }
+
+ Window* root_window_;
+
+ DISALLOW_COPY_AND_ASSIGN(StackingMadrigalLayoutManager);
+};
+
+class StackingMadrigalVisibilityClient : public aura::client::VisibilityClient {
+ public:
+ explicit StackingMadrigalVisibilityClient(Window* root_window)
+ : ignored_window_(NULL) {
+ aura::client::SetVisibilityClient(root_window, this);
+ }
+ virtual ~StackingMadrigalVisibilityClient() {
+ }
+
+ void set_ignored_window(Window* ignored_window) {
+ ignored_window_ = ignored_window;
+ }
+
+ private:
+ // Overridden from client::VisibilityClient:
+ virtual void UpdateLayerVisibility(Window* window, bool visible) OVERRIDE {
+ if (!visible) {
+ if (window == ignored_window_)
+ window->layer()->set_delegate(NULL);
+ else
+ window->layer()->SetVisible(visible);
+ } else {
+ window->layer()->SetVisible(visible);
+ }
+ }
+
+ Window* ignored_window_;
+
+ DISALLOW_COPY_AND_ASSIGN(StackingMadrigalVisibilityClient);
+};
+
+// This test attempts to reconstruct a circumstance that can happen when the
+// aura client attempts to manipulate the visibility and delegate of a layer
+// independent of window visibility.
+// A use case is where the client attempts to keep a window visible onscreen
+// even after code has called Hide() on the window. The use case for this would
+// be that window hides are animated (e.g. the window fades out). To prevent
+// spurious updating the client code may also clear window's layer's delegate,
+// so that the window cannot attempt to paint or update it further. The window
+// uses the presence of a NULL layer delegate as a signal in stacking to note
+// that the window is being manipulated by such a use case and its stacking
+// should not be adjusted.
+// One issue that can arise when a window opens two transient children, and the
+// first is hidden. Subsequent attempts to activate the transient parent can
+// result in the transient parent being stacked above the second transient
+// child. A fix is made to Window::StackAbove to prevent this, and this test
+// verifies this fix.
+TEST_F(TransientWindowManagerTest, StackingMadrigal) {
+ new StackingMadrigalLayoutManager(GetContext());
+ StackingMadrigalVisibilityClient visibility_client(GetContext());
+
+ scoped_ptr<Window> window1(CreateTestWindowWithId(1, GetContext()));
+ scoped_ptr<Window> window11(CreateTransientChild(11, window1.get()));
+
+ visibility_client.set_ignored_window(window11.get());
+
+ window11->Show();
+ window11->Hide();
+
+ // As a transient, window11 should still be stacked above window1, even when
+ // hidden.
+ EXPECT_TRUE(aura::test::WindowIsAbove(window11.get(), window1.get()));
+ EXPECT_TRUE(aura::test::LayerIsAbove(window11.get(), window1.get()));
+
+ // A new transient should still be above window1. It will appear behind
+ // window11 because we don't stack windows on top of targets with NULL
+ // delegates.
+ scoped_ptr<Window> window12(CreateTransientChild(12, window1.get()));
+ window12->Show();
+
+ EXPECT_TRUE(aura::test::WindowIsAbove(window12.get(), window1.get()));
+ EXPECT_TRUE(aura::test::LayerIsAbove(window12.get(), window1.get()));
+
+ // In earlier versions of the StackChildAbove() method, attempting to stack
+ // window1 above window12 at this point would actually restack the layers
+ // resulting in window12's layer being below window1's layer (though the
+ // windows themselves would still be correctly stacked, so events would pass
+ // through.)
+ GetContext()->StackChildAbove(window1.get(), window12.get());
+
+ // Both window12 and its layer should be stacked above window1.
+ EXPECT_TRUE(aura::test::WindowIsAbove(window12.get(), window1.get()));
+ EXPECT_TRUE(aura::test::LayerIsAbove(window12.get(), window1.get()));
+}
+
+// Test for an issue where attempting to stack a primary window on top of a
+// transient with a NULL layer delegate causes that primary window to be moved,
+// but the layer order not changed to match. http://crbug.com/112562
+TEST_F(TransientWindowManagerTest, StackOverClosingTransient) {
+ scoped_ptr<Window> window1(CreateTestWindowWithId(1, GetContext()));
+ scoped_ptr<Window> transient1(CreateTransientChild(11, window1.get()));
+ scoped_ptr<Window> window2(CreateTestWindowWithId(2, GetContext()));
+ scoped_ptr<Window> transient2(CreateTransientChild(21, window2.get()));
+
+ // Both windows and layers are stacked in creation order.
+ Window* root = GetContext();
+ ASSERT_EQ(4u, root->children().size());
+ EXPECT_EQ(root->children()[0], window1.get());
+ EXPECT_EQ(root->children()[1], transient1.get());
+ EXPECT_EQ(root->children()[2], window2.get());
+ EXPECT_EQ(root->children()[3], transient2.get());
+ ASSERT_EQ(4u, root->layer()->children().size());
+ EXPECT_EQ(root->layer()->children()[0], window1->layer());
+ EXPECT_EQ(root->layer()->children()[1], transient1->layer());
+ EXPECT_EQ(root->layer()->children()[2], window2->layer());
+ EXPECT_EQ(root->layer()->children()[3], transient2->layer());
+ EXPECT_EQ("1 11 2 21", ChildWindowIDsAsString(GetContext()));
+
+ // This brings window1 and its transient to the front.
+ root->StackChildAtTop(window1.get());
+ EXPECT_EQ("2 21 1 11", ChildWindowIDsAsString(GetContext()));
+
+ EXPECT_EQ(root->children()[0], window2.get());
+ EXPECT_EQ(root->children()[1], transient2.get());
+ EXPECT_EQ(root->children()[2], window1.get());
+ EXPECT_EQ(root->children()[3], transient1.get());
+ EXPECT_EQ(root->layer()->children()[0], window2->layer());
+ EXPECT_EQ(root->layer()->children()[1], transient2->layer());
+ EXPECT_EQ(root->layer()->children()[2], window1->layer());
+ EXPECT_EQ(root->layer()->children()[3], transient1->layer());
+
+ // Pretend we're closing the top-most transient, then bring window2 to the
+ // front. This mimics activating a browser window while the status bubble
+ // is fading out. The transient should stay topmost.
+ transient1->layer()->set_delegate(NULL);
+ root->StackChildAtTop(window2.get());
+
+ EXPECT_EQ(root->children()[0], window1.get());
+ EXPECT_EQ(root->children()[1], window2.get());
+ EXPECT_EQ(root->children()[2], transient2.get());
+ EXPECT_EQ(root->children()[3], transient1.get());
+ EXPECT_EQ(root->layer()->children()[0], window1->layer());
+ EXPECT_EQ(root->layer()->children()[1], window2->layer());
+ EXPECT_EQ(root->layer()->children()[2], transient2->layer());
+ EXPECT_EQ(root->layer()->children()[3], transient1->layer());
+
+ // Close the transient. Remaining windows are stable.
+ transient1.reset();
+
+ ASSERT_EQ(3u, root->children().size());
+ EXPECT_EQ(root->children()[0], window1.get());
+ EXPECT_EQ(root->children()[1], window2.get());
+ EXPECT_EQ(root->children()[2], transient2.get());
+ ASSERT_EQ(3u, root->layer()->children().size());
+ EXPECT_EQ(root->layer()->children()[0], window1->layer());
+ EXPECT_EQ(root->layer()->children()[1], window2->layer());
+ EXPECT_EQ(root->layer()->children()[2], transient2->layer());
+
+ // Open another window on top.
+ scoped_ptr<Window> window3(CreateTestWindowWithId(3, GetContext()));
+
+ ASSERT_EQ(4u, root->children().size());
+ EXPECT_EQ(root->children()[0], window1.get());
+ EXPECT_EQ(root->children()[1], window2.get());
+ EXPECT_EQ(root->children()[2], transient2.get());
+ EXPECT_EQ(root->children()[3], window3.get());
+ ASSERT_EQ(4u, root->layer()->children().size());
+ EXPECT_EQ(root->layer()->children()[0], window1->layer());
+ EXPECT_EQ(root->layer()->children()[1], window2->layer());
+ EXPECT_EQ(root->layer()->children()[2], transient2->layer());
+ EXPECT_EQ(root->layer()->children()[3], window3->layer());
+
+ // Pretend we're closing the topmost non-transient window, then bring
+ // window2 to the top. It should not move.
+ window3->layer()->set_delegate(NULL);
+ root->StackChildAtTop(window2.get());
+
+ ASSERT_EQ(4u, root->children().size());
+ EXPECT_EQ(root->children()[0], window1.get());
+ EXPECT_EQ(root->children()[1], window2.get());
+ EXPECT_EQ(root->children()[2], transient2.get());
+ EXPECT_EQ(root->children()[3], window3.get());
+ ASSERT_EQ(4u, root->layer()->children().size());
+ EXPECT_EQ(root->layer()->children()[0], window1->layer());
+ EXPECT_EQ(root->layer()->children()[1], window2->layer());
+ EXPECT_EQ(root->layer()->children()[2], transient2->layer());
+ EXPECT_EQ(root->layer()->children()[3], window3->layer());
+
+ // Bring window1 to the top. It should move ahead of window2, but not
+ // ahead of window3 (with NULL delegate).
+ root->StackChildAtTop(window1.get());
+
+ ASSERT_EQ(4u, root->children().size());
+ EXPECT_EQ(root->children()[0], window2.get());
+ EXPECT_EQ(root->children()[1], transient2.get());
+ EXPECT_EQ(root->children()[2], window1.get());
+ EXPECT_EQ(root->children()[3], window3.get());
+ ASSERT_EQ(4u, root->layer()->children().size());
+ EXPECT_EQ(root->layer()->children()[0], window2->layer());
+ EXPECT_EQ(root->layer()->children()[1], transient2->layer());
+ EXPECT_EQ(root->layer()->children()[2], window1->layer());
+ EXPECT_EQ(root->layer()->children()[3], window3->layer());
+}
+
+} // namespace corewm
+} // namespace views
diff --git a/ui/views/corewm/transient_window_stacking_client.cc b/ui/views/corewm/transient_window_stacking_client.cc
index e3373ff..ef08cc0 100644
--- a/ui/views/corewm/transient_window_stacking_client.cc
+++ b/ui/views/corewm/transient_window_stacking_client.cc
@@ -6,6 +6,9 @@
#include <algorithm>
+#include "ui/views/corewm/transient_window_manager.h"
+#include "ui/views/corewm/window_util.h"
+
using aura::Window;
namespace views {
@@ -17,7 +20,7 @@ namespace {
// 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()) {
+ for (; window; window = GetTransientParent(window)) {
if (window->parent() == parent)
ancestors->push_back(window);
}
@@ -51,27 +54,53 @@ void FindCommonTransientAncestor(Window** window1, Window** window2) {
}
}
-// 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;
+// Adjusts |target| so that we don't attempt to stack on top of a window with a
+// NULL delegate.
+void SkipNullDelegates(Window::StackDirection direction, Window** target) {
+ const Window::Windows& children((*target)->parent()->children());
+ 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
+ // TransientWindowManagerTest.StackingMadrigal and StackOverClosingTransient
+ // for an explanation of this.
+ while (target_i > 0) {
+ const size_t index = direction == Window::STACK_ABOVE ?
+ target_i : target_i - 1;
+ if (!children[index]->layer() ||
+ children[index]->layer()->delegate() != NULL)
+ break;
+ --target_i;
+ }
+ *target = children[target_i];
}
} // namespace
+// static
+TransientWindowStackingClient* TransientWindowStackingClient::instance_ = NULL;
+
TransientWindowStackingClient::TransientWindowStackingClient() {
+ instance_ = this;
}
TransientWindowStackingClient::~TransientWindowStackingClient() {
+ if (instance_ == this)
+ instance_ = NULL;
}
bool TransientWindowStackingClient::AdjustStacking(
Window** child,
Window** target,
Window::StackDirection* direction) {
+ const TransientWindowManager* transient_manager =
+ TransientWindowManager::Get((*child)->parent());
+ if (transient_manager &&
+ transient_manager->IsStackingTransient(*child, *target))
+ return true;
+
// 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.
@@ -89,7 +118,16 @@ bool TransientWindowStackingClient::AdjustStacking(
}
*target = siblings[target_i];
}
- return true;
+
+ SkipNullDelegates(*direction, target);
+
+ // If we couldn't find a valid target position, don't move anything.
+ if (*direction == Window::STACK_ABOVE &&
+ ((*target)->layer() && (*target)->layer()->delegate() == NULL)) {
+ return false;
+ }
+
+ return *child != *target;
}
} // namespace corewm
diff --git a/ui/views/corewm/transient_window_stacking_client.h b/ui/views/corewm/transient_window_stacking_client.h
index f8c1982..04e0eaf 100644
--- a/ui/views/corewm/transient_window_stacking_client.h
+++ b/ui/views/corewm/transient_window_stacking_client.h
@@ -11,6 +11,8 @@
namespace views {
namespace corewm {
+class TransientWindowManager;
+
class VIEWS_EXPORT TransientWindowStackingClient
: public aura::client::WindowStackingClient {
public:
@@ -23,6 +25,11 @@ class VIEWS_EXPORT TransientWindowStackingClient
aura::Window::StackDirection* direction) OVERRIDE;
private:
+ // Purely for DCHECKs.
+ friend class TransientWindowManager;
+
+ static TransientWindowStackingClient* instance_;
+
DISALLOW_COPY_AND_ASSIGN(TransientWindowStackingClient);
};
diff --git a/ui/views/corewm/transient_window_stacking_client_unittest.cc b/ui/views/corewm/transient_window_stacking_client_unittest.cc
index 05d7b3e..c4570b7 100644
--- a/ui/views/corewm/transient_window_stacking_client_unittest.cc
+++ b/ui/views/corewm/transient_window_stacking_client_unittest.cc
@@ -7,6 +7,8 @@
#include "base/memory/scoped_ptr.h"
#include "ui/aura/test/aura_test_base.h"
#include "ui/aura/test/test_windows.h"
+#include "ui/compositor/test/test_layers.h"
+#include "ui/views/corewm/window_util.h"
using aura::test::ChildWindowIDsAsString;
using aura::test::CreateTestWindowWithId;
@@ -49,12 +51,12 @@ TEST_F(TransientWindowStackingClientTest, TransientChildrenGroupAbove) {
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.
+ AddTransientChild(w1.get(), w11); // w11 is now owned by w1.
+ AddTransientChild(w2.get(), w21); // w21 is now owned by w2.
+ AddTransientChild(w2.get(), w22); // w22 is now owned by w2.
+ AddTransientChild(w21, w211); // w211 is now owned by w21.
+ AddTransientChild(w21, w212); // w212 is now owned by w21.
+ AddTransientChild(w21, 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).
@@ -119,12 +121,12 @@ TEST_F(TransientWindowStackingClientTest, TransientChildrenGroupBelow) {
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.
+ AddTransientChild(w1.get(), w11); // w11 is now owned by w1.
+ AddTransientChild(w2.get(), w21); // w21 is now owned by w2.
+ AddTransientChild(w2.get(), w22); // w22 is now owned by w2.
+ AddTransientChild(w21, w211); // w211 is now owned by w21.
+ AddTransientChild(w21, w212); // w212 is now owned by w21.
+ AddTransientChild(w21, 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).
@@ -173,5 +175,43 @@ TEST_F(TransientWindowStackingClientTest, TransientChildrenGroupBelow) {
EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
}
+TEST_F(TransientWindowStackingClientTest,
+ StackWindowsWhoseLayersHaveNoDelegate) {
+ scoped_ptr<Window> window1(CreateTestWindowWithId(1, root_window()));
+ window1->layer()->set_name("1");
+ scoped_ptr<Window> window2(CreateTestWindowWithId(2, root_window()));
+ window2->layer()->set_name("2");
+ scoped_ptr<Window> window3(CreateTestWindowWithId(3, root_window()));
+ window3->layer()->set_name("3");
+
+ // This brings |window1| (and its layer) to the front.
+ root_window()->StackChildAbove(window1.get(), window3.get());
+ EXPECT_EQ("2 3 1", ChildWindowIDsAsString(root_window()));
+ EXPECT_EQ("2 3 1",
+ ui::test::ChildLayerNamesAsString(*root_window()->layer()));
+
+ // Since |window1| does not have a delegate, |window2| should not move in
+ // front of it, nor should its layer.
+ window1->layer()->set_delegate(NULL);
+ root_window()->StackChildAbove(window2.get(), window1.get());
+ EXPECT_EQ("3 2 1", ChildWindowIDsAsString(root_window()));
+ EXPECT_EQ("3 2 1",
+ ui::test::ChildLayerNamesAsString(*root_window()->layer()));
+
+ // It should still be possible to stack |window3| immediately below |window1|.
+ root_window()->StackChildBelow(window3.get(), window1.get());
+ EXPECT_EQ("2 3 1", ChildWindowIDsAsString(root_window()));
+ EXPECT_EQ("2 3 1",
+ ui::test::ChildLayerNamesAsString(*root_window()->layer()));
+
+ // Since neither |window3| nor |window1| have a delegate, |window2| should
+ // not move in front of either.
+ window3->layer()->set_delegate(NULL);
+ root_window()->StackChildBelow(window2.get(), window1.get());
+ EXPECT_EQ("2 3 1", ChildWindowIDsAsString(root_window()));
+ EXPECT_EQ("2 3 1",
+ ui::test::ChildLayerNamesAsString(*root_window()->layer()));
+}
+
} // namespace corewm
} // namespace views
diff --git a/ui/views/corewm/window_modality_controller.cc b/ui/views/corewm/window_modality_controller.cc
index b52a9d6..d87f088 100644
--- a/ui/views/corewm/window_modality_controller.cc
+++ b/ui/views/corewm/window_modality_controller.cc
@@ -63,13 +63,13 @@ bool IsModalTransientChild(aura::Window* transient, aura::Window* original) {
aura::Window* GetModalTransientChild(
aura::Window* activatable,
aura::Window* original) {
- aura::Window::Windows::const_iterator it;
- for (it = activatable->transient_children().begin();
- it != activatable->transient_children().end();
+ for (aura::Window::Windows::const_iterator it =
+ GetTransientChildren(activatable).begin();
+ it != GetTransientChildren(activatable).end();
++it) {
aura::Window* transient = *it;
if (IsModalTransientChild(transient, original)) {
- return transient->transient_children().empty() ?
+ return GetTransientChildren(transient).empty() ?
transient : GetModalTransientChild(transient, original);
}
}
@@ -153,8 +153,8 @@ void WindowModalityController::OnWindowPropertyChanged(aura::Window* window,
window->GetProperty(aura::client::kModalKey) != ui::MODAL_TYPE_NONE &&
window->IsVisible()) {
ActivateWindow(window);
- ui::GestureRecognizer::Get()->TransferEventsTo(
- window->transient_parent(), NULL);
+ ui::GestureRecognizer::Get()->TransferEventsTo(GetTransientParent(window),
+ NULL);
}
}
@@ -163,8 +163,8 @@ void WindowModalityController::OnWindowVisibilityChanged(
bool visible) {
if (visible && window->GetProperty(aura::client::kModalKey) !=
ui::MODAL_TYPE_NONE) {
- ui::GestureRecognizer::Get()->TransferEventsTo(
- window->transient_parent(), NULL);
+ ui::GestureRecognizer::Get()->TransferEventsTo(GetTransientParent(window),
+ NULL);
// Make sure no other window has capture, otherwise |window| won't get mouse
// events.
aura::Window* capture_window = aura::client::GetCaptureWindow(window);
diff --git a/ui/views/corewm/window_util.cc b/ui/views/corewm/window_util.cc
index eaee174..64a23d1 100644
--- a/ui/views/corewm/window_util.cc
+++ b/ui/views/corewm/window_util.cc
@@ -8,6 +8,7 @@
#include "ui/aura/root_window.h"
#include "ui/aura/window.h"
#include "ui/compositor/layer.h"
+#include "ui/views/corewm/transient_window_manager.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
@@ -137,5 +138,42 @@ ui::Layer* RecreateWindowLayers(aura::Window* window, bool set_bounds) {
return old_layer;
}
+aura::Window* GetTransientParent(aura::Window* window) {
+ return const_cast<aura::Window*>(GetTransientParent(
+ const_cast<const aura::Window*>(window)));
+}
+
+const aura::Window* GetTransientParent(const aura::Window* window) {
+ const TransientWindowManager* manager = TransientWindowManager::Get(window);
+ return manager ? manager->transient_parent() : NULL;
+}
+
+const std::vector<aura::Window*>& GetTransientChildren(
+ const aura::Window* window) {
+ const TransientWindowManager* manager = TransientWindowManager::Get(window);
+ if (manager)
+ return manager->transient_children();
+
+ static std::vector<aura::Window*>* shared = new std::vector<aura::Window*>;
+ return *shared;
+}
+
+void AddTransientChild(aura::Window* parent, aura::Window* child) {
+ TransientWindowManager::Get(parent)->AddTransientChild(child);
+}
+
+void RemoveTransientChild(aura::Window* parent, aura::Window* child) {
+ TransientWindowManager::Get(parent)->RemoveTransientChild(child);
+}
+
+bool HasTransientAncestor(const aura::Window* window,
+ const aura::Window* ancestor) {
+ const aura::Window* transient_parent = GetTransientParent(window);
+ if (transient_parent == ancestor)
+ return true;
+ return transient_parent ?
+ HasTransientAncestor(transient_parent, ancestor) : false;
+}
+
} // namespace corewm
} // namespace views
diff --git a/ui/views/corewm/window_util.h b/ui/views/corewm/window_util.h
index 01a3ea4..c3b552d 100644
--- a/ui/views/corewm/window_util.h
+++ b/ui/views/corewm/window_util.h
@@ -5,6 +5,8 @@
#ifndef UI_VIEWS_COREWM_WINDOW_UTIL_H_
#define UI_VIEWS_COREWM_WINDOW_UTIL_H_
+#include <vector>
+
#include "base/compiler_specific.h"
#include "ui/views/views_export.h"
@@ -47,6 +49,22 @@ VIEWS_EXPORT void DeepDeleteLayers(ui::Layer* layer);
VIEWS_EXPORT ui::Layer* RecreateWindowLayers(aura::Window* window,
bool set_bounds) WARN_UNUSED_RESULT;
+// Convenience functions that get the TransientWindowManager for the window and
+// redirect appropriately. These are preferable to calling functions on
+// TransientWindowManager as they handle the appropriate NULL checks.
+VIEWS_EXPORT aura::Window* GetTransientParent(aura::Window* window);
+VIEWS_EXPORT const aura::Window* GetTransientParent(const aura::Window* window);
+VIEWS_EXPORT const std::vector<aura::Window*>& GetTransientChildren(
+ const aura::Window* window);
+VIEWS_EXPORT void AddTransientChild(aura::Window* parent, aura::Window* child);
+VIEWS_EXPORT void RemoveTransientChild(aura::Window* parent,
+ aura::Window* child);
+
+// Returns true if |window| has |ancestor| as a transient ancestor. A transient
+// ancestor is found by following the transient parent chain of the window.
+VIEWS_EXPORT bool HasTransientAncestor(const aura::Window* window,
+ const aura::Window* ancestor);
+
} // namespace corewm
} // namespace views
diff --git a/ui/views/corewm/wm_state.cc b/ui/views/corewm/wm_state.cc
index 0799247..16d9e7a 100644
--- a/ui/views/corewm/wm_state.cc
+++ b/ui/views/corewm/wm_state.cc
@@ -4,19 +4,27 @@
#include "ui/views/corewm/wm_state.h"
+#include "ui/views/corewm/transient_window_controller.h"
#include "ui/views/corewm/transient_window_stacking_client.h"
namespace views {
namespace corewm {
WMState::WMState()
- : window_stacking_client_(new TransientWindowStackingClient) {
+ : window_stacking_client_(new TransientWindowStackingClient),
+ transient_window_client_(new TransientWindowController) {
aura::client::SetWindowStackingClient(window_stacking_client_.get());
+ aura::client::SetTransientWindowClient(transient_window_client_.get());
}
WMState::~WMState() {
if (aura::client::GetWindowStackingClient() == window_stacking_client_.get())
aura::client::SetWindowStackingClient(NULL);
+
+ if (aura::client::GetTransientWindowClient() ==
+ transient_window_client_.get()) {
+ aura::client::SetTransientWindowClient(NULL);
+ }
}
} // namespace corewm
diff --git a/ui/views/corewm/wm_state.h b/ui/views/corewm/wm_state.h
index 1e0ee4f..e8a09f2 100644
--- a/ui/views/corewm/wm_state.h
+++ b/ui/views/corewm/wm_state.h
@@ -11,6 +11,7 @@
namespace views {
namespace corewm {
+class TransientWindowController;
class TransientWindowStackingClient;
// Installs state needed by the window manager.
@@ -22,6 +23,7 @@ class VIEWS_EXPORT WMState {
// WindowStackingClient:
private:
scoped_ptr<TransientWindowStackingClient> window_stacking_client_;
+ scoped_ptr<TransientWindowController> transient_window_client_;
DISALLOW_COPY_AND_ASSIGN(WMState);
};
diff --git a/ui/views/views.gyp b/ui/views/views.gyp
index ce8e690..3cfd592 100644
--- a/ui/views/views.gyp
+++ b/ui/views/views.gyp
@@ -263,6 +263,10 @@
'corewm/tooltip_controller.h',
'corewm/tooltip_win.cc',
'corewm/tooltip_win.h',
+ 'corewm/transient_window_controller.cc',
+ 'corewm/transient_window_controller.h',
+ 'corewm/transient_window_manager.cc',
+ 'corewm/transient_window_manager.h',
'corewm/transient_window_stacking_client.cc',
'corewm/transient_window_stacking_client.h',
'corewm/visibility_controller.cc',
@@ -768,6 +772,7 @@
'corewm/shadow_controller_unittest.cc',
'corewm/tooltip_aura_unittest.cc',
'corewm/tooltip_controller_unittest.cc',
+ 'corewm/transient_window_manager_unittest.cc',
'corewm/transient_window_stacking_client_unittest.cc',
'corewm/visibility_controller_unittest.cc',
'corewm/window_animations_unittest.cc',
diff --git a/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc b/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc
index b4541d0..00e3f6d 100644
--- a/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc
+++ b/ui/views/widget/desktop_aura/desktop_root_window_host_x11.cc
@@ -37,6 +37,7 @@
#include "ui/views/corewm/compound_event_filter.h"
#include "ui/views/corewm/corewm_switches.h"
#include "ui/views/corewm/tooltip_aura.h"
+#include "ui/views/corewm/window_util.h"
#include "ui/views/ime/input_method.h"
#include "ui/views/linux_ui/linux_ui.h"
#include "ui/views/views_delegate.h"
@@ -241,8 +242,9 @@ void DesktopRootWindowHostX11::OnRootWindowCreated(
// If we're given a parent, we need to mark ourselves as transient to another
// window. Otherwise activation gets screwy.
gfx::NativeView parent = params.parent;
- if (!params.child && params.parent)
- parent->AddTransientChild(content_window_);
+ if (!params.child && params.parent) {
+ corewm::AddTransientChild(parent, content_window_);
+ }
// Ensure that the X11DesktopHandler exists so that it dispatches activation
// messages to us.
@@ -366,9 +368,9 @@ void DesktopRootWindowHostX11::CenterWindow(const gfx::Size& size) {
// If |window_|'s transient parent bounds are big enough to contain |size|,
// use them instead.
- if (content_window_->transient_parent()) {
+ if (corewm::GetTransientParent(content_window_)) {
gfx::Rect transient_parent_rect =
- content_window_->transient_parent()->GetBoundsInScreen();
+ corewm::GetTransientParent(content_window_)->GetBoundsInScreen();
if (transient_parent_rect.height() >= size.height() &&
transient_parent_rect.width() >= size.width()) {
parent_bounds = transient_parent_rect;
diff --git a/ui/views/widget/native_widget_aura.cc b/ui/views/widget/native_widget_aura.cc
index 1f97ac1..d2ec6cf 100644
--- a/ui/views/widget/native_widget_aura.cc
+++ b/ui/views/widget/native_widget_aura.cc
@@ -27,6 +27,7 @@
#include "ui/gfx/font.h"
#include "ui/gfx/screen.h"
#include "ui/native_theme/native_theme_aura.h"
+#include "ui/views/corewm/window_util.h"
#include "ui/views/drag_utils.h"
#include "ui/views/ime/input_method_bridge.h"
#include "ui/views/views_delegate.h"
@@ -131,7 +132,7 @@ void NativeWidgetAura::InitNativeWidget(const Widget::InitParams& params) {
// Set up the transient child before the window is added. This way the
// LayoutManager knows the window has a transient parent.
if (parent && parent->type() != ui::wm::WINDOW_TYPE_UNKNOWN) {
- parent->AddTransientChild(window_);
+ corewm::AddTransientChild(parent, window_);
if (!context)
context = parent;
parent = NULL;
@@ -310,9 +311,9 @@ void NativeWidgetAura::CenterWindow(const gfx::Size& size) {
// If |window_|'s transient parent's bounds are big enough to fit it, then we
// center it with respect to the transient parent.
- if (window_->transient_parent()) {
- gfx::Rect transient_parent_rect = window_->transient_parent()->
- GetBoundsInRootWindow();
+ if (views::corewm::GetTransientParent(window_)) {
+ gfx::Rect transient_parent_rect =
+ views::corewm::GetTransientParent(window_)->GetBoundsInRootWindow();
transient_parent_rect.Intersect(work_area);
if (transient_parent_rect.height() >= size.height() &&
transient_parent_rect.width() >= size.width())
@@ -1082,7 +1083,7 @@ void NativeWidgetPrivate::GetAllChildWidgets(gfx::NativeView native_view,
void NativeWidgetPrivate::GetAllOwnedWidgets(gfx::NativeView native_view,
Widget::Widgets* owned) {
const aura::Window::Windows& transient_children =
- native_view->transient_children();
+ views::corewm::GetTransientChildren(native_view);
for (aura::Window::Windows::const_iterator i = transient_children.begin();
i != transient_children.end(); ++i) {
NativeWidgetPrivate* native_widget = static_cast<NativeWidgetPrivate*>(
diff --git a/ui/wm/core/easy_resize_window_targeter.cc b/ui/wm/core/easy_resize_window_targeter.cc
index f3a2b0a..1f0e90a 100644
--- a/ui/wm/core/easy_resize_window_targeter.cc
+++ b/ui/wm/core/easy_resize_window_targeter.cc
@@ -4,6 +4,7 @@
#include "ui/wm/public/easy_resize_window_targeter.h"
+#include "ui/aura/client/transient_window_client.h"
#include "ui/aura/window.h"
#include "ui/gfx/geometry/insets_f.h"
#include "ui/gfx/geometry/rect.h"
@@ -25,10 +26,7 @@ EasyResizeWindowTargeter::~EasyResizeWindowTargeter() {
bool EasyResizeWindowTargeter::EventLocationInsideBounds(
aura::Window* window,
const ui::LocatedEvent& event) const {
- // Use the extended bounds only for immediate child windows of |container_|.
- // Use the default targetter otherwise.
- if (window->parent() == container_ && (!window->transient_parent() ||
- window->transient_parent() == container_)) {
+ if (ShouldUseExtendedBounds(window)) {
gfx::RectF bounds(window->bounds());
gfx::Transform transform = window->layer()->transform();
transform.TransformRect(&bounds);
@@ -45,4 +43,18 @@ bool EasyResizeWindowTargeter::EventLocationInsideBounds(
return WindowTargeter::EventLocationInsideBounds(window, event);
}
+bool EasyResizeWindowTargeter::ShouldUseExtendedBounds(
+ const aura::Window* window) const {
+ // Use the extended bounds only for immediate child windows of |container_|.
+ // Use the default targetter otherwise.
+ if (window->parent() != container_)
+ return false;
+
+ aura::client::TransientWindowClient* transient_window_client =
+ aura::client::GetTransientWindowClient();
+ return !transient_window_client ||
+ !transient_window_client->GetTransientParent(window) ||
+ transient_window_client->GetTransientParent(window) == container_;
+}
+
} // namespace wm
diff --git a/ui/wm/public/easy_resize_window_targeter.h b/ui/wm/public/easy_resize_window_targeter.h
index c4c7137..f873509 100644
--- a/ui/wm/public/easy_resize_window_targeter.h
+++ b/ui/wm/public/easy_resize_window_targeter.h
@@ -36,6 +36,10 @@ class EasyResizeWindowTargeter : public aura::WindowTargeter {
const ui::LocatedEvent& event) const OVERRIDE;
private:
+ // Returns true if the hit testing (EventLocationInsideBounds()) should use
+ // the extended bounds.
+ bool ShouldUseExtendedBounds(const aura::Window* window) const;
+
aura::Window* container_;
gfx::Insets mouse_extend_;
gfx::Insets touch_extend_;