Commit cea2b789 authored by Avery Musbach's avatar Avery Musbach Committed by Commit Bot

overview: Allow dragging windows on nonprimary displays in tablet mode

In tablet mode, if you start to drag a window from the top of a
nonprimary display, before the present CL, the functionality is
completely broken. You do not even see the window. If you try to drag a
window from overview on a nonprimary display, before the present CL, the
drop target is created on the primary display. After the present CL,
dragging a window (either from the top or from overview) on a nonprimary
display shall be similar to dragging a window on the primary display.
Future work will address functionality where a window is dragged from
one display to another.

Test: ash_unittests OverviewSessionTest.*
Bug: 916856, 964063
Change-Id: Iddbafc7b289ab2f711db47ebaf18bfcfcda2539c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1617906
Commit-Queue: Avery Musbach <amusbach@chromium.org>
Reviewed-by: default avatarMitsuru Oshima <oshima@chromium.org>
Reviewed-by: default avatarXiaoqian Dai <xdai@chromium.org>
Cr-Commit-Position: refs/heads/master@{#661110}
parent a7614c0c
......@@ -182,14 +182,17 @@ class ShutdownAnimationFpsCounterObserver : public OverviewObserver {
std::unique_ptr<views::Widget> CreateDropTargetWidget(
aura::Window* dragged_window,
bool animate) {
aura::Window* parent = dragged_window->parent();
gfx::Rect bounds = dragged_window->bounds();
::wm::ConvertRectToScreen(parent, &bounds);
views::Widget::InitParams params;
params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS;
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.activatable = views::Widget::InitParams::Activatable::ACTIVATABLE_NO;
params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
params.accept_events = false;
params.parent = dragged_window->parent();
params.bounds = dragged_window->bounds();
params.parent = parent;
params.bounds = bounds;
auto widget = std::make_unique<views::Widget>();
widget->set_focus_on_creation(false);
widget->Init(params);
......@@ -581,11 +584,7 @@ void OverviewGrid::AddItem(aura::Window* window,
const base::flat_set<OverviewItem*>& ignored_items,
size_t index) {
DCHECK(!GetOverviewItemContaining(window));
// When an overview item is dragged, this function might be called on the
// wrong grid. See http://crbug.com/916856.
if (index > window_list_.size())
index = 0u;
DCHECK_LE(index, window_list_.size());
window_observer_.Add(window);
window_state_observer_.Add(wm::GetWindowState(window));
......@@ -634,27 +633,17 @@ void OverviewGrid::AddDropTargetForDraggingFromOverview(
overview_session_->AddItem(drop_target_widget_->GetNativeWindow(),
/*reposition=*/true, /*animate=*/false,
/*ignored_items=*/{dragged_item}, position);
OverviewItem* drop_target = GetDropTarget();
// See the comment in RemoveDropTarget() for how |drop_target| can be null.
if (drop_target) {
// This part is necessary because |OverviewItem::OnSelectorItemDragStarted|
// is called on all overview items before the drop target exists among them.
// That is because |AddDropTargetForDraggingFromOverview| is only called for
// drag to snap, but |OnSelectorItemDragStarted| is called before the drag
// has been disambiguated between drag to close and drag to snap.
drop_target->OnSelectorItemDragStarted(dragged_item);
}
// This part is necessary because |OverviewItem::OnSelectorItemDragStarted| is
// called on all overview items before the drop target exists among them. That
// is because |AddDropTargetForDraggingFromOverview| is only called for drag
// to snap, but |OnSelectorItemDragStarted| is called before the drag has been
// disambiguated between drag to close and drag to snap.
GetDropTarget()->OnSelectorItemDragStarted(dragged_item);
}
void OverviewGrid::RemoveDropTarget() {
DCHECK(drop_target_widget_);
OverviewItem* drop_target = GetDropTarget();
// TODO(http://crbug.com/916856): Disable tab and app dragging that doesn't
// happen in the primary display.
// The |drop_target_widget_| may be not in the same display as the dragged
// window/item, which will cause |drop_target| to be null.
if (drop_target)
overview_session_->RemoveItem(drop_target);
overview_session_->RemoveItem(GetDropTarget());
drop_target_widget_.reset();
}
......
......@@ -970,7 +970,8 @@ void OverviewItem::SetItemBounds(const gfx::RectF& target_bounds,
screen_rect, target_bounds, top_view_inset, kHeaderHeightDp);
// Do not set transform for drop target, set bounds instead.
if (overview_grid_->IsDropTargetWindow(window)) {
window->layer()->SetBounds(gfx::ToEnclosedRect(overview_item_bounds));
window->SetBoundsInScreen(gfx::ToEnclosedRect(overview_item_bounds),
wm::GetWindowState(window)->GetDisplay());
window->SetTransform(gfx::Transform());
return;
}
......
......@@ -1240,6 +1240,109 @@ TEST_F(OverviewSessionTest, RemoveDisplayWithAnimation) {
EXPECT_FALSE(InOverviewSession());
}
// Tests that dragging a window from the top of a display creates a drop target
// on that display.
TEST_F(OverviewSessionTest, DropTargetOnCorrectDisplayForDraggingFromTop) {
UpdateDisplay("600x600,600x600");
EnterTabletMode();
// DisplayConfigurationObserver enables mirror mode when tablet mode is
// enabled. Disable mirror mode to test multiple displays.
display_manager()->SetMirrorMode(display::MirrorMode::kOff, base::nullopt);
base::RunLoop().RunUntilIdle();
const aura::Window::Windows root_windows = Shell::Get()->GetAllRootWindows();
ASSERT_EQ(2u, root_windows.size());
std::unique_ptr<aura::Window> primary_screen_window =
CreateTestWindow(gfx::Rect(0, 0, 600, 600));
primary_screen_window->SetProperty(aura::client::kAppType,
static_cast<int>(AppType::BROWSER));
ASSERT_EQ(root_windows[0], primary_screen_window->GetRootWindow());
std::unique_ptr<aura::Window> secondary_screen_window =
CreateTestWindow(gfx::Rect(600, 0, 600, 600));
secondary_screen_window->SetProperty(aura::client::kAppType,
static_cast<int>(AppType::BROWSER));
ASSERT_EQ(root_windows[1], secondary_screen_window->GetRootWindow());
ASSERT_FALSE(InOverviewSession());
{
std::unique_ptr<WindowResizer> resizer =
CreateWindowResizer(primary_screen_window.get(), gfx::Point(400, 0),
HTCAPTION, ::wm::WINDOW_MOVE_SOURCE_TOUCH);
ASSERT_TRUE(InOverviewSession());
EXPECT_FALSE(GetDropTarget(1));
ASSERT_TRUE(GetDropTarget(0));
EXPECT_EQ(root_windows[0], GetDropTarget(0)->root_window());
resizer->CompleteDrag();
}
ASSERT_FALSE(InOverviewSession());
{
std::unique_ptr<WindowResizer> resizer =
CreateWindowResizer(secondary_screen_window.get(), gfx::Point(400, 0),
HTCAPTION, ::wm::WINDOW_MOVE_SOURCE_TOUCH);
ASSERT_TRUE(InOverviewSession());
EXPECT_FALSE(GetDropTarget(0));
ASSERT_TRUE(GetDropTarget(1));
EXPECT_EQ(root_windows[1], GetDropTarget(1)->root_window());
resizer->CompleteDrag();
}
ASSERT_FALSE(InOverviewSession());
}
// Tests that dragging a window from overview creates a drop target on the same
// display.
TEST_F(OverviewSessionTest, DropTargetOnCorrectDisplayForDraggingFromOverview) {
UpdateDisplay("600x600,600x600");
EnterTabletMode();
// DisplayConfigurationObserver enables mirror mode when tablet mode is
// enabled. Disable mirror mode to test multiple displays.
display_manager()->SetMirrorMode(display::MirrorMode::kOff, base::nullopt);
base::RunLoop().RunUntilIdle();
const aura::Window::Windows root_windows = Shell::Get()->GetAllRootWindows();
ASSERT_EQ(2u, root_windows.size());
std::unique_ptr<aura::Window> primary_screen_window =
CreateTestWindow(gfx::Rect(0, 0, 600, 600));
ASSERT_EQ(root_windows[0], primary_screen_window->GetRootWindow());
std::unique_ptr<aura::Window> secondary_screen_window =
CreateTestWindow(gfx::Rect(600, 0, 600, 600));
ASSERT_EQ(root_windows[1], secondary_screen_window->GetRootWindow());
ToggleOverview();
OverviewItem* primary_screen_item =
GetWindowItemForWindow(0, primary_screen_window.get());
OverviewItem* secondary_screen_item =
GetWindowItemForWindow(1, secondary_screen_window.get());
EXPECT_FALSE(GetDropTarget(0));
EXPECT_FALSE(GetDropTarget(1));
gfx::PointF drag_point = primary_screen_item->target_bounds().CenterPoint();
overview_session()->InitiateDrag(primary_screen_item, drag_point);
EXPECT_FALSE(GetDropTarget(0));
EXPECT_FALSE(GetDropTarget(1));
drag_point.Offset(5.f, 0.f);
overview_session()->Drag(primary_screen_item, drag_point);
EXPECT_FALSE(GetDropTarget(1));
ASSERT_TRUE(GetDropTarget(0));
EXPECT_EQ(root_windows[0], GetDropTarget(0)->root_window());
overview_session()->CompleteDrag(primary_screen_item, drag_point);
EXPECT_FALSE(GetDropTarget(0));
EXPECT_FALSE(GetDropTarget(1));
drag_point = secondary_screen_item->target_bounds().CenterPoint();
overview_session()->InitiateDrag(secondary_screen_item, drag_point);
EXPECT_FALSE(GetDropTarget(0));
EXPECT_FALSE(GetDropTarget(1));
drag_point.Offset(5.f, 0.f);
overview_session()->Drag(secondary_screen_item, drag_point);
EXPECT_FALSE(GetDropTarget(0));
ASSERT_TRUE(GetDropTarget(1));
EXPECT_EQ(root_windows[1], GetDropTarget(1)->root_window());
overview_session()->CompleteDrag(secondary_screen_item, drag_point);
EXPECT_FALSE(GetDropTarget(0));
EXPECT_FALSE(GetDropTarget(1));
}
namespace {
// A simple window delegate that returns the specified hit-test code when
......
......@@ -409,7 +409,8 @@ void TabletModeWindowDragDelegate::UpdateDraggedWindowTransform(
scale = (1.0f - scale) * y_diff / y_full + scale;
gfx::Transform transform;
const gfx::Rect window_bounds = dragged_window_->bounds();
gfx::Rect window_bounds = dragged_window_->bounds();
::wm::ConvertRectToScreen(dragged_window_->parent(), &window_bounds);
transform.Translate(
(location_in_screen.x() - window_bounds.x()) -
(initial_location_in_screen_.x() - window_bounds.x()) * scale,
......
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