diff options
author | oshima@chromium.org <oshima@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-21 14:27:57 +0000 |
---|---|---|
committer | oshima@chromium.org <oshima@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-21 14:27:57 +0000 |
commit | f059c6946d6c3a29e8d7fc7435ec16a33110eefa (patch) | |
tree | 9021517ace5019264959b0ad836845c2d38de2bc | |
parent | f6988625efcda9a87181724c0d108928b3c35fb1 (diff) | |
download | chromium_src-f059c6946d6c3a29e8d7fc7435ec16a33110eefa.zip chromium_src-f059c6946d6c3a29e8d7fc7435ec16a33110eefa.tar.gz chromium_src-f059c6946d6c3a29e8d7fc7435ec16a33110eefa.tar.bz2 |
Move a window if the sceren bounds being set is in other display.
- Fix StackingController::GetDefaultParent so that it uses
the same root window as its transient parent.
- Updated WorkspaceWindowResizer to move the dragged window to other display if the new destination matches it. This is short term, temporary solution until better drag&drop is implemented.
BUG=123160
TEST=ExtendedDesktopTest.MoveWindow/MoveWindowWithTransient
Review URL: https://chromiumcodereview.appspot.com/10795027
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@147798 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | ash/display/screen_position_controller.cc | 80 | ||||
-rw-r--r-- | ash/extended_desktop_unittest.cc | 103 | ||||
-rw-r--r-- | ash/root_window_controller.cc | 6 | ||||
-rw-r--r-- | ash/shell.cc | 12 | ||||
-rw-r--r-- | ash/wm/stacking_controller.cc | 44 | ||||
-rw-r--r-- | ash/wm/stacking_controller.h | 13 | ||||
-rw-r--r-- | ash/wm/system_modal_container_layout_manager.cc | 8 | ||||
-rw-r--r-- | ash/wm/system_modal_container_layout_manager.h | 3 | ||||
-rw-r--r-- | ash/wm/workspace/workspace_window_resizer.cc | 24 | ||||
-rw-r--r-- | ui/aura/window.cc | 4 |
10 files changed, 257 insertions, 40 deletions
diff --git a/ash/display/screen_position_controller.cc b/ash/display/screen_position_controller.cc index 3c464b4..80091ef 100644 --- a/ash/display/screen_position_controller.cc +++ b/ash/display/screen_position_controller.cc @@ -5,13 +5,50 @@ #include "ash/display/screen_position_controller.h" #include "ash/display/display_controller.h" +#include "ash/shell.h" #include "ash/shell_window_ids.h" +#include "ash/wm/system_modal_container_layout_manager.h" #include "ash/wm/window_properties.h" +#include "ui/aura/client/activation_client.h" +#include "ui/aura/client/capture_client.h" +#include "ui/aura/client/stacking_client.h" +#include "ui/aura/focus_manager.h" #include "ui/aura/root_window.h" +#include "ui/aura/window_tracker.h" #include "ui/gfx/display.h" #include "ui/gfx/screen.h" namespace ash { +namespace { + +// Move all transient children to |dst_root|, including the ones in +// the child windows and transient children of the transient children. +void MoveAllTransientChildrenToNewRoot(aura::RootWindow* dst_root, + aura::Window* window) { + aura::Window::Windows transient_children = window->transient_children(); + for (aura::Window::Windows::iterator iter = transient_children.begin(); + iter != transient_children.end(); ++iter) { + aura::Window* transient_child = *iter; + int container_id = transient_child->parent()->id(); + DCHECK_GE(container_id, 0); + aura::Window* container = Shell::GetContainer(dst_root, container_id); + gfx::Rect parent_bounds_in_screen = transient_child->GetBoundsInScreen(); + container->AddChild(transient_child); + transient_child->SetBoundsInScreen(parent_bounds_in_screen); + + // Transient children may have transient children. + MoveAllTransientChildrenToNewRoot(dst_root, + transient_child); + } + // Move transient children of the child windows if any. + aura::Window::Windows children = window->children(); + for (aura::Window::Windows::iterator iter = children.begin(); + iter != children.end(); ++iter) + MoveAllTransientChildrenToNewRoot(dst_root, *iter); +} + +} // namespace + namespace internal { void ScreenPositionController::ConvertPointToScreen( @@ -48,9 +85,46 @@ void ScreenPositionController::SetBounds( window->SetBounds(bounds); return; } - // TODO(oshima): Pick the new root window that most closely shares - // the bounds. For a new widget, NativeWidgetAura picks the right - // root window. + + // Don't move a transient windows to other root window. + // It moves when its transient_parent moves. + if (!window->transient_parent()) { + aura::RootWindow* dst_root = Shell::GetRootWindowMatching(bounds); + aura::Window* dst_container = NULL; + if (dst_root != window->GetRootWindow()) { + int container_id = window->parent()->id(); + // All containers that uses screen coordinates must have valid + // window ids. + DCHECK_GE(container_id, 0); + // Don't move modal screen. + if (!SystemModalContainerLayoutManager::IsModalScreen(window)) + dst_container = Shell::GetContainer(dst_root, container_id); + } + + if (dst_container && window->parent() != dst_container) { + aura::Window* focused = window->GetFocusManager()->GetFocusedWindow(); + aura::client::ActivationClient* activation_client = + aura::client::GetActivationClient(window->GetRootWindow()); + aura::Window* active = activation_client->GetActiveWindow(); + + aura::WindowTracker tracker; + if (focused) + tracker.Add(focused); + if (active && focused != active) + tracker.Add(active); + + dst_container->AddChild(window); + + MoveAllTransientChildrenToNewRoot(dst_root, window); + + // Restore focused/active window. + if (tracker.Contains(focused)) + window->GetFocusManager()->SetFocusedWindow(focused, NULL); + else if (tracker.Contains(active)) + activation_client->ActivateWindow(active); + } + } + gfx::Point origin(bounds.origin()); const gfx::Point display_origin = gfx::Screen::GetDisplayNearestWindow(window).bounds().origin(); diff --git a/ash/extended_desktop_unittest.cc b/ash/extended_desktop_unittest.cc index d4cce05..179055e 100644 --- a/ash/extended_desktop_unittest.cc +++ b/ash/extended_desktop_unittest.cc @@ -24,15 +24,23 @@ namespace ash { namespace { -views::Widget* CreateTestWidget(const gfx::Rect& bounds) { +views::Widget* CreateTestWidgetWithParent(views::Widget* parent, + const gfx::Rect& bounds, + bool child) { views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); + params.parent_widget = parent; params.bounds = bounds; + params.child = child; views::Widget* widget = new views::Widget; widget->Init(params); widget->Show(); return widget; } +views::Widget* CreateTestWidget(const gfx::Rect& bounds) { + return CreateTestWidgetWithParent(NULL, bounds, false); +} + class ModalWidgetDelegate : public views::WidgetDelegateView { public: ModalWidgetDelegate() {} @@ -345,6 +353,99 @@ TEST_F(ExtendedDesktopTest, Capture) { EXPECT_EQ("0 0", r1_d2.GetMouseButtonCountsAndReset()); } +TEST_F(ExtendedDesktopTest, MoveWindow) { + internal::DisplayController::SetVirtualScreenCoordinatesEnabled(true); + UpdateDisplay("0+0-1000x600,1001+0-600x400"); + Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); + views::Widget* d1 = CreateTestWidget(gfx::Rect(10, 10, 100, 100)); + + EXPECT_EQ(root_windows[0], d1->GetNativeView()->GetRootWindow()); + + d1->SetBounds(gfx::Rect(1010, 10, 100, 100)); + EXPECT_EQ("1010,10 100x100", + d1->GetWindowBoundsInScreen().ToString()); + + EXPECT_EQ(root_windows[1], d1->GetNativeView()->GetRootWindow()); + + d1->SetBounds(gfx::Rect(10, 10, 100, 100)); + EXPECT_EQ("10,10 100x100", + d1->GetWindowBoundsInScreen().ToString()); + + EXPECT_EQ(root_windows[0], d1->GetNativeView()->GetRootWindow()); + + // Make sure the bounds which doesn't fit to the root window + // works correctly. + d1->SetBounds(gfx::Rect(1560, 30, 100, 100)); + EXPECT_EQ(root_windows[1], d1->GetNativeView()->GetRootWindow()); + EXPECT_EQ("1560,30 100x100", + d1->GetWindowBoundsInScreen().ToString()); + + // Setting outside of root windows will be moved to primary root window. + // TODO(oshima): This one probably should pick the closest root window. + d1->SetBounds(gfx::Rect(200, 10, 100, 100)); + EXPECT_EQ(root_windows[0], d1->GetNativeView()->GetRootWindow()); + + internal::DisplayController::SetVirtualScreenCoordinatesEnabled(false); +} + +TEST_F(ExtendedDesktopTest, MoveWindowWithTransient) { + internal::DisplayController::SetVirtualScreenCoordinatesEnabled(true); + UpdateDisplay("0+0-1000x600,1001+0-600x400"); + Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); + views::Widget* w1 = CreateTestWidget(gfx::Rect(10, 10, 100, 100)); + views::Widget* w1_t1 = CreateTestWidgetWithParent( + w1, gfx::Rect(50, 50, 50, 50), false /* transient */); + // Transient child of the transient child. + views::Widget* w1_t11 = CreateTestWidgetWithParent( + w1_t1, gfx::Rect(1200, 70, 30, 30), false /* transient */); + + views::Widget* w11 = CreateTestWidgetWithParent( + w1, gfx::Rect(10, 10, 40, 40), true /* child */); + views::Widget* w11_t1 = CreateTestWidgetWithParent( + w1, gfx::Rect(1300, 100, 80, 80), false /* transient */); + + EXPECT_EQ(root_windows[0], w1->GetNativeView()->GetRootWindow()); + EXPECT_EQ(root_windows[0], w11->GetNativeView()->GetRootWindow()); + EXPECT_EQ(root_windows[0], w1_t1->GetNativeView()->GetRootWindow()); + EXPECT_EQ(root_windows[0], w1_t11->GetNativeView()->GetRootWindow()); + EXPECT_EQ(root_windows[0], w11_t1->GetNativeView()->GetRootWindow()); + EXPECT_EQ("50,50 50x50", + w1_t1->GetWindowBoundsInScreen().ToString()); + EXPECT_EQ("1200,70 30x30", + w1_t11->GetWindowBoundsInScreen().ToString()); + EXPECT_EQ("20,20 40x40", + w11->GetWindowBoundsInScreen().ToString()); + EXPECT_EQ("1300,100 80x80", + w11_t1->GetWindowBoundsInScreen().ToString()); + + w1->SetBounds(gfx::Rect(1100,10,100,100)); + + EXPECT_EQ(root_windows[1], w1_t1->GetNativeView()->GetRootWindow()); + EXPECT_EQ(root_windows[1], w1_t1->GetNativeView()->GetRootWindow()); + EXPECT_EQ(root_windows[1], w1_t11->GetNativeView()->GetRootWindow()); + EXPECT_EQ(root_windows[1], w11->GetNativeView()->GetRootWindow()); + EXPECT_EQ(root_windows[1], w11_t1->GetNativeView()->GetRootWindow()); + + EXPECT_EQ("1110,20 40x40", + w11->GetWindowBoundsInScreen().ToString()); + // Transient window's screen bounds stays the same. + EXPECT_EQ("50,50 50x50", + w1_t1->GetWindowBoundsInScreen().ToString()); + EXPECT_EQ("1200,70 30x30", + w1_t11->GetWindowBoundsInScreen().ToString()); + EXPECT_EQ("1300,100 80x80", + w11_t1->GetWindowBoundsInScreen().ToString()); + + // Transient window doesn't move between root window unless + // its transient parent moves. + w1_t1->SetBounds(gfx::Rect(10, 50, 50, 50)); + EXPECT_EQ(root_windows[1], w1_t1->GetNativeView()->GetRootWindow()); + EXPECT_EQ("10,50 50x50", + w1_t1->GetWindowBoundsInScreen().ToString()); + + internal::DisplayController::SetVirtualScreenCoordinatesEnabled(false); +} + namespace internal { // Test if the Window::ConvertPointToWindow works across root windows. // TODO(oshima): Move multiple display suport and this test to aura. diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc index 0ef08bc..ef046bd 100644 --- a/ash/root_window_controller.cc +++ b/ash/root_window_controller.cc @@ -70,11 +70,9 @@ void MoveAllWindows(aura::RootWindow* src, iter != children.end(); ++iter) { aura::Window* window = *iter; // Don't move modal screen. - if ((id == internal::kShellWindowId_SystemModalContainer || - id == internal::kShellWindowId_LockSystemModalContainer) && - window->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_NONE) { + if (internal::SystemModalContainerLayoutManager::IsModalScreen(window)) continue; - } + // Update the restore bounds to make it relative to the display. gfx::Rect restore_bounds; if (internal::DisplayController::IsVirtualScreenCoordinatesEnabled()) diff --git a/ash/shell.cc b/ash/shell.cc index 2590195..630d44e 100644 --- a/ash/shell.cc +++ b/ash/shell.cc @@ -33,6 +33,7 @@ #include "ash/tooltips/tooltip_controller.h" #include "ash/touch/touch_observer_hud.h" #include "ash/wm/activation_controller.h" +#include "ash/wm/always_on_top_controller.h" #include "ash/wm/app_list_controller.h" #include "ash/wm/base_layout_manager.h" #include "ash/wm/capture_controller.h" @@ -60,6 +61,7 @@ #include "ash/wm/window_cycle_controller.h" #include "ash/wm/window_modality_controller.h" #include "ash/wm/window_util.h" +#include "ash/wm/window_properties.h" #include "ash/wm/workspace/workspace_event_filter.h" #include "ash/wm/workspace/workspace_layout_manager.h" #include "ash/wm/workspace/workspace_manager.h" @@ -720,6 +722,16 @@ void Shell::InitRootWindowController( root_window->SetCursor(ui::kCursorPointer); controller->InitLayoutManagers(); + + // TODO(oshima): Move the instance to RootWindowController when + // the extended desktop is enabled by default. + internal::AlwaysOnTopController* always_on_top_controller = + new internal::AlwaysOnTopController; + always_on_top_controller->SetContainers( + root_window->GetChildById(internal::kShellWindowId_DefaultContainer), + root_window->GetChildById(internal::kShellWindowId_AlwaysOnTopContainer)); + root_window->SetProperty(internal::kAlwaysOnTopControllerKey, + always_on_top_controller); } //////////////////////////////////////////////////////////////////////////////// diff --git a/ash/wm/stacking_controller.cc b/ash/wm/stacking_controller.cc index 6d44525..71c3bde 100644 --- a/ash/wm/stacking_controller.cc +++ b/ash/wm/stacking_controller.cc @@ -31,8 +31,8 @@ aura::RootWindow* FindContainerRoot(const gfx::Rect& bounds) { return Shell::GetRootWindowMatching(bounds); } -aura::Window* GetContainerById(const gfx::Rect& bounds, int id) { - return Shell::GetContainer(FindContainerRoot(bounds), id); +aura::Window* GetContainerById(aura::RootWindow* root, int id) { + return Shell::GetContainer(root, id); } aura::Window* GetContainerForWindow(aura::Window* window) { @@ -68,24 +68,34 @@ StackingController::~StackingController() { aura::Window* StackingController::GetDefaultParent(aura::Window* window, const gfx::Rect& bounds) { + aura::RootWindow* target_root = NULL; + if (window->transient_parent()) { + // Transient window should use the same root as its transient parent. + target_root = window->transient_parent()->GetRootWindow(); + } else { + target_root = FindContainerRoot(bounds); + } + switch (window->type()) { case aura::client::WINDOW_TYPE_NORMAL: case aura::client::WINDOW_TYPE_POPUP: if (IsSystemModal(window)) - return GetSystemModalContainer(window, bounds); + return GetSystemModalContainer(target_root, window); else if (IsWindowModal(window)) return GetContainerForWindow(window->transient_parent()); - return GetAlwaysOnTopController(bounds)->GetContainer(window); + return GetAlwaysOnTopController(target_root)->GetContainer(window); case aura::client::WINDOW_TYPE_PANEL: - return GetContainerById(bounds, internal::kShellWindowId_PanelContainer); + return GetContainerById(target_root, + internal::kShellWindowId_PanelContainer); case aura::client::WINDOW_TYPE_MENU: - return GetContainerById(bounds, internal::kShellWindowId_MenuContainer); + return GetContainerById( + target_root, internal::kShellWindowId_MenuContainer); case aura::client::WINDOW_TYPE_TOOLTIP: return GetContainerById( - bounds, internal::kShellWindowId_DragImageAndTooltipContainer); + target_root, internal::kShellWindowId_DragImageAndTooltipContainer); case aura::client::WINDOW_TYPE_CONTROL: return GetContainerById( - bounds, internal::kShellWindowId_UnparentedControlContainer); + target_root, internal::kShellWindowId_UnparentedControlContainer); default: NOTREACHED() << "Window " << window->id() << " has unhandled type " << window->type(); @@ -98,17 +108,16 @@ aura::Window* StackingController::GetDefaultParent(aura::Window* window, // StackingController, private: aura::Window* StackingController::GetSystemModalContainer( - aura::Window* window, - const gfx::Rect& bounds) const { + aura::RootWindow* root, + aura::Window* window) const { DCHECK(IsSystemModal(window)); // If screen lock is not active, all modal windows are placed into the // normal modal container. - // TODO(oshima): support multiple root windows. aura::Window* lock_container = - GetContainerById(bounds, internal::kShellWindowId_LockScreenContainer); + GetContainerById(root, internal::kShellWindowId_LockScreenContainer); if (!lock_container->children().size()) { - return GetContainerById(bounds, + return GetContainerById(root, internal::kShellWindowId_SystemModalContainer); } @@ -120,18 +129,19 @@ aura::Window* StackingController::GetSystemModalContainer( aura::Window* container = NULL; if (window_container_id < lock_container_id) { container = GetContainerById( - bounds, internal::kShellWindowId_SystemModalContainer); + root, internal::kShellWindowId_SystemModalContainer); } else { container = GetContainerById( - bounds, internal::kShellWindowId_LockSystemModalContainer); + root, internal::kShellWindowId_LockSystemModalContainer); } return container; } +// TODO(oshima): Remove this once extended desktop is on by default. internal::AlwaysOnTopController* -StackingController::GetAlwaysOnTopController(const gfx::Rect& bounds) { - aura::RootWindow* root_window = FindContainerRoot(bounds); +StackingController::GetAlwaysOnTopController( + aura::RootWindow* root_window) { internal::AlwaysOnTopController* controller = root_window->GetProperty(internal::kAlwaysOnTopControllerKey); if (!controller) { diff --git a/ash/wm/stacking_controller.h b/ash/wm/stacking_controller.h index cfff386..ae90555 100644 --- a/ash/wm/stacking_controller.h +++ b/ash/wm/stacking_controller.h @@ -10,6 +10,10 @@ #include "base/memory/scoped_ptr.h" #include "ui/aura/client/stacking_client.h" +namespace aura{ +class RootWindow; +} + namespace ash { namespace internal { @@ -30,13 +34,12 @@ class StackingController : public aura::client::StackingClient { // normal modal container. // Otherwise those that originate from LockScreen container and above are // placed in the screen lock modal container. - aura::Window* GetSystemModalContainer(aura::Window* window, - const gfx::Rect& bounds) const; + aura::Window* GetSystemModalContainer(aura::RootWindow* root, + aura::Window* window) const; - // Returns the AlwaysOnTopController of the root window that matches - // |bounds|. + // Returns the AlwaysOnTopController of the |root_window|. internal::AlwaysOnTopController* GetAlwaysOnTopController( - const gfx::Rect& bounds); + aura::RootWindow* root_window); DISALLOW_COPY_AND_ASSIGN(StackingController); }; diff --git a/ash/wm/system_modal_container_layout_manager.cc b/ash/wm/system_modal_container_layout_manager.cc index c6975d9..283c9df 100644 --- a/ash/wm/system_modal_container_layout_manager.cc +++ b/ash/wm/system_modal_container_layout_manager.cc @@ -153,6 +153,14 @@ bool SystemModalContainerLayoutManager::CanWindowReceiveEvents( return wm::GetActivatableWindow(window) == modal_window(); } +bool SystemModalContainerLayoutManager::IsModalScreen( + aura::Window* window) { + int id = window->parent()->id(); + return (id == internal::kShellWindowId_SystemModalContainer || + id == internal::kShellWindowId_LockSystemModalContainer) && + window->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_NONE; +} + //////////////////////////////////////////////////////////////////////////////// // SystemModalContainerLayoutManager, private: diff --git a/ash/wm/system_modal_container_layout_manager.h b/ash/wm/system_modal_container_layout_manager.h index e3a71d8..f2aa51c 100644 --- a/ash/wm/system_modal_container_layout_manager.h +++ b/ash/wm/system_modal_container_layout_manager.h @@ -57,6 +57,9 @@ class ASH_EXPORT SystemModalContainerLayoutManager // Overridden from SystemModalContainerEventFilterDelegate: virtual bool CanWindowReceiveEvents(aura::Window* window) OVERRIDE; + // Is the |window| modal screen? + static bool IsModalScreen(aura::Window* window); + private: void AddModalWindow(aura::Window* window); void RemoveModalWindow(aura::Window* window); diff --git a/ash/wm/workspace/workspace_window_resizer.cc b/ash/wm/workspace/workspace_window_resizer.cc index 0c998cb..5912280 100644 --- a/ash/wm/workspace/workspace_window_resizer.cc +++ b/ash/wm/workspace/workspace_window_resizer.cc @@ -106,13 +106,23 @@ void WorkspaceWindowResizer::CompleteDrag(int event_flags) { details_.window->SetBounds(bounds); return; } - - ui::ScopedLayerAnimationSettings scoped_setter( - details_.window->layer()->GetAnimator()); - // Use a small duration since the grid is small. - scoped_setter.SetTransitionDuration( - base::TimeDelta::FromMilliseconds(kSnapDurationMS)); - details_.window->SetBounds(bounds); + // TODO(oshima|yusukes): This is temporary solution until better drag & move + // is implemented. (crbug.com/136816). + gfx::Rect dst_bounds = + ScreenAsh::ConvertRectToScreen(details_.window->parent(), bounds); + gfx::Display dst_display = gfx::Screen::GetDisplayMatching(dst_bounds); + if (dst_display.id() != + gfx::Screen::GetDisplayNearestWindow(details_.window).id()) { + // Don't animate when moving to another display. + details_.window->SetBoundsInScreen(dst_bounds); + } else { + ui::ScopedLayerAnimationSettings scoped_setter( + details_.window->layer()->GetAnimator()); + // Use a small duration since the grid is small. + scoped_setter.SetTransitionDuration( + base::TimeDelta::FromMilliseconds(kSnapDurationMS)); + details_.window->SetBounds(bounds); + } } void WorkspaceWindowResizer::RevertDrag() { diff --git a/ui/aura/window.cc b/ui/aura/window.cc index 7f8dd83..a94ccfe 100644 --- a/ui/aura/window.cc +++ b/ui/aura/window.cc @@ -298,9 +298,7 @@ void Window::SetBoundsInScreen(const gfx::Rect& new_bounds_in_screen) { gfx::Point origin = new_bounds_in_screen.origin(); aura::client::ScreenPositionClient* screen_position_client = aura::client::GetScreenPositionClient(root); - screen_position_client->ConvertPointFromScreen( - parent(), &origin); - SetBounds(gfx::Rect(origin, new_bounds_in_screen.size())); + screen_position_client->SetBounds(this, new_bounds_in_screen); return; } SetBounds(new_bounds_in_screen); |