From 6344760afdb784d456ae77cb366b06962c4069c5 Mon Sep 17 00:00:00 2001 From: "skuhne@chromium.org" Date: Sun, 9 Mar 2014 17:58:25 +0000 Subject: Adding a gray semi transparent backdrop behind the topmost window within the default container This is part of the "always maximized" feature. Windows which cannot be maximized - or cannot be made to cover the entire screen should have a backdrop behind them which covers the desktop. Tried various ways to implement this and this seems to be the best solution. BUG=337567, 337563 Review URL: https://codereview.chromium.org/169643005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@255863 0039d316-1c4b-4281-b951-d872f2087c98 --- ash/ash.gyp | 5 + .../maximize_mode/maximize_mode_window_manager.cc | 72 +++++++-- .../maximize_mode/maximize_mode_window_manager.h | 16 +- .../maximize_mode/workspace_backdrop_delegate.cc | 154 ++++++++++++++++++ ash/wm/maximize_mode/workspace_backdrop_delegate.h | 80 ++++++++++ ash/wm/workspace/workspace_layout_manager.cc | 22 ++- ash/wm/workspace/workspace_layout_manager.h | 24 +++ .../workspace/workspace_layout_manager_delegate.h | 49 ++++++ .../workspace/workspace_layout_manager_unittest.cc | 172 +++++++++++++++++++++ ash/wm/workspace_controller.cc | 6 + ash/wm/workspace_controller.h | 6 + 11 files changed, 585 insertions(+), 21 deletions(-) create mode 100644 ash/wm/maximize_mode/workspace_backdrop_delegate.cc create mode 100644 ash/wm/maximize_mode/workspace_backdrop_delegate.h create mode 100644 ash/wm/workspace/workspace_layout_manager_delegate.h (limited to 'ash') diff --git a/ash/ash.gyp b/ash/ash.gyp index b1f0e25..ac21917 100644 --- a/ash/ash.gyp +++ b/ash/ash.gyp @@ -540,6 +540,8 @@ 'wm/lock_state_observer.h', 'wm/maximize_mode/maximize_mode_window_manager.cc', 'wm/maximize_mode/maximize_mode_window_manager.h', + 'wm/maximize_mode/workspace_backdrop_delegate.cc', + 'wm/maximize_mode/workspace_backdrop_delegate.h', 'wm/mru_window_tracker.cc', 'wm/mru_window_tracker.h', 'wm/overlay_event_filter.cc', @@ -643,6 +645,7 @@ 'wm/workspace/workspace_event_handler.h', 'wm/workspace/workspace_layout_manager.cc', 'wm/workspace/workspace_layout_manager.h', + 'wm/workspace/workspace_layout_manager_delegate.h', 'wm/workspace/workspace_types.h', 'wm/workspace/workspace_window_resizer.cc', 'wm/workspace/workspace_window_resizer.h', @@ -969,6 +972,8 @@ 'wm/window_positioner_unittest.cc', 'wm/window_state_unittest.cc', 'wm/window_util_unittest.cc', + 'wm/maximize_mode/workspace_backdrop_delegate.cc', + 'wm/maximize_mode/workspace_backdrop_delegate.h', 'wm/workspace/magnetism_matcher_unittest.cc', 'wm/workspace/multi_window_resize_controller_unittest.cc', 'wm/workspace/phantom_window_controller_unittest.cc', diff --git a/ash/wm/maximize_mode/maximize_mode_window_manager.cc b/ash/wm/maximize_mode/maximize_mode_window_manager.cc index cd42ba9..6858f36 100644 --- a/ash/wm/maximize_mode/maximize_mode_window_manager.cc +++ b/ash/wm/maximize_mode/maximize_mode_window_manager.cc @@ -4,9 +4,12 @@ #include "ash/wm/maximize_mode/maximize_mode_window_manager.h" +#include "ash/root_window_controller.h" #include "ash/shell.h" -#include "ash/switchable_windows.h" +#include "ash/shell_window_ids.h" +#include "ash/wm/maximize_mode/workspace_backdrop_delegate.h" #include "ash/wm/mru_window_tracker.h" +#include "ash/wm/workspace_controller.h" #include "ui/aura/window.h" #include "ui/gfx/screen.h" @@ -14,7 +17,9 @@ namespace ash { namespace internal { MaximizeModeWindowManager::~MaximizeModeWindowManager() { + Shell::GetInstance()->RemoveShellObserver(this); Shell::GetScreen()->RemoveObserver(this); + EnableBackdropBehindTopWindowOnEachDisplay(false); RemoveWindowCreationObservers(); RestoreAllWindows(); } @@ -23,6 +28,22 @@ int MaximizeModeWindowManager::GetNumberOfManagedWindows() { return initial_state_type_.size(); } +void MaximizeModeWindowManager::OnOverviewModeStarted() { + if (backdrops_hidden_) + return; + + EnableBackdropBehindTopWindowOnEachDisplay(false); + backdrops_hidden_ = true; +} + +void MaximizeModeWindowManager::OnOverviewModeEnded() { + if (!backdrops_hidden_) + return; + + backdrops_hidden_ = false; + EnableBackdropBehindTopWindowOnEachDisplay(true); +} + void MaximizeModeWindowManager::OnWindowDestroying(aura::Window* window) { // If a known window gets destroyed we need to remove all knowledge about it. if (!IsContainerWindow(window)) @@ -65,10 +86,15 @@ void MaximizeModeWindowManager::OnDisplayRemoved(const gfx::Display& display) { DisplayConfigurationChanged(); } -MaximizeModeWindowManager::MaximizeModeWindowManager() { +MaximizeModeWindowManager::MaximizeModeWindowManager() + : backdrops_hidden_(false) { + // TODO(skuhne): Turn off the overview mode and full screen modes before + // entering the MaximzieMode. MaximizeAllWindows(); AddWindowCreationObservers(); + EnableBackdropBehindTopWindowOnEachDisplay(true); Shell::GetScreen()->AddObserver(this); + Shell::GetInstance()->AddShellObserver(this); } void MaximizeModeWindowManager::MaximizeAllWindows() { @@ -110,7 +136,6 @@ void MaximizeModeWindowManager::MaximizeAndTrackWindow( else window_state->SetRestoreBoundsInScreen(initial_rect); CenterWindow(window); - // TODO(skuhne): Add a background cover layer. } else { // Minimized windows can remain as they are. if (state != wm::WINDOW_STATE_TYPE_MINIMIZED) @@ -128,7 +153,6 @@ void MaximizeModeWindowManager::RestoreAndForgetWindow( // Restore window if it can be restored. if (state != wm::WINDOW_STATE_TYPE_MAXIMIZED) { if (!CanMaximize(window)) { - // TODO(skuhne): Remove the background cover layer. if (window_state->HasRestoreBounds()) { // TODO(skuhne): If the system shuts down in maximized mode, the proper // restore coordinates should get saved. @@ -187,19 +211,17 @@ void MaximizeModeWindowManager::CenterWindow(aura::Window* window) { void MaximizeModeWindowManager::AddWindowCreationObservers() { DCHECK(observed_container_windows_.empty()); - // Observe window activations and switchable containers on all root windows - // for newly created windows during overview. + // Observe window activations/creations in the default containers on all root + // windows. aura::Window::Windows root_windows = Shell::GetAllRootWindows(); for (aura::Window::Windows::const_iterator iter = root_windows.begin(); iter != root_windows.end(); ++iter) { - for (size_t i = 0; i < kSwitchableWindowContainerIdsLength; ++i) { - aura::Window* container = Shell::GetContainer(*iter, - kSwitchableWindowContainerIds[i]); - DCHECK(observed_container_windows_.find(container) == - observed_container_windows_.end()); - container->AddObserver(this); - observed_container_windows_.insert(container); - } + aura::Window* container = Shell::GetContainer(*iter, + internal::kShellWindowId_DefaultContainer); + DCHECK(observed_container_windows_.find(container) == + observed_container_windows_.end()); + container->AddObserver(this); + observed_container_windows_.insert(container); } } @@ -213,8 +235,10 @@ void MaximizeModeWindowManager::RemoveWindowCreationObservers() { } void MaximizeModeWindowManager::DisplayConfigurationChanged() { + EnableBackdropBehindTopWindowOnEachDisplay(false); RemoveWindowCreationObservers(); AddWindowCreationObservers(); + EnableBackdropBehindTopWindowOnEachDisplay(true); } bool MaximizeModeWindowManager::IsContainerWindow(aura::Window* window) { @@ -222,5 +246,25 @@ bool MaximizeModeWindowManager::IsContainerWindow(aura::Window* window) { observed_container_windows_.end(); } +void MaximizeModeWindowManager::EnableBackdropBehindTopWindowOnEachDisplay( + bool enable) { + if (backdrops_hidden_) + return; + // Inform the WorkspaceLayoutManager that we want to show a backdrop behind + // the topmost window of its container. + Shell::RootWindowControllerList controllers = + Shell::GetAllRootWindowControllers(); + for (Shell::RootWindowControllerList::iterator iter = controllers.begin(); + iter != controllers.end(); ++iter) { + RootWindowController* controller = *iter; + aura::Window* container = Shell::GetContainer( + controller->root_window(), + internal::kShellWindowId_DefaultContainer); + controller->workspace_controller()->SetMaximizeBackdropDelegate( + scoped_ptr( + enable ? new WorkspaceBackdropDelegate(container) : NULL)); + } +} + } // namespace internal } // namespace ash diff --git a/ash/wm/maximize_mode/maximize_mode_window_manager.h b/ash/wm/maximize_mode/maximize_mode_window_manager.h index ba5d1bd..f8af8d0 100644 --- a/ash/wm/maximize_mode/maximize_mode_window_manager.h +++ b/ash/wm/maximize_mode/maximize_mode_window_manager.h @@ -9,6 +9,7 @@ #include #include "ash/ash_export.h" +#include "ash/shell_observer.h" #include "ash/wm/window_state.h" #include "base/basictypes.h" #include "base/compiler_specific.h" @@ -27,12 +28,13 @@ namespace internal{ // With the destruction of the manager all windows will be restored to their // original state. class ASH_EXPORT MaximizeModeWindowManager : public aura::WindowObserver, - public gfx::DisplayObserver { + public gfx::DisplayObserver, + public ShellObserver { public: // This should only be deleted by the creator (ash::Shell). virtual ~MaximizeModeWindowManager(); - // Returns the number of maximized & tracked windows by this manager. + // Returns the number of maximized & tracked windows by this manager. int GetNumberOfManagedWindows(); // Overridden from WindowObserver: @@ -48,6 +50,10 @@ class ASH_EXPORT MaximizeModeWindowManager : public aura::WindowObserver, virtual void OnDisplayAdded(const gfx::Display& display) OVERRIDE; virtual void OnDisplayRemoved(const gfx::Display& display) OVERRIDE; + // ShellObserver overrides: + void OnOverviewModeStarted(); + void OnOverviewModeEnded(); + protected: friend class ash::Shell; @@ -98,12 +104,18 @@ class ASH_EXPORT MaximizeModeWindowManager : public aura::WindowObserver, // Returns true when the |window| is a container window. bool IsContainerWindow(aura::Window* window); + // Add a backdrop behind the currently active window on each desktop. + void EnableBackdropBehindTopWindowOnEachDisplay(bool enable); + // Every window which got touched by our window manager gets added here. WindowToStateType initial_state_type_; // All container windows which have to be tracked. std::set observed_container_windows_; + // True if all backdrops are hidden. + bool backdrops_hidden_; + DISALLOW_COPY_AND_ASSIGN(MaximizeModeWindowManager); }; diff --git a/ash/wm/maximize_mode/workspace_backdrop_delegate.cc b/ash/wm/maximize_mode/workspace_backdrop_delegate.cc new file mode 100644 index 0000000..e996fca --- /dev/null +++ b/ash/wm/maximize_mode/workspace_backdrop_delegate.cc @@ -0,0 +1,154 @@ +// Copyright 2014 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/wm/maximize_mode/workspace_backdrop_delegate.h" + +#include "ash/wm/window_animations.h" +#include "ash/wm/window_util.h" +#include "base/auto_reset.h" +#include "ui/aura/window.h" +#include "ui/compositor/layer.h" +#include "ui/compositor/scoped_layer_animation_settings.h" +#include "ui/views/background.h" +#include "ui/views/corewm/window_util.h" +#include "ui/views/widget/widget.h" + +namespace ash { + +namespace internal { + +namespace { + +// The opacity of the backdrop. +const float kBackdropOpacity = 0.5f; + +} // namespace + +WorkspaceBackdropDelegate::WorkspaceBackdropDelegate(aura::Window* container) + : background_(NULL), + container_(container), + in_restacking_(false) { + background_ = new views::Widget; + views::Widget::InitParams params( + views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); + params.parent = container_; + params.bounds = container_->bounds(); + params.layer_type = aura::WINDOW_LAYER_SOLID_COLOR; + // To disallow the MRU list from picking this window up it should not be + // activateable. + params.can_activate = false; + background_->Init(params); + background_->GetNativeView()->SetName("WorkspaceBackdropDelegate"); + background_->GetNativeView()->layer()->SetColor(SK_ColorBLACK); + Show(); + RestackBackdrop(); + container_->AddObserver(this); +} + +WorkspaceBackdropDelegate::~WorkspaceBackdropDelegate() { + container_->RemoveObserver(this); + ui::ScopedLayerAnimationSettings settings( + background_->GetNativeView()->layer()->GetAnimator()); + background_->Close(); + settings.AddObserver(views::corewm::CreateHidingWindowAnimationObserver( + background_->GetNativeView())); + background_->GetNativeView()->layer()->SetOpacity(0.0f); +} + +void WorkspaceBackdropDelegate::OnWindowBoundsChanged( + aura::Window* window, + const gfx::Rect& old_bounds, + const gfx::Rect& new_bounds) { + // The container size has changed and the layer needs to be adapt to it. + AdjustToContainerBounds(); +} + +void WorkspaceBackdropDelegate::OnWindowAddedToLayout(aura::Window* child) { + RestackBackdrop(); +} + +void WorkspaceBackdropDelegate::OnWindowRemovedFromLayout(aura::Window* child) { + RestackBackdrop(); +} + +void WorkspaceBackdropDelegate::OnChildWindowVisibilityChanged( + aura::Window* child, + bool visible) { + RestackBackdrop(); +} + +void WorkspaceBackdropDelegate::OnWindowStackingChanged(aura::Window* window) { + RestackBackdrop(); +} + +void WorkspaceBackdropDelegate::OnPostWindowStateTypeChange( + wm::WindowState* window_state, + wm::WindowStateType old_type) { + RestackBackdrop(); +} + +void WorkspaceBackdropDelegate::RestackBackdrop() { + // Avoid recursive calls. + if (in_restacking_) + return; + + aura::Window* window = GetCurrentTopWindow(); + if (!window) { + // Hide backdrop since no suitable window was found. + background_->Hide(); + return; + } + if (window == background_->GetNativeWindow() && + background_->IsVisible()) { + return; + } + // We are changing the order of windows which will cause recursion. + base::AutoReset lock(&in_restacking_, true); + if (!background_->IsVisible()) + Show(); + // Since the backdrop needs to be immediately behind the window and the + // stacking functions only guarantee a "it's above or below", we need + // to re-arrange the two windows twice. + container_->StackChildAbove(background_->GetNativeView(), window); + container_->StackChildAbove(window, background_->GetNativeView()); +} + +aura::Window* WorkspaceBackdropDelegate::GetCurrentTopWindow() { + const aura::Window::Windows& windows = container_->children(); + for (aura::Window::Windows::const_reverse_iterator window_iter = + windows.rbegin(); + window_iter != windows.rend(); ++window_iter) { + aura::Window* window = *window_iter; + if (window->TargetVisibility() && + window->type() == ui::wm::WINDOW_TYPE_NORMAL && + ash::wm::CanActivateWindow(window)) + return window; + } + return NULL; +} + +void WorkspaceBackdropDelegate::AdjustToContainerBounds() { + // Cover the entire container window. + gfx::Rect target_rect(gfx::Point(0, 0), container_->bounds().size()); + if (target_rect != background_->GetNativeWindow()->bounds()) { + // This needs to be instant. + ui::ScopedLayerAnimationSettings settings( + background_->GetNativeView()->layer()->GetAnimator()); + settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(0)); + background_->GetNativeWindow()->SetBounds(target_rect); + if (!background_->IsVisible()) + background_->GetNativeView()->layer()->SetOpacity(kBackdropOpacity); + } +} + +void WorkspaceBackdropDelegate::Show() { + background_->GetNativeView()->layer()->SetOpacity(0.0f); + background_->Show(); + ui::ScopedLayerAnimationSettings settings( + background_->GetNativeView()->layer()->GetAnimator()); + background_->GetNativeView()->layer()->SetOpacity(kBackdropOpacity); +} + +} // namespace internal +} // namespace ash diff --git a/ash/wm/maximize_mode/workspace_backdrop_delegate.h b/ash/wm/maximize_mode/workspace_backdrop_delegate.h new file mode 100644 index 0000000..02ba3a3 --- /dev/null +++ b/ash/wm/maximize_mode/workspace_backdrop_delegate.h @@ -0,0 +1,80 @@ +// Copyright 2014 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_WM_MAXIMIZE_MODE_WORKSPACE_BACKDROP_DELEGATE_H_ +#define ASH_WM_MAXIMIZE_MODE_WORKSPACE_BACKDROP_DELEGATE_H_ + +#include "ash/wm/workspace/workspace_layout_manager_delegate.h" +#include "ui/aura/window_observer.h" + +namespace aura { +class Window; +} + +namespace ui { +class Layer; +} + +namespace views { +class Widget; +} + +namespace ash { + +namespace internal { + +// A background which gets created for a container |window| and which gets +// stacked behind the topmost window (within that container) covering the +// entire container. +class WorkspaceBackdropDelegate : public aura::WindowObserver, + public WorkspaceLayoutManagerDelegate { + public: + explicit WorkspaceBackdropDelegate(aura::Window* container); + virtual ~WorkspaceBackdropDelegate(); + + // WindowObserver overrides: + virtual void OnWindowBoundsChanged(aura::Window* window, + const gfx::Rect& old_bounds, + const gfx::Rect& new_bounds) OVERRIDE; + + // WorkspaceLayoutManagerDelegate overrides: + virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE; + virtual void OnWindowRemovedFromLayout(aura::Window* child) OVERRIDE; + virtual void OnChildWindowVisibilityChanged(aura::Window* child, + bool visible) OVERRIDE; + virtual void OnWindowStackingChanged(aura::Window* window) OVERRIDE; + virtual void OnPostWindowStateTypeChange( + wm::WindowState* window_state, + wm::WindowStateType old_type) OVERRIDE; + + private: + // Restack the backdrop relatively to the other windows in the container. + void RestackBackdrop(); + + // Returns the current visible top level window in the container. + aura::Window* GetCurrentTopWindow(); + + // Position & size the background over the container window. + void AdjustToContainerBounds(); + + // Show the overlay. + void Show(); + + // The background which covers the rest of the screen. + views::Widget* background_; + + // The window which is being "maximized". + aura::Window* container_; + + // If true, the |RestackOrHideWindow| might recurse. + bool in_restacking_; + + DISALLOW_COPY_AND_ASSIGN(WorkspaceBackdropDelegate); +}; + +} // namespace internal + +} // namespace ash + +#endif // ASH_WM_MAXIMIZE_MODE_WORKSPACE_BACKDROP_DELEGATE_H_ diff --git a/ash/wm/workspace/workspace_layout_manager.cc b/ash/wm/workspace/workspace_layout_manager.cc index 1aaebf9..687324c 100644 --- a/ash/wm/workspace/workspace_layout_manager.cc +++ b/ash/wm/workspace/workspace_layout_manager.cc @@ -17,6 +17,7 @@ #include "ash/wm/window_state.h" #include "ash/wm/window_util.h" #include "ash/wm/wm_event.h" +#include "ash/wm/workspace/workspace_layout_manager_delegate.h" #include "ui/aura/client/activation_client.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/window.h" @@ -50,12 +51,8 @@ WorkspaceLayoutManager::WorkspaceLayoutManager(aura::Window* window) WorkspaceLayoutManager::~WorkspaceLayoutManager() { if (root_window_) root_window_->RemoveObserver(this); - for (WindowSet::const_iterator i = windows_.begin(); - i != windows_.end(); - ++i) { + for (WindowSet::const_iterator i = windows_.begin(); i != windows_.end(); ++i) (*i)->RemoveObserver(this); - wm::GetWindowState(*i)->RemoveObserver(this); - } Shell::GetInstance()->RemoveShellObserver(this); Shell::GetInstance()->activation_client()->RemoveObserver(this); } @@ -64,6 +61,11 @@ void WorkspaceLayoutManager::SetShelf(internal::ShelfLayoutManager* shelf) { shelf_ = shelf; } +void WorkspaceLayoutManager::SetMaximizeBackdropDelegate( + scoped_ptr delegate) { + backdrop_delegate_.reset(delegate.release()); +} + ////////////////////////////////////////////////////////////////////////////// // WorkspaceLayoutManager, aura::LayoutManager implementation: @@ -76,6 +78,8 @@ void WorkspaceLayoutManager::OnWindowAddedToLayout(Window* child) { window_state->AddObserver(this); UpdateShelfVisibility(); UpdateFullscreenState(); + if (backdrop_delegate_) + backdrop_delegate_->OnWindowAddedToLayout(child); WindowPositioner::RearrangeVisibleWindowOnShow(child); } @@ -91,6 +95,8 @@ void WorkspaceLayoutManager::OnWillRemoveWindowFromLayout(Window* child) { void WorkspaceLayoutManager::OnWindowRemovedFromLayout(Window* child) { UpdateShelfVisibility(); UpdateFullscreenState(); + if (backdrop_delegate_) + backdrop_delegate_->OnWindowRemovedFromLayout(child); } void WorkspaceLayoutManager::OnChildWindowVisibilityChanged(Window* child, @@ -106,6 +112,8 @@ void WorkspaceLayoutManager::OnChildWindowVisibilityChanged(Window* child, WindowPositioner::RearrangeVisibleWindowOnHideOrRemove(child); UpdateFullscreenState(); UpdateShelfVisibility(); + if (backdrop_delegate_) + backdrop_delegate_->OnChildWindowVisibilityChanged(child, visible); } void WorkspaceLayoutManager::SetChildBounds( @@ -166,6 +174,8 @@ void WorkspaceLayoutManager::OnWindowPropertyChanged(Window* window, void WorkspaceLayoutManager::OnWindowStackingChanged(aura::Window* window) { UpdateShelfVisibility(); UpdateFullscreenState(); + if (backdrop_delegate_) + backdrop_delegate_->OnWindowStackingChanged(window); } void WorkspaceLayoutManager::OnWindowDestroying(aura::Window* window) { @@ -214,6 +224,8 @@ void WorkspaceLayoutManager::OnPostWindowStateTypeChange( } UpdateShelfVisibility(); + if (backdrop_delegate_) + backdrop_delegate_->OnPostWindowStateTypeChange(window_state, old_type); } ////////////////////////////////////////////////////////////////////////////// diff --git a/ash/wm/workspace/workspace_layout_manager.h b/ash/wm/workspace/workspace_layout_manager.h index 6e2547a..ff15728 100644 --- a/ash/wm/workspace/workspace_layout_manager.h +++ b/ash/wm/workspace/workspace_layout_manager.h @@ -13,6 +13,7 @@ #include "ash/wm/wm_types.h" #include "base/basictypes.h" #include "base/compiler_specific.h" +#include "base/memory/scoped_ptr.h" #include "ui/aura/client/activation_change_observer.h" #include "ui/aura/layout_manager.h" #include "ui/aura/window_observer.h" @@ -36,6 +37,7 @@ class WMEvent; namespace internal { class ShelfLayoutManager; +class WorkspaceLayoutManagerDelegate; // LayoutManager used on the window created for a workspace. class ASH_EXPORT WorkspaceLayoutManager @@ -50,6 +52,12 @@ class ASH_EXPORT WorkspaceLayoutManager void SetShelf(internal::ShelfLayoutManager* shelf); + // A delegate which can be set to add a backdrop behind the top most visible + // window. With the call the ownership of the delegate will be transferred to + // the WorkspaceLayoutManager. + void SetMaximizeBackdropDelegate( + scoped_ptr delegate); + // Overridden from aura::LayoutManager: virtual void OnWindowResized() OVERRIDE {} virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE; @@ -103,6 +111,18 @@ class ASH_EXPORT WorkspaceLayoutManager // has changed. void UpdateFullscreenState(); + // Updates the bounds of the window for a stte type change from + // |old_show_type|. + void UpdateBoundsFromStateType(wm::WindowState* window_state, + wm::WindowStateType old_state_type); + + // If |window_state| is maximized or fullscreen the bounds of the + // window are set and true is returned. Does nothing otherwise. + bool SetMaximizedOrFullscreenBounds(wm::WindowState* window_state); + + // Animates the window bounds to |bounds|. + void SetChildBoundsAnimated(aura::Window* child, const gfx::Rect& bounds); + internal::ShelfLayoutManager* shelf_; aura::Window* window_; aura::Window* root_window_; @@ -116,6 +136,10 @@ class ASH_EXPORT WorkspaceLayoutManager // True if this workspace is currently in fullscreen mode. bool is_fullscreen_; + // A window which covers the full container and which gets inserted behind the + // topmost visible window. + scoped_ptr backdrop_delegate_; + DISALLOW_COPY_AND_ASSIGN(WorkspaceLayoutManager); }; diff --git a/ash/wm/workspace/workspace_layout_manager_delegate.h b/ash/wm/workspace/workspace_layout_manager_delegate.h new file mode 100644 index 0000000..a32c028 --- /dev/null +++ b/ash/wm/workspace/workspace_layout_manager_delegate.h @@ -0,0 +1,49 @@ +// Copyright 2014 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_WM_WORKSPACE_WORKSPACE_LAYOUT_MANAGER_DELEGATE_H_ +#define ASH_WM_WORKSPACE_WORKSPACE_LAYOUT_MANAGER_DELEGATE_H_ + +#include "ash/wm/wm_types.h" + +namespace aura { +class Window; +} + +namespace ash { +namespace wm { +class WindowState; +} + +namespace internal { + +// A delegate which can be set to create and control a backdrop which gets +// placed below the top level window. +class WorkspaceLayoutManagerDelegate { + public: + WorkspaceLayoutManagerDelegate() {} + virtual ~WorkspaceLayoutManagerDelegate() {} + + // A window got added to the layout. + virtual void OnWindowAddedToLayout(aura::Window* child) = 0; + + // A window got removed from the layout. + virtual void OnWindowRemovedFromLayout(aura::Window* child) = 0; + + // The visibility of a window has changed. + virtual void OnChildWindowVisibilityChanged(aura::Window* child, + bool visible) = 0; + + // The stacking order of a window has changed. + virtual void OnWindowStackingChanged(aura::Window* window) = 0; + + // A window state type has changed. + virtual void OnPostWindowStateTypeChange(wm::WindowState* window_state, + wm::WindowStateType old_type) = 0; +}; + +} // namespace internal +} // namespace ash + +#endif // ASH_WM_WORKSPACE_WORKSPACE_LAYOUT_MANAGER_DELEGATE_H_ diff --git a/ash/wm/workspace/workspace_layout_manager_unittest.cc b/ash/wm/workspace/workspace_layout_manager_unittest.cc index 77706e9..a27b484 100644 --- a/ash/wm/workspace/workspace_layout_manager_unittest.cc +++ b/ash/wm/workspace/workspace_layout_manager_unittest.cc @@ -14,6 +14,7 @@ #include "ash/shell_observer.h" #include "ash/shell_window_ids.h" #include "ash/test/ash_test_base.h" +#include "ash/wm/maximize_mode/workspace_backdrop_delegate.h" #include "ash/wm/window_state.h" #include "ash/wm/window_util.h" #include "ash/wm/wm_event.h" @@ -774,4 +775,175 @@ TEST_F(WorkspaceLayoutManagerSoloTest, NotResizeWhenScreenIsLocked) { EXPECT_EQ(window_bounds.ToString(), window->bounds().ToString()); } +// Following tests are written to test the backdrop functionality. + +namespace { + +class WorkspaceLayoutManagerBackdropTest : public test::AshTestBase { + public: + WorkspaceLayoutManagerBackdropTest() {} + virtual ~WorkspaceLayoutManagerBackdropTest() {} + + virtual void SetUp() OVERRIDE { + test::AshTestBase::SetUp(); + UpdateDisplay("800x600"); + default_container_ = Shell::GetContainer( + Shell::GetPrimaryRootWindow(), + internal::kShellWindowId_DefaultContainer); + // We set the size to something smaller then the display to avoid resizing + // issues with the shelf. + default_container_->SetBounds(gfx::Rect(0, 0, 800, 500)); + } + + aura::Window* CreateTestWindow(const gfx::Rect& bounds) { + aura::Window* window = CreateTestWindowInShellWithBounds(bounds); + return window; + } + + // Turn the top window back drop on / off. + void ShowTopWindowBackdrop(bool show) { + scoped_ptr backdrop; + if (show) { + backdrop.reset(new ash::internal::WorkspaceBackdropDelegate( + default_container_)); + } + (static_cast + (default_container_->layout_manager()))->SetMaximizeBackdropDelegate( + backdrop.Pass()); + // Closing and / or opening can be a delayed operation. + base::MessageLoop::current()->RunUntilIdle(); + } + + // Return the default container. + aura::Window* default_container() { return default_container_; } + + // Return the order of windows (top most first) as they are in the default + // container. If the window is visible it will be a big letter, otherwise a + // small one. The backdrop will be an X and unknown windows will be shown as + // '!'. + std::string GetWindowOrderAsString(aura::Window* backdrop, + aura::Window* wa, + aura::Window* wb, + aura::Window* wc) { + std::string result; + for (int i = static_cast(default_container()->children().size()) - 1; + i >= 0; + --i) { + if (!result.empty()) + result += ","; + if (default_container()->children()[i] == wa) + result += default_container()->children()[i]->IsVisible() ? "A" : "a"; + else if (default_container()->children()[i] == wb) + result += default_container()->children()[i]->IsVisible() ? "B" : "b"; + else if (default_container()->children()[i] == wc) + result += default_container()->children()[i]->IsVisible() ? "C" : "c"; + else if (default_container()->children()[i] == backdrop) + result += default_container()->children()[i]->IsVisible() ? "X" : "x"; + else + result += "!"; + } + return result; + } + + private: + // The default container. + aura::Window* default_container_; + + DISALLOW_COPY_AND_ASSIGN(WorkspaceLayoutManagerBackdropTest); +}; + +} // namespace + +// Check that creating the BackDrop without destroying it does not lead into +// a crash. +TEST_F(WorkspaceLayoutManagerBackdropTest, BackdropCrashTest) { + ShowTopWindowBackdrop(true); +} + +// Verify basic assumptions about the backdrop. +TEST_F(WorkspaceLayoutManagerBackdropTest, BasicBackdropTests) { + // Create a backdrop and see that there is one window (the backdrop) and + // that the size is the same as the default container as well as that it is + // not visible. + ShowTopWindowBackdrop(true); + ASSERT_EQ(1U, default_container()->children().size()); + EXPECT_FALSE(default_container()->children()[0]->IsVisible()); + + { + // Add a window and make sure that the backdrop is the second child. + scoped_ptr window(CreateTestWindow(gfx::Rect(1, 2, 3, 4))); + window->Show(); + ASSERT_EQ(2U, default_container()->children().size()); + EXPECT_TRUE(default_container()->children()[0]->IsVisible()); + EXPECT_TRUE(default_container()->children()[1]->IsVisible()); + EXPECT_EQ(window.get(), default_container()->children()[1]); + EXPECT_EQ(default_container()->bounds().ToString(), + default_container()->children()[0]->bounds().ToString()); + } + + // With the window gone the backdrop should be invisible again. + ASSERT_EQ(1U, default_container()->children().size()); + EXPECT_FALSE(default_container()->children()[0]->IsVisible()); + + // Destroying the Backdrop should empty the container. + ShowTopWindowBackdrop(false); + ASSERT_EQ(0U, default_container()->children().size()); +} + +// Verify that the backdrop gets properly created and placed. +TEST_F(WorkspaceLayoutManagerBackdropTest, VerifyBackdropAndItsStacking) { + scoped_ptr window1(CreateTestWindow(gfx::Rect(1, 2, 3, 4))); + window1->Show(); + + // Get the default container and check that only a single window is in there. + ASSERT_EQ(1U, default_container()->children().size()); + EXPECT_EQ(window1.get(), default_container()->children()[0]); + EXPECT_EQ("A", GetWindowOrderAsString(NULL, window1.get(), NULL, NULL)); + + // Create 2 more windows and check that they are also in the container. + scoped_ptr window2(CreateTestWindow(gfx::Rect(10, 2, 3, 4))); + scoped_ptr window3(CreateTestWindow(gfx::Rect(20, 2, 3, 4))); + window2->Show(); + window3->Show(); + + aura::Window* backdrop = NULL; + EXPECT_EQ("C,B,A", + GetWindowOrderAsString(backdrop, window1.get(), window2.get(), + window3.get())); + + // Turn on the backdrop mode and check that the window shows up where it + // should be (second highest number). + ShowTopWindowBackdrop(true); + backdrop = default_container()->children()[2]; + EXPECT_EQ("C,X,B,A", + GetWindowOrderAsString(backdrop, window1.get(), window2.get(), + window3.get())); + + // Switch the order of windows and check that it still remains in that + // location. + default_container()->StackChildAtTop(window2.get()); + EXPECT_EQ("B,X,C,A", + GetWindowOrderAsString(backdrop, window1.get(), window2.get(), + window3.get())); + + // Make the top window invisible and check. + window2.get()->Hide(); + EXPECT_EQ("b,C,X,A", + GetWindowOrderAsString(backdrop, window1.get(), window2.get(), + window3.get())); + // Then delete window after window and see that everything is in order. + window1.reset(); + EXPECT_EQ("b,C,X", + GetWindowOrderAsString(backdrop, window1.get(), window2.get(), + window3.get())); + window3.reset(); + EXPECT_EQ("b,x", + GetWindowOrderAsString(backdrop, window1.get(), window2.get(), + window3.get())); + ShowTopWindowBackdrop(false); + EXPECT_EQ("b", + GetWindowOrderAsString(NULL, window1.get(), window2.get(), + window3.get())); +} + } // namespace ash diff --git a/ash/wm/workspace_controller.cc b/ash/wm/workspace_controller.cc index 55ccf64..9b9f35e 100644 --- a/ash/wm/workspace_controller.cc +++ b/ash/wm/workspace_controller.cc @@ -13,6 +13,7 @@ #include "ash/wm/window_util.h" #include "ash/wm/workspace/workspace_event_handler.h" #include "ash/wm/workspace/workspace_layout_manager.h" +#include "ash/wm/workspace/workspace_layout_manager_delegate.h" #include "ui/aura/client/activation_client.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/window.h" @@ -135,5 +136,10 @@ void WorkspaceController::DoInitialAnimation() { } } +void WorkspaceController::SetMaximizeBackdropDelegate( + scoped_ptr delegate) { + layout_manager_->SetMaximizeBackdropDelegate(delegate.Pass()); +} + } // namespace internal } // namespace ash diff --git a/ash/wm/workspace_controller.h b/ash/wm/workspace_controller.h index 84df41c..175ebe7 100644 --- a/ash/wm/workspace_controller.h +++ b/ash/wm/workspace_controller.h @@ -21,6 +21,7 @@ class ShelfLayoutManager; class WorkspaceControllerTestHelper; class WorkspaceEventHandler; class WorkspaceLayoutManager; +class WorkspaceLayoutManagerDelegate; // WorkspaceController acts as a central place that ties together all the // various workspace pieces. @@ -37,6 +38,11 @@ class ASH_EXPORT WorkspaceController { // Starts the animation that occurs on first login. void DoInitialAnimation(); + // Add a delegate which adds a backdrop behind the top window of the default + // workspace. + void SetMaximizeBackdropDelegate( + scoped_ptr delegate); + private: friend class WorkspaceControllerTestHelper; -- cgit v1.1