Home | History | Annotate | Download | only in desktop_background
      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/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 
     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 
     54 DesktopBackgroundController::~DesktopBackgroundController() {
     55   Shell::GetInstance()->display_controller()->RemoveObserver(this);
     56   Shell::GetInstance()->RemoveShellObserver(this);
     57 }
     58 
     59 gfx::ImageSkia DesktopBackgroundController::GetWallpaper() const {
     60   if (current_wallpaper_)
     61     return current_wallpaper_->image();
     62   return gfx::ImageSkia();
     63 }
     64 
     65 void DesktopBackgroundController::AddObserver(
     66     DesktopBackgroundControllerObserver* observer) {
     67   observers_.AddObserver(observer);
     68 }
     69 
     70 void DesktopBackgroundController::RemoveObserver(
     71     DesktopBackgroundControllerObserver* observer) {
     72   observers_.RemoveObserver(observer);
     73 }
     74 
     75 WallpaperLayout DesktopBackgroundController::GetWallpaperLayout() const {
     76   if (current_wallpaper_)
     77     return current_wallpaper_->layout();
     78   return WALLPAPER_LAYOUT_CENTER_CROPPED;
     79 }
     80 
     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 
    102 void DesktopBackgroundController::CreateEmptyWallpaper() {
    103   current_wallpaper_.reset(NULL);
    104   SetDesktopBackgroundImageMode();
    105 }
    106 
    107 bool DesktopBackgroundController::MoveDesktopToLockedContainer() {
    108   if (locked_)
    109     return false;
    110   locked_ = true;
    111   return ReparentBackgroundWidgets(GetBackgroundContainerId(false),
    112                                    GetBackgroundContainerId(true));
    113 }
    114 
    115 bool DesktopBackgroundController::MoveDesktopToUnlockedContainer() {
    116   if (!locked_)
    117     return false;
    118   locked_ = false;
    119   return ReparentBackgroundWidgets(GetBackgroundContainerId(true),
    120                                    GetBackgroundContainerId(false));
    121 }
    122 
    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 
    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
    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 
    177 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 
    192 void DesktopBackgroundController::SetDesktopBackgroundImageMode() {
    193   desktop_background_mode_ = BACKGROUND_IMAGE;
    194   InstallDesktopControllerForAllWindows();
    195 }
    196 
    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 
    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 
    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 
    266 int DesktopBackgroundController::GetBackgroundContainerId(bool locked) {
    267   return locked ? kShellWindowId_LockScreenBackgroundContainer
    268                 : kShellWindowId_DesktopBackgroundContainer;
    269 }
    270 
    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