cc: Initialize wait_for_beginframe_interval in tests.
[chromium-blink-merge.git] / ash / desktop_background / desktop_background_controller.cc
blobed7414eaff178fa6aa8207a67c24d776e145a263
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/display/display_info.h"
13 #include "ash/display/display_manager.h"
14 #include "ash/root_window_controller.h"
15 #include "ash/shell.h"
16 #include "ash/shell_factory.h"
17 #include "ash/shell_window_ids.h"
18 #include "ash/wm/root_window_layout_manager.h"
19 #include "base/bind.h"
20 #include "base/command_line.h"
21 #include "base/files/file_util.h"
22 #include "base/logging.h"
23 #include "base/synchronization/cancellation_flag.h"
24 #include "base/threading/worker_pool.h"
25 #include "components/wallpaper/wallpaper_resizer.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/geometry/rect.h"
32 #include "ui/gfx/image/image_skia.h"
33 #include "ui/views/widget/widget.h"
35 using content::BrowserThread;
36 using wallpaper::WallpaperResizer;
37 using wallpaper::WallpaperLayout;
38 using wallpaper::WALLPAPER_LAYOUT_CENTER;
39 using wallpaper::WALLPAPER_LAYOUT_CENTER_CROPPED;
40 using wallpaper::WALLPAPER_LAYOUT_STRETCH;
41 using wallpaper::WALLPAPER_LAYOUT_TILE;
43 namespace ash {
44 namespace {
46 // How long to wait reloading the wallpaper after the max display has
47 // changed?
48 const int kWallpaperReloadDelayMs = 100;
50 } // namespace
52 DesktopBackgroundController::DesktopBackgroundController()
53 : locked_(false),
54 desktop_background_mode_(BACKGROUND_NONE),
55 wallpaper_reload_delay_(kWallpaperReloadDelayMs) {
56 Shell::GetInstance()->display_controller()->AddObserver(this);
57 Shell::GetInstance()->AddShellObserver(this);
60 DesktopBackgroundController::~DesktopBackgroundController() {
61 Shell::GetInstance()->display_controller()->RemoveObserver(this);
62 Shell::GetInstance()->RemoveShellObserver(this);
65 gfx::ImageSkia DesktopBackgroundController::GetWallpaper() const {
66 if (current_wallpaper_)
67 return current_wallpaper_->image();
68 return gfx::ImageSkia();
71 void DesktopBackgroundController::AddObserver(
72 DesktopBackgroundControllerObserver* observer) {
73 observers_.AddObserver(observer);
76 void DesktopBackgroundController::RemoveObserver(
77 DesktopBackgroundControllerObserver* observer) {
78 observers_.RemoveObserver(observer);
81 WallpaperLayout DesktopBackgroundController::GetWallpaperLayout() const {
82 if (current_wallpaper_)
83 return current_wallpaper_->layout();
84 return WALLPAPER_LAYOUT_CENTER_CROPPED;
87 bool DesktopBackgroundController::SetWallpaperImage(const gfx::ImageSkia& image,
88 WallpaperLayout layout) {
89 VLOG(1) << "SetWallpaper: image_id=" << WallpaperResizer::GetImageId(image)
90 << " layout=" << layout;
92 if (WallpaperIsAlreadyLoaded(image, true /* compare_layouts */, layout)) {
93 VLOG(1) << "Wallpaper is already loaded";
94 return false;
97 current_wallpaper_.reset(
98 new WallpaperResizer(image, GetMaxDisplaySizeInNative(), layout,
99 BrowserThread::GetBlockingPool()));
100 current_wallpaper_->StartResize();
102 FOR_EACH_OBSERVER(DesktopBackgroundControllerObserver,
103 observers_,
104 OnWallpaperDataChanged());
105 SetDesktopBackgroundImageMode();
106 return true;
109 void DesktopBackgroundController::CreateEmptyWallpaper() {
110 current_wallpaper_.reset(NULL);
111 SetDesktopBackgroundImageMode();
114 bool DesktopBackgroundController::MoveDesktopToLockedContainer() {
115 if (locked_)
116 return false;
117 locked_ = true;
118 return ReparentBackgroundWidgets(GetBackgroundContainerId(false),
119 GetBackgroundContainerId(true));
122 bool DesktopBackgroundController::MoveDesktopToUnlockedContainer() {
123 if (!locked_)
124 return false;
125 locked_ = false;
126 return ReparentBackgroundWidgets(GetBackgroundContainerId(true),
127 GetBackgroundContainerId(false));
130 void DesktopBackgroundController::OnDisplayConfigurationChanged() {
131 gfx::Size max_display_size = GetMaxDisplaySizeInNative();
132 if (current_max_display_size_ != max_display_size) {
133 current_max_display_size_ = max_display_size;
134 if (desktop_background_mode_ == BACKGROUND_IMAGE &&
135 current_wallpaper_.get()) {
136 timer_.Stop();
137 timer_.Start(FROM_HERE,
138 base::TimeDelta::FromMilliseconds(wallpaper_reload_delay_),
139 base::Bind(&DesktopBackgroundController::UpdateWallpaper,
140 base::Unretained(this), false /* clear cache */));
145 void DesktopBackgroundController::OnRootWindowAdded(aura::Window* root_window) {
146 // The background hasn't been set yet.
147 if (desktop_background_mode_ == BACKGROUND_NONE)
148 return;
150 // Handle resolution change for "built-in" images.
151 gfx::Size max_display_size = GetMaxDisplaySizeInNative();
152 if (current_max_display_size_ != max_display_size) {
153 current_max_display_size_ = max_display_size;
154 if (desktop_background_mode_ == BACKGROUND_IMAGE &&
155 current_wallpaper_.get())
156 UpdateWallpaper(true /* clear cache */);
159 InstallDesktopController(root_window);
162 // static
163 gfx::Size DesktopBackgroundController::GetMaxDisplaySizeInNative() {
164 int width = 0;
165 int height = 0;
166 std::vector<gfx::Display> displays = Shell::GetScreen()->GetAllDisplays();
167 DisplayManager* display_manager = Shell::GetInstance()->display_manager();
169 for (std::vector<gfx::Display>::iterator iter = displays.begin();
170 iter != displays.end(); ++iter) {
171 // Don't use size_in_pixel because we want to use the native pixel size.
172 gfx::Size size_in_pixel =
173 display_manager->GetDisplayInfo(iter->id()).bounds_in_native().size();
174 if (iter->rotation() == gfx::Display::ROTATE_90 ||
175 iter->rotation() == gfx::Display::ROTATE_270) {
176 size_in_pixel = gfx::Size(size_in_pixel.height(), size_in_pixel.width());
178 width = std::max(size_in_pixel.width(), width);
179 height = std::max(size_in_pixel.height(), height);
181 return gfx::Size(width, height);
184 bool DesktopBackgroundController::WallpaperIsAlreadyLoaded(
185 const gfx::ImageSkia& image,
186 bool compare_layouts,
187 WallpaperLayout layout) const {
188 if (!current_wallpaper_.get())
189 return false;
191 // Compare layouts only if necessary.
192 if (compare_layouts && layout != current_wallpaper_->layout())
193 return false;
195 return WallpaperResizer::GetImageId(image) ==
196 current_wallpaper_->original_image_id();
199 void DesktopBackgroundController::SetDesktopBackgroundImageMode() {
200 desktop_background_mode_ = BACKGROUND_IMAGE;
201 InstallDesktopControllerForAllWindows();
204 void DesktopBackgroundController::InstallDesktopController(
205 aura::Window* root_window) {
206 DesktopBackgroundWidgetController* component = NULL;
207 int container_id = GetBackgroundContainerId(locked_);
209 switch (desktop_background_mode_) {
210 case BACKGROUND_IMAGE: {
211 views::Widget* widget =
212 CreateDesktopBackground(root_window, container_id);
213 component = new DesktopBackgroundWidgetController(widget);
214 break;
216 case BACKGROUND_NONE:
217 NOTREACHED();
218 return;
220 GetRootWindowController(root_window)->SetAnimatingWallpaperController(
221 new AnimatingDesktopController(component));
223 component->StartAnimating(GetRootWindowController(root_window));
226 void DesktopBackgroundController::InstallDesktopControllerForAllWindows() {
227 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
228 for (aura::Window::Windows::iterator iter = root_windows.begin();
229 iter != root_windows.end(); ++iter) {
230 InstallDesktopController(*iter);
232 current_max_display_size_ = GetMaxDisplaySizeInNative();
235 bool DesktopBackgroundController::ReparentBackgroundWidgets(int src_container,
236 int dst_container) {
237 bool moved = false;
238 Shell::RootWindowControllerList controllers =
239 Shell::GetAllRootWindowControllers();
240 for (Shell::RootWindowControllerList::iterator iter = controllers.begin();
241 iter != controllers.end(); ++iter) {
242 RootWindowController* root_window_controller = *iter;
243 // In the steady state (no animation playing) the background widget
244 // controller exists in the RootWindowController.
245 DesktopBackgroundWidgetController* desktop_controller =
246 root_window_controller->wallpaper_controller();
247 if (desktop_controller) {
248 moved |=
249 desktop_controller->Reparent(root_window_controller->GetRootWindow(),
250 src_container,
251 dst_container);
253 // During desktop show animations the controller lives in
254 // AnimatingDesktopController owned by RootWindowController.
255 // NOTE: If a wallpaper load happens during a desktop show animation there
256 // can temporarily be two desktop background widgets. We must reparent
257 // both of them - one above and one here.
258 DesktopBackgroundWidgetController* animating_controller =
259 root_window_controller->animating_wallpaper_controller() ?
260 root_window_controller->animating_wallpaper_controller()->
261 GetController(false) :
262 NULL;
263 if (animating_controller) {
264 moved |= animating_controller->Reparent(
265 root_window_controller->GetRootWindow(),
266 src_container,
267 dst_container);
270 return moved;
273 int DesktopBackgroundController::GetBackgroundContainerId(bool locked) {
274 return locked ? kShellWindowId_LockScreenBackgroundContainer
275 : kShellWindowId_DesktopBackgroundContainer;
278 void DesktopBackgroundController::UpdateWallpaper(bool clear_cache) {
279 current_wallpaper_.reset(NULL);
280 ash::Shell::GetInstance()->user_wallpaper_delegate()->UpdateWallpaper(
281 clear_cache);
284 } // namespace ash