Commit 6344760a authored by skuhne@chromium.org's avatar skuhne@chromium.org

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
parent 74e50c0c
...@@ -540,6 +540,8 @@ ...@@ -540,6 +540,8 @@
'wm/lock_state_observer.h', 'wm/lock_state_observer.h',
'wm/maximize_mode/maximize_mode_window_manager.cc', 'wm/maximize_mode/maximize_mode_window_manager.cc',
'wm/maximize_mode/maximize_mode_window_manager.h', '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.cc',
'wm/mru_window_tracker.h', 'wm/mru_window_tracker.h',
'wm/overlay_event_filter.cc', 'wm/overlay_event_filter.cc',
...@@ -643,6 +645,7 @@ ...@@ -643,6 +645,7 @@
'wm/workspace/workspace_event_handler.h', 'wm/workspace/workspace_event_handler.h',
'wm/workspace/workspace_layout_manager.cc', 'wm/workspace/workspace_layout_manager.cc',
'wm/workspace/workspace_layout_manager.h', 'wm/workspace/workspace_layout_manager.h',
'wm/workspace/workspace_layout_manager_delegate.h',
'wm/workspace/workspace_types.h', 'wm/workspace/workspace_types.h',
'wm/workspace/workspace_window_resizer.cc', 'wm/workspace/workspace_window_resizer.cc',
'wm/workspace/workspace_window_resizer.h', 'wm/workspace/workspace_window_resizer.h',
...@@ -969,6 +972,8 @@ ...@@ -969,6 +972,8 @@
'wm/window_positioner_unittest.cc', 'wm/window_positioner_unittest.cc',
'wm/window_state_unittest.cc', 'wm/window_state_unittest.cc',
'wm/window_util_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/magnetism_matcher_unittest.cc',
'wm/workspace/multi_window_resize_controller_unittest.cc', 'wm/workspace/multi_window_resize_controller_unittest.cc',
'wm/workspace/phantom_window_controller_unittest.cc', 'wm/workspace/phantom_window_controller_unittest.cc',
......
...@@ -4,9 +4,12 @@ ...@@ -4,9 +4,12 @@
#include "ash/wm/maximize_mode/maximize_mode_window_manager.h" #include "ash/wm/maximize_mode/maximize_mode_window_manager.h"
#include "ash/root_window_controller.h"
#include "ash/shell.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/mru_window_tracker.h"
#include "ash/wm/workspace_controller.h"
#include "ui/aura/window.h" #include "ui/aura/window.h"
#include "ui/gfx/screen.h" #include "ui/gfx/screen.h"
...@@ -14,7 +17,9 @@ namespace ash { ...@@ -14,7 +17,9 @@ namespace ash {
namespace internal { namespace internal {
MaximizeModeWindowManager::~MaximizeModeWindowManager() { MaximizeModeWindowManager::~MaximizeModeWindowManager() {
Shell::GetInstance()->RemoveShellObserver(this);
Shell::GetScreen()->RemoveObserver(this); Shell::GetScreen()->RemoveObserver(this);
EnableBackdropBehindTopWindowOnEachDisplay(false);
RemoveWindowCreationObservers(); RemoveWindowCreationObservers();
RestoreAllWindows(); RestoreAllWindows();
} }
...@@ -23,6 +28,22 @@ int MaximizeModeWindowManager::GetNumberOfManagedWindows() { ...@@ -23,6 +28,22 @@ int MaximizeModeWindowManager::GetNumberOfManagedWindows() {
return initial_state_type_.size(); 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) { void MaximizeModeWindowManager::OnWindowDestroying(aura::Window* window) {
// If a known window gets destroyed we need to remove all knowledge about it. // If a known window gets destroyed we need to remove all knowledge about it.
if (!IsContainerWindow(window)) if (!IsContainerWindow(window))
...@@ -65,10 +86,15 @@ void MaximizeModeWindowManager::OnDisplayRemoved(const gfx::Display& display) { ...@@ -65,10 +86,15 @@ void MaximizeModeWindowManager::OnDisplayRemoved(const gfx::Display& display) {
DisplayConfigurationChanged(); DisplayConfigurationChanged();
} }
MaximizeModeWindowManager::MaximizeModeWindowManager() { MaximizeModeWindowManager::MaximizeModeWindowManager()
: backdrops_hidden_(false) {
// TODO(skuhne): Turn off the overview mode and full screen modes before
// entering the MaximzieMode.
MaximizeAllWindows(); MaximizeAllWindows();
AddWindowCreationObservers(); AddWindowCreationObservers();
EnableBackdropBehindTopWindowOnEachDisplay(true);
Shell::GetScreen()->AddObserver(this); Shell::GetScreen()->AddObserver(this);
Shell::GetInstance()->AddShellObserver(this);
} }
void MaximizeModeWindowManager::MaximizeAllWindows() { void MaximizeModeWindowManager::MaximizeAllWindows() {
...@@ -110,7 +136,6 @@ void MaximizeModeWindowManager::MaximizeAndTrackWindow( ...@@ -110,7 +136,6 @@ void MaximizeModeWindowManager::MaximizeAndTrackWindow(
else else
window_state->SetRestoreBoundsInScreen(initial_rect); window_state->SetRestoreBoundsInScreen(initial_rect);
CenterWindow(window); CenterWindow(window);
// TODO(skuhne): Add a background cover layer.
} else { } else {
// Minimized windows can remain as they are. // Minimized windows can remain as they are.
if (state != wm::WINDOW_STATE_TYPE_MINIMIZED) if (state != wm::WINDOW_STATE_TYPE_MINIMIZED)
...@@ -128,7 +153,6 @@ void MaximizeModeWindowManager::RestoreAndForgetWindow( ...@@ -128,7 +153,6 @@ void MaximizeModeWindowManager::RestoreAndForgetWindow(
// Restore window if it can be restored. // Restore window if it can be restored.
if (state != wm::WINDOW_STATE_TYPE_MAXIMIZED) { if (state != wm::WINDOW_STATE_TYPE_MAXIMIZED) {
if (!CanMaximize(window)) { if (!CanMaximize(window)) {
// TODO(skuhne): Remove the background cover layer.
if (window_state->HasRestoreBounds()) { if (window_state->HasRestoreBounds()) {
// TODO(skuhne): If the system shuts down in maximized mode, the proper // TODO(skuhne): If the system shuts down in maximized mode, the proper
// restore coordinates should get saved. // restore coordinates should get saved.
...@@ -187,19 +211,17 @@ void MaximizeModeWindowManager::CenterWindow(aura::Window* window) { ...@@ -187,19 +211,17 @@ void MaximizeModeWindowManager::CenterWindow(aura::Window* window) {
void MaximizeModeWindowManager::AddWindowCreationObservers() { void MaximizeModeWindowManager::AddWindowCreationObservers() {
DCHECK(observed_container_windows_.empty()); DCHECK(observed_container_windows_.empty());
// Observe window activations and switchable containers on all root windows // Observe window activations/creations in the default containers on all root
// for newly created windows during overview. // windows.
aura::Window::Windows root_windows = Shell::GetAllRootWindows(); aura::Window::Windows root_windows = Shell::GetAllRootWindows();
for (aura::Window::Windows::const_iterator iter = root_windows.begin(); for (aura::Window::Windows::const_iterator iter = root_windows.begin();
iter != root_windows.end(); ++iter) { iter != root_windows.end(); ++iter) {
for (size_t i = 0; i < kSwitchableWindowContainerIdsLength; ++i) { aura::Window* container = Shell::GetContainer(*iter,
aura::Window* container = Shell::GetContainer(*iter, internal::kShellWindowId_DefaultContainer);
kSwitchableWindowContainerIds[i]); DCHECK(observed_container_windows_.find(container) ==
DCHECK(observed_container_windows_.find(container) == observed_container_windows_.end());
observed_container_windows_.end()); container->AddObserver(this);
container->AddObserver(this); observed_container_windows_.insert(container);
observed_container_windows_.insert(container);
}
} }
} }
...@@ -213,8 +235,10 @@ void MaximizeModeWindowManager::RemoveWindowCreationObservers() { ...@@ -213,8 +235,10 @@ void MaximizeModeWindowManager::RemoveWindowCreationObservers() {
} }
void MaximizeModeWindowManager::DisplayConfigurationChanged() { void MaximizeModeWindowManager::DisplayConfigurationChanged() {
EnableBackdropBehindTopWindowOnEachDisplay(false);
RemoveWindowCreationObservers(); RemoveWindowCreationObservers();
AddWindowCreationObservers(); AddWindowCreationObservers();
EnableBackdropBehindTopWindowOnEachDisplay(true);
} }
bool MaximizeModeWindowManager::IsContainerWindow(aura::Window* window) { bool MaximizeModeWindowManager::IsContainerWindow(aura::Window* window) {
...@@ -222,5 +246,25 @@ bool MaximizeModeWindowManager::IsContainerWindow(aura::Window* window) { ...@@ -222,5 +246,25 @@ bool MaximizeModeWindowManager::IsContainerWindow(aura::Window* window) {
observed_container_windows_.end(); 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 internal
} // namespace ash } // namespace ash
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <set> #include <set>
#include "ash/ash_export.h" #include "ash/ash_export.h"
#include "ash/shell_observer.h"
#include "ash/wm/window_state.h" #include "ash/wm/window_state.h"
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
...@@ -27,12 +28,13 @@ namespace internal{ ...@@ -27,12 +28,13 @@ namespace internal{
// With the destruction of the manager all windows will be restored to their // With the destruction of the manager all windows will be restored to their
// original state. // original state.
class ASH_EXPORT MaximizeModeWindowManager : public aura::WindowObserver, class ASH_EXPORT MaximizeModeWindowManager : public aura::WindowObserver,
public gfx::DisplayObserver { public gfx::DisplayObserver,
public ShellObserver {
public: public:
// This should only be deleted by the creator (ash::Shell). // This should only be deleted by the creator (ash::Shell).
virtual ~MaximizeModeWindowManager(); virtual ~MaximizeModeWindowManager();
// Returns the number of maximized & tracked windows by this manager. // Returns the number of maximized & tracked windows by this manager.
int GetNumberOfManagedWindows(); int GetNumberOfManagedWindows();
// Overridden from WindowObserver: // Overridden from WindowObserver:
...@@ -48,6 +50,10 @@ class ASH_EXPORT MaximizeModeWindowManager : public aura::WindowObserver, ...@@ -48,6 +50,10 @@ class ASH_EXPORT MaximizeModeWindowManager : public aura::WindowObserver,
virtual void OnDisplayAdded(const gfx::Display& display) OVERRIDE; virtual void OnDisplayAdded(const gfx::Display& display) OVERRIDE;
virtual void OnDisplayRemoved(const gfx::Display& display) OVERRIDE; virtual void OnDisplayRemoved(const gfx::Display& display) OVERRIDE;
// ShellObserver overrides:
void OnOverviewModeStarted();
void OnOverviewModeEnded();
protected: protected:
friend class ash::Shell; friend class ash::Shell;
...@@ -98,12 +104,18 @@ class ASH_EXPORT MaximizeModeWindowManager : public aura::WindowObserver, ...@@ -98,12 +104,18 @@ class ASH_EXPORT MaximizeModeWindowManager : public aura::WindowObserver,
// Returns true when the |window| is a container window. // Returns true when the |window| is a container window.
bool IsContainerWindow(aura::Window* 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. // Every window which got touched by our window manager gets added here.
WindowToStateType initial_state_type_; WindowToStateType initial_state_type_;
// All container windows which have to be tracked. // All container windows which have to be tracked.
std::set<aura::Window*> observed_container_windows_; std::set<aura::Window*> observed_container_windows_;
// True if all backdrops are hidden.
bool backdrops_hidden_;
DISALLOW_COPY_AND_ASSIGN(MaximizeModeWindowManager); DISALLOW_COPY_AND_ASSIGN(MaximizeModeWindowManager);
}; };
......
// 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
// 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_
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "ash/wm/window_state.h" #include "ash/wm/window_state.h"
#include "ash/wm/window_util.h" #include "ash/wm/window_util.h"
#include "ash/wm/wm_event.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/activation_client.h"
#include "ui/aura/client/aura_constants.h" #include "ui/aura/client/aura_constants.h"
#include "ui/aura/window.h" #include "ui/aura/window.h"
...@@ -50,12 +51,8 @@ WorkspaceLayoutManager::WorkspaceLayoutManager(aura::Window* window) ...@@ -50,12 +51,8 @@ WorkspaceLayoutManager::WorkspaceLayoutManager(aura::Window* window)
WorkspaceLayoutManager::~WorkspaceLayoutManager() { WorkspaceLayoutManager::~WorkspaceLayoutManager() {
if (root_window_) if (root_window_)
root_window_->RemoveObserver(this); root_window_->RemoveObserver(this);
for (WindowSet::const_iterator i = windows_.begin(); for (WindowSet::const_iterator i = windows_.begin(); i != windows_.end(); ++i)
i != windows_.end();
++i) {
(*i)->RemoveObserver(this); (*i)->RemoveObserver(this);
wm::GetWindowState(*i)->RemoveObserver(this);
}
Shell::GetInstance()->RemoveShellObserver(this); Shell::GetInstance()->RemoveShellObserver(this);
Shell::GetInstance()->activation_client()->RemoveObserver(this); Shell::GetInstance()->activation_client()->RemoveObserver(this);
} }
...@@ -64,6 +61,11 @@ void WorkspaceLayoutManager::SetShelf(internal::ShelfLayoutManager* shelf) { ...@@ -64,6 +61,11 @@ void WorkspaceLayoutManager::SetShelf(internal::ShelfLayoutManager* shelf) {
shelf_ = shelf; shelf_ = shelf;
} }
void WorkspaceLayoutManager::SetMaximizeBackdropDelegate(
scoped_ptr<WorkspaceLayoutManagerDelegate> delegate) {
backdrop_delegate_.reset(delegate.release());
}
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// WorkspaceLayoutManager, aura::LayoutManager implementation: // WorkspaceLayoutManager, aura::LayoutManager implementation:
...@@ -76,6 +78,8 @@ void WorkspaceLayoutManager::OnWindowAddedToLayout(Window* child) { ...@@ -76,6 +78,8 @@ void WorkspaceLayoutManager::OnWindowAddedToLayout(Window* child) {
window_state->AddObserver(this); window_state->AddObserver(this);
UpdateShelfVisibility(); UpdateShelfVisibility();
UpdateFullscreenState(); UpdateFullscreenState();
if (backdrop_delegate_)
backdrop_delegate_->OnWindowAddedToLayout(child);
WindowPositioner::RearrangeVisibleWindowOnShow(child); WindowPositioner::RearrangeVisibleWindowOnShow(child);
} }
...@@ -91,6 +95,8 @@ void WorkspaceLayoutManager::OnWillRemoveWindowFromLayout(Window* child) { ...@@ -91,6 +95,8 @@ void WorkspaceLayoutManager::OnWillRemoveWindowFromLayout(Window* child) {
void WorkspaceLayoutManager::OnWindowRemovedFromLayout(Window* child) { void WorkspaceLayoutManager::OnWindowRemovedFromLayout(Window* child) {
UpdateShelfVisibility(); UpdateShelfVisibility();
UpdateFullscreenState(); UpdateFullscreenState();
if (backdrop_delegate_)
backdrop_delegate_->OnWindowRemovedFromLayout(child);
} }
void WorkspaceLayoutManager::OnChildWindowVisibilityChanged(Window* child, void WorkspaceLayoutManager::OnChildWindowVisibilityChanged(Window* child,
...@@ -106,6 +112,8 @@ void WorkspaceLayoutManager::OnChildWindowVisibilityChanged(Window* child, ...@@ -106,6 +112,8 @@ void WorkspaceLayoutManager::OnChildWindowVisibilityChanged(Window* child,
WindowPositioner::RearrangeVisibleWindowOnHideOrRemove(child); WindowPositioner::RearrangeVisibleWindowOnHideOrRemove(child);
UpdateFullscreenState(); UpdateFullscreenState();
UpdateShelfVisibility(); UpdateShelfVisibility();
if (backdrop_delegate_)
backdrop_delegate_->OnChildWindowVisibilityChanged(child, visible);
} }
void WorkspaceLayoutManager::SetChildBounds( void WorkspaceLayoutManager::SetChildBounds(
...@@ -166,6 +174,8 @@ void WorkspaceLayoutManager::OnWindowPropertyChanged(Window* window, ...@@ -166,6 +174,8 @@ void WorkspaceLayoutManager::OnWindowPropertyChanged(Window* window,
void WorkspaceLayoutManager::OnWindowStackingChanged(aura::Window* window) { void WorkspaceLayoutManager::OnWindowStackingChanged(aura::Window* window) {
UpdateShelfVisibility(); UpdateShelfVisibility();
UpdateFullscreenState(); UpdateFullscreenState();
if (backdrop_delegate_)
backdrop_delegate_->OnWindowStackingChanged(window);
} }
void WorkspaceLayoutManager::OnWindowDestroying(aura::Window* window) { void WorkspaceLayoutManager::OnWindowDestroying(aura::Window* window) {
...@@ -214,6 +224,8 @@ void WorkspaceLayoutManager::OnPostWindowStateTypeChange( ...@@ -214,6 +224,8 @@ void WorkspaceLayoutManager::OnPostWindowStateTypeChange(
} }
UpdateShelfVisibility(); UpdateShelfVisibility();
if (backdrop_delegate_)
backdrop_delegate_->OnPostWindowStateTypeChange(window_state, old_type);
} }
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "ash/wm/wm_types.h" #include "ash/wm/wm_types.h"
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "ui/aura/client/activation_change_observer.h" #include "ui/aura/client/activation_change_observer.h"
#include "ui/aura/layout_manager.h" #include "ui/aura/layout_manager.h"
#include "ui/aura/window_observer.h" #include "ui/aura/window_observer.h"
...@@ -36,6 +37,7 @@ class WMEvent; ...@@ -36,6 +37,7 @@ class WMEvent;
namespace internal { namespace internal {
class ShelfLayoutManager; class ShelfLayoutManager;
class WorkspaceLayoutManagerDelegate;
// LayoutManager used on the window created for a workspace. // LayoutManager used on the window created for a workspace.
class ASH_EXPORT WorkspaceLayoutManager class ASH_EXPORT WorkspaceLayoutManager
...@@ -50,6 +52,12 @@ class ASH_EXPORT WorkspaceLayoutManager ...@@ -50,6 +52,12 @@ class ASH_EXPORT WorkspaceLayoutManager
void SetShelf(internal::ShelfLayoutManager* shelf); 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: // Overridden from aura::LayoutManager:
virtual void OnWindowResized() OVERRIDE {} virtual void OnWindowResized() OVERRIDE {}
virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE; virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE;
...@@ -103,6 +111,18 @@ class ASH_EXPORT WorkspaceLayoutManager ...@@ -103,6 +111,18 @@ class ASH_EXPORT WorkspaceLayoutManager
// has changed. // has changed.
void UpdateFullscreenState(); 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_; internal::ShelfLayoutManager* shelf_;
aura::Window* window_; aura::Window* window_;
aura::Window* root_window_; aura::Window* root_window_;
...@@ -116,6 +136,10 @@ class ASH_EXPORT WorkspaceLayoutManager ...@@ -116,6 +136,10 @@ class ASH_EXPORT WorkspaceLayoutManager
// True if this workspace is currently in fullscreen mode. // True if this workspace is currently in fullscreen mode.
bool is_fullscreen_; 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); DISALLOW_COPY_AND_ASSIGN(WorkspaceLayoutManager);
}; };
......
// 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_
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "ash/shell_observer.h" #include "ash/shell_observer.h"
#include "ash/shell_window_ids.h" #include "ash/shell_window_ids.h"
#include "ash/test/ash_test_base.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_state.h"
#include "ash/wm/window_util.h" #include "ash/wm/window_util.h"
#include "ash/wm/wm_event.h" #include "ash/wm/wm_event.h"
...@@ -774,4 +775,175 @@ TEST_F(WorkspaceLayoutManagerSoloTest, NotResizeWhenScreenIsLocked) { ...@@ -774,4 +775,175 @@ TEST_F(WorkspaceLayoutManagerSoloTest, NotResizeWhenScreenIsLocked) {
EXPECT_EQ(window_bounds.ToString(), window->bounds().ToString()); 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 } // namespace ash
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "ash/wm/window_util.h" #include "ash/wm/window_util.h"
#include "ash/wm/workspace/workspace_event_handler.h" #include "ash/wm/workspace/workspace_event_handler.h"
#include "ash/wm/workspace/workspace_layout_manager.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/activation_client.h"
#include "ui/aura/client/aura_constants.h" #include "ui/aura/client/aura_constants.h"
#include "ui/aura/window.h" #include "ui/aura/window.h"
...@@ -135,5 +136,10 @@ void WorkspaceController::DoInitialAnimation() { ...@@ -135,5 +136,10 @@ void WorkspaceController::DoInitialAnimation() {
} }
} }
void WorkspaceController::SetMaximizeBackdropDelegate(
scoped_ptr<WorkspaceLayoutManagerDelegate> delegate) {
layout_manager_->SetMaximizeBackdropDelegate(delegate.Pass());
}
} // namespace internal } // namespace internal
} // namespace ash } // namespace ash
...@@ -21,6 +21,7 @@ class ShelfLayoutManager; ...@@ -21,6 +21,7 @@ class ShelfLayoutManager;
class WorkspaceControllerTestHelper; class WorkspaceControllerTestHelper;
class WorkspaceEventHandler; class WorkspaceEventHandler;
class WorkspaceLayoutManager; class WorkspaceLayoutManager;
class WorkspaceLayoutManagerDelegate;
// WorkspaceController acts as a central place that ties together all the // WorkspaceController acts as a central place that ties together all the
// various workspace pieces. // various workspace pieces.
...@@ -37,6 +38,11 @@ class ASH_EXPORT WorkspaceController { ...@@ -37,6 +38,11 @@ class ASH_EXPORT WorkspaceController {
// Starts the animation that occurs on first login. // Starts the animation that occurs on first login.
void DoInitialAnimation(); void DoInitialAnimation();
// Add a delegate which adds a backdrop behind the top window of the default
// workspace.
void SetMaximizeBackdropDelegate(
scoped_ptr<WorkspaceLayoutManagerDelegate> delegate);
private: private:
friend class WorkspaceControllerTestHelper; friend class WorkspaceControllerTestHelper;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment