diff options
author | jamescook@chromium.org <jamescook@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-02-17 19:06:41 +0000 |
---|---|---|
committer | jamescook@chromium.org <jamescook@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-02-17 19:06:41 +0000 |
commit | 27a84042eaf11de85667ea58e2da81ef1963a6ac (patch) | |
tree | 83ecac6b6effb2dce4b64991219e43243d08229d | |
parent | 4e8d5c8ada6452b59975f9da496d7c8b4858763e (diff) | |
download | chromium_src-27a84042eaf11de85667ea58e2da81ef1963a6ac.zip chromium_src-27a84042eaf11de85667ea58e2da81ef1963a6ac.tar.gz chromium_src-27a84042eaf11de85667ea58e2da81ef1963a6ac.tar.bz2 |
Aura: New window shadows, desktop background debug toggle
+ Shadows support different appearances for active and inactive states.
+ Shadow opacity animates on activation change.
+ ImageGrid supports changing its images, allowing us to maintain our use of a single set of shadow layers per window.
+ Press control-alt-B in a debug build to reset the desktop background to a solid color, useful with a white background for testing shadows.
+ Window shadow art assets were added in an earlier revision.
After this change lands I will delete the previous art assets, ui/resources/aura/shadow_rect_*
BUG=113075
TEST=aura_shell_unittests, added to ShadowControllerTest and ImageGridTest
Review URL: https://chromiumcodereview.appspot.com/9414028
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@122547 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | ash/accelerators/accelerator_controller.cc | 14 | ||||
-rw-r--r-- | ash/accelerators/accelerator_controller_unittest.cc | 3 | ||||
-rw-r--r-- | ash/shell.cc | 35 | ||||
-rw-r--r-- | ash/shell.h | 18 | ||||
-rw-r--r-- | ash/shell/window_type_launcher.cc | 2 | ||||
-rw-r--r-- | ash/wm/image_grid.cc | 58 | ||||
-rw-r--r-- | ash/wm/image_grid.h | 34 | ||||
-rw-r--r-- | ash/wm/image_grid_unittest.cc | 61 | ||||
-rw-r--r-- | ash/wm/shadow.cc | 132 | ||||
-rw-r--r-- | ash/wm/shadow.h | 34 | ||||
-rw-r--r-- | ash/wm/shadow_controller.cc | 28 | ||||
-rw-r--r-- | ash/wm/shadow_controller.h | 3 | ||||
-rw-r--r-- | ash/wm/shadow_controller_unittest.cc | 39 | ||||
-rw-r--r-- | ui/resources/ui_resources.grd | 24 |
14 files changed, 386 insertions, 99 deletions
diff --git a/ash/accelerators/accelerator_controller.cc b/ash/accelerators/accelerator_controller.cc index cb26296..0dc741d 100644 --- a/ash/accelerators/accelerator_controller.cc +++ b/ash/accelerators/accelerator_controller.cc @@ -50,6 +50,7 @@ enum AcceleratorAction { PRINT_WINDOW_HIERARCHY, ROTATE_SCREEN, TOGGLE_COMPACT_WINDOW_MODE, + TOGGLE_DESKTOP_BACKGROUND_MODE, TOGGLE_ROOT_WINDOW_FULL_SCREEN, #endif }; @@ -124,6 +125,8 @@ const struct AcceleratorData { ROTATE_SCREEN }, { ui::ET_TRANSLATED_KEY_PRESS, ui::VKEY_A, false, true, true, TOGGLE_COMPACT_WINDOW_MODE }, + { ui::ET_TRANSLATED_KEY_PRESS, ui::VKEY_B, false, true, true, + TOGGLE_DESKTOP_BACKGROUND_MODE }, { ui::ET_TRANSLATED_KEY_PRESS, ui::VKEY_F11, false, true, false, TOGGLE_ROOT_WINDOW_FULL_SCREEN }, { ui::ET_TRANSLATED_KEY_PRESS, ui::VKEY_L, false, false, true, @@ -204,6 +207,15 @@ bool HandleToggleCompactWindowMode() { return true; } +bool HandleToggleDesktopBackgroundMode() { + ash::Shell* shell = ash::Shell::GetInstance(); + if (shell->desktop_background_mode() == ash::Shell::BACKGROUND_IMAGE) + shell->SetDesktopBackgroundMode(ash::Shell::BACKGROUND_SOLID_COLOR); + else + shell->SetDesktopBackgroundMode(ash::Shell::BACKGROUND_IMAGE); + return true; +} + bool HandleToggleRootWindowFullScreen() { aura::RootWindow::GetInstance()->ToggleFullScreen(); return true; @@ -381,6 +393,8 @@ bool AcceleratorController::AcceleratorPressed( return HandleRotateScreen(); case TOGGLE_COMPACT_WINDOW_MODE: return HandleToggleCompactWindowMode(); + case TOGGLE_DESKTOP_BACKGROUND_MODE: + return HandleToggleDesktopBackgroundMode(); case TOGGLE_ROOT_WINDOW_FULL_SCREEN: return HandleToggleRootWindowFullScreen(); case PRINT_LAYER_HIERARCHY: diff --git a/ash/accelerators/accelerator_controller_unittest.cc b/ash/accelerators/accelerator_controller_unittest.cc index 10bbf5a..d85d337 100644 --- a/ash/accelerators/accelerator_controller_unittest.cc +++ b/ash/accelerators/accelerator_controller_unittest.cc @@ -637,6 +637,9 @@ TEST_F(AcceleratorControllerTest, GlobalAccelerators) { // ToggleCompactWindowMode EXPECT_TRUE(GetController()->Process( PostImeAccelerator(ui::VKEY_A, false, true, true))); + // ToggleDesktopBackgroundMode + EXPECT_TRUE(GetController()->Process( + PostImeAccelerator(ui::VKEY_B, false, true, true))); #if !defined(OS_LINUX) // ToggleDesktopFullScreen (not implemented yet on Linux) EXPECT_TRUE(GetController()->Process( diff --git a/ash/shell.cc b/ash/shell.cc index 5be7eec..ebb35ea 100644 --- a/ash/shell.cc +++ b/ash/shell.cc @@ -215,6 +215,7 @@ Shell::Shell(ShellDelegate* delegate) shelf_(NULL), dynamic_window_mode_(false), window_mode_(MODE_OVERLAPPING), + desktop_background_mode_(BACKGROUND_IMAGE), root_window_layout_(NULL), status_widget_(NULL) { // Pass ownership of the filter to the root window. @@ -462,6 +463,27 @@ void Shell::SetWindowModeForMonitorSize(const gfx::Size& monitor_size) { ChangeWindowMode(new_mode); } +void Shell::SetDesktopBackgroundMode(BackgroundMode mode) { + if (mode == BACKGROUND_SOLID_COLOR) { + // Set a solid black background. + // TODO(derat): Remove this in favor of having the compositor only clear the + // viewport when there are regions not covered by a layer: + // http://crbug.com/113445 + ui::Layer* background_layer = new ui::Layer(ui::Layer::LAYER_SOLID_COLOR); + background_layer->SetColor(SK_ColorBLACK); + GetContainer(internal::kShellWindowId_DesktopBackgroundContainer)-> + layer()->Add(background_layer); + root_window_layout_->SetBackgroundLayer(background_layer); + root_window_layout_->SetBackgroundWidget(NULL); + } else { + // Create the desktop background image. + root_window_layout_->SetBackgroundLayer(NULL); + root_window_layout_->SetBackgroundWidget( + internal::CreateDesktopBackground()); + } + desktop_background_mode_ = mode; +} + bool Shell::IsScreenLocked() const { const aura::Window* lock_screen_container = GetContainer( internal::kShellWindowId_LockScreenContainer); @@ -543,15 +565,7 @@ void Shell::SetupCompactWindowMode() { MaximizeWindows(default_container); // Set a solid black background. - // TODO(derat): Remove this in favor of having the compositor only clear the - // viewport when there are regions not covered by a layer: - // http://crbug.com/113445 - ui::Layer* background_layer = new ui::Layer(ui::Layer::LAYER_SOLID_COLOR); - background_layer->SetColor(SK_ColorBLACK); - GetContainer(internal::kShellWindowId_DesktopBackgroundContainer)-> - layer()->Add(background_layer); - root_window_layout_->SetBackgroundLayer(background_layer); - root_window_layout_->SetBackgroundWidget(NULL); + SetDesktopBackgroundMode(BACKGROUND_SOLID_COLOR); } void Shell::SetupNonCompactWindowMode() { @@ -599,8 +613,7 @@ void Shell::SetupNonCompactWindowMode() { RestoreMaximizedWindows(default_container); // Create the desktop background image. - root_window_layout_->SetBackgroundWidget(internal::CreateDesktopBackground()); - root_window_layout_->SetBackgroundLayer(NULL); + SetDesktopBackgroundMode(BACKGROUND_IMAGE); } void Shell::ResetLayoutManager(int container_id) { diff --git a/ash/shell.h b/ash/shell.h index 25b98b2..bc1e24f 100644 --- a/ash/shell.h +++ b/ash/shell.h @@ -28,6 +28,9 @@ namespace gfx { class Point; class Rect; } +namespace ui { +class Layer; +} namespace views { class NonClientFrameView; class Widget; @@ -78,6 +81,11 @@ class ASH_EXPORT Shell { MODE_OVERLAPPING, }; + enum BackgroundMode { + BACKGROUND_IMAGE, + BACKGROUND_SOLID_COLOR + }; + enum Direction { FORWARD, BACKWARD @@ -96,6 +104,10 @@ class ASH_EXPORT Shell { return compact_status_area_offset_; } + BackgroundMode desktop_background_mode() const { + return desktop_background_mode_; + } + aura::Window* GetContainer(int container_id); const aura::Window* GetContainer(int container_id) const; @@ -123,6 +135,9 @@ class ASH_EXPORT Shell { // Sets an appropriate window mode for the given screen resolution. void SetWindowModeForMonitorSize(const gfx::Size& monitor_size); + // Sets the desktop background mode. + void SetDesktopBackgroundMode(BackgroundMode mode); + // Returns true if the screen is locked. bool IsScreenLocked() const; @@ -261,6 +276,9 @@ class ASH_EXPORT Shell { // Can change at runtime. WindowMode window_mode_; + // Can change at runtime. + BackgroundMode desktop_background_mode_; + // Owned by aura::RootWindow, cached here for type safety. internal::RootWindowLayoutManager* root_window_layout_; diff --git a/ash/shell/window_type_launcher.cc b/ash/shell/window_type_launcher.cc index 0153d1c..63dde99 100644 --- a/ash/shell/window_type_launcher.cc +++ b/ash/shell/window_type_launcher.cc @@ -171,7 +171,7 @@ void InitWindowTypeLauncher() { gfx::Rect(120, 150, 400, 400)); widget->GetNativeView()->SetName("WindowTypeLauncher"); ash::internal::SetShadowType(widget->GetNativeView(), - ash::internal::SHADOW_TYPE_NONE); + ash::internal::SHADOW_TYPE_RECTANGULAR); widget->Show(); } diff --git a/ash/wm/image_grid.cc b/ash/wm/image_grid.cc index d888762..99ef5c7 100644 --- a/ash/wm/image_grid.cc +++ b/ash/wm/image_grid.cc @@ -26,7 +26,8 @@ gfx::Rect ImageGrid::TestAPI::GetTransformedLayerBounds( } ImageGrid::ImageGrid() - : top_image_height_(0), + : layer_(new ui::Layer(ui::Layer::LAYER_NOT_DRAWN)), + top_image_height_(0), bottom_image_height_(0), left_image_width_(0), right_image_width_(0), @@ -39,26 +40,24 @@ ImageGrid::ImageGrid() ImageGrid::~ImageGrid() { } -void ImageGrid::Init(const gfx::Image* top_left_image, - const gfx::Image* top_image, - const gfx::Image* top_right_image, - const gfx::Image* left_image, - const gfx::Image* center_image, - const gfx::Image* right_image, - const gfx::Image* bottom_left_image, - const gfx::Image* bottom_image, - const gfx::Image* bottom_right_image) { - layer_.reset(new ui::Layer(ui::Layer::LAYER_NOT_DRAWN)); - - InitImage(top_left_image, &top_left_layer_, &top_left_painter_); - InitImage(top_image, &top_layer_, &top_painter_); - InitImage(top_right_image, &top_right_layer_, &top_right_painter_); - InitImage(left_image, &left_layer_, &left_painter_); - InitImage(center_image, ¢er_layer_, ¢er_painter_); - InitImage(right_image, &right_layer_, &right_painter_); - InitImage(bottom_left_image, &bottom_left_layer_, &bottom_left_painter_); - InitImage(bottom_image, &bottom_layer_, &bottom_painter_); - InitImage(bottom_right_image, &bottom_right_layer_, &bottom_right_painter_); +void ImageGrid::SetImages(const gfx::Image* top_left_image, + const gfx::Image* top_image, + const gfx::Image* top_right_image, + const gfx::Image* left_image, + const gfx::Image* center_image, + const gfx::Image* right_image, + const gfx::Image* bottom_left_image, + const gfx::Image* bottom_image, + const gfx::Image* bottom_right_image) { + SetImage(top_left_image, &top_left_layer_, &top_left_painter_); + SetImage(top_image, &top_layer_, &top_painter_); + SetImage(top_right_image, &top_right_layer_, &top_right_painter_); + SetImage(left_image, &left_layer_, &left_painter_); + SetImage(center_image, ¢er_layer_, ¢er_painter_); + SetImage(right_image, &right_layer_, &right_painter_); + SetImage(bottom_left_image, &bottom_left_layer_, &bottom_left_painter_); + SetImage(bottom_image, &bottom_layer_, &bottom_painter_); + SetImage(bottom_right_image, &bottom_right_layer_, &bottom_right_painter_); top_image_height_ = GetImageSize(top_image).height(); bottom_image_height_ = GetImageSize(bottom_image).height(); @@ -77,6 +76,9 @@ void ImageGrid::Init(const gfx::Image* top_left_image, right_column_width_ = max(GetImageSize(top_right_image).width(), max(GetImageSize(right_image).width(), GetImageSize(bottom_right_image).width())); + + // Invalidate previous |size_| so calls to SetSize() will recompute it. + size_.SetSize(0, 0); } void ImageGrid::SetSize(const gfx::Size& size) { @@ -224,12 +226,20 @@ bool ImageGrid::LayerExceedsSize(const ui::Layer* layer, layer->bounds().height() > size.height(); } -void ImageGrid::InitImage(const gfx::Image* image, - scoped_ptr<ui::Layer>* layer_ptr, - scoped_ptr<ImagePainter>* painter_ptr) { +void ImageGrid::SetImage(const gfx::Image* image, + scoped_ptr<ui::Layer>* layer_ptr, + scoped_ptr<ImagePainter>* painter_ptr) { + // Clean out old layers and painters. + if (layer_ptr->get()) + layer_->Remove(layer_ptr->get()); + layer_ptr->reset(); + painter_ptr->reset(); + + // If we're not using an image, we're done. if (!image) return; + // Set up the new layer and painter. layer_ptr->reset(new ui::Layer(ui::Layer::LAYER_TEXTURED)); const gfx::Size size = GetImageSize(image); diff --git a/ash/wm/image_grid.h b/ash/wm/image_grid.h index 0f8bf2b..0c1417c 100644 --- a/ash/wm/image_grid.h +++ b/ash/wm/image_grid.h @@ -109,17 +109,18 @@ class ASH_EXPORT ImageGrid { int left_image_width() const { return left_image_width_; } int right_image_width() const { return right_image_width_; } - // Initializes the grid to display the passed-in images (any of which can be - // NULL). Ownership of the images remains with the caller. - void Init(const gfx::Image* top_left_image, - const gfx::Image* top_image, - const gfx::Image* top_right_image, - const gfx::Image* left_image, - const gfx::Image* center_image, - const gfx::Image* right_image, - const gfx::Image* bottom_left_image, - const gfx::Image* bottom_image, - const gfx::Image* bottom_right_image); + // Sets the grid to display the passed-in images (any of which can be NULL). + // Ownership of the images remains with the caller. May be called more than + // once to switch images. + void SetImages(const gfx::Image* top_left_image, + const gfx::Image* top_image, + const gfx::Image* top_right_image, + const gfx::Image* left_image, + const gfx::Image* center_image, + const gfx::Image* right_image, + const gfx::Image* bottom_left_image, + const gfx::Image* bottom_image, + const gfx::Image* bottom_right_image); void SetSize(const gfx::Size& size); @@ -153,11 +154,12 @@ class ASH_EXPORT ImageGrid { // Returns true if |layer|'s bounds don't fit within |size|. static bool LayerExceedsSize(const ui::Layer* layer, const gfx::Size& size); - // Initializes |layer_ptr| and |painter_ptr| to display |image|. - // Also adds the passed-in layer to |layer_|. - void InitImage(const gfx::Image* image, - scoped_ptr<ui::Layer>* layer_ptr, - scoped_ptr<ImagePainter>* painter_ptr); + // Sets |layer_ptr| and |painter_ptr| to display |image| and adds the + // passed-in layer to |layer_|. If image is NULL resets |layer_ptr| and + // |painter_ptr| and removes any existing layer from |layer_|. + void SetImage(const gfx::Image* image, + scoped_ptr<ui::Layer>* layer_ptr, + scoped_ptr<ImagePainter>* painter_ptr); // Layer that contains all of the image layers. scoped_ptr<ui::Layer> layer_; diff --git a/ash/wm/image_grid_unittest.cc b/ash/wm/image_grid_unittest.cc index f2fe71b..b2d74b5 100644 --- a/ash/wm/image_grid_unittest.cc +++ b/ash/wm/image_grid_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -38,9 +38,9 @@ TEST_F(ImageGridTest, Basic) { scoped_ptr<gfx::Image> image_BxB(CreateImage(gfx::Size(kBorder, kBorder))); ImageGrid grid; - grid.Init(image_BxB.get(), image_1xB.get(), image_BxB.get(), - image_Bx1.get(), image_1x1.get(), image_Bx1.get(), - image_BxB.get(), image_1xB.get(), image_BxB.get()); + grid.SetImages(image_BxB.get(), image_1xB.get(), image_BxB.get(), + image_Bx1.get(), image_1x1.get(), image_Bx1.get(), + image_BxB.get(), image_1xB.get(), image_BxB.get()); ImageGrid::TestAPI test_api(&grid); ASSERT_TRUE(test_api.top_left_layer() != NULL); @@ -124,9 +124,9 @@ TEST_F(ImageGridTest, SingleImage) { scoped_ptr<gfx::Image> image(CreateImage(gfx::Size(kBorder, kBorder))); ImageGrid grid; - grid.Init(NULL, image.get(), NULL, - NULL, NULL, NULL, - NULL, NULL, NULL); + grid.SetImages(NULL, image.get(), NULL, + NULL, NULL, NULL, + NULL, NULL, NULL); ImageGrid::TestAPI test_api(&grid); EXPECT_TRUE(test_api.top_left_layer() == NULL); @@ -149,6 +149,45 @@ TEST_F(ImageGridTest, SingleImage) { *test_api.top_layer()).ToString()); } +// Check that we don't crash when we reset existing images to NULL and +// reset NULL images to new ones. +TEST_F(ImageGridTest, ResetImages) { + const int kBorder = 1; + scoped_ptr<gfx::Image> image(CreateImage(gfx::Size(kBorder, kBorder))); + + ImageGrid grid; + grid.SetImages(NULL, image.get(), NULL, + NULL, NULL, NULL, + NULL, NULL, NULL); + + // Only the top edge has a layer. + ImageGrid::TestAPI test_api(&grid); + ASSERT_TRUE(test_api.top_left_layer() == NULL); + ASSERT_FALSE(test_api.top_layer() == NULL); + ASSERT_TRUE(test_api.top_right_layer() == NULL); + ASSERT_TRUE(test_api.left_layer() == NULL); + ASSERT_TRUE(test_api.center_layer() == NULL); + ASSERT_TRUE(test_api.right_layer() == NULL); + ASSERT_TRUE(test_api.bottom_left_layer() == NULL); + ASSERT_TRUE(test_api.bottom_layer() == NULL); + ASSERT_TRUE(test_api.bottom_right_layer() == NULL); + + grid.SetImages(NULL, NULL, NULL, + NULL, NULL, NULL, + NULL, image.get(), NULL); + + // Now only the bottom edge has a layer. + ASSERT_TRUE(test_api.top_left_layer() == NULL); + ASSERT_TRUE(test_api.top_layer() == NULL); + ASSERT_TRUE(test_api.top_right_layer() == NULL); + ASSERT_TRUE(test_api.left_layer() == NULL); + ASSERT_TRUE(test_api.center_layer() == NULL); + ASSERT_TRUE(test_api.right_layer() == NULL); + ASSERT_TRUE(test_api.bottom_left_layer() == NULL); + ASSERT_FALSE(test_api.bottom_layer() == NULL); + ASSERT_TRUE(test_api.bottom_right_layer() == NULL); +} + // Test that side (top, left, right, bottom) layers that are narrower than their // adjacent corner layers stay pinned to the outside edges instead of getting // moved inwards or scaled. This exercises the scenario used for shadows. @@ -165,9 +204,9 @@ TEST_F(ImageGridTest, SmallerSides) { scoped_ptr<gfx::Image> right_image(CreateImage(gfx::Size(kEdge, kEdge))); ImageGrid grid; - grid.Init(top_left_image.get(), top_image.get(), top_right_image.get(), - left_image.get(), NULL, right_image.get(), - NULL, NULL, NULL); + grid.SetImages(top_left_image.get(), top_image.get(), top_right_image.get(), + left_image.get(), NULL, right_image.get(), + NULL, NULL, NULL); ImageGrid::TestAPI test_api(&grid); const gfx::Size kSize(20, 30); @@ -218,7 +257,7 @@ TEST_F(ImageGridTest, TooSmall) { CreateImage(gfx::Size(kCorner, kCorner))); ImageGrid grid; - grid.Init( + grid.SetImages( top_left_image.get(), top_image.get(), top_right_image.get(), left_image.get(), center_image.get(), right_image.get(), bottom_left_image.get(), bottom_image.get(), bottom_right_image.get()); diff --git a/ash/wm/shadow.cc b/ash/wm/shadow.cc index e25a8e4..8f33765 100644 --- a/ash/wm/shadow.cc +++ b/ash/wm/shadow.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -7,6 +7,20 @@ #include "ash/wm/image_grid.h" #include "grit/ui_resources.h" #include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/compositor/scoped_layer_animation_settings.h" + +namespace { + +// Shadow opacity for active window. +const float kActiveShadowOpacity = 1.0f; + +// Shadow opacity for inactive window. +const float kInactiveShadowOpacity = 0.2f; + +// Duration for opacity animation in milliseconds. +const int64 kAnimationDurationMs = 200; + +} // namespace namespace ash { namespace internal { @@ -17,35 +31,117 @@ Shadow::Shadow() { Shadow::~Shadow() { } -ui::Layer* Shadow::layer() const { return image_grid_->layer(); } - void Shadow::Init() { + style_ = STYLE_ACTIVE; image_grid_.reset(new ImageGrid); - - ResourceBundle& res = ResourceBundle::GetSharedInstance(); - image_grid_->Init(&res.GetImageNamed(IDR_AURA_SHADOW_RECT_TOP_LEFT), - &res.GetImageNamed(IDR_AURA_SHADOW_RECT_TOP), - &res.GetImageNamed(IDR_AURA_SHADOW_RECT_TOP_RIGHT), - &res.GetImageNamed(IDR_AURA_SHADOW_RECT_LEFT), - NULL, - &res.GetImageNamed(IDR_AURA_SHADOW_RECT_RIGHT), - &res.GetImageNamed(IDR_AURA_SHADOW_RECT_BOTTOM_LEFT), - &res.GetImageNamed(IDR_AURA_SHADOW_RECT_BOTTOM), - &res.GetImageNamed(IDR_AURA_SHADOW_RECT_BOTTOM_RIGHT)); + UpdateImagesForStyle(); + image_grid_->layer()->set_name("Shadow"); + image_grid_->layer()->SetOpacity(kActiveShadowOpacity); } void Shadow::SetContentBounds(const gfx::Rect& content_bounds) { content_bounds_ = content_bounds; + UpdateImageGridBounds(); +} + +ui::Layer* Shadow::layer() const { + return image_grid_->layer(); +} + +void Shadow::SetStyle(Style style) { + if (style_ == style) + return; + style_ = style; + + // Stop waiting for any as yet unfinished implicit animations. + StopObservingImplicitAnimations(); + + // If we're becoming active, switch images now. Because the inactive image + // has a very low opacity the switch isn't noticeable and this approach + // allows us to use only a single set of shadow images at a time. + if (style == STYLE_ACTIVE) { + UpdateImagesForStyle(); + // Opacity was baked into inactive image, start opacity low to match. + image_grid_->layer()->SetOpacity(kInactiveShadowOpacity); + } + + { + // Property sets within this scope will be implicitly animated. + ui::ScopedLayerAnimationSettings settings(layer()->GetAnimator()); + settings.AddObserver(this); + settings.SetTransitionDuration( + base::TimeDelta::FromMilliseconds(kAnimationDurationMs)); + switch (style_) { + case STYLE_ACTIVE: + image_grid_->layer()->SetOpacity(kActiveShadowOpacity); + break; + case STYLE_INACTIVE: + image_grid_->layer()->SetOpacity(kInactiveShadowOpacity); + break; + default: + NOTREACHED(); + break; + } + } +} + +void Shadow::OnImplicitAnimationsCompleted() { + // If we just finished going inactive, switch images. This doesn't cause + // a visual pop because the inactive image opacity is so low. + if (style_ == STYLE_INACTIVE) { + UpdateImagesForStyle(); + // Opacity is baked into inactive image, so set fully opaque. + image_grid_->layer()->SetOpacity(1.0f); + } +} + +void Shadow::UpdateImagesForStyle() { + ResourceBundle& res = ResourceBundle::GetSharedInstance(); + switch (style_) { + case STYLE_ACTIVE: + image_grid_->SetImages( + &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_TOP_LEFT), + &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_TOP), + &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_TOP_RIGHT), + &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_LEFT), + NULL, + &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_RIGHT), + &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_BOTTOM_LEFT), + &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_BOTTOM), + &res.GetImageNamed(IDR_AURA_SHADOW_ACTIVE_BOTTOM_RIGHT)); + break; + case STYLE_INACTIVE: + image_grid_->SetImages( + &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_TOP_LEFT), + &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_TOP), + &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_TOP_RIGHT), + &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_LEFT), + NULL, + &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_RIGHT), + &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_BOTTOM_LEFT), + &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_BOTTOM), + &res.GetImageNamed(IDR_AURA_SHADOW_INACTIVE_BOTTOM_RIGHT)); + break; + default: + NOTREACHED(); + break; + } + + // Image sizes may have changed. + UpdateImageGridBounds(); +} + +void Shadow::UpdateImageGridBounds() { image_grid_->SetSize( - gfx::Size(content_bounds.width() + + gfx::Size(content_bounds_.width() + image_grid_->left_image_width() + image_grid_->right_image_width(), - content_bounds.height() + + content_bounds_.height() + image_grid_->top_image_height() + image_grid_->bottom_image_height())); image_grid_->layer()->SetBounds( - gfx::Rect(content_bounds.x() - image_grid_->left_image_width(), - content_bounds.y() - image_grid_->top_image_height(), + gfx::Rect(content_bounds_.x() - image_grid_->left_image_width(), + content_bounds_.y() - image_grid_->top_image_height(), image_grid_->layer()->bounds().width(), image_grid_->layer()->bounds().height())); } diff --git a/ash/wm/shadow.h b/ash/wm/shadow.h index d16021f..551fad4 100644 --- a/ash/wm/shadow.h +++ b/ash/wm/shadow.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -9,6 +9,7 @@ #include "base/basictypes.h" #include "base/memory/scoped_ptr.h" #include "ash/ash_export.h" +#include "ui/gfx/compositor/layer_animation_observer.h" #include "ui/gfx/rect.h" namespace ui { @@ -21,11 +22,21 @@ namespace internal { class ImageGrid; // Simple class that draws a drop shadow around content at given bounds. -class ASH_EXPORT Shadow { +class ASH_EXPORT Shadow : public ui::ImplicitAnimationObserver { public: + enum Style { + // Active windows have more opaque shadows, shifted down to make the window + // appear "higher". + STYLE_ACTIVE, + // Inactive windows have less opaque shadows. + STYLE_INACTIVE, + }; + Shadow(); ~Shadow(); + void Init(); + // Returns |image_grid_|'s ui::Layer. This is exposed so it can be added to // the same layer as the content and stacked below it. SetContentBounds() // should be used to adjust the shadow's size and position (rather than @@ -33,13 +44,28 @@ class ASH_EXPORT Shadow { ui::Layer* layer() const; const gfx::Rect& content_bounds() const { return content_bounds_; } - - void Init(); + Style style() const { return style_; } // Moves and resizes |image_grid_| to frame |content_bounds|. void SetContentBounds(const gfx::Rect& content_bounds); + // Sets the shadow's style, animating opacity as necessary. + void SetStyle(Style style); + + // ui::ImplicitAnimationObserver overrides: + virtual void OnImplicitAnimationsCompleted() OVERRIDE; + private: + // Updates the |image_grid_| images to the current |style_|. + void UpdateImagesForStyle(); + + // Updates the |image_grid_| bounds based on its image sizes and the + // current |content_bounds_|. + void UpdateImageGridBounds(); + + // The current style, set when the transition animation starts. + Style style_; + scoped_ptr<ImageGrid> image_grid_; // Bounds of the content that the shadow encloses. diff --git a/ash/wm/shadow_controller.cc b/ash/wm/shadow_controller.cc index 2f75453..ed7af82 100644 --- a/ash/wm/shadow_controller.cc +++ b/ash/wm/shadow_controller.cc @@ -12,6 +12,7 @@ #include "ash/wm/window_properties.h" #include "base/command_line.h" #include "base/logging.h" +#include "ui/aura/client/activation_client.h" #include "ui/aura/env.h" #include "ui/aura/root_window.h" #include "ui/aura/window.h" @@ -31,9 +32,6 @@ ShadowType GetShadowTypeFromWindow(aura::Window* window) { switch (window->type()) { case aura::client::WINDOW_TYPE_NORMAL: case aura::client::WINDOW_TYPE_PANEL: - return CommandLine::ForCurrentProcess()->HasSwitch( - switches::kAuraTranslucentFrames) ? - SHADOW_TYPE_NONE : SHADOW_TYPE_RECTANGULAR; case aura::client::WINDOW_TYPE_MENU: case aura::client::WINDOW_TYPE_TOOLTIP: return SHADOW_TYPE_RECTANGULAR; @@ -47,6 +45,8 @@ ShadowType GetShadowTypeFromWindow(aura::Window* window) { ShadowController::ShadowController() { aura::Env::GetInstance()->AddObserver(this); + // Watch for window activation changes. + aura::RootWindow::GetInstance()->AddObserver(this); } ShadowController::~ShadowController() { @@ -54,6 +54,7 @@ ShadowController::~ShadowController() { it != window_shadows_.end(); ++it) { it->first->RemoveObserver(this); } + aura::RootWindow::GetInstance()->RemoveObserver(this); aura::Env::GetInstance()->RemoveObserver(this); } @@ -66,8 +67,20 @@ void ShadowController::OnWindowInitialized(aura::Window* window) { void ShadowController::OnWindowPropertyChanged(aura::Window* window, const void* key, intptr_t old) { - if (key == kShadowTypeKey) + if (key == kShadowTypeKey) { HandlePossibleShadowVisibilityChange(window); + return; + } + if (key == aura::client::kRootWindowActiveWindowKey) { + aura::Window* inactive = reinterpret_cast<aura::Window*>(old); + if (inactive) + HandleWindowActivationChange(inactive, false); + aura::Window* active = + window->GetProperty(aura::client::kRootWindowActiveWindowKey); + if (active) + HandleWindowActivationChange(active, true); + return; + } } void ShadowController::OnWindowBoundsChanged(aura::Window* window, @@ -99,6 +112,13 @@ Shadow* ShadowController::GetShadowForWindow(aura::Window* window) { return it != window_shadows_.end() ? it->second.get() : NULL; } +void ShadowController::HandleWindowActivationChange(aura::Window* window, + bool active) { + Shadow* shadow = GetShadowForWindow(window); + if (shadow) + shadow->SetStyle(active ? Shadow::STYLE_ACTIVE : Shadow::STYLE_INACTIVE); +} + void ShadowController::HandlePossibleShadowVisibilityChange( aura::Window* window) { const bool should_show = ShouldShowShadowForWindow(window); diff --git a/ash/wm/shadow_controller.h b/ash/wm/shadow_controller.h index b1c7e7a..ea3862d 100644 --- a/ash/wm/shadow_controller.h +++ b/ash/wm/shadow_controller.h @@ -70,6 +70,9 @@ class ASH_EXPORT ShadowController : public aura::EnvObserver, // exists. Shadow* GetShadowForWindow(aura::Window* window); + // Updates the shadow style for |window| based on whether it is |active|. + void HandleWindowActivationChange(aura::Window* window, bool active); + // Shows or hides |window|'s shadow as needed (creating the shadow if // necessary). void HandlePossibleShadowVisibilityChange(aura::Window* window); diff --git a/ash/wm/shadow_controller_unittest.cc b/ash/wm/shadow_controller_unittest.cc index d91ced7..2d07f50 100644 --- a/ash/wm/shadow_controller_unittest.cc +++ b/ash/wm/shadow_controller_unittest.cc @@ -12,13 +12,14 @@ #include "ash/wm/shadow.h" #include "ash/wm/shadow_types.h" #include "ash/wm/window_properties.h" +#include "ash/wm/window_util.h" #include "base/memory/scoped_ptr.h" #include "ui/aura/root_window.h" #include "ui/aura/window.h" #include "ui/gfx/compositor/layer.h" namespace ash { -namespace test { +namespace internal { typedef ash::test::AuraShellTestBase ShadowControllerTest; @@ -87,5 +88,39 @@ TEST_F(ShadowControllerTest, ShadowBounds) { shadow->content_bounds().ToString()); } -} // namespace test +// Tests that activating a window changes the shadow style. +TEST_F(ShadowControllerTest, ShadowStyle) { + ShadowController::TestApi api( + ash::Shell::GetInstance()->shadow_controller()); + + scoped_ptr<aura::Window> window1(new aura::Window(NULL)); + window1->SetType(aura::client::WINDOW_TYPE_NORMAL); + window1->Init(ui::Layer::LAYER_TEXTURED); + window1->SetParent(NULL); + window1->SetBounds(gfx::Rect(10, 20, 300, 400)); + window1->Show(); + ActivateWindow(window1.get()); + + // window1 is active, so style should have active appearance. + Shadow* shadow1 = api.GetShadowForWindow(window1.get()); + ASSERT_TRUE(shadow1 != NULL); + EXPECT_EQ(Shadow::STYLE_ACTIVE, shadow1->style()); + + // Create another window and activate it. + scoped_ptr<aura::Window> window2(new aura::Window(NULL)); + window2->SetType(aura::client::WINDOW_TYPE_NORMAL); + window2->Init(ui::Layer::LAYER_TEXTURED); + window2->SetParent(NULL); + window2->SetBounds(gfx::Rect(11, 21, 301, 401)); + window2->Show(); + ActivateWindow(window2.get()); + + // window1 is now inactive, so shadow should go inactive. + Shadow* shadow2 = api.GetShadowForWindow(window2.get()); + ASSERT_TRUE(shadow2 != NULL); + EXPECT_EQ(Shadow::STYLE_INACTIVE, shadow1->style()); + EXPECT_EQ(Shadow::STYLE_ACTIVE, shadow2->style()); +} + +} // namespace internal } // namespace ash diff --git a/ui/resources/ui_resources.grd b/ui/resources/ui_resources.grd index bbe1246..4b4816e 100644 --- a/ui/resources/ui_resources.grd +++ b/ui/resources/ui_resources.grd @@ -154,14 +154,22 @@ <include name="IDR_AURA_LAUNCHER_ICON_APPLIST_HOT" file="aura/applist_h.png" type="BINDATA" /> <include name="IDR_AURA_LAUNCHER_ICON_APPLIST_PUSHED" file="aura/applist_p.png" type="BINDATA" /> <include name="IDR_AURA_LAUNCHER_BACKGROUND" file="aura/launcher_background.png" type="BINDATA" /> - <include name="IDR_AURA_SHADOW_RECT_TOP_LEFT" file="aura/shadow_rect_top_left.png" type="BINDATA" /> - <include name="IDR_AURA_SHADOW_RECT_TOP" file="aura/shadow_rect_top.png" type="BINDATA" /> - <include name="IDR_AURA_SHADOW_RECT_TOP_RIGHT" file="aura/shadow_rect_top_right.png" type="BINDATA" /> - <include name="IDR_AURA_SHADOW_RECT_LEFT" file="aura/shadow_rect_left.png" type="BINDATA" /> - <include name="IDR_AURA_SHADOW_RECT_RIGHT" file="aura/shadow_rect_right.png" type="BINDATA" /> - <include name="IDR_AURA_SHADOW_RECT_BOTTOM_LEFT" file="aura/shadow_rect_bottom_left.png" type="BINDATA" /> - <include name="IDR_AURA_SHADOW_RECT_BOTTOM" file="aura/shadow_rect_bottom.png" type="BINDATA" /> - <include name="IDR_AURA_SHADOW_RECT_BOTTOM_RIGHT" file="aura/shadow_rect_bottom_right.png" type="BINDATA" /> + <include name="IDR_AURA_SHADOW_ACTIVE_TOP_LEFT" file="aura/window_shadow_active_top_left.png" type="BINDATA" /> + <include name="IDR_AURA_SHADOW_ACTIVE_TOP" file="aura/window_shadow_active_top.png" type="BINDATA" /> + <include name="IDR_AURA_SHADOW_ACTIVE_TOP_RIGHT" file="aura/window_shadow_active_top_right.png" type="BINDATA" /> + <include name="IDR_AURA_SHADOW_ACTIVE_LEFT" file="aura/window_shadow_active_left.png" type="BINDATA" /> + <include name="IDR_AURA_SHADOW_ACTIVE_RIGHT" file="aura/window_shadow_active_right.png" type="BINDATA" /> + <include name="IDR_AURA_SHADOW_ACTIVE_BOTTOM_LEFT" file="aura/window_shadow_active_bottom_left.png" type="BINDATA" /> + <include name="IDR_AURA_SHADOW_ACTIVE_BOTTOM" file="aura/window_shadow_active_bottom.png" type="BINDATA" /> + <include name="IDR_AURA_SHADOW_ACTIVE_BOTTOM_RIGHT" file="aura/window_shadow_active_bottom_right.png" type="BINDATA" /> + <include name="IDR_AURA_SHADOW_INACTIVE_TOP_LEFT" file="aura/window_shadow_inactive_top_left.png" type="BINDATA" /> + <include name="IDR_AURA_SHADOW_INACTIVE_TOP" file="aura/window_shadow_inactive_top.png" type="BINDATA" /> + <include name="IDR_AURA_SHADOW_INACTIVE_TOP_RIGHT" file="aura/window_shadow_inactive_top_right.png" type="BINDATA" /> + <include name="IDR_AURA_SHADOW_INACTIVE_LEFT" file="aura/window_shadow_inactive_left.png" type="BINDATA" /> + <include name="IDR_AURA_SHADOW_INACTIVE_RIGHT" file="aura/window_shadow_inactive_right.png" type="BINDATA" /> + <include name="IDR_AURA_SHADOW_INACTIVE_BOTTOM_LEFT" file="aura/window_shadow_inactive_bottom_left.png" type="BINDATA" /> + <include name="IDR_AURA_SHADOW_INACTIVE_BOTTOM" file="aura/window_shadow_inactive_bottom.png" type="BINDATA" /> + <include name="IDR_AURA_SHADOW_INACTIVE_BOTTOM_RIGHT" file="aura/window_shadow_inactive_bottom_right.png" type="BINDATA" /> <include name="IDR_AURA_STATUS_MOCK" file="aura/statusbar.png" type="BINDATA" /> <include name="IDR_AURA_WALLPAPER" file="aura/wallpaper.png" type="BINDATA" /> <include name="IDR_AURA_WINDOW_CLOSE_ICON" file="aura/slab_close.png" type="BINDATA" /> |