summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjamescook@chromium.org <jamescook@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-17 19:06:41 +0000
committerjamescook@chromium.org <jamescook@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-17 19:06:41 +0000
commit27a84042eaf11de85667ea58e2da81ef1963a6ac (patch)
tree83ecac6b6effb2dce4b64991219e43243d08229d
parent4e8d5c8ada6452b59975f9da496d7c8b4858763e (diff)
downloadchromium_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.cc14
-rw-r--r--ash/accelerators/accelerator_controller_unittest.cc3
-rw-r--r--ash/shell.cc35
-rw-r--r--ash/shell.h18
-rw-r--r--ash/shell/window_type_launcher.cc2
-rw-r--r--ash/wm/image_grid.cc58
-rw-r--r--ash/wm/image_grid.h34
-rw-r--r--ash/wm/image_grid_unittest.cc61
-rw-r--r--ash/wm/shadow.cc132
-rw-r--r--ash/wm/shadow.h34
-rw-r--r--ash/wm/shadow_controller.cc28
-rw-r--r--ash/wm/shadow_controller.h3
-rw-r--r--ash/wm/shadow_controller_unittest.cc39
-rw-r--r--ui/resources/ui_resources.grd24
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, &center_layer_, &center_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, &center_layer_, &center_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" />