summaryrefslogtreecommitdiffstats
path: root/ash
diff options
context:
space:
mode:
authorskuhne@chromium.org <skuhne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-09 17:58:25 +0000
committerskuhne@chromium.org <skuhne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-03-09 17:58:25 +0000
commit6344760afdb784d456ae77cb366b06962c4069c5 (patch)
tree1eb596a4c7f6898e29572d623b967b882f50d262 /ash
parent74e50c0cc9c4f0ba3301ae678c0939e3628b8e7b (diff)
downloadchromium_src-6344760afdb784d456ae77cb366b06962c4069c5.zip
chromium_src-6344760afdb784d456ae77cb366b06962c4069c5.tar.gz
chromium_src-6344760afdb784d456ae77cb366b06962c4069c5.tar.bz2
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
Diffstat (limited to 'ash')
-rw-r--r--ash/ash.gyp5
-rw-r--r--ash/wm/maximize_mode/maximize_mode_window_manager.cc72
-rw-r--r--ash/wm/maximize_mode/maximize_mode_window_manager.h16
-rw-r--r--ash/wm/maximize_mode/workspace_backdrop_delegate.cc154
-rw-r--r--ash/wm/maximize_mode/workspace_backdrop_delegate.h80
-rw-r--r--ash/wm/workspace/workspace_layout_manager.cc22
-rw-r--r--ash/wm/workspace/workspace_layout_manager.h24
-rw-r--r--ash/wm/workspace/workspace_layout_manager_delegate.h49
-rw-r--r--ash/wm/workspace/workspace_layout_manager_unittest.cc172
-rw-r--r--ash/wm/workspace_controller.cc6
-rw-r--r--ash/wm/workspace_controller.h6
11 files changed, 585 insertions, 21 deletions
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<WorkspaceLayoutManagerDelegate>(
+ 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 <set>
#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<aura::Window*> 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<bool> 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<WorkspaceLayoutManagerDelegate> 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<WorkspaceLayoutManagerDelegate> 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<WorkspaceLayoutManagerDelegate> 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<ash::internal::WorkspaceLayoutManagerDelegate> backdrop;
+ if (show) {
+ backdrop.reset(new ash::internal::WorkspaceBackdropDelegate(
+ default_container_));
+ }
+ (static_cast<internal::WorkspaceLayoutManager*>
+ (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<int>(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<aura::Window> 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<aura::Window> 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<aura::Window> window2(CreateTestWindow(gfx::Rect(10, 2, 3, 4)));
+ scoped_ptr<aura::Window> 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<WorkspaceLayoutManagerDelegate> 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<WorkspaceLayoutManagerDelegate> delegate);
+
private:
friend class WorkspaceControllerTestHelper;