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_controller.h"
7 #include "ash/ash_switches.h"
8 #include "ash/desktop_background/desktop_background_controller_observer.h"
9 #include "ash/desktop_background/desktop_background_view.h"
10 #include "ash/desktop_background/desktop_background_widget_controller.h"
11 #include "ash/desktop_background/user_wallpaper_delegate.h"
12 #include "ash/desktop_background/wallpaper_resizer.h"
13 #include "ash/display/display_info.h"
14 #include "ash/display/display_manager.h"
15 #include "ash/root_window_controller.h"
16 #include "ash/shell.h"
17 #include "ash/shell_factory.h"
18 #include "ash/shell_window_ids.h"
19 #include "ash/wm/root_window_layout_manager.h"
20 #include "base/bind.h"
21 #include "base/command_line.h"
22 #include "base/file_util.h"
23 #include "base/logging.h"
24 #include "base/synchronization/cancellation_flag.h"
25 #include "base/threading/worker_pool.h"
26 #include "content/public/browser/browser_thread.h"
27 #include "ui/aura/window.h"
28 #include "ui/aura/window_event_dispatcher.h"
29 #include "ui/compositor/layer.h"
30 #include "ui/gfx/codec/jpeg_codec.h"
31 #include "ui/gfx/image/image_skia.h"
32 #include "ui/gfx/rect.h"
33 #include "ui/views/widget/widget.h"
35 using content::BrowserThread
;
40 // How long to wait reloading the wallpaper after the max display has
42 const int kWallpaperReloadDelayMs
= 2000;
46 DesktopBackgroundController::DesktopBackgroundController()
48 desktop_background_mode_(BACKGROUND_NONE
),
49 wallpaper_reload_delay_(kWallpaperReloadDelayMs
) {
50 Shell::GetInstance()->display_controller()->AddObserver(this);
51 Shell::GetInstance()->AddShellObserver(this);
54 DesktopBackgroundController::~DesktopBackgroundController() {
55 Shell::GetInstance()->display_controller()->RemoveObserver(this);
56 Shell::GetInstance()->RemoveShellObserver(this);
59 gfx::ImageSkia
DesktopBackgroundController::GetWallpaper() const {
60 if (current_wallpaper_
)
61 return current_wallpaper_
->image();
62 return gfx::ImageSkia();
65 void DesktopBackgroundController::AddObserver(
66 DesktopBackgroundControllerObserver
* observer
) {
67 observers_
.AddObserver(observer
);
70 void DesktopBackgroundController::RemoveObserver(
71 DesktopBackgroundControllerObserver
* observer
) {
72 observers_
.RemoveObserver(observer
);
75 WallpaperLayout
DesktopBackgroundController::GetWallpaperLayout() const {
76 if (current_wallpaper_
)
77 return current_wallpaper_
->layout();
78 return WALLPAPER_LAYOUT_CENTER_CROPPED
;
81 bool DesktopBackgroundController::SetWallpaperImage(const gfx::ImageSkia
& image
,
82 WallpaperLayout layout
) {
83 VLOG(1) << "SetWallpaper: image_id=" << WallpaperResizer::GetImageId(image
)
84 << " layout=" << layout
;
86 if (WallpaperIsAlreadyLoaded(image
, true /* compare_layouts */, layout
)) {
87 VLOG(1) << "Wallpaper is already loaded";
91 current_wallpaper_
.reset(
92 new WallpaperResizer(image
, GetMaxDisplaySizeInNative(), layout
));
93 current_wallpaper_
->StartResize();
95 FOR_EACH_OBSERVER(DesktopBackgroundControllerObserver
,
97 OnWallpaperDataChanged());
98 SetDesktopBackgroundImageMode();
102 void DesktopBackgroundController::CreateEmptyWallpaper() {
103 current_wallpaper_
.reset(NULL
);
104 SetDesktopBackgroundImageMode();
107 bool DesktopBackgroundController::MoveDesktopToLockedContainer() {
111 return ReparentBackgroundWidgets(GetBackgroundContainerId(false),
112 GetBackgroundContainerId(true));
115 bool DesktopBackgroundController::MoveDesktopToUnlockedContainer() {
119 return ReparentBackgroundWidgets(GetBackgroundContainerId(true),
120 GetBackgroundContainerId(false));
123 void DesktopBackgroundController::OnDisplayConfigurationChanged() {
124 gfx::Size max_display_size
= GetMaxDisplaySizeInNative();
125 if (current_max_display_size_
!= max_display_size
) {
126 current_max_display_size_
= max_display_size
;
127 if (desktop_background_mode_
== BACKGROUND_IMAGE
&&
128 current_wallpaper_
.get()) {
130 timer_
.Start(FROM_HERE
,
131 base::TimeDelta::FromMilliseconds(wallpaper_reload_delay_
),
133 &DesktopBackgroundController::UpdateWallpaper
);
138 void DesktopBackgroundController::OnRootWindowAdded(aura::Window
* root_window
) {
139 // The background hasn't been set yet.
140 if (desktop_background_mode_
== BACKGROUND_NONE
)
143 // Handle resolution change for "built-in" images.
144 gfx::Size max_display_size
= GetMaxDisplaySizeInNative();
145 if (current_max_display_size_
!= max_display_size
) {
146 current_max_display_size_
= max_display_size
;
147 if (desktop_background_mode_
== BACKGROUND_IMAGE
&&
148 current_wallpaper_
.get())
152 InstallDesktopController(root_window
);
156 gfx::Size
DesktopBackgroundController::GetMaxDisplaySizeInNative() {
159 std::vector
<gfx::Display
> displays
= Shell::GetScreen()->GetAllDisplays();
160 DisplayManager
* display_manager
= Shell::GetInstance()->display_manager();
162 for (std::vector
<gfx::Display
>::iterator iter
= displays
.begin();
163 iter
!= displays
.end(); ++iter
) {
164 // Don't use size_in_pixel because we want to use the native pixel size.
165 gfx::Size size_in_pixel
=
166 display_manager
->GetDisplayInfo(iter
->id()).bounds_in_native().size();
167 if (iter
->rotation() == gfx::Display::ROTATE_90
||
168 iter
->rotation() == gfx::Display::ROTATE_270
) {
169 size_in_pixel
= gfx::Size(size_in_pixel
.height(), size_in_pixel
.width());
171 width
= std::max(size_in_pixel
.width(), width
);
172 height
= std::max(size_in_pixel
.height(), height
);
174 return gfx::Size(width
, height
);
177 bool DesktopBackgroundController::WallpaperIsAlreadyLoaded(
178 const gfx::ImageSkia
& image
,
179 bool compare_layouts
,
180 WallpaperLayout layout
) const {
181 if (!current_wallpaper_
.get())
184 // Compare layouts only if necessary.
185 if (compare_layouts
&& layout
!= current_wallpaper_
->layout())
188 return WallpaperResizer::GetImageId(image
) ==
189 current_wallpaper_
->original_image_id();
192 void DesktopBackgroundController::SetDesktopBackgroundImageMode() {
193 desktop_background_mode_
= BACKGROUND_IMAGE
;
194 InstallDesktopControllerForAllWindows();
197 void DesktopBackgroundController::InstallDesktopController(
198 aura::Window
* root_window
) {
199 DesktopBackgroundWidgetController
* component
= NULL
;
200 int container_id
= GetBackgroundContainerId(locked_
);
202 switch (desktop_background_mode_
) {
203 case BACKGROUND_IMAGE
: {
204 views::Widget
* widget
=
205 CreateDesktopBackground(root_window
, container_id
);
206 component
= new DesktopBackgroundWidgetController(widget
);
209 case BACKGROUND_NONE
:
213 GetRootWindowController(root_window
)->SetAnimatingWallpaperController(
214 new AnimatingDesktopController(component
));
216 component
->StartAnimating(GetRootWindowController(root_window
));
219 void DesktopBackgroundController::InstallDesktopControllerForAllWindows() {
220 aura::Window::Windows root_windows
= Shell::GetAllRootWindows();
221 for (aura::Window::Windows::iterator iter
= root_windows
.begin();
222 iter
!= root_windows
.end(); ++iter
) {
223 InstallDesktopController(*iter
);
225 current_max_display_size_
= GetMaxDisplaySizeInNative();
228 bool DesktopBackgroundController::ReparentBackgroundWidgets(int src_container
,
231 Shell::RootWindowControllerList controllers
=
232 Shell::GetAllRootWindowControllers();
233 for (Shell::RootWindowControllerList::iterator iter
= controllers
.begin();
234 iter
!= controllers
.end(); ++iter
) {
235 RootWindowController
* root_window_controller
= *iter
;
236 // In the steady state (no animation playing) the background widget
237 // controller exists in the RootWindowController.
238 DesktopBackgroundWidgetController
* desktop_controller
=
239 root_window_controller
->wallpaper_controller();
240 if (desktop_controller
) {
242 desktop_controller
->Reparent(root_window_controller
->GetRootWindow(),
246 // During desktop show animations the controller lives in
247 // AnimatingDesktopController owned by RootWindowController.
248 // NOTE: If a wallpaper load happens during a desktop show animation there
249 // can temporarily be two desktop background widgets. We must reparent
250 // both of them - one above and one here.
251 DesktopBackgroundWidgetController
* animating_controller
=
252 root_window_controller
->animating_wallpaper_controller() ?
253 root_window_controller
->animating_wallpaper_controller()->
254 GetController(false) :
256 if (animating_controller
) {
257 moved
|= animating_controller
->Reparent(
258 root_window_controller
->GetRootWindow(),
266 int DesktopBackgroundController::GetBackgroundContainerId(bool locked
) {
267 return locked
? kShellWindowId_LockScreenBackgroundContainer
268 : kShellWindowId_DesktopBackgroundContainer
;
271 void DesktopBackgroundController::UpdateWallpaper() {
272 current_wallpaper_
.reset(NULL
);
273 ash::Shell::GetInstance()->user_wallpaper_delegate()->
274 UpdateWallpaper(true /* clear cache */);