• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "ash/desktop_background/desktop_background_controller.h"
6 
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/files/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"
34 
35 using content::BrowserThread;
36 
37 namespace ash {
38 namespace {
39 
40 // How long to wait reloading the wallpaper after the max display has
41 // changed?
42 const int kWallpaperReloadDelayMs = 2000;
43 
44 }  // namespace
45 
DesktopBackgroundController()46 DesktopBackgroundController::DesktopBackgroundController()
47     : locked_(false),
48       desktop_background_mode_(BACKGROUND_NONE),
49       wallpaper_reload_delay_(kWallpaperReloadDelayMs) {
50   Shell::GetInstance()->display_controller()->AddObserver(this);
51   Shell::GetInstance()->AddShellObserver(this);
52 }
53 
~DesktopBackgroundController()54 DesktopBackgroundController::~DesktopBackgroundController() {
55   Shell::GetInstance()->display_controller()->RemoveObserver(this);
56   Shell::GetInstance()->RemoveShellObserver(this);
57 }
58 
GetWallpaper() const59 gfx::ImageSkia DesktopBackgroundController::GetWallpaper() const {
60   if (current_wallpaper_)
61     return current_wallpaper_->image();
62   return gfx::ImageSkia();
63 }
64 
AddObserver(DesktopBackgroundControllerObserver * observer)65 void DesktopBackgroundController::AddObserver(
66     DesktopBackgroundControllerObserver* observer) {
67   observers_.AddObserver(observer);
68 }
69 
RemoveObserver(DesktopBackgroundControllerObserver * observer)70 void DesktopBackgroundController::RemoveObserver(
71     DesktopBackgroundControllerObserver* observer) {
72   observers_.RemoveObserver(observer);
73 }
74 
GetWallpaperLayout() const75 WallpaperLayout DesktopBackgroundController::GetWallpaperLayout() const {
76   if (current_wallpaper_)
77     return current_wallpaper_->layout();
78   return WALLPAPER_LAYOUT_CENTER_CROPPED;
79 }
80 
SetWallpaperImage(const gfx::ImageSkia & image,WallpaperLayout layout)81 bool DesktopBackgroundController::SetWallpaperImage(const gfx::ImageSkia& image,
82                                                     WallpaperLayout layout) {
83   VLOG(1) << "SetWallpaper: image_id=" << WallpaperResizer::GetImageId(image)
84           << " layout=" << layout;
85 
86   if (WallpaperIsAlreadyLoaded(image, true /* compare_layouts */, layout)) {
87     VLOG(1) << "Wallpaper is already loaded";
88     return false;
89   }
90 
91   current_wallpaper_.reset(
92       new WallpaperResizer(image, GetMaxDisplaySizeInNative(), layout));
93   current_wallpaper_->StartResize();
94 
95   FOR_EACH_OBSERVER(DesktopBackgroundControllerObserver,
96                     observers_,
97                     OnWallpaperDataChanged());
98   SetDesktopBackgroundImageMode();
99   return true;
100 }
101 
CreateEmptyWallpaper()102 void DesktopBackgroundController::CreateEmptyWallpaper() {
103   current_wallpaper_.reset(NULL);
104   SetDesktopBackgroundImageMode();
105 }
106 
MoveDesktopToLockedContainer()107 bool DesktopBackgroundController::MoveDesktopToLockedContainer() {
108   if (locked_)
109     return false;
110   locked_ = true;
111   return ReparentBackgroundWidgets(GetBackgroundContainerId(false),
112                                    GetBackgroundContainerId(true));
113 }
114 
MoveDesktopToUnlockedContainer()115 bool DesktopBackgroundController::MoveDesktopToUnlockedContainer() {
116   if (!locked_)
117     return false;
118   locked_ = false;
119   return ReparentBackgroundWidgets(GetBackgroundContainerId(true),
120                                    GetBackgroundContainerId(false));
121 }
122 
OnDisplayConfigurationChanged()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()) {
129       timer_.Stop();
130       timer_.Start(FROM_HERE,
131                    base::TimeDelta::FromMilliseconds(wallpaper_reload_delay_),
132                    this,
133                    &DesktopBackgroundController::UpdateWallpaper);
134     }
135   }
136 }
137 
OnRootWindowAdded(aura::Window * root_window)138 void DesktopBackgroundController::OnRootWindowAdded(aura::Window* root_window) {
139   // The background hasn't been set yet.
140   if (desktop_background_mode_ == BACKGROUND_NONE)
141     return;
142 
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())
149       UpdateWallpaper();
150   }
151 
152   InstallDesktopController(root_window);
153 }
154 
155 // static
GetMaxDisplaySizeInNative()156 gfx::Size DesktopBackgroundController::GetMaxDisplaySizeInNative() {
157   int width = 0;
158   int height = 0;
159   std::vector<gfx::Display> displays = Shell::GetScreen()->GetAllDisplays();
160   DisplayManager* display_manager = Shell::GetInstance()->display_manager();
161 
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());
170     }
171     width = std::max(size_in_pixel.width(), width);
172     height = std::max(size_in_pixel.height(), height);
173   }
174   return gfx::Size(width, height);
175 }
176 
WallpaperIsAlreadyLoaded(const gfx::ImageSkia & image,bool compare_layouts,WallpaperLayout layout) const177 bool DesktopBackgroundController::WallpaperIsAlreadyLoaded(
178     const gfx::ImageSkia& image,
179     bool compare_layouts,
180     WallpaperLayout layout) const {
181   if (!current_wallpaper_.get())
182     return false;
183 
184   // Compare layouts only if necessary.
185   if (compare_layouts && layout != current_wallpaper_->layout())
186     return false;
187 
188   return WallpaperResizer::GetImageId(image) ==
189          current_wallpaper_->original_image_id();
190 }
191 
SetDesktopBackgroundImageMode()192 void DesktopBackgroundController::SetDesktopBackgroundImageMode() {
193   desktop_background_mode_ = BACKGROUND_IMAGE;
194   InstallDesktopControllerForAllWindows();
195 }
196 
InstallDesktopController(aura::Window * root_window)197 void DesktopBackgroundController::InstallDesktopController(
198     aura::Window* root_window) {
199   DesktopBackgroundWidgetController* component = NULL;
200   int container_id = GetBackgroundContainerId(locked_);
201 
202   switch (desktop_background_mode_) {
203     case BACKGROUND_IMAGE: {
204       views::Widget* widget =
205           CreateDesktopBackground(root_window, container_id);
206       component = new DesktopBackgroundWidgetController(widget);
207       break;
208     }
209     case BACKGROUND_NONE:
210       NOTREACHED();
211       return;
212   }
213   GetRootWindowController(root_window)->SetAnimatingWallpaperController(
214       new AnimatingDesktopController(component));
215 
216   component->StartAnimating(GetRootWindowController(root_window));
217 }
218 
InstallDesktopControllerForAllWindows()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);
224   }
225   current_max_display_size_ = GetMaxDisplaySizeInNative();
226 }
227 
ReparentBackgroundWidgets(int src_container,int dst_container)228 bool DesktopBackgroundController::ReparentBackgroundWidgets(int src_container,
229                                                             int dst_container) {
230   bool moved = false;
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) {
241       moved |=
242           desktop_controller->Reparent(root_window_controller->GetRootWindow(),
243                                        src_container,
244                                        dst_container);
245     }
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) :
255         NULL;
256     if (animating_controller) {
257       moved |= animating_controller->Reparent(
258           root_window_controller->GetRootWindow(),
259           src_container,
260           dst_container);
261     }
262   }
263   return moved;
264 }
265 
GetBackgroundContainerId(bool locked)266 int DesktopBackgroundController::GetBackgroundContainerId(bool locked) {
267   return locked ? kShellWindowId_LockScreenBackgroundContainer
268                 : kShellWindowId_DesktopBackgroundContainer;
269 }
270 
UpdateWallpaper()271 void DesktopBackgroundController::UpdateWallpaper() {
272   current_wallpaper_.reset(NULL);
273   ash::Shell::GetInstance()->user_wallpaper_delegate()->
274       UpdateWallpaper(true /* clear cache */);
275 }
276 
277 }  // namespace ash
278