Roll leveldb from r73 to r75.
[chromium-blink-merge.git] / ash / desktop_background / desktop_background_controller.cc
blob83ffe466f9dd3a157a7e2c7c26619bfacfb91128
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/desktop_background/desktop_background_controller_observer.h"
8 #include "ash/desktop_background/desktop_background_view.h"
9 #include "ash/desktop_background/desktop_background_widget_controller.h"
10 #include "ash/desktop_background/user_wallpaper_delegate.h"
11 #include "ash/desktop_background/wallpaper_resizer.h"
12 #include "ash/root_window_controller.h"
13 #include "ash/shell.h"
14 #include "ash/shell_factory.h"
15 #include "ash/shell_window_ids.h"
16 #include "ash/wm/root_window_layout_manager.h"
17 #include "base/bind.h"
18 #include "base/logging.h"
19 #include "base/synchronization/cancellation_flag.h"
20 #include "base/threading/worker_pool.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "grit/ash_wallpaper_resources.h"
23 #include "ui/aura/root_window.h"
24 #include "ui/aura/window.h"
25 #include "ui/compositor/layer.h"
26 #include "ui/gfx/rect.h"
27 #include "ui/gfx/image/image.h"
28 #include "ui/views/widget/widget.h"
30 using ash::internal::DesktopBackgroundWidgetController;
31 using ash::internal::kAnimatingDesktopController;
32 using ash::internal::kDesktopController;
33 using content::BrowserThread;
35 namespace ash {
36 namespace {
38 const SkColor kTransparentColor = SkColorSetARGB(0x00, 0x00, 0x00, 0x00);
40 internal::RootWindowLayoutManager* GetRootWindowLayoutManager(
41 aura::RootWindow* root_window) {
42 return static_cast<internal::RootWindowLayoutManager*>(
43 root_window->layout_manager());
46 // Returns the maximum width and height of all root windows.
47 gfx::Size GetRootWindowsSize() {
48 int width = 0;
49 int height = 0;
50 Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
51 for (Shell::RootWindowList::iterator iter = root_windows.begin();
52 iter != root_windows.end(); ++iter) {
53 gfx::Size root_window_size = (*iter)->GetHostSize();
54 if (root_window_size.width() > width)
55 width = root_window_size.width();
56 if (root_window_size.height() > height)
57 height = root_window_size.height();
59 return gfx::Size(width, height);
62 } // namespace
64 #if defined(GOOGLE_CHROME_BUILD)
65 const WallpaperInfo kDefaultLargeWallpaper =
66 { IDR_AURA_WALLPAPERS_2_LANDSCAPE8_LARGE, WALLPAPER_LAYOUT_CENTER_CROPPED };
67 const WallpaperInfo kDefaultSmallWallpaper =
68 { IDR_AURA_WALLPAPERS_2_LANDSCAPE8_SMALL, WALLPAPER_LAYOUT_CENTER };
69 const WallpaperInfo kGuestLargeWallpaper =
70 { IDR_AURA_WALLPAPERS_2_LANDSCAPE7_LARGE, WALLPAPER_LAYOUT_CENTER_CROPPED };
71 const WallpaperInfo kGuestSmallWallpaper =
72 { IDR_AURA_WALLPAPERS_2_LANDSCAPE7_SMALL, WALLPAPER_LAYOUT_CENTER };
73 #else
74 const WallpaperInfo kDefaultLargeWallpaper =
75 { IDR_AURA_WALLPAPERS_5_GRADIENT5_LARGE, WALLPAPER_LAYOUT_TILE };
76 const WallpaperInfo kDefaultSmallWallpaper =
77 { IDR_AURA_WALLPAPERS_5_GRADIENT5_SMALL, WALLPAPER_LAYOUT_TILE };
78 const WallpaperInfo kGuestLargeWallpaper = kDefaultLargeWallpaper;
79 const WallpaperInfo kGuestSmallWallpaper = kDefaultSmallWallpaper;
80 #endif
82 const int kSmallWallpaperMaxWidth = 1366;
83 const int kSmallWallpaperMaxHeight = 800;
84 const int kLargeWallpaperMaxWidth = 2560;
85 const int kLargeWallpaperMaxHeight = 1700;
86 const int kWallpaperThumbnailWidth = 108;
87 const int kWallpaperThumbnailHeight = 68;
89 // DesktopBackgroundController::WallpaperLoader wraps background wallpaper
90 // loading.
91 class DesktopBackgroundController::WallpaperLoader
92 : public base::RefCountedThreadSafe<
93 DesktopBackgroundController::WallpaperLoader> {
94 public:
95 explicit WallpaperLoader(const WallpaperInfo& info)
96 : info_(info) {
99 static void LoadOnWorkerPoolThread(scoped_refptr<WallpaperLoader> wl) {
100 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI));
101 wl->LoadingWallpaper();
104 void Cancel() {
105 cancel_flag_.Set();
108 int idr() const {
109 return info_.idr;
112 WallpaperResizer* ReleaseWallpaperResizer() {
113 return wallpaper_resizer_.release();
116 private:
117 friend class base::RefCountedThreadSafe<
118 DesktopBackgroundController::WallpaperLoader>;
120 void LoadingWallpaper() {
121 if (cancel_flag_.IsSet())
122 return;
123 wallpaper_resizer_.reset(new WallpaperResizer(info_, GetRootWindowsSize()));
126 ~WallpaperLoader() {}
128 base::CancellationFlag cancel_flag_;
130 scoped_ptr<WallpaperResizer> wallpaper_resizer_;
132 const WallpaperInfo info_;
134 DISALLOW_COPY_AND_ASSIGN(WallpaperLoader);
137 DesktopBackgroundController::DesktopBackgroundController()
138 : locked_(false),
139 desktop_background_mode_(BACKGROUND_NONE),
140 background_color_(kTransparentColor),
141 weak_ptr_factory_(this) {
144 DesktopBackgroundController::~DesktopBackgroundController() {
145 CancelPendingWallpaperOperation();
148 gfx::ImageSkia DesktopBackgroundController::GetWallpaper() const {
149 if (current_wallpaper_)
150 return current_wallpaper_->wallpaper_image();
151 return gfx::ImageSkia();
154 void DesktopBackgroundController::AddObserver(
155 DesktopBackgroundControllerObserver* observer) {
156 observers_.AddObserver(observer);
159 void DesktopBackgroundController::RemoveObserver(
160 DesktopBackgroundControllerObserver* observer) {
161 observers_.RemoveObserver(observer);
164 WallpaperLayout DesktopBackgroundController::GetWallpaperLayout() const {
165 if (current_wallpaper_)
166 return current_wallpaper_->wallpaper_info().layout;
167 return WALLPAPER_LAYOUT_CENTER_CROPPED;
170 gfx::ImageSkia DesktopBackgroundController::GetCurrentWallpaperImage() {
171 if (desktop_background_mode_ != BACKGROUND_IMAGE)
172 return gfx::ImageSkia();
173 return GetWallpaper();
176 int DesktopBackgroundController::GetWallpaperIDR() const {
177 if (wallpaper_loader_.get())
178 return wallpaper_loader_->idr();
179 else if (current_wallpaper_)
180 return current_wallpaper_->wallpaper_info().idr;
181 else
182 return -1;
185 void DesktopBackgroundController::OnRootWindowAdded(
186 aura::RootWindow* root_window) {
187 // The background hasn't been set yet.
188 if (desktop_background_mode_ == BACKGROUND_NONE)
189 return;
191 // Handle resolution change for "built-in" images.
192 if (BACKGROUND_IMAGE == desktop_background_mode_ &&
193 current_wallpaper_.get()) {
194 gfx::Size root_window_size = root_window->GetHostSize();
195 int width = current_wallpaper_->wallpaper_image().width();
196 int height = current_wallpaper_->wallpaper_image().height();
197 // Reloads wallpaper if current wallpaper is smaller than the new added root
198 // window.
199 if (width < root_window_size.width() ||
200 height < root_window_size.height()) {
201 current_wallpaper_.reset(NULL);
202 ash::Shell::GetInstance()->user_wallpaper_delegate()->
203 UpdateWallpaper();
207 InstallDesktopController(root_window);
210 void DesktopBackgroundController::SetDefaultWallpaper(
211 const WallpaperInfo& info) {
212 DCHECK_NE(GetWallpaperIDR(), info.idr);
214 CancelPendingWallpaperOperation();
215 wallpaper_loader_ = new WallpaperLoader(info);
216 base::WorkerPool::PostTaskAndReply(
217 FROM_HERE,
218 base::Bind(&WallpaperLoader::LoadOnWorkerPoolThread, wallpaper_loader_),
219 base::Bind(&DesktopBackgroundController::OnWallpaperLoadCompleted,
220 weak_ptr_factory_.GetWeakPtr(),
221 wallpaper_loader_),
222 true /* task_is_slow */);
225 void DesktopBackgroundController::SetCustomWallpaper(
226 const gfx::ImageSkia& wallpaper,
227 WallpaperLayout layout) {
228 CancelPendingWallpaperOperation();
229 if (current_wallpaper_.get() &&
230 current_wallpaper_->wallpaper_image().BackedBySameObjectAs(wallpaper)) {
231 return;
234 WallpaperInfo info = { -1, layout };
235 current_wallpaper_.reset(new WallpaperResizer(info, GetRootWindowsSize(),
236 wallpaper));
237 current_wallpaper_->StartResize();
238 FOR_EACH_OBSERVER(DesktopBackgroundControllerObserver, observers_,
239 OnWallpaperDataChanged());
240 SetDesktopBackgroundImageMode();
243 void DesktopBackgroundController::CancelPendingWallpaperOperation() {
244 // Set canceled flag of previous request to skip unneeded loading.
245 if (wallpaper_loader_.get())
246 wallpaper_loader_->Cancel();
248 // Cancel reply callback for previous request.
249 weak_ptr_factory_.InvalidateWeakPtrs();
252 void DesktopBackgroundController::SetDesktopBackgroundSolidColorMode(
253 SkColor color) {
254 background_color_ = color;
255 desktop_background_mode_ = BACKGROUND_SOLID_COLOR;
257 InstallDesktopControllerForAllWindows();
260 void DesktopBackgroundController::CreateEmptyWallpaper() {
261 current_wallpaper_.reset(NULL);
262 SetDesktopBackgroundImageMode();
265 WallpaperResolution DesktopBackgroundController::GetAppropriateResolution() {
266 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
267 WallpaperResolution resolution = WALLPAPER_RESOLUTION_SMALL;
268 Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
269 for (Shell::RootWindowList::iterator iter = root_windows.begin();
270 iter != root_windows.end(); ++iter) {
271 // Compare to host size as constants are defined in terms of
272 // physical pixel size.
273 // TODO(oshima): This may not be ideal for fractional scaling
274 // scenario. Revisit and fix if necessary.
275 gfx::Size host_window_size = (*iter)->GetHostSize();
276 if (host_window_size.width() > kSmallWallpaperMaxWidth ||
277 host_window_size.height() > kSmallWallpaperMaxHeight) {
278 resolution = WALLPAPER_RESOLUTION_LARGE;
281 return resolution;
284 bool DesktopBackgroundController::MoveDesktopToLockedContainer() {
285 if (locked_)
286 return false;
287 locked_ = true;
288 return ReparentBackgroundWidgets(GetBackgroundContainerId(false),
289 GetBackgroundContainerId(true));
292 bool DesktopBackgroundController::MoveDesktopToUnlockedContainer() {
293 if (!locked_)
294 return false;
295 locked_ = false;
296 return ReparentBackgroundWidgets(GetBackgroundContainerId(true),
297 GetBackgroundContainerId(false));
300 void DesktopBackgroundController::OnWindowDestroying(aura::Window* window) {
301 window->SetProperty(kDesktopController,
302 static_cast<internal::DesktopBackgroundWidgetController*>(NULL));
303 window->SetProperty(kAnimatingDesktopController,
304 static_cast<internal::AnimatingDesktopController*>(NULL));
307 void DesktopBackgroundController::SetDesktopBackgroundImageMode() {
308 desktop_background_mode_ = BACKGROUND_IMAGE;
309 InstallDesktopControllerForAllWindows();
312 void DesktopBackgroundController::OnWallpaperLoadCompleted(
313 scoped_refptr<WallpaperLoader> wl) {
314 current_wallpaper_.reset(wl->ReleaseWallpaperResizer());
315 FOR_EACH_OBSERVER(DesktopBackgroundControllerObserver, observers_,
316 OnWallpaperDataChanged());
318 SetDesktopBackgroundImageMode();
320 DCHECK(wl.get() == wallpaper_loader_.get());
321 wallpaper_loader_ = NULL;
324 void DesktopBackgroundController::NotifyAnimationFinished() {
325 Shell* shell = Shell::GetInstance();
326 shell->GetPrimaryRootWindowController()->HandleDesktopBackgroundVisible();
327 shell->user_wallpaper_delegate()->OnWallpaperAnimationFinished();
330 ui::Layer* DesktopBackgroundController::SetColorLayerForContainer(
331 SkColor color,
332 aura::RootWindow* root_window,
333 int container_id) {
334 ui::Layer* background_layer = new ui::Layer(ui::LAYER_SOLID_COLOR);
335 background_layer->SetColor(color);
337 Shell::GetContainer(root_window,container_id)->
338 layer()->Add(background_layer);
340 base::MessageLoop::current()->PostTask(
341 FROM_HERE,
342 base::Bind(&DesktopBackgroundController::NotifyAnimationFinished,
343 weak_ptr_factory_.GetWeakPtr()));
345 return background_layer;
348 void DesktopBackgroundController::InstallDesktopController(
349 aura::RootWindow* root_window) {
350 internal::DesktopBackgroundWidgetController* component = NULL;
351 int container_id = GetBackgroundContainerId(locked_);
353 switch (desktop_background_mode_) {
354 case BACKGROUND_IMAGE: {
355 views::Widget* widget = internal::CreateDesktopBackground(root_window,
356 container_id);
357 component = new internal::DesktopBackgroundWidgetController(widget);
358 break;
360 case BACKGROUND_SOLID_COLOR: {
361 ui::Layer* layer = SetColorLayerForContainer(background_color_,
362 root_window,
363 container_id);
364 component = new internal::DesktopBackgroundWidgetController(layer);
365 break;
367 case BACKGROUND_NONE:
368 NOTREACHED();
369 return;
371 // Ensure we're only observing the root window once. Don't rely on a window
372 // property check as those can be cleared by tests resetting the background.
373 if (!root_window->HasObserver(this))
374 root_window->AddObserver(this);
376 internal::AnimatingDesktopController* animating_controller =
377 root_window->GetProperty(kAnimatingDesktopController);
378 if (animating_controller)
379 animating_controller->StopAnimating();
380 root_window->SetProperty(kAnimatingDesktopController,
381 new internal::AnimatingDesktopController(component));
384 void DesktopBackgroundController::InstallDesktopControllerForAllWindows() {
385 Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
386 for (Shell::RootWindowList::iterator iter = root_windows.begin();
387 iter != root_windows.end(); ++iter) {
388 InstallDesktopController(*iter);
392 bool DesktopBackgroundController::ReparentBackgroundWidgets(int src_container,
393 int dst_container) {
394 bool moved = false;
395 Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
396 for (Shell::RootWindowList::iterator iter = root_windows.begin();
397 iter != root_windows.end(); ++iter) {
398 aura::RootWindow* root_window = *iter;
399 // In the steady state (no animation playing) the background widget
400 // controller exists in the kDesktopController property.
401 DesktopBackgroundWidgetController* desktop_controller = root_window->
402 GetProperty(kDesktopController);
403 if (desktop_controller) {
404 moved |= desktop_controller->Reparent(root_window,
405 src_container,
406 dst_container);
408 // During desktop show animations the controller lives in
409 // kAnimatingDesktopController.
410 // NOTE: If a wallpaper load happens during a desktop show animation there
411 // can temporarily be two desktop background widgets. We must reparent
412 // both of them - one above and one here.
413 DesktopBackgroundWidgetController* animating_controller =
414 root_window->GetProperty(kAnimatingDesktopController) ?
415 root_window->GetProperty(kAnimatingDesktopController)->
416 GetController(false) :
417 NULL;
418 if (animating_controller) {
419 moved |= animating_controller->Reparent(root_window,
420 src_container,
421 dst_container);
424 return moved;
427 int DesktopBackgroundController::GetBackgroundContainerId(bool locked) {
428 return locked ? internal::kShellWindowId_LockScreenBackgroundContainer :
429 internal::kShellWindowId_DesktopBackgroundContainer;
432 } // namespace ash