Index: chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc |
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc |
index d4fc18e80b3eac8c62d1b5ee9b9f17abc9f7f52e..8dd8c709df56a3d987398c19c0ad049dfd63c789 100644 |
--- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc |
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc |
@@ -18,6 +18,7 @@ |
#include "base/strings/string_number_conversions.h" |
#include "build/build_config.h" |
#include "chrome/browser/chrome_notification_types.h" |
+#include "chrome/browser/platform_util.h" |
#include "chrome/browser/ui/browser.h" |
#include "chrome/browser/ui/browser_commands.h" |
#include "chrome/browser/ui/browser_list.h" |
@@ -172,6 +173,12 @@ void TabDragControllerTest::AddTabAndResetBrowser(Browser* browser) { |
AddBlankTabAndShow(browser); |
StopAnimating(GetTabStripForBrowser(browser)); |
ResetIDs(browser->tab_strip_model(), 0); |
+#if defined(OS_MACOSX) |
+ // Currently MacViews' browser windows are shown in the background anc could |
+ // be obscured by other windows if there are any. This should be fixed in |
+ // order to be consistent with other platforms. |
+ EXPECT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser)); |
+#endif // OS_MACOSX |
} |
Browser* TabDragControllerTest::CreateAnotherWindowBrowserAndRelayout() { |
@@ -182,7 +189,8 @@ Browser* TabDragControllerTest::CreateAnotherWindowBrowserAndRelayout() { |
// Resize the two windows so they're right next to each other. |
gfx::Rect work_area = |
gfx::Screen::GetScreen() |
- ->GetDisplayNearestWindow(browser()->window()->GetNativeWindow()) |
+ ->GetDisplayNearestWindow(platform_util::GetViewForWindow( |
+ browser()->window()->GetNativeWindow())) |
.work_area(); |
gfx::Size half_size = |
gfx::Size(work_area.width() / 3 - 10, work_area.height() / 2 - 10); |
@@ -250,7 +258,7 @@ class ScreenEventGeneratorDelegate |
#endif |
-#if !defined(OS_CHROMEOS) |
+#if !defined(OS_CHROMEOS) && defined(USE_AURA) |
// Following classes verify a crash scenario. Specifically on Windows when focus |
// changes it can trigger capture being lost. This was causing a crash in tab |
@@ -373,6 +381,9 @@ class DetachToBrowserTabDragControllerTest |
event_generator_.reset( |
new ui::test::EventGenerator(ash::Shell::GetPrimaryRootWindow())); |
#endif |
+#if defined(OS_MACOSX) |
+ EXPECT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); |
+#endif |
} |
InputSource input_source() const { |
@@ -863,7 +874,8 @@ IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, |
// Resize the browser window so that it is as big as the work area. |
gfx::Rect work_area = |
gfx::Screen::GetScreen() |
- ->GetDisplayNearestWindow(browser()->window()->GetNativeWindow()) |
+ ->GetDisplayNearestWindow(platform_util::GetViewForWindow( |
+ browser()->window()->GetNativeWindow())) |
.work_area(); |
browser()->window()->SetBounds(work_area); |
const gfx::Rect initial_bounds(browser()->window()->GetBounds()); |
@@ -1223,6 +1235,7 @@ IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, MAYBE_DragAll) { |
TabStrip* tab_strip = GetTabStripForBrowser(browser()); |
browser()->tab_strip_model()->AddTabAtToSelection(0); |
browser()->tab_strip_model()->AddTabAtToSelection(1); |
+ const gfx::Rect initial_bounds = browser()->window()->GetBounds(); |
// Move to the first tab and drag it enough so that it would normally |
// detach. |
@@ -1246,8 +1259,193 @@ IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, MAYBE_DragAll) { |
// Remaining browser window should not be maximized |
EXPECT_FALSE(browser()->window()->IsMaximized()); |
+ |
+ const gfx::Rect final_bounds = browser()->window()->GetBounds(); |
+ EXPECT_EQ(initial_bounds.size(), final_bounds.size()); |
+ EXPECT_EQ(initial_bounds.origin().x(), final_bounds.origin().x()); |
+ EXPECT_EQ(initial_bounds.origin().y() + GetDetachY(tab_strip), |
+ final_bounds.origin().y()); |
+} |
+ |
+#if defined(OS_MACOSX) |
+// Makes sure we can drag the window using WindowServer by dragging on a tab. |
+// |
+// All other tests move the windows without relying on the WindowServer, because |
+// BridgedNativeWidget::RunMoveLoop() immediately offsets the window on first |
+// mouse drag. If we generate more mouse move events after that, it's presumed |
+// that the WindowServer will move the window. In order for that to work we need |
+// to generate global CGEvents instead of app-specific NSEvents, that's what |
+// ui_test_utils::DragAndDrop() is for. |
+// |
+// If the WindowServer fails to move the window, the final window bounds won't |
+// match the expected ones. |
+IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, |
+ MacDragsWindowUsingCocoaMoveLoop) { |
+ // Add another tab. |
+ AddTabAndResetBrowser(browser()); |
+ |
+ TabStrip* tab_strip = GetTabStripForBrowser(browser()); |
+ browser()->tab_strip_model()->AddTabAtToSelection(0); |
+ browser()->tab_strip_model()->AddTabAtToSelection(1); |
+ const gfx::Rect initial_bounds = browser()->window()->GetBounds(); |
+ |
+ // Move to the first tab and drag it enough so that it would normally |
+ // detach. |
+ gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0))); |
+ |
+ // If we don't make the interactive_ui_tests the active application, we won't |
+ // be able to monitor NSMouseMoved events and ui_test_utils::DragAndDrop() |
+ // will deadlock. |
+ EXPECT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); |
+ |
+ // We need to move the window using multiple intermediate events in order |
+ // to verify that CocoaWindowMoveLoop is working correctly. |
+ const int steps = 10; |
+ ui_test_utils::DragAndDrop( |
+ tab_0_center, |
+ gfx::Point(tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip)), |
+ steps); |
+ |
+ // Should not be dragging. |
+ EXPECT_FALSE(tab_strip->IsDragSessionActive()); |
+ EXPECT_FALSE(TabDragController::IsActive()); |
+ EXPECT_FALSE(GetIsDragged(browser())); |
+ |
+ // And there should only be one window. |
+ EXPECT_EQ(1u, browser_list->size()); |
+ EXPECT_EQ("0 1", IDString(browser()->tab_strip_model())); |
+ |
+ // Remaining browser window should not be maximized |
+ EXPECT_FALSE(browser()->window()->IsMaximized()); |
+ |
+ const gfx::Rect final_bounds = browser()->window()->GetBounds(); |
+ EXPECT_EQ(initial_bounds.size(), final_bounds.size()); |
+ EXPECT_EQ(initial_bounds.origin().x(), final_bounds.origin().x()); |
+ EXPECT_EQ(initial_bounds.origin().y() + GetDetachY(tab_strip), |
+ final_bounds.origin().y()); |
} |
+// Tests that when the first mouse event that starts RunMoveLoop does not |
+// overlap the Mac menu bar. BridgedNativeWidget::RunMoveLoop() shifts both the |
+// mouse position and the expected window frame after detachment. |
+IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, |
+ MacDetachesWindowOnTopOfMacMenuBar) { |
+ // Add another tab. |
+ AddTabAndResetBrowser(browser()); |
+ |
+ // Make sure there's enough space to trigger detachment. |
+ TabStrip* tab_strip = GetTabStripForBrowser(browser()); |
+ browser()->window()->SetBounds(gfx::Rect(100, 100, 400, 200)); |
+ DCHECK_GT(browser()->window()->GetBounds().y(), GetDetachY(tab_strip)); |
+ |
+ // If we don't make the interactive_ui_tests the active application, we won't |
+ // be able to monitor NSMouseMoved events and ui_test_utils::DragAndDrop() |
+ // will deadlock. |
+ EXPECT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); |
+ |
+ gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0))); |
+ gfx::Point on_top_of_menu_bar(tab_0_center.x(), 0); |
+ ui_test_utils::DragAndDrop(tab_0_center, on_top_of_menu_bar); |
+ |
+ // Should not be dragging. |
+ EXPECT_FALSE(tab_strip->IsDragSessionActive()); |
+ EXPECT_FALSE(TabDragController::IsActive()); |
+ EXPECT_FALSE(GetIsDragged(browser())); |
+ |
+ // Second tab should successfully detach. |
+ EXPECT_EQ(2u, browser_list->size()); |
+ EXPECT_EQ("1", IDString(browser()->tab_strip_model())); |
+} |
+ |
+// Detaches and reattaches second tab. Will fail if detached window is not moved |
+// synchronously at the start of BridgedNativeWidget::RunMoveLoop(): the check |
+// for expected WindowServerFrame() will fail. |
+IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, |
+ MacDetachesAndReattachesSecondTab) { |
+ using ui_test_utils::DragAndDropOperation; |
+ |
+ // Add another tab. |
+ AddTabAndResetBrowser(browser()); |
+ |
+ TabStrip* tab_strip = GetTabStripForBrowser(browser()); |
+ browser()->window()->SetBounds(gfx::Rect(100, 100, 400, 200)); |
+ const gfx::Rect initial_bounds = browser()->window()->GetBounds(); |
+ |
+ gfx::Point tab_1_center(GetCenterInScreenCoordinates(tab_strip->tab_at(1))); |
+ gfx::Point tab_1_shake(tab_1_center.x(), |
+ tab_1_center.y() + GetDetachY(tab_strip) * 2); |
+ |
+ // If we don't make the interactive_ui_tests the active application, we won't |
+ // be able to monitor NSMouseMoved events and ui_test_utils::DragAndDrop() |
+ // will deadlock. |
+ EXPECT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); |
+ |
+ std::list<DragAndDropOperation> operations; |
+ operations.emplace_back(DragAndDropOperation::Move(tab_1_center)); |
+ operations.emplace_back(DragAndDropOperation::MouseDown()); |
+ operations.emplace_back(DragAndDropOperation::Move(tab_1_shake)); |
+ operations.emplace_back(DragAndDropOperation::Move(tab_1_center)); |
+ operations.emplace_back(DragAndDropOperation::MouseUp()); |
+ |
+ ui_test_utils::DragAndDrop(operations); |
+ |
+ // Should not be dragging. |
+ EXPECT_FALSE(tab_strip->IsDragSessionActive()); |
+ EXPECT_FALSE(TabDragController::IsActive()); |
+ EXPECT_FALSE(GetIsDragged(browser())); |
+ |
+ // And there should only be one window. |
+ EXPECT_EQ(1u, browser_list->size()); |
+ EXPECT_EQ("0 1", IDString(browser()->tab_strip_model())); |
+ |
+ // The window should remain in its original place. |
+ const gfx::Rect final_bounds = browser()->window()->GetBounds(); |
+ EXPECT_EQ(initial_bounds, final_bounds); |
+} |
+ |
+// Tests that when the first mouse event that starts RunMoveLoop does not |
+// overlap the Mac menu bar. BridgedNativeWidget::RunMoveLoop() shifts both the |
+// mouse position and the expected window frame after detachment. |
+IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, |
+ MacDetachesWindowAtTopOfScreen) { |
+ using ui_test_utils::DragAndDropOperation; |
+ |
+ // Add another tab. |
+ AddTabAndResetBrowser(browser()); |
+ |
+ // Make sure there's enough space to trigger detachment. |
+ TabStrip* tab_strip = GetTabStripForBrowser(browser()); |
+ browser()->window()->SetBounds(gfx::Rect(2500, 200, 400, 200)); |
+ DCHECK_GT(browser()->window()->GetBounds().y(), GetDetachY(tab_strip)); |
+ |
+ gfx::Point tab_0_center(GetCenterInScreenCoordinates(tab_strip->tab_at(0))); |
+ gfx::Point at_top_of_screen(tab_0_center.x(), 0); |
+ gfx::Point below_top_of_screen(tab_0_center.x(), 100); |
+ |
+ std::list<DragAndDropOperation> operations; |
+ operations.push_back(DragAndDropOperation::Move(tab_0_center)); |
+ operations.push_back(DragAndDropOperation::MouseDown()); |
+ operations.push_back(DragAndDropOperation::Move(at_top_of_screen)); |
+ operations.push_back(DragAndDropOperation::Move(below_top_of_screen)); |
+ operations.push_back(DragAndDropOperation::MouseUp()); |
+ ui_test_utils::DragAndDrop(operations); |
+ |
+ // Should not be dragging. |
+ EXPECT_FALSE(tab_strip->IsDragSessionActive()); |
+ EXPECT_FALSE(TabDragController::IsActive()); |
+ EXPECT_FALSE(GetIsDragged(browser())); |
+ |
+ // Second tab should successfully detach. |
+ EXPECT_EQ(2u, browser_list->size()); |
+ EXPECT_EQ("1", IDString(browser()->tab_strip_model())); |
+ |
+ Browser* browser2 = browser_list->get(1); |
+ EXPECT_EQ(browser2->window()->GetBounds().size(), |
+ browser()->window()->GetBounds().size()); |
+} |
+ |
+#endif // OS_MACOSX |
+ |
namespace { |
// Invoked from the nested message loop. |
@@ -1476,6 +1674,8 @@ IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, |
TabStrip* tab_strip2 = GetTabStripForBrowser(browser2); |
const gfx::Rect initial_bounds(browser2->window()->GetBounds()); |
+ EXPECT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); |
+ |
// Move to the first tab and drag it enough so that it detaches, but not |
// enough that it attaches to browser2. |
gfx::Point tab_0_center( |
@@ -1523,12 +1723,8 @@ void CancelOnNewTabWhenDraggingStep2( |
// Add another tab. This should trigger exiting the nested loop. Add at the |
// to exercise past crash when model/tabstrip got out of sync (474082). |
- content::WindowedNotificationObserver observer( |
- content::NOTIFICATION_LOAD_STOP, |
- content::NotificationService::AllSources()); |
chrome::AddTabAt(browser_list->GetLastActive(), GURL(url::kAboutBlankURL), |
0, false); |
- observer.Wait(); |
} |
} // namespace |
@@ -1553,10 +1749,18 @@ IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest, |
gfx::Point tab_0_center( |
GetCenterInScreenCoordinates(tab_strip->tab_at(0))); |
ASSERT_TRUE(PressInput(tab_0_center)); |
+ content::WindowedNotificationObserver observer( |
+ content::NOTIFICATION_LOAD_STOP, |
+ content::NotificationService::AllSources()); |
ASSERT_TRUE(DragInputToNotifyWhenDone( |
tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip), |
base::Bind(&CancelOnNewTabWhenDraggingStep2, this, browser_list))); |
- QuitWhenNotDragging(); |
+ observer.Wait(); |
+ |
+ // On MacViews the Drag ends while waiting for NOTIFICATION_LOAD_STOP. |
+ if (TabDragController::IsActive()) { |
+ QuitWhenNotDragging(); |
+ } |
// Should be two windows and not dragging. |
ASSERT_FALSE(TabDragController::IsActive()); |
@@ -2142,6 +2346,7 @@ class DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest |
} |
void QuitWhenNotDragging() { |
+ DCHECK(TabDragController::IsActive()); |
test::QuitWhenNotDraggingImpl(); |
base::MessageLoop::current()->Run(); |
} |