Commit 205c1437 authored by Xiaoqian Dai's avatar Xiaoqian Dai Committed by Commit Bot

[reland] splitscreen: Adjust bubble dialog bounds if splitscreen is active.

When a dialog is added to a window that's currently showig in
splitscreen, we should adjust the dialog bounds to show the dialog
aligned within its own side of the split, rather than across the divider
bar.

Note the divider is still placed on top of the snapped windows and its
transient children if they are placed in default container.

Bug: 878268
TBR=xiyuan@chromium.org

Reviewed-on: https://chromium-review.googlesource.com/c/1274197
Commit-Queue: Xiaoqian Dai <xdai@chromium.org>
Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#598827}
Change-Id: I3e7377c053d14fcf3fd882abff2f860a88a61332
Reviewed-on: https://chromium-review.googlesource.com/c/1280674Reviewed-by: default avatarXiaoqian Dai <xdai@chromium.org>
Cr-Commit-Position: refs/heads/master@{#599693}
parent 80b32be8
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#include "ui/compositor_extra/shadow.h" #include "ui/compositor_extra/shadow.h"
#include "ui/display/test/display_manager_test_api.h" #include "ui/display/test/display_manager_test_api.h"
#include "ui/events/test/event_generator.h" #include "ui/events/test/event_generator.h"
#include "ui/views/bubble/bubble_dialog_delegate_view.h"
#include "ui/views/widget/widget.h" #include "ui/views/widget/widget.h"
#include "ui/wm/core/shadow_controller.h" #include "ui/wm/core/shadow_controller.h"
#include "ui/wm/core/shadow_types.h" #include "ui/wm/core/shadow_types.h"
...@@ -89,6 +90,17 @@ class OverviewStatesObserver : public ShellObserver { ...@@ -89,6 +90,17 @@ class OverviewStatesObserver : public ShellObserver {
DISALLOW_COPY_AND_ASSIGN(OverviewStatesObserver); DISALLOW_COPY_AND_ASSIGN(OverviewStatesObserver);
}; };
// The test BubbleDialogDelegateView for bubbles.
class TestBubbleDialogDelegateView : public views::BubbleDialogDelegateView {
public:
explicit TestBubbleDialogDelegateView(views::View* anchor_view)
: BubbleDialogDelegateView(anchor_view, views::BubbleBorder::NONE) {}
~TestBubbleDialogDelegateView() override {}
private:
DISALLOW_COPY_AND_ASSIGN(TestBubbleDialogDelegateView);
};
} // namespace } // namespace
class SplitViewControllerTest : public AshTestBase { class SplitViewControllerTest : public AshTestBase {
...@@ -1614,6 +1626,35 @@ TEST_F(SplitViewControllerTest, ActivateNonSnappableWindow) { ...@@ -1614,6 +1626,35 @@ TEST_F(SplitViewControllerTest, ActivateNonSnappableWindow) {
EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting()); EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting());
} }
// Tests that if a snapped window has a bubble transient child, the bubble's
// bounds should always align with the snapped window's bounds.
TEST_F(SplitViewControllerTest, AdjustTransientChildBounds) {
std::unique_ptr<views::Widget> widget(CreateTestWidget());
aura::Window* window = widget->GetNativeWindow();
window->SetProperty(aura::client::kResizeBehaviorKey,
ws::mojom::kResizeBehaviorCanResize |
ws::mojom::kResizeBehaviorCanMaximize);
split_view_controller()->SnapWindow(window, SplitViewController::LEFT);
const gfx::Rect window_bounds = window->GetBoundsInScreen();
// Create a bubble widget that's anchored to |widget|.
views::Widget* bubble_widget = views::BubbleDialogDelegateView::CreateBubble(
new TestBubbleDialogDelegateView(widget->GetContentsView()));
aura::Window* bubble_window = bubble_widget->GetNativeWindow();
EXPECT_TRUE(::wm::HasTransientAncestor(bubble_window, window));
// Test that the bubble is created inside its anchor widget.
EXPECT_TRUE(window_bounds.Contains(bubble_window->GetBoundsInScreen()));
// Now try to manually move the bubble out of the snapped window.
bubble_window->SetBoundsInScreen(
split_view_controller()->GetSnappedWindowBoundsInScreen(
window, SplitViewController::RIGHT),
display::Screen::GetScreen()->GetDisplayNearestWindow(window));
// Test that the bubble can't be moved outside of its anchor widget.
EXPECT_TRUE(window_bounds.Contains(bubble_window->GetBoundsInScreen()));
EndSplitView();
}
// Test the tab-dragging related functionalities in tablet mode. Tab(s) can be // Test the tab-dragging related functionalities in tablet mode. Tab(s) can be
// dragged out of a window and then put in split view mode or merge into another // dragged out of a window and then put in split view mode or merge into another
// window. // window.
......
...@@ -25,7 +25,10 @@ ...@@ -25,7 +25,10 @@
#include "ui/views/view.h" #include "ui/views/view.h"
#include "ui/views/view_targeter_delegate.h" #include "ui/views/view_targeter_delegate.h"
#include "ui/views/widget/widget.h" #include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
#include "ui/wm/core/coordinate_conversion.h" #include "ui/wm/core/coordinate_conversion.h"
#include "ui/wm/core/transient_window_manager.h"
#include "ui/wm/core/window_util.h"
#include "ui/wm/public/activation_client.h" #include "ui/wm/public/activation_client.h"
namespace ash { namespace ash {
...@@ -383,6 +386,7 @@ gfx::Rect SplitViewDivider::GetDividerBoundsInScreen(bool is_dragging) { ...@@ -383,6 +386,7 @@ gfx::Rect SplitViewDivider::GetDividerBoundsInScreen(bool is_dragging) {
void SplitViewDivider::AddObservedWindow(aura::Window* window) { void SplitViewDivider::AddObservedWindow(aura::Window* window) {
if (!base::ContainsValue(observed_windows_, window)) { if (!base::ContainsValue(observed_windows_, window)) {
window->AddObserver(this); window->AddObserver(this);
::wm::TransientWindowManager::GetOrCreate(window)->AddObserver(this);
observed_windows_.push_back(window); observed_windows_.push_back(window);
} }
} }
...@@ -392,6 +396,7 @@ void SplitViewDivider::RemoveObservedWindow(aura::Window* window) { ...@@ -392,6 +396,7 @@ void SplitViewDivider::RemoveObservedWindow(aura::Window* window) {
std::find(observed_windows_.begin(), observed_windows_.end(), window); std::find(observed_windows_.begin(), observed_windows_.end(), window);
if (iter != observed_windows_.end()) { if (iter != observed_windows_.end()) {
window->RemoveObserver(this); window->RemoveObserver(this);
::wm::TransientWindowManager::GetOrCreate(window)->RemoveObserver(this);
observed_windows_.erase(iter); observed_windows_.erase(iter);
} }
} }
...@@ -413,6 +418,33 @@ void SplitViewDivider::OnWindowDestroying(aura::Window* window) { ...@@ -413,6 +418,33 @@ void SplitViewDivider::OnWindowDestroying(aura::Window* window) {
RemoveObservedWindow(window); RemoveObservedWindow(window);
} }
void SplitViewDivider::OnWindowBoundsChanged(aura::Window* window,
const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds,
ui::PropertyChangeReason reason) {
// We only care about the bounds change of windows in
// |transient_windows_observer_|.
if (!transient_windows_observer_.IsObserving(window))
return;
// |window|'s transient parent must be one of the windows in
// |observed_windows_|.
aura::Window* transient_parent = nullptr;
for (auto* observed_window : observed_windows_) {
if (::wm::HasTransientAncestor(window, observed_window)) {
transient_parent = observed_window;
break;
}
}
DCHECK(transient_parent);
gfx::Rect transient_bounds = window->GetBoundsInScreen();
transient_bounds.AdjustToFit(transient_parent->GetBoundsInScreen());
window->SetBoundsInScreen(
transient_bounds,
display::Screen::GetScreen()->GetDisplayNearestWindow(window));
}
void SplitViewDivider::OnWindowActivated(ActivationReason reason, void SplitViewDivider::OnWindowActivated(ActivationReason reason,
aura::Window* gained_active, aura::Window* gained_active,
aura::Window* lost_active) { aura::Window* lost_active) {
...@@ -428,6 +460,26 @@ void SplitViewDivider::OnWindowActivated(ActivationReason reason, ...@@ -428,6 +460,26 @@ void SplitViewDivider::OnWindowActivated(ActivationReason reason,
} }
} }
void SplitViewDivider::OnTransientChildAdded(aura::Window* window,
aura::Window* transient) {
// For now, we only care about dialog bubbles type transient child. We may
// observe other types transient child window as well if need arises in the
// future.
views::Widget* widget = views::Widget::GetWidgetForNativeWindow(transient);
if (!widget || !widget->widget_delegate()->AsBubbleDialogDelegate())
return;
// At this moment, the transient window may not have the valid bounds yet.
// Start observe the transient window.
transient_windows_observer_.Add(transient);
}
void SplitViewDivider::OnTransientChildRemoved(aura::Window* window,
aura::Window* transient) {
if (transient_windows_observer_.IsObserving(transient))
transient_windows_observer_.Remove(transient);
}
void SplitViewDivider::CreateDividerWidget(aura::Window* root_window) { void SplitViewDivider::CreateDividerWidget(aura::Window* root_window) {
DCHECK(!divider_widget_); DCHECK(!divider_widget_);
// Native widget owns this widget. // Native widget owns this widget.
......
...@@ -9,12 +9,14 @@ ...@@ -9,12 +9,14 @@
#include "ash/ash_export.h" #include "ash/ash_export.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/scoped_observer.h"
#include "ui/aura/window.h" #include "ui/aura/window.h"
#include "ui/aura/window_observer.h" #include "ui/aura/window_observer.h"
#include "ui/display/display.h" #include "ui/display/display.h"
#include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/size.h"
#include "ui/wm/core/transient_window_observer.h"
#include "ui/wm/public/activation_change_observer.h" #include "ui/wm/public/activation_change_observer.h"
namespace views { namespace views {
...@@ -34,7 +36,8 @@ enum class OrientationLockType; ...@@ -34,7 +36,8 @@ enum class OrientationLockType;
// to resize the left and right windows accordingly. The divider widget should // to resize the left and right windows accordingly. The divider widget should
// always placed above its observed windows to be able to receive events. // always placed above its observed windows to be able to receive events.
class ASH_EXPORT SplitViewDivider : public aura::WindowObserver, class ASH_EXPORT SplitViewDivider : public aura::WindowObserver,
public ::wm::ActivationChangeObserver { public ::wm::ActivationChangeObserver,
public ::wm::TransientWindowObserver {
public: public:
SplitViewDivider(SplitViewController* controller, aura::Window* root_window); SplitViewDivider(SplitViewController* controller, aura::Window* root_window);
~SplitViewDivider() override; ~SplitViewDivider() override;
...@@ -74,6 +77,16 @@ class ASH_EXPORT SplitViewDivider : public aura::WindowObserver, ...@@ -74,6 +77,16 @@ class ASH_EXPORT SplitViewDivider : public aura::WindowObserver,
void OnWindowActivated(ActivationReason reason, void OnWindowActivated(ActivationReason reason,
aura::Window* gained_active, aura::Window* gained_active,
aura::Window* lost_active) override; aura::Window* lost_active) override;
void OnWindowBoundsChanged(aura::Window* window,
const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds,
ui::PropertyChangeReason reason) override;
// ::wm::TransientWindowObserver:
void OnTransientChildAdded(aura::Window* window,
aura::Window* transient) override;
void OnTransientChildRemoved(aura::Window* window,
aura::Window* transient) override;
views::Widget* divider_widget() { return divider_widget_; } views::Widget* divider_widget() { return divider_widget_; }
...@@ -101,6 +114,10 @@ class ASH_EXPORT SplitViewDivider : public aura::WindowObserver, ...@@ -101,6 +114,10 @@ class ASH_EXPORT SplitViewDivider : public aura::WindowObserver,
// Tracks observed windows. // Tracks observed windows.
aura::Window::Windows observed_windows_; aura::Window::Windows observed_windows_;
// Tracks observed transient windows.
ScopedObserver<aura::Window, aura::WindowObserver>
transient_windows_observer_{this};
DISALLOW_COPY_AND_ASSIGN(SplitViewDivider); DISALLOW_COPY_AND_ASSIGN(SplitViewDivider);
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment