diff options
author | oshima@chromium.org <oshima@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-08-01 11:45:29 +0000 |
---|---|---|
committer | oshima@chromium.org <oshima@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-08-01 11:45:29 +0000 |
commit | b42910f2a08d5eb08015f202c18bb05af1575125 (patch) | |
tree | 61b4c0ef2390fab101fa8d2f0f47a48ef77d2c45 | |
parent | 44ea8c724f68466ba84a574540f799085b69871e (diff) | |
download | chromium_src-b42910f2a08d5eb08015f202c18bb05af1575125.zip chromium_src-b42910f2a08d5eb08015f202c18bb05af1575125.tar.gz chromium_src-b42910f2a08d5eb08015f202c18bb05af1575125.tar.bz2 |
open new window in the same root window where the launcher was in
* Introduced ScopedRootWindowActivator to temporarily switch
active root window.
BUG=241571
TEST=covered by test
Review URL: https://chromiumcodereview.appspot.com/19945008
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@215000 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | ash/ash.gyp | 2 | ||||
-rw-r--r-- | ash/launcher/launcher_view.cc | 6 | ||||
-rw-r--r-- | ash/scoped_target_root_window.cc | 21 | ||||
-rw-r--r-- | ash/scoped_target_root_window.h | 33 | ||||
-rw-r--r-- | ash/shell.cc | 18 | ||||
-rw-r--r-- | ash/shell.h | 24 | ||||
-rw-r--r-- | chrome/browser/ui/window_sizer/window_sizer_ash.cc | 14 | ||||
-rw-r--r-- | chrome/browser/ui/window_sizer/window_sizer_ash_uitest.cc | 199 | ||||
-rw-r--r-- | chrome/chrome_tests.gypi | 1 |
9 files changed, 291 insertions, 27 deletions
diff --git a/ash/ash.gyp b/ash/ash.gyp index 29a3c38..dc8ee39 100644 --- a/ash/ash.gyp +++ b/ash/ash.gyp @@ -175,6 +175,8 @@ 'root_window_controller.h', 'rotator/screen_rotation.cc', 'rotator/screen_rotation.h', + 'scoped_target_root_window.cc', + 'scoped_target_root_window.h', 'screen_ash.cc', 'screen_ash.h', 'screensaver/screensaver_view.cc', diff --git a/ash/launcher/launcher_view.cc b/ash/launcher/launcher_view.cc index ede55d4..015ba3f 100644 --- a/ash/launcher/launcher_view.cc +++ b/ash/launcher/launcher_view.cc @@ -20,6 +20,7 @@ #include "ash/launcher/overflow_button.h" #include "ash/launcher/tabbed_launcher_button.h" #include "ash/root_window_controller.h" +#include "ash/scoped_target_root_window.h" #include "ash/shelf/shelf_layout_manager.h" #include "ash/shelf/shelf_widget.h" #include "ash/shell_delegate.h" @@ -1496,6 +1497,8 @@ void LauncherView::ButtonPressed(views::Button* sender, return; { + ScopedTargetRootWindow scoped_target( + sender->GetWidget()->GetNativeView()->GetRootWindow()); // Slow down activation animations if shift key is pressed. scoped_ptr<ui::ScopedAnimationDurationScaleMode> slowing_animations; if (event.IsShiftDown()) { @@ -1596,6 +1599,9 @@ void LauncherView::ShowMenu( launcher_menu_runner_.reset( new views::MenuRunner(menu_model_adapter->CreateMenu())); + ScopedTargetRootWindow scoped_target( + source->GetWidget()->GetNativeView()->GetRootWindow()); + // Determine the menu alignment dependent on the shelf. views::MenuItemView::AnchorPosition menu_alignment = views::MenuItemView::TOPLEFT; diff --git a/ash/scoped_target_root_window.cc b/ash/scoped_target_root_window.cc new file mode 100644 index 0000000..b488a6f --- /dev/null +++ b/ash/scoped_target_root_window.cc @@ -0,0 +1,21 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#include "ash/scoped_target_root_window.h" + +#include "ash/shell.h" + +namespace ash { +namespace internal { + +ScopedTargetRootWindow::ScopedTargetRootWindow( + aura::RootWindow* root_window) { + Shell::GetInstance()->scoped_target_root_window_ = root_window; +} + +ScopedTargetRootWindow::~ScopedTargetRootWindow() { + Shell::GetInstance()->scoped_target_root_window_ = NULL; +} + +} // namespace internal +} // namespace ash diff --git a/ash/scoped_target_root_window.h b/ash/scoped_target_root_window.h new file mode 100644 index 0000000..ab695be --- /dev/null +++ b/ash/scoped_target_root_window.h @@ -0,0 +1,33 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#ifndef ASH_SCOPED_TARGET_ROOT_WINDOW_H_ +#define ASH_SCOPED_TARGET_ROOT_WINDOW_H_ + +#include "base/basictypes.h" + +namespace aura { +class RootWindow; +} + +namespace ash { +namespace internal { + +// Constructing a ScopedTargetRootWindow allows temporarily +// switching a target root window so that a new window gets created +// in the same window where a user interaction happened. +// An example usage is to specify the target root window when creating +// a new window using launcher's icon. +class ScopedTargetRootWindow { + public: + explicit ScopedTargetRootWindow(aura::RootWindow* root_window); + ~ScopedTargetRootWindow(); + + private: + DISALLOW_COPY_AND_ASSIGN(ScopedTargetRootWindow); +}; + +} // namespace internal +} // namespace ash + +#endif // ASH_SCOPED_TARGET_ROOT_WINDOW_H_ diff --git a/ash/shell.cc b/ash/shell.cc index 1cf22a4..818b309 100644 --- a/ash/shell.cc +++ b/ash/shell.cc @@ -201,7 +201,8 @@ bool Shell::initially_hide_cursor_ = false; Shell::Shell(ShellDelegate* delegate) : screen_(new ScreenAsh), - active_root_window_(NULL), + target_root_window_(NULL), + scoped_target_root_window_(NULL), delegate_(delegate), activation_client_(NULL), #if defined(OS_CHROMEOS) && defined(USE_X11) @@ -249,8 +250,7 @@ Shell::~Shell() { // Remove the focus from any window. This will prevent overhead and side // effects (e.g. crashes) from changing focus during shutdown. // See bug crbug.com/134502. - if (active_root_window_) - aura::client::GetFocusClient(active_root_window_)->FocusWindow(NULL); + aura::client::GetFocusClient(GetPrimaryRootWindow())->FocusWindow(NULL); // Please keep in same order as in Init() because it's easy to miss one. RemovePreTargetHandler(event_rewriter_filter_.get()); @@ -386,7 +386,10 @@ aura::RootWindow* Shell::GetPrimaryRootWindow() { // static aura::RootWindow* Shell::GetActiveRootWindow() { - return GetInstance()->active_root_window_; + Shell* shell = GetInstance(); + if (shell->scoped_target_root_window_) + return shell->scoped_target_root_window_; + return shell->target_root_window_; } // static @@ -499,7 +502,7 @@ void Shell::Init() { display_controller_->Start(); display_controller_->InitPrimaryDisplay(); aura::RootWindow* root_window = display_controller_->GetPrimaryRootWindow(); - active_root_window_ = root_window; + target_root_window_ = root_window; cursor_manager_.SetDisplay(DisplayController::GetPrimaryDisplay()); @@ -883,7 +886,8 @@ void Shell::InitRootWindowForSecondaryDisplay(aura::RootWindow* root) { high_contrast_controller_->OnRootWindowAdded(root); root->ShowRootWindow(); // Activate new root for testing. - active_root_window_ = root; + // TODO(oshima): remove this. + target_root_window_ = root; // Create a launcher if a user is already logged. if (Shell::GetInstance()->session_state_delegate()->NumberOfLoggedInUsers()) @@ -970,7 +974,7 @@ void Shell::OnEvent(ui::Event* event) { void Shell::OnWindowActivated(aura::Window* gained_active, aura::Window* lost_active) { if (gained_active) - active_root_window_ = gained_active->GetRootWindow(); + target_root_window_ = gained_active->GetRootWindow(); } } // namespace ash diff --git a/ash/shell.h b/ash/shell.h index c2c1303..b6c669c 100644 --- a/ash/shell.h +++ b/ash/shell.h @@ -119,6 +119,7 @@ class OverlayEventFilter; class ResizeShadowController; class RootWindowController; class RootWindowLayoutManager; +class ScopedTargetRootWindow; class ScreenPositionController; class SlowAnimationEventFilter; class StatusAreaWidget; @@ -178,10 +179,12 @@ class ASH_EXPORT Shell // that has a launcher. static aura::RootWindow* GetPrimaryRootWindow(); - // Returns the active RootWindow. The active RootWindow is the one that - // contains the current active window as a decendant child. The active - // RootWindow remains the same even when the active window becomes NULL, - // until the another window who has a different root window becomes active. + // Returns a RootWindow when used as a target when creating a new window. + // The root window of the active window is used in most cases, but can + // be overridden by using ScopedTargetRootWindow(). + // If you want to get a RootWindow of the active window, just use + // |wm::GetActiveWindow()->GetRootWindow()|. + // TODO(oshima): Rename to GetTargetRootWindow() crbug.com/266378. static aura::RootWindow* GetActiveRootWindow(); // Returns the global Screen object that's always active in ash. @@ -206,8 +209,8 @@ class ASH_EXPORT Shell // application windows to be maximized only. static bool IsForcedMaximizeMode(); - void set_active_root_window(aura::RootWindow* active_root_window) { - active_root_window_ = active_root_window; + void set_active_root_window(aura::RootWindow* target_root_window) { + target_root_window_ = target_root_window; } // Shows the context menu for the background and launcher at @@ -473,6 +476,7 @@ class ASH_EXPORT Shell FRIEND_TEST_ALL_PREFIXES(WindowManagerTest, MouseEventCursors); FRIEND_TEST_ALL_PREFIXES(WindowManagerTest, TransformActivate); friend class internal::RootWindowController; + friend class internal::ScopedTargetRootWindow; friend class test::ShellTestApi; friend class shell::WindowWatcher; @@ -510,8 +514,12 @@ class ASH_EXPORT Shell ScreenAsh* screen_; - // Active root window. Never becomes NULL during the session. - aura::RootWindow* active_root_window_; + // When no explicit target display/RootWindow is given, new windows are + // created on |scoped_target_root_window_| , unless NULL in + // which case they are created on |target_root_window_|. + // |target_root_window_| never becomes NULL during the session. + aura::RootWindow* target_root_window_; + aura::RootWindow* scoped_target_root_window_; // The CompoundEventFilter owned by aura::Env object. scoped_ptr<views::corewm::CompoundEventFilter> env_filter_; diff --git a/chrome/browser/ui/window_sizer/window_sizer_ash.cc b/chrome/browser/ui/window_sizer/window_sizer_ash.cc index 4537423..a4ee1d1 100644 --- a/chrome/browser/ui/window_sizer/window_sizer_ash.cc +++ b/chrome/browser/ui/window_sizer/window_sizer_ash.cc @@ -135,15 +135,6 @@ bool MoveRect(const gfx::Rect& work_area, return false; } -// Adjust the |target_in_screen| rectangle so it moves as much as possible into -// the |work_area| . -void AdjustTargetRectVerticallyAgainstWorkspace(const gfx::Rect& work_area, - gfx::Rect* target_in_screen) { - if (target_in_screen->bottom() > work_area.bottom()) - target_in_screen->set_y(std::max(work_area.y(), - work_area.bottom() - target_in_screen->height())); -} - } // namespace // static @@ -205,8 +196,7 @@ bool WindowSizer::GetBoundsOverrideAsh(gfx::Rect* bounds_in_screen, if ((!count || !top_window)) { if (has_saved_bounds) { // Restore to previous state - if there is one. - AdjustTargetRectVerticallyAgainstWorkspace(work_area, - bounds_in_screen); + bounds_in_screen->AdjustToFit(work_area); return true; } // When using "small screens" we want to always open in full screen mode. @@ -239,7 +229,7 @@ bool WindowSizer::GetBoundsOverrideAsh(gfx::Rect* bounds_in_screen, bounds_in_screen->CenterPoint().x() < work_area.CenterPoint().x(); MoveRect(work_area, *bounds_in_screen, move_right); - AdjustTargetRectVerticallyAgainstWorkspace(work_area, bounds_in_screen); + bounds_in_screen->AdjustToFit(work_area); return true; } diff --git a/chrome/browser/ui/window_sizer/window_sizer_ash_uitest.cc b/chrome/browser/ui/window_sizer/window_sizer_ash_uitest.cc new file mode 100644 index 0000000..61f702d --- /dev/null +++ b/chrome/browser/ui/window_sizer/window_sizer_ash_uitest.cc @@ -0,0 +1,199 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/launcher/launcher.h" +#include "ash/launcher/launcher_view.h" +#include "ash/shell.h" +#include "base/command_line.h" +#include "base/message_loop/message_loop.h" +#include "chrome/browser/lifetime/application_lifetime.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_list.h" +#include "chrome/browser/ui/browser_window.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "ui/aura/root_window.h" +#include "ui/aura/test/event_generator.h" +#include "ui/base/test/ui_controls.h" +#include "ui/views/controls/menu/menu_controller.h" +#include "ui/views/view.h" +#include "ui/views/view_model.h" + +namespace { + +class WindowSizerTest : public InProcessBrowserTest { + public: + WindowSizerTest() {} + virtual ~WindowSizerTest() {} + + virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { + InProcessBrowserTest::SetUpCommandLine(command_line); + // Make screens sufficiently wide to host 2 browsers side by side. + command_line->AppendSwitchASCII("ash-host-window-bounds", + "600x600,601+0-600x600"); + } + + private: + DISALLOW_COPY_AND_ASSIGN(WindowSizerTest); +}; + +void CloseBrowser(Browser* browser) { + browser->window()->Close(); + base::MessageLoop::current()->RunUntilIdle(); +} + +gfx::Rect GetChromeIconBoundsForRootWindow(aura::RootWindow* root_window) { + ash::Launcher* launcher = ash::Launcher::ForWindow(root_window); + const ash::internal::LauncherView* launcher_view = + launcher->GetLauncherViewForTest(); + const views::ViewModel* view_model = launcher_view->view_model_for_test(); + + EXPECT_EQ(2, view_model->view_size()); + return view_model->view_at(0)->GetBoundsInScreen(); +} + +void OpenBrowserUsingShelfOnRootWindow(aura::RootWindow* root_window) { + aura::test::EventGenerator generator(root_window); + gfx::Point center = + GetChromeIconBoundsForRootWindow(root_window).CenterPoint(); + gfx::Display display = + ash::Shell::GetScreen()->GetDisplayNearestWindow(root_window); + const gfx::Point& origin = display.bounds().origin(); + center.Offset(- origin.x(), - origin.y()); + generator.MoveMouseTo(center); + generator.ClickLeftButton(); +} + +} // namespace + +#if defined(OS_WIN) +#define MAYBE_OpenBrowserUsingShelfOnOhterDisplay DISABLED_OpenBrowserUsingShelfOnOhterDisplay +#define MAYBE_OpenBrowserUsingContextMenuOnOhterDisplay DISABLED_OpenBrowserUsingContextMenuOnOhterDisplay +#else +#define MAYBE_OpenBrowserUsingShelfOnOhterDisplay OpenBrowserUsingShelfOnOhterDisplay +#define MAYBE_OpenBrowserUsingContextMenuOnOhterDisplay OpenBrowserUsingContextMenuOnOhterDisplay +#endif + +IN_PROC_BROWSER_TEST_F(WindowSizerTest, + MAYBE_OpenBrowserUsingShelfOnOhterDisplay) { + // Don't shutdown when closing the last browser window. + chrome::StartKeepAlive(); + + ash::Shell::RootWindowList root_windows = ash::Shell::GetAllRootWindows(); + + BrowserList* browser_list = + BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH); + + EXPECT_EQ(1u, browser_list->size()); + // Close the browser window so that clicking icon will create a new window. + CloseBrowser(browser_list->get(0)); + EXPECT_EQ(0u, browser_list->size()); + EXPECT_EQ(root_windows[0], ash::Shell::GetActiveRootWindow()); + + OpenBrowserUsingShelfOnRootWindow(root_windows[1]); + + // A new browser must be created on 2nd display. + EXPECT_EQ(1u, browser_list->size()); + EXPECT_EQ(root_windows[1], + browser_list->get(0)->window()->GetNativeWindow()->GetRootWindow()); + EXPECT_EQ(root_windows[1], ash::Shell::GetActiveRootWindow()); + + // Close the browser window so that clicking icon will create a new window. + CloseBrowser(browser_list->get(0)); + EXPECT_EQ(0u, browser_list->size()); + + OpenBrowserUsingShelfOnRootWindow(root_windows[0]); + + // A new browser must be created on 1st display. + EXPECT_EQ(1u, browser_list->size()); + EXPECT_EQ(root_windows[0], + browser_list->get(0)->window()->GetNativeWindow()->GetRootWindow()); + EXPECT_EQ(root_windows[0], ash::Shell::GetActiveRootWindow()); + + // Balanced with the chrome::StartKeepAlive above. + chrome::EndKeepAlive(); +} + +namespace { + +class WindowSizerContextMenuTest : public WindowSizerTest { + public: + WindowSizerContextMenuTest() {} + virtual ~WindowSizerContextMenuTest() {} + + static void Step1(gfx::Point release_point) { + ui_controls::SendMouseEventsNotifyWhenDone( + ui_controls::RIGHT, ui_controls::DOWN, + base::Bind(&WindowSizerContextMenuTest::Step2, release_point)); + } + + static void Step2(gfx::Point release_point) { + ui_controls::SendMouseMoveNotifyWhenDone( + release_point.x(), release_point.y(), + base::Bind(&WindowSizerContextMenuTest::Step3)); + } + + static void Step3() { + ui_controls::SendMouseEventsNotifyWhenDone( + ui_controls::RIGHT, ui_controls::UP, + base::Bind(&WindowSizerContextMenuTest::QuitLoop)); + } + + static void QuitLoop() { + base::MessageLoop::current()->PostTask( + FROM_HERE, + base::MessageLoop::QuitWhenIdleClosure()); + } + + private: + DISALLOW_COPY_AND_ASSIGN(WindowSizerContextMenuTest); +}; + +void OpenBrowserUsingContextMenuOnRootWindow(aura::RootWindow* root_window) { + gfx::Point chrome_icon = + GetChromeIconBoundsForRootWindow(root_window).CenterPoint(); + gfx::Point release_point = chrome_icon; + release_point.Offset(50, -120); + ui_controls::SendMouseMoveNotifyWhenDone( + chrome_icon.x(), chrome_icon.y(), + base::Bind(&WindowSizerContextMenuTest::Step1, release_point)); + base::MessageLoop::current()->Run(); +} + +} // namespace + +IN_PROC_BROWSER_TEST_F(WindowSizerContextMenuTest, + MAYBE_OpenBrowserUsingContextMenuOnOhterDisplay) { + // Don't shutdown when closing the last browser window. + chrome::StartKeepAlive(); + + views::MenuController::TurnOffContextMenuSelectionHoldForTest(); + + ash::Shell::RootWindowList root_windows = ash::Shell::GetAllRootWindows(); + + BrowserList* browser_list = + BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH); + + EXPECT_EQ(1u, browser_list->size()); + EXPECT_EQ(root_windows[0], ash::Shell::GetActiveRootWindow()); + CloseBrowser(browser_list->get(0)); + + OpenBrowserUsingContextMenuOnRootWindow(root_windows[1]); + + // A new browser must be created on 2nd display. + EXPECT_EQ(1u, browser_list->size()); + EXPECT_EQ(root_windows[1], + browser_list->get(0)->window()->GetNativeWindow()->GetRootWindow()); + EXPECT_EQ(root_windows[1], ash::Shell::GetActiveRootWindow()); + + OpenBrowserUsingContextMenuOnRootWindow(root_windows[0]); + + // Next new browser must be created on 1st display. + EXPECT_EQ(2u, browser_list->size()); + EXPECT_EQ(root_windows[0], + browser_list->get(1)->window()->GetNativeWindow()->GetRootWindow()); + EXPECT_EQ(root_windows[0], ash::Shell::GetActiveRootWindow()); + + // Balanced with the chrome::StartKeepAlive above. + chrome::EndKeepAlive(); +} diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index ced2f88..0f9ef56 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -329,6 +329,7 @@ ['use_ash==1', { 'sources': [ '../ash/drag_drop/drag_drop_interactive_uitest.cc', + 'browser/ui/window_sizer/window_sizer_ash_uitest.cc', ], }], ['OS=="linux" and toolkit_views==1', { |