1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ash/desktop_background/desktop_background_view.h"
9 #include "ash/ash_export.h"
10 #include "ash/desktop_background/desktop_background_controller.h"
11 #include "ash/desktop_background/desktop_background_widget_controller.h"
12 #include "ash/desktop_background/user_wallpaper_delegate.h"
13 #include "ash/root_window_controller.h"
14 #include "ash/session_state_delegate.h"
15 #include "ash/shell.h"
16 #include "ash/shell_window_ids.h"
17 #include "ash/wm/property_util.h"
18 #include "ash/wm/window_animations.h"
19 #include "base/message_loop.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "ui/aura/root_window.h"
22 #include "ui/base/resource/resource_bundle.h"
23 #include "ui/compositor/layer.h"
24 #include "ui/compositor/layer_animation_observer.h"
25 #include "ui/compositor/scoped_layer_animation_settings.h"
26 #include "ui/gfx/canvas.h"
27 #include "ui/gfx/image/image.h"
28 #include "ui/views/widget/widget.h"
29 #include "ui/views/widget/widget_observer.h"
35 class ShowWallpaperAnimationObserver
: public ui::ImplicitAnimationObserver
,
36 public views::WidgetObserver
{
38 ShowWallpaperAnimationObserver(aura::RootWindow
* root_window
,
39 views::Widget
* desktop_widget
,
40 bool is_initial_animation
)
41 : root_window_(root_window
),
42 desktop_widget_(desktop_widget
),
43 is_initial_animation_(is_initial_animation
) {
44 DCHECK(desktop_widget_
);
45 desktop_widget_
->AddObserver(this);
48 virtual ~ShowWallpaperAnimationObserver() {
49 StopObservingImplicitAnimations();
51 desktop_widget_
->RemoveObserver(this);
55 // Overridden from ui::ImplicitAnimationObserver:
56 virtual void OnImplicitAnimationsScheduled() OVERRIDE
{
57 if (is_initial_animation_
) {
58 GetRootWindowController(root_window_
)->
59 HandleInitialDesktopBackgroundAnimationStarted();
63 virtual void OnImplicitAnimationsCompleted() OVERRIDE
{
64 GetRootWindowController(root_window_
)->HandleDesktopBackgroundVisible();
65 ash::Shell::GetInstance()->user_wallpaper_delegate()->
66 OnWallpaperAnimationFinished();
67 // Only removes old component when wallpaper animation finished. If we
68 // remove the old one before the new wallpaper is done fading in there will
69 // be a white flash during the animation.
70 if (root_window_
->GetProperty(kAnimatingDesktopController
)) {
71 DesktopBackgroundWidgetController
* controller
=
72 root_window_
->GetProperty(kAnimatingDesktopController
)->
74 // |desktop_widget_| should be the same animating widget we try to move
75 // to |kDesktopController|. Otherwise, we may close |desktop_widget_|
76 // before move it to |kDesktopController|.
77 DCHECK_EQ(controller
->widget(), desktop_widget_
);
78 // Release the old controller and close its background widget.
79 root_window_
->SetProperty(kDesktopController
, controller
);
84 // Overridden from views::WidgetObserver.
85 virtual void OnWidgetDestroying(views::Widget
* widget
) OVERRIDE
{
89 aura::RootWindow
* root_window_
;
90 views::Widget
* desktop_widget_
;
92 // Is this object observing the initial brightness/grayscale animation?
93 const bool is_initial_animation_
;
95 DISALLOW_COPY_AND_ASSIGN(ShowWallpaperAnimationObserver
);
98 // For our scaling ratios we need to round positive numbers.
99 int RoundPositive(double x
) {
100 return static_cast<int>(floor(x
+ 0.5));
105 ////////////////////////////////////////////////////////////////////////////////
106 // DesktopBackgroundView, public:
108 DesktopBackgroundView::DesktopBackgroundView() {
109 set_context_menu_controller(this);
112 DesktopBackgroundView::~DesktopBackgroundView() {
115 ////////////////////////////////////////////////////////////////////////////////
116 // DesktopBackgroundView, views::View overrides:
118 void DesktopBackgroundView::OnPaint(gfx::Canvas
* canvas
) {
119 // Scale the image while maintaining the aspect ratio, cropping as
120 // necessary to fill the background. Ideally the image should be larger
121 // than the largest display supported, if not we will center it rather than
122 // streching to avoid upsampling artifacts (Note that we could tile too, but
123 // decided not to do this at the moment).
124 DesktopBackgroundController
* controller
=
125 ash::Shell::GetInstance()->desktop_background_controller();
126 gfx::ImageSkia wallpaper
= controller
->GetWallpaper();
127 WallpaperLayout wallpaper_layout
= controller
->GetWallpaperLayout();
129 gfx::Rect
wallpaper_rect(0, 0, wallpaper
.width(), wallpaper
.height());
130 if (wallpaper_layout
== WALLPAPER_LAYOUT_CENTER_CROPPED
&&
131 wallpaper
.width() > width() && wallpaper
.height() > height()) {
132 // The dimension with the smallest ratio must be cropped, the other one
133 // is preserved. Both are set in gfx::Size cropped_size.
134 double horizontal_ratio
= static_cast<double>(width()) /
135 static_cast<double>(wallpaper
.width());
136 double vertical_ratio
= static_cast<double>(height()) /
137 static_cast<double>(wallpaper
.height());
139 gfx::Size cropped_size
;
140 if (vertical_ratio
> horizontal_ratio
) {
141 cropped_size
= gfx::Size(
142 RoundPositive(static_cast<double>(width()) / vertical_ratio
),
145 cropped_size
= gfx::Size(wallpaper
.width(),
146 RoundPositive(static_cast<double>(height()) / horizontal_ratio
));
149 gfx::Rect wallpaper_cropped_rect
= wallpaper_rect
;
150 wallpaper_cropped_rect
.ClampToCenteredSize(cropped_size
);
151 canvas
->DrawImageInt(wallpaper
,
152 wallpaper_cropped_rect
.x(), wallpaper_cropped_rect
.y(),
153 wallpaper_cropped_rect
.width(), wallpaper_cropped_rect
.height(),
154 0, 0, width(), height(),
156 } else if (wallpaper_layout
== WALLPAPER_LAYOUT_TILE
) {
157 canvas
->TileImageInt(wallpaper
, 0, 0, width(), height());
158 } else if (wallpaper_layout
== WALLPAPER_LAYOUT_STRETCH
) {
159 // This is generally not recommended as it may show artifacts.
160 canvas
->DrawImageInt(wallpaper
, 0, 0, wallpaper
.width(),
161 wallpaper
.height(), 0, 0, width(), height(), true);
163 // All other are simply centered, and not scaled (but may be clipped).
164 canvas
->DrawImageInt(wallpaper
, (width() - wallpaper
.width()) / 2,
165 (height() - wallpaper
.height()) / 2);
169 bool DesktopBackgroundView::OnMousePressed(const ui::MouseEvent
& event
) {
173 void DesktopBackgroundView::ShowContextMenuForView(
175 const gfx::Point
& point
,
176 ui::MenuSourceType source_type
) {
177 Shell::GetInstance()->ShowContextMenu(point
, source_type
);
180 views::Widget
* CreateDesktopBackground(aura::RootWindow
* root_window
,
182 DesktopBackgroundController
* controller
=
183 ash::Shell::GetInstance()->desktop_background_controller();
184 ash::UserWallpaperDelegate
* wallpaper_delegate
=
185 ash::Shell::GetInstance()->user_wallpaper_delegate();
187 views::Widget
* desktop_widget
= new views::Widget
;
188 views::Widget::InitParams
params(
189 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS
);
190 if (controller
->GetWallpaper().isNull())
191 params
.transparent
= true;
192 params
.parent
= root_window
->GetChildById(container_id
);
193 desktop_widget
->Init(params
);
194 desktop_widget
->SetContentsView(new DesktopBackgroundView());
195 int animation_type
= wallpaper_delegate
->GetAnimationType();
196 views::corewm::SetWindowVisibilityAnimationType(
197 desktop_widget
->GetNativeView(), animation_type
);
199 // Enable wallpaper transition for the following cases:
200 // 1. Initial(OOBE) wallpaper animation.
201 // 2. Wallpaper fades in from a non empty background.
202 // 3. From an empty background, chrome transit to a logged in user session.
203 // 4. From an empty background, guest user logged in.
204 if (wallpaper_delegate
->ShouldShowInitialAnimation() ||
205 root_window
->GetProperty(kAnimatingDesktopController
) ||
206 Shell::GetInstance()->session_state_delegate()->NumberOfLoggedInUsers()) {
207 views::corewm::SetWindowVisibilityAnimationTransition(
208 desktop_widget
->GetNativeView(), views::corewm::ANIMATE_SHOW
);
210 // Disable animation if transition to login screen from an empty background.
211 views::corewm::SetWindowVisibilityAnimationTransition(
212 desktop_widget
->GetNativeView(), views::corewm::ANIMATE_NONE
);
215 desktop_widget
->SetBounds(params
.parent
->bounds());
216 ui::ScopedLayerAnimationSettings
settings(
217 desktop_widget
->GetNativeView()->layer()->GetAnimator());
218 settings
.SetPreemptionStrategy(ui::LayerAnimator::ENQUEUE_NEW_ANIMATION
);
219 settings
.AddObserver(new ShowWallpaperAnimationObserver(
220 root_window
, desktop_widget
,
221 wallpaper_delegate
->ShouldShowInitialAnimation()));
222 desktop_widget
->Show();
223 desktop_widget
->GetNativeView()->SetName("DesktopBackgroundView");
224 return desktop_widget
;
227 } // namespace internal