diff --git a/ash/shell/toplevel_window.cc b/ash/shell/toplevel_window.cc index b12a37c8d712c5..ea8b79fe52887b 100644 --- a/ash/shell/toplevel_window.cc +++ b/ash/shell/toplevel_window.cc @@ -76,6 +76,7 @@ void ToplevelWindow::SaveWindowPlacement(const gfx::Rect& bounds, } bool ToplevelWindow::GetSavedWindowPlacement( + const views::Widget* widget, gfx::Rect* bounds, ui::WindowShowState* show_state) const { bool is_saved_bounds = !!saved_state; diff --git a/ash/shell/toplevel_window.h b/ash/shell/toplevel_window.h index 71bbfa237126e1..8a31d26969639e 100644 --- a/ash/shell/toplevel_window.h +++ b/ash/shell/toplevel_window.h @@ -38,6 +38,7 @@ class ToplevelWindow : public views::WidgetDelegateView { const gfx::Rect& bounds, ui::WindowShowState show_state) OVERRIDE; virtual bool GetSavedWindowPlacement( + const views::Widget* widget, gfx::Rect* bounds, ui::WindowShowState* show_state) const OVERRIDE; virtual View* GetContentsView() OVERRIDE; diff --git a/ash/wm/window_positioner.cc b/ash/wm/window_positioner.cc index 58f4fb91dd54b1..f5b0da6662ef53 100644 --- a/ash/wm/window_positioner.cc +++ b/ash/wm/window_positioner.cc @@ -283,11 +283,23 @@ bool WindowPositioner::DisableAutoPositioning(bool ignore) { void WindowPositioner::RearrangeVisibleWindowOnShow( aura::Window* added_window) { wm::WindowState* added_window_state = wm::GetWindowState(added_window); + if (!added_window->TargetVisibility()) + return; if (!UseAutoWindowManager(added_window) || - added_window_state->bounds_changed_by_user() || - !added_window->TargetVisibility()) + added_window_state->bounds_changed_by_user()) { + if (added_window_state->minimum_visibility()) { + // Guarante minimum visibility within the work area. + gfx::Rect work_area = GetWorkAreaForWindowInParent(added_window); + gfx::Rect bounds = added_window->bounds(); + gfx::Rect new_bounds = bounds; + ash::wm::AdjustBoundsToEnsureMinimumWindowVisibility(work_area, + &new_bounds); + if (new_bounds != bounds) + added_window->SetBounds(new_bounds); + } return; + } // Find a single open managed window. bool single_window; aura::Window* other_shown_window = GetReferenceWindow( diff --git a/ash/wm/window_positioner_unittest.cc b/ash/wm/window_positioner_unittest.cc index 497e01490b1f0e..fb41626e84246e 100644 --- a/ash/wm/window_positioner_unittest.cc +++ b/ash/wm/window_positioner_unittest.cc @@ -11,6 +11,7 @@ #include "ui/aura/root_window.h" #include "ui/gfx/screen.h" #include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_delegate.h" namespace ash { @@ -49,4 +50,54 @@ TEST_F(WindowPositionerTest, OpenDefaultWindowOnSecondDisplay) { second_root_window).bounds().Contains(bounds)); } +namespace { + +// A WidgetDelegate that returns the out of display saved bounds. +class OutOfDisplayDelegate : public views::WidgetDelegate { + public: + explicit OutOfDisplayDelegate(views::Widget* widget) : widget_(widget) {} + virtual ~OutOfDisplayDelegate() {} + + // Overridden from WidgetDelegate: + virtual void DeleteDelegate() OVERRIDE { + delete this; + } + virtual views::Widget* GetWidget() OVERRIDE { + return widget_; + } + virtual const views::Widget* GetWidget() const OVERRIDE { + return widget_; + } + virtual bool GetSavedWindowPlacement( + const views::Widget* widget, + gfx::Rect* bounds, + ui::WindowShowState* show_state) const OVERRIDE { + bounds->SetRect(450, 10, 100, 100); + *show_state = ui::SHOW_STATE_NORMAL; + return true; + } + + private: + views::Widget* widget_; + + DISALLOW_COPY_AND_ASSIGN(OutOfDisplayDelegate); +}; + +} // namespace + +TEST_F(WindowPositionerTest, EnsureMinimumVisibility) { + UpdateDisplay("400x400"); + views::Widget* widget = new views::Widget(); + views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); + params.delegate = new OutOfDisplayDelegate(widget); + params.context = Shell::GetPrimaryRootWindow(); + widget->Init(params); + widget->SetBounds(gfx::Rect(450,10, 100, 100)); + wm::GetWindowState(widget->GetNativeView())->set_minimum_visibility(true); + widget->Show(); + // Make sure the bounds is adjusted to be inside the work area. + EXPECT_EQ("390,10 100x100", widget->GetWindowBoundsInScreen().ToString()); + widget->CloseNow(); +} + } // namespace diff --git a/ash/wm/window_state.cc b/ash/wm/window_state.cc index b3448e918557cf..1a06a58da1bb0a 100644 --- a/ash/wm/window_state.cc +++ b/ash/wm/window_state.cc @@ -41,6 +41,7 @@ WindowState::WindowState(aura::Window* window) always_restores_to_restore_bounds_(false), hide_shelf_when_fullscreen_(true), animate_to_fullscreen_(true), + minimum_visibility_(false), window_show_type_(ToWindowShowType(GetShowState())) { window_->AddObserver(this); } diff --git a/ash/wm/window_state.h b/ash/wm/window_state.h index 320977ebb4ed87..2bbdd035b0d127 100644 --- a/ash/wm/window_state.h +++ b/ash/wm/window_state.h @@ -148,6 +148,18 @@ class ASH_EXPORT WindowState : public aura::WindowObserver { animate_to_fullscreen_ = value; } + // If the minimum visibilty is true, ash will try to keep a + // minimum amount of the window is always visible on the work area + // when shown. + // TODO(oshima): Consolidate this and window_position_managed + // into single parameter to control the window placement. + bool minimum_visibility() const { + return minimum_visibility_; + } + void set_minimum_visibility(bool minimum_visibility) { + minimum_visibility_ = minimum_visibility; + } + // Gets/Sets the bounds of the window before it was moved by the auto window // management. As long as it was not auto-managed, it will return NULL. const gfx::Rect* pre_auto_manage_window_bounds() const { @@ -262,6 +274,7 @@ class ASH_EXPORT WindowState : public aura::WindowObserver { bool always_restores_to_restore_bounds_; bool hide_shelf_when_fullscreen_; bool animate_to_fullscreen_; + bool minimum_visibility_; // A property to remember the window position which was set before the // auto window position manager changed the window bounds, so that it can get diff --git a/ash/wm/workspace/workspace_layout_manager_unittest.cc b/ash/wm/workspace/workspace_layout_manager_unittest.cc index f735e0cd056275..1963b9b8e47570 100644 --- a/ash/wm/workspace/workspace_layout_manager_unittest.cc +++ b/ash/wm/workspace/workspace_layout_manager_unittest.cc @@ -33,6 +33,7 @@ class MaximizeDelegateView : public views::WidgetDelegateView { virtual ~MaximizeDelegateView() {} virtual bool GetSavedWindowPlacement( + const views::Widget* widget, gfx::Rect* bounds, ui::WindowShowState* show_state) const OVERRIDE { *bounds = initial_bounds_; diff --git a/chrome/browser/ui/views/chrome_views_delegate.cc b/chrome/browser/ui/views/chrome_views_delegate.cc index 785a6a0fde5c1a..2f121754bcfaeb 100644 --- a/chrome/browser/ui/views/chrome_views_delegate.cc +++ b/chrome/browser/ui/views/chrome_views_delegate.cc @@ -39,6 +39,7 @@ #if defined(USE_ASH) #include "ash/shell.h" +#include "ash/wm/window_state.h" #include "chrome/browser/ui/ash/ash_init.h" #include "chrome/browser/ui/ash/ash_util.h" #endif @@ -92,6 +93,7 @@ void ChromeViewsDelegate::SaveWindowPlacement(const views::Widget* window, } bool ChromeViewsDelegate::GetSavedWindowPlacement( + const views::Widget* widget, const std::string& window_name, gfx::Rect* bounds, ui::WindowShowState* show_state) const { @@ -115,6 +117,18 @@ bool ChromeViewsDelegate::GetSavedWindowPlacement( dictionary->GetBoolean("maximized", &maximized); *show_state = maximized ? ui::SHOW_STATE_MAXIMIZED : ui::SHOW_STATE_NORMAL; +#if defined(USE_ASH) + // On Ash environment, a window won't span across displays. Adjust + // the bounds to fit the work area. + gfx::NativeView window = widget->GetNativeView(); + if (chrome::GetHostDesktopTypeForNativeView(window) == + chrome::HOST_DESKTOP_TYPE_ASH) { + gfx::Display display = gfx::Screen::GetScreenFor(window)-> + GetDisplayMatching(*bounds); + bounds->AdjustToFit(display.work_area()); + ash::wm::GetWindowState(window)->set_minimum_visibility(true); + } +#endif return true; } diff --git a/chrome/browser/ui/views/chrome_views_delegate.h b/chrome/browser/ui/views/chrome_views_delegate.h index d7aa49a8ca7b55..9d5df1b150e094 100644 --- a/chrome/browser/ui/views/chrome_views_delegate.h +++ b/chrome/browser/ui/views/chrome_views_delegate.h @@ -22,6 +22,7 @@ class ChromeViewsDelegate : public views::ViewsDelegate { const gfx::Rect& bounds, ui::WindowShowState show_state) OVERRIDE; virtual bool GetSavedWindowPlacement( + const views::Widget* widget, const std::string& window_name, gfx::Rect* bounds, ui::WindowShowState* show_state) const OVERRIDE; diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc index 2884c46819f402..6c5227623f475c 100644 --- a/chrome/browser/ui/views/frame/browser_view.cc +++ b/chrome/browser/ui/views/frame/browser_view.cc @@ -1626,6 +1626,7 @@ void BrowserView::SaveWindowPlacement(const gfx::Rect& bounds, } bool BrowserView::GetSavedWindowPlacement( + const views::Widget* widget, gfx::Rect* bounds, ui::WindowShowState* show_state) const { if (!ShouldSaveOrRestoreWindowPos()) diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h index 2d35817a7b7eef..39fdf085f4865c 100644 --- a/chrome/browser/ui/views/frame/browser_view.h +++ b/chrome/browser/ui/views/frame/browser_view.h @@ -407,6 +407,7 @@ class BrowserView : public BrowserWindow, virtual void SaveWindowPlacement(const gfx::Rect& bounds, ui::WindowShowState show_state) OVERRIDE; virtual bool GetSavedWindowPlacement( + const views::Widget* widget, gfx::Rect* bounds, ui::WindowShowState* show_state) const OVERRIDE; virtual views::View* GetContentsView() OVERRIDE; diff --git a/ui/views/test/test_views_delegate.cc b/ui/views/test/test_views_delegate.cc index 58105d658decfb..eb9476a16abafc 100644 --- a/ui/views/test/test_views_delegate.cc +++ b/ui/views/test/test_views_delegate.cc @@ -36,6 +36,7 @@ void TestViewsDelegate::SaveWindowPlacement(const Widget* window, } bool TestViewsDelegate::GetSavedWindowPlacement( + const Widget* window, const std::string& window_name, gfx::Rect* bounds, ui:: WindowShowState* show_state) const { diff --git a/ui/views/test/test_views_delegate.h b/ui/views/test/test_views_delegate.h index 4c2e31b25266ee..b5c35d3d15d711 100644 --- a/ui/views/test/test_views_delegate.h +++ b/ui/views/test/test_views_delegate.h @@ -33,6 +33,7 @@ class TestViewsDelegate : public ViewsDelegate { const gfx::Rect& bounds, ui::WindowShowState show_state) OVERRIDE; virtual bool GetSavedWindowPlacement( + const Widget* window, const std::string& window_name, gfx::Rect* bounds, ui::WindowShowState* show_state) const OVERRIDE; diff --git a/ui/views/views_delegate.h b/ui/views/views_delegate.h index b118913f96f228..4acb7741730d95 100644 --- a/ui/views/views_delegate.h +++ b/ui/views/views_delegate.h @@ -68,6 +68,7 @@ class VIEWS_EXPORT ViewsDelegate { // Retrieves the saved position and size and "show" state for the window with // the specified name. virtual bool GetSavedWindowPlacement( + const Widget* widget, const std::string& window_name, gfx::Rect* bounds, ui::WindowShowState* show_state) const = 0; diff --git a/ui/views/widget/widget.cc b/ui/views/widget/widget.cc index bb1c9f0b92e901..d3af615e107fda 100644 --- a/ui/views/widget/widget.cc +++ b/ui/views/widget/widget.cc @@ -1396,7 +1396,7 @@ bool Widget::GetSavedWindowPlacement(gfx::Rect* bounds, // track maximized state independently of sizing information. // Restore the window's placement from the controller. - if (widget_delegate_->GetSavedWindowPlacement(bounds, show_state)) { + if (widget_delegate_->GetSavedWindowPlacement(this, bounds, show_state)) { if (!widget_delegate_->ShouldRestoreWindowSize()) { bounds->set_size(non_client_view_->GetPreferredSize()); } else { diff --git a/ui/views/widget/widget_delegate.cc b/ui/views/widget/widget_delegate.cc index 37816da4eeff77..fbace27c316a29 100644 --- a/ui/views/widget/widget_delegate.cc +++ b/ui/views/widget/widget_delegate.cc @@ -118,6 +118,7 @@ void WidgetDelegate::SaveWindowPlacement(const gfx::Rect& bounds, } bool WidgetDelegate::GetSavedWindowPlacement( + const Widget* widget, gfx::Rect* bounds, ui::WindowShowState* show_state) const { std::string window_name = GetWindowName(); @@ -125,7 +126,7 @@ bool WidgetDelegate::GetSavedWindowPlacement( return false; return ViewsDelegate::views_delegate->GetSavedWindowPlacement( - window_name, bounds, show_state); + widget, window_name, bounds, show_state); } bool WidgetDelegate::ShouldRestoreWindowSize() const { diff --git a/ui/views/widget/widget_delegate.h b/ui/views/widget/widget_delegate.h index 4466e52cfa23b5..16e29a8b3385ad 100644 --- a/ui/views/widget/widget_delegate.h +++ b/ui/views/widget/widget_delegate.h @@ -104,7 +104,8 @@ class VIEWS_EXPORT WidgetDelegate { // Retrieves the window's bounds and "show" states. // This behavior can be overridden to provide additional functionality. - virtual bool GetSavedWindowPlacement(gfx::Rect* bounds, + virtual bool GetSavedWindowPlacement(const Widget* widget, + gfx::Rect* bounds, ui::WindowShowState* show_state) const; // Returns true if the window's size should be restored. If this is false,