Home | History | Annotate | Download | only in shelf
      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/shelf/shelf_widget.h"
      6 
      7 #include "ash/ash_switches.h"
      8 #include "ash/focus_cycler.h"
      9 #include "ash/root_window_controller.h"
     10 #include "ash/session_state_delegate.h"
     11 #include "ash/shelf/shelf_delegate.h"
     12 #include "ash/shelf/shelf_layout_manager.h"
     13 #include "ash/shelf/shelf_model.h"
     14 #include "ash/shelf/shelf_navigator.h"
     15 #include "ash/shelf/shelf_view.h"
     16 #include "ash/shelf/shelf_widget.h"
     17 #include "ash/shell.h"
     18 #include "ash/shell_window_ids.h"
     19 #include "ash/system/tray/system_tray_delegate.h"
     20 #include "ash/wm/status_area_layout_manager.h"
     21 #include "ash/wm/window_properties.h"
     22 #include "ash/wm/workspace_controller.h"
     23 #include "grit/ash_resources.h"
     24 #include "ui/aura/client/activation_client.h"
     25 #include "ui/aura/root_window.h"
     26 #include "ui/aura/window.h"
     27 #include "ui/aura/window_observer.h"
     28 #include "ui/base/resource/resource_bundle.h"
     29 #include "ui/compositor/layer.h"
     30 #include "ui/compositor/scoped_layer_animation_settings.h"
     31 #include "ui/events/event_constants.h"
     32 #include "ui/gfx/canvas.h"
     33 #include "ui/gfx/image/image.h"
     34 #include "ui/gfx/image/image_skia_operations.h"
     35 #include "ui/gfx/skbitmap_operations.h"
     36 #include "ui/views/accessible_pane_view.h"
     37 #include "ui/views/widget/widget.h"
     38 #include "ui/views/widget/widget_delegate.h"
     39 
     40 namespace {
     41 // Size of black border at bottom (or side) of launcher.
     42 const int kNumBlackPixels = 3;
     43 // Alpha to paint dimming image with.
     44 const int kDimAlpha = 128;
     45 
     46 // The time to dim and un-dim.
     47 const int kTimeToDimMs = 3000;  // Slow in dimming.
     48 const int kTimeToUnDimMs = 200;  // Fast in activating.
     49 
     50 // Class used to slightly dim shelf items when maximized and visible.
     51 class DimmerView : public views::View,
     52                    public views::WidgetDelegate,
     53                    ash::internal::BackgroundAnimatorDelegate {
     54  public:
     55   // If |disable_dimming_animations_for_test| is set, all alpha animations will
     56   // be performed instantly.
     57   DimmerView(ash::ShelfWidget* shelf_widget,
     58              bool disable_dimming_animations_for_test);
     59   virtual ~DimmerView();
     60 
     61   // Called by |DimmerEventFilter| when the mouse |hovered| state changes.
     62   void SetHovered(bool hovered);
     63 
     64   // Force the dimmer to be undimmed.
     65   void ForceUndimming(bool force);
     66 
     67   // views::WidgetDelegate overrides:
     68   virtual views::Widget* GetWidget() OVERRIDE {
     69     return View::GetWidget();
     70   }
     71   virtual const views::Widget* GetWidget() const OVERRIDE {
     72     return View::GetWidget();
     73   }
     74 
     75   // ash::internal::BackgroundAnimatorDelegate overrides:
     76   virtual void UpdateBackground(int alpha) OVERRIDE {
     77     alpha_ = alpha;
     78     SchedulePaint();
     79   }
     80 
     81   // views::View overrides:
     82   virtual void OnPaintBackground(gfx::Canvas* canvas) OVERRIDE;
     83 
     84   // A function to test the current alpha used.
     85   int get_dimming_alpha_for_test() { return alpha_; }
     86 
     87  private:
     88   // This class monitors mouse events to see if it is on top of the launcher.
     89   class DimmerEventFilter : public ui::EventHandler {
     90    public:
     91     explicit DimmerEventFilter(DimmerView* owner);
     92     virtual ~DimmerEventFilter();
     93 
     94     // Overridden from ui::EventHandler:
     95     virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
     96     virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE;
     97 
     98    private:
     99     // The owning class.
    100     DimmerView* owner_;
    101 
    102     // TRUE if the mouse is inside the shelf.
    103     bool mouse_inside_;
    104 
    105     // TRUE if a touch event is inside the shelf.
    106     bool touch_inside_;
    107 
    108     DISALLOW_COPY_AND_ASSIGN(DimmerEventFilter);
    109   };
    110 
    111   // The owning shelf.
    112   ash::ShelfWidget* shelf_;
    113 
    114   // The alpha to use for covering the shelf.
    115   int alpha_;
    116 
    117   // True if the event filter claims that we should not be dimmed.
    118   bool is_hovered_;
    119 
    120   // True if someone forces us not to be dimmed (e.g. a menu is open).
    121   bool force_hovered_;
    122 
    123   // True if animations should be suppressed for a test.
    124   bool disable_dimming_animations_for_test_;
    125 
    126   // The animator for the background transitions.
    127   ash::internal::BackgroundAnimator background_animator_;
    128 
    129   // Notification of entering / exiting of the shelf area by mouse.
    130   scoped_ptr<DimmerEventFilter> event_filter_;
    131 
    132   DISALLOW_COPY_AND_ASSIGN(DimmerView);
    133 };
    134 
    135 DimmerView::DimmerView(ash::ShelfWidget* shelf_widget,
    136                        bool disable_dimming_animations_for_test)
    137     : shelf_(shelf_widget),
    138       alpha_(kDimAlpha),
    139       is_hovered_(false),
    140       force_hovered_(false),
    141       disable_dimming_animations_for_test_(disable_dimming_animations_for_test),
    142       background_animator_(this, 0, kDimAlpha) {
    143   event_filter_.reset(new DimmerEventFilter(this));
    144   // Make sure it is undimmed at the beginning and then fire off the dimming
    145   // animation.
    146   background_animator_.SetPaintsBackground(false,
    147                                            ash::BACKGROUND_CHANGE_IMMEDIATE);
    148   SetHovered(false);
    149 }
    150 
    151 DimmerView::~DimmerView() {
    152 }
    153 
    154 void DimmerView::SetHovered(bool hovered) {
    155   // Remember the hovered state so that we can correct the state once a
    156   // possible force state has disappeared.
    157   is_hovered_ = hovered;
    158   // Undimm also if we were forced to by e.g. an open menu.
    159   hovered |= force_hovered_;
    160   background_animator_.SetDuration(hovered ? kTimeToUnDimMs : kTimeToDimMs);
    161   background_animator_.SetPaintsBackground(!hovered,
    162       disable_dimming_animations_for_test_ ?
    163           ash::BACKGROUND_CHANGE_IMMEDIATE : ash::BACKGROUND_CHANGE_ANIMATE);
    164 }
    165 
    166 void DimmerView::ForceUndimming(bool force) {
    167   bool previous = force_hovered_;
    168   force_hovered_ = force;
    169   // If the forced change does change the result we apply the change.
    170   if (is_hovered_ || force_hovered_ != is_hovered_ || previous)
    171     SetHovered(is_hovered_);
    172 }
    173 
    174 void DimmerView::OnPaintBackground(gfx::Canvas* canvas) {
    175   SkPaint paint;
    176   ResourceBundle& rb = ResourceBundle::GetSharedInstance();
    177   gfx::ImageSkia launcher_background =
    178       *rb.GetImageNamed(IDR_AURA_LAUNCHER_DIMMING).ToImageSkia();
    179 
    180   if (shelf_->GetAlignment() != ash::SHELF_ALIGNMENT_BOTTOM) {
    181     launcher_background = gfx::ImageSkiaOperations::CreateRotatedImage(
    182         launcher_background,
    183         shelf_->shelf_layout_manager()->SelectValueForShelfAlignment(
    184             SkBitmapOperations::ROTATION_90_CW,
    185             SkBitmapOperations::ROTATION_90_CW,
    186             SkBitmapOperations::ROTATION_270_CW,
    187             SkBitmapOperations::ROTATION_180_CW));
    188   }
    189   paint.setAlpha(alpha_);
    190   canvas->DrawImageInt(
    191       launcher_background,
    192       0, 0, launcher_background.width(), launcher_background.height(),
    193       0, 0, width(), height(),
    194       false,
    195       paint);
    196 }
    197 
    198 DimmerView::DimmerEventFilter::DimmerEventFilter(DimmerView* owner)
    199     : owner_(owner),
    200       mouse_inside_(false),
    201       touch_inside_(false) {
    202   ash::Shell::GetInstance()->AddPreTargetHandler(this);
    203 }
    204 
    205 DimmerView::DimmerEventFilter::~DimmerEventFilter() {
    206   ash::Shell::GetInstance()->RemovePreTargetHandler(this);
    207 }
    208 
    209 void DimmerView::DimmerEventFilter::OnMouseEvent(ui::MouseEvent* event) {
    210   if (event->type() != ui::ET_MOUSE_MOVED &&
    211       event->type() != ui::ET_MOUSE_DRAGGED)
    212     return;
    213   bool inside = owner_->GetBoundsInScreen().Contains(event->root_location());
    214   if (mouse_inside_ || touch_inside_ != inside || touch_inside_)
    215     owner_->SetHovered(inside || touch_inside_);
    216   mouse_inside_ = inside;
    217 }
    218 
    219 void DimmerView::DimmerEventFilter::OnTouchEvent(ui::TouchEvent* event) {
    220   bool touch_inside = false;
    221   if (event->type() != ui::ET_TOUCH_RELEASED &&
    222       event->type() != ui::ET_TOUCH_CANCELLED)
    223     touch_inside = owner_->GetBoundsInScreen().Contains(event->root_location());
    224 
    225   if (mouse_inside_ || touch_inside_ != mouse_inside_ || touch_inside)
    226     owner_->SetHovered(mouse_inside_ || touch_inside);
    227   touch_inside_ = touch_inside;
    228 }
    229 
    230 }  // namespace
    231 
    232 namespace ash {
    233 
    234 // The contents view of the Shelf. This view contains ShelfView and
    235 // sizes it to the width of the shelf minus the size of the status area.
    236 class ShelfWidget::DelegateView : public views::WidgetDelegate,
    237                                   public views::AccessiblePaneView,
    238                                   public internal::BackgroundAnimatorDelegate,
    239                                   public aura::WindowObserver {
    240  public:
    241   explicit DelegateView(ShelfWidget* shelf);
    242   virtual ~DelegateView();
    243 
    244   void set_focus_cycler(internal::FocusCycler* focus_cycler) {
    245     focus_cycler_ = focus_cycler;
    246   }
    247   internal::FocusCycler* focus_cycler() {
    248     return focus_cycler_;
    249   }
    250 
    251   ui::Layer* opaque_background() { return &opaque_background_; }
    252 
    253   // Set if the shelf area is dimmed (eg when a window is maximized).
    254   void SetDimmed(bool dimmed);
    255   bool GetDimmed() const;
    256 
    257   void SetParentLayer(ui::Layer* layer);
    258 
    259   // views::View overrides:
    260   virtual void OnPaintBackground(gfx::Canvas* canvas) OVERRIDE;
    261 
    262   // views::WidgetDelegateView overrides:
    263   virtual views::Widget* GetWidget() OVERRIDE {
    264     return View::GetWidget();
    265   }
    266   virtual const views::Widget* GetWidget() const OVERRIDE {
    267     return View::GetWidget();
    268   }
    269 
    270   virtual bool CanActivate() const OVERRIDE;
    271   virtual void Layout() OVERRIDE;
    272   virtual void ReorderChildLayers(ui::Layer* parent_layer) OVERRIDE;
    273   // This will be called when the parent local bounds change.
    274   virtual void OnBoundsChanged(const gfx::Rect& old_bounds) OVERRIDE;
    275 
    276   // aura::WindowObserver overrides:
    277   // This will be called when the shelf itself changes its absolute position.
    278   // Since the |dimmer_| panel needs to be placed in screen coordinates it needs
    279   // to be repositioned. The difference to the OnBoundsChanged call above is
    280   // that this gets also triggered when the shelf only moves.
    281   virtual void OnWindowBoundsChanged(aura::Window* window,
    282                                      const gfx::Rect& old_bounds,
    283                                      const gfx::Rect& new_bounds) OVERRIDE;
    284 
    285   // BackgroundAnimatorDelegate overrides:
    286   virtual void UpdateBackground(int alpha) OVERRIDE;
    287 
    288   // Force the shelf to be presented in an undimmed state.
    289   void ForceUndimming(bool force);
    290 
    291   // A function to test the current alpha used by the dimming bar. If there is
    292   // no dimmer active, the function will return -1.
    293   int GetDimmingAlphaForTest();
    294 
    295   // A function to test the bounds of the dimming bar. Returns gfx::Rect() if
    296   // the dimmer is inactive.
    297   gfx::Rect GetDimmerBoundsForTest();
    298 
    299   // Disable dimming animations for running tests. This needs to be called
    300   // prior to the creation of of the |dimmer_|.
    301   void disable_dimming_animations_for_test() {
    302     disable_dimming_animations_for_test_ = true;
    303   }
    304 
    305  private:
    306   ShelfWidget* shelf_;
    307   scoped_ptr<views::Widget> dimmer_;
    308   internal::FocusCycler* focus_cycler_;
    309   int alpha_;
    310   ui::Layer opaque_background_;
    311 
    312   // The view which does the dimming.
    313   DimmerView* dimmer_view_;
    314 
    315   // True if dimming animations should be turned off.
    316   bool disable_dimming_animations_for_test_;
    317 
    318   DISALLOW_COPY_AND_ASSIGN(DelegateView);
    319 };
    320 
    321 ShelfWidget::DelegateView::DelegateView(ShelfWidget* shelf)
    322     : shelf_(shelf),
    323       focus_cycler_(NULL),
    324       alpha_(0),
    325       opaque_background_(ui::LAYER_SOLID_COLOR),
    326       dimmer_view_(NULL),
    327       disable_dimming_animations_for_test_(false) {
    328   set_allow_deactivate_on_esc(true);
    329   opaque_background_.SetColor(SK_ColorBLACK);
    330   opaque_background_.SetBounds(GetLocalBounds());
    331   opaque_background_.SetOpacity(0.0f);
    332 }
    333 
    334 ShelfWidget::DelegateView::~DelegateView() {
    335   // Make sure that the dimmer goes away since it might have set an observer.
    336   SetDimmed(false);
    337 }
    338 
    339 void ShelfWidget::DelegateView::SetDimmed(bool value) {
    340   if (value == (dimmer_.get() != NULL))
    341     return;
    342 
    343   if (value) {
    344     dimmer_.reset(new views::Widget);
    345     views::Widget::InitParams params(
    346         views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
    347     params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
    348     params.can_activate = false;
    349     params.accept_events = false;
    350     params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
    351     params.parent = shelf_->GetNativeView();
    352     dimmer_->Init(params);
    353     dimmer_->GetNativeWindow()->SetName("ShelfDimmer");
    354     dimmer_->SetBounds(shelf_->GetWindowBoundsInScreen());
    355     // The launcher should not take focus when it is initially shown.
    356     dimmer_->set_focus_on_creation(false);
    357     dimmer_view_ = new DimmerView(shelf_, disable_dimming_animations_for_test_);
    358     dimmer_->SetContentsView(dimmer_view_);
    359     dimmer_->GetNativeView()->SetName("ShelfDimmerView");
    360     dimmer_->Show();
    361     shelf_->GetNativeView()->AddObserver(this);
    362   } else {
    363     // Some unit tests will come here with a destroyed window.
    364     if (shelf_->GetNativeView())
    365       shelf_->GetNativeView()->RemoveObserver(this);
    366     dimmer_view_ = NULL;
    367     dimmer_.reset(NULL);
    368   }
    369 }
    370 
    371 bool ShelfWidget::DelegateView::GetDimmed() const {
    372   return dimmer_.get() && dimmer_->IsVisible();
    373 }
    374 
    375 void ShelfWidget::DelegateView::SetParentLayer(ui::Layer* layer) {
    376   layer->Add(&opaque_background_);
    377   ReorderLayers();
    378 }
    379 
    380 void ShelfWidget::DelegateView::OnPaintBackground(gfx::Canvas* canvas) {
    381   ResourceBundle& rb = ResourceBundle::GetSharedInstance();
    382   gfx::ImageSkia launcher_background =
    383       *rb.GetImageSkiaNamed(IDR_AURA_LAUNCHER_BACKGROUND);
    384   if (SHELF_ALIGNMENT_BOTTOM != shelf_->GetAlignment())
    385     launcher_background = gfx::ImageSkiaOperations::CreateRotatedImage(
    386         launcher_background,
    387         shelf_->shelf_layout_manager()->SelectValueForShelfAlignment(
    388             SkBitmapOperations::ROTATION_90_CW,
    389             SkBitmapOperations::ROTATION_90_CW,
    390             SkBitmapOperations::ROTATION_270_CW,
    391             SkBitmapOperations::ROTATION_180_CW));
    392   const gfx::Rect dock_bounds(shelf_->shelf_layout_manager()->dock_bounds());
    393   SkPaint paint;
    394   paint.setAlpha(alpha_);
    395   canvas->DrawImageInt(
    396       launcher_background,
    397       0, 0, launcher_background.width(), launcher_background.height(),
    398       (SHELF_ALIGNMENT_BOTTOM == shelf_->GetAlignment() &&
    399        dock_bounds.x() == 0 && dock_bounds.width() > 0) ?
    400            dock_bounds.width() : 0, 0,
    401       SHELF_ALIGNMENT_BOTTOM == shelf_->GetAlignment() ?
    402           width() - dock_bounds.width() : width(), height(),
    403       false,
    404       paint);
    405   if (SHELF_ALIGNMENT_BOTTOM == shelf_->GetAlignment() &&
    406       dock_bounds.width() > 0) {
    407     // The part of the shelf background that is in the corner below the docked
    408     // windows close to the work area is an arched gradient that blends
    409     // vertically oriented docked background and horizontal shelf.
    410     gfx::ImageSkia launcher_corner =
    411         *rb.GetImageSkiaNamed(IDR_AURA_LAUNCHER_CORNER);
    412     if (dock_bounds.x() == 0) {
    413       launcher_corner = gfx::ImageSkiaOperations::CreateRotatedImage(
    414           launcher_corner, SkBitmapOperations::ROTATION_90_CW);
    415     }
    416     canvas->DrawImageInt(
    417         launcher_corner,
    418         0, 0, launcher_corner.width(), launcher_corner.height(),
    419         dock_bounds.x() > 0 ? dock_bounds.x() : dock_bounds.width() - height(),
    420         0,
    421         height(), height(),
    422         false,
    423         paint);
    424     // The part of the shelf background that is just below the docked windows
    425     // is drawn using the last (lowest) 1-pixel tall strip of the image asset.
    426     // This avoids showing the border 3D shadow between the shelf and the dock.
    427     canvas->DrawImageInt(
    428         launcher_background,
    429         0, launcher_background.height() - 1, launcher_background.width(), 1,
    430         dock_bounds.x() > 0 ? dock_bounds.x() + height() : 0, 0,
    431         dock_bounds.width() - height(), height(),
    432         false,
    433         paint);
    434   }
    435   gfx::Rect black_rect =
    436       shelf_->shelf_layout_manager()->SelectValueForShelfAlignment(
    437           gfx::Rect(0, height() - kNumBlackPixels, width(), kNumBlackPixels),
    438           gfx::Rect(0, 0, kNumBlackPixels, height()),
    439           gfx::Rect(width() - kNumBlackPixels, 0, kNumBlackPixels, height()),
    440           gfx::Rect(0, 0, width(), kNumBlackPixels));
    441   canvas->FillRect(black_rect, SK_ColorBLACK);
    442 }
    443 
    444 bool ShelfWidget::DelegateView::CanActivate() const {
    445   // Allow to activate as fallback.
    446   if (shelf_->activating_as_fallback_)
    447     return true;
    448   // Allow to activate from the focus cycler.
    449   if (focus_cycler_ && focus_cycler_->widget_activating() == GetWidget())
    450     return true;
    451   // Disallow activating in other cases, especially when using mouse.
    452   return false;
    453 }
    454 
    455 void ShelfWidget::DelegateView::Layout() {
    456   for(int i = 0; i < child_count(); ++i) {
    457     if (shelf_->shelf_layout_manager()->IsHorizontalAlignment()) {
    458       child_at(i)->SetBounds(child_at(i)->x(), child_at(i)->y(),
    459                              child_at(i)->width(), height());
    460     } else {
    461       child_at(i)->SetBounds(child_at(i)->x(), child_at(i)->y(),
    462                              width(), child_at(i)->height());
    463     }
    464   }
    465 }
    466 
    467 void ShelfWidget::DelegateView::ReorderChildLayers(ui::Layer* parent_layer) {
    468   views::View::ReorderChildLayers(parent_layer);
    469   parent_layer->StackAtBottom(&opaque_background_);
    470 }
    471 
    472 void ShelfWidget::DelegateView::OnBoundsChanged(const gfx::Rect& old_bounds) {
    473   opaque_background_.SetBounds(GetLocalBounds());
    474   if (dimmer_)
    475     dimmer_->SetBounds(GetBoundsInScreen());
    476 }
    477 
    478 void ShelfWidget::DelegateView::OnWindowBoundsChanged(
    479     aura::Window* window,
    480     const gfx::Rect& old_bounds,
    481     const gfx::Rect& new_bounds) {
    482   // Coming here the shelf got repositioned and since the |dimmer_| is placed
    483   // in screen coordinates and not relative to the parent it needs to be
    484   // repositioned accordingly.
    485   dimmer_->SetBounds(GetBoundsInScreen());
    486 }
    487 
    488 void ShelfWidget::DelegateView::ForceUndimming(bool force) {
    489   if (GetDimmed())
    490     dimmer_view_->ForceUndimming(force);
    491 }
    492 
    493 int ShelfWidget::DelegateView::GetDimmingAlphaForTest() {
    494   if (GetDimmed())
    495     return dimmer_view_->get_dimming_alpha_for_test();
    496   return -1;
    497 }
    498 
    499 gfx::Rect ShelfWidget::DelegateView::GetDimmerBoundsForTest() {
    500   if (GetDimmed())
    501     return dimmer_view_->GetBoundsInScreen();
    502   return gfx::Rect();
    503 }
    504 
    505 void ShelfWidget::DelegateView::UpdateBackground(int alpha) {
    506   alpha_ = alpha;
    507   SchedulePaint();
    508 }
    509 
    510 ShelfWidget::ShelfWidget(aura::Window* shelf_container,
    511                          aura::Window* status_container,
    512                          internal::WorkspaceController* workspace_controller)
    513     : delegate_view_(new DelegateView(this)),
    514       background_animator_(delegate_view_, 0, kLauncherBackgroundAlpha),
    515       activating_as_fallback_(false),
    516       window_container_(shelf_container) {
    517   views::Widget::InitParams params(
    518       views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
    519   params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
    520   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
    521   params.parent = shelf_container;
    522   params.delegate = delegate_view_;
    523   Init(params);
    524 
    525   // The shelf should not take focus when initially shown.
    526   set_focus_on_creation(false);
    527   SetContentsView(delegate_view_);
    528   delegate_view_->SetParentLayer(GetLayer());
    529 
    530   status_area_widget_ = new internal::StatusAreaWidget(status_container);
    531   status_area_widget_->CreateTrayViews();
    532   if (Shell::GetInstance()->session_state_delegate()->
    533           IsActiveUserSessionStarted()) {
    534     status_area_widget_->Show();
    535   }
    536   Shell::GetInstance()->focus_cycler()->AddWidget(status_area_widget_);
    537 
    538   shelf_layout_manager_ = new internal::ShelfLayoutManager(this);
    539   shelf_layout_manager_->AddObserver(this);
    540   shelf_container->SetLayoutManager(shelf_layout_manager_);
    541   shelf_layout_manager_->set_workspace_controller(workspace_controller);
    542   workspace_controller->SetShelf(shelf_layout_manager_);
    543 
    544   status_container->SetLayoutManager(
    545       new internal::StatusAreaLayoutManager(this));
    546 
    547   views::Widget::AddObserver(this);
    548 }
    549 
    550 ShelfWidget::~ShelfWidget() {
    551   RemoveObserver(this);
    552 }
    553 
    554 void ShelfWidget::SetPaintsBackground(
    555     ShelfBackgroundType background_type,
    556     BackgroundAnimatorChangeType change_type) {
    557   ui::Layer* opaque_background = delegate_view_->opaque_background();
    558   float target_opacity =
    559       (background_type == SHELF_BACKGROUND_MAXIMIZED) ? 1.0f : 0.0f;
    560   scoped_ptr<ui::ScopedLayerAnimationSettings> opaque_background_animation;
    561   if (change_type != BACKGROUND_CHANGE_IMMEDIATE) {
    562     opaque_background_animation.reset(new ui::ScopedLayerAnimationSettings(
    563         opaque_background->GetAnimator()));
    564     opaque_background_animation->SetTransitionDuration(
    565         base::TimeDelta::FromMilliseconds(kTimeToSwitchBackgroundMs));
    566   }
    567   opaque_background->SetOpacity(target_opacity);
    568 
    569   // TODO(mukai): use ui::Layer on both opaque_background and normal background
    570   // retire background_animator_ at all. It would be simpler.
    571   // See also DockedBackgroundWidget::SetPaintsBackground.
    572   background_animator_.SetPaintsBackground(
    573       background_type != SHELF_BACKGROUND_DEFAULT,
    574       change_type);
    575   delegate_view_->SchedulePaint();
    576 }
    577 
    578 ShelfBackgroundType ShelfWidget::GetBackgroundType() const {
    579   if (delegate_view_->opaque_background()->GetTargetOpacity() == 1.0f)
    580     return SHELF_BACKGROUND_MAXIMIZED;
    581   if (background_animator_.paints_background())
    582     return SHELF_BACKGROUND_OVERLAP;
    583 
    584   return SHELF_BACKGROUND_DEFAULT;
    585 }
    586 
    587 // static
    588 bool ShelfWidget::ShelfAlignmentAllowed() {
    589   if (!ash::switches::ShowShelfAlignmentMenu())
    590     return false;
    591   user::LoginStatus login_status =
    592       Shell::GetInstance()->system_tray_delegate()->GetUserLoginStatus();
    593 
    594   switch (login_status) {
    595     case user::LOGGED_IN_USER:
    596     case user::LOGGED_IN_OWNER:
    597       return true;
    598     case user::LOGGED_IN_LOCKED:
    599     case user::LOGGED_IN_PUBLIC:
    600     case user::LOGGED_IN_LOCALLY_MANAGED:
    601     case user::LOGGED_IN_GUEST:
    602     case user::LOGGED_IN_RETAIL_MODE:
    603     case user::LOGGED_IN_KIOSK_APP:
    604     case user::LOGGED_IN_NONE:
    605       return false;
    606   }
    607 
    608   DCHECK(false);
    609   return false;
    610 }
    611 
    612 ShelfAlignment ShelfWidget::GetAlignment() const {
    613   return shelf_layout_manager_->GetAlignment();
    614 }
    615 
    616 void ShelfWidget::SetAlignment(ShelfAlignment alignment) {
    617   if (launcher_)
    618     launcher_->SetAlignment(alignment);
    619   status_area_widget_->SetShelfAlignment(alignment);
    620   delegate_view_->SchedulePaint();
    621 }
    622 
    623 void ShelfWidget::SetDimsShelf(bool dimming) {
    624   delegate_view_->SetDimmed(dimming);
    625   // Repaint all children, allowing updates to reflect dimmed state eg:
    626   // status area background, app list button and overflow button.
    627   if (launcher_)
    628     launcher_->SchedulePaint();
    629   status_area_widget_->GetContentsView()->SchedulePaint();
    630 }
    631 
    632 bool ShelfWidget::GetDimsShelf() const {
    633   return delegate_view_->GetDimmed();
    634 }
    635 
    636 void ShelfWidget::CreateLauncher() {
    637   if (launcher_)
    638     return;
    639 
    640   Shell* shell = Shell::GetInstance();
    641   // This needs to be called before shelf_model().
    642   ShelfDelegate* shelf_delegate = shell->GetShelfDelegate();
    643   if (!shelf_delegate)
    644     return;  // Not ready to create Launcher
    645 
    646   launcher_.reset(new Launcher(shell->shelf_model(),
    647                                shell->GetShelfDelegate(),
    648                                this));
    649   SetFocusCycler(shell->focus_cycler());
    650 
    651   // Inform the root window controller.
    652   internal::RootWindowController::ForWindow(window_container_)->
    653       OnLauncherCreated();
    654 
    655   launcher_->SetVisible(
    656       shell->session_state_delegate()->IsActiveUserSessionStarted());
    657   shelf_layout_manager_->LayoutShelf();
    658   Show();
    659 }
    660 
    661 bool ShelfWidget::IsLauncherVisible() const {
    662   return launcher_.get() && launcher_->IsVisible();
    663 }
    664 
    665 void ShelfWidget::SetLauncherVisibility(bool visible) {
    666   if (launcher_)
    667     launcher_->SetVisible(visible);
    668 }
    669 
    670 void ShelfWidget::SetFocusCycler(internal::FocusCycler* focus_cycler) {
    671   delegate_view_->set_focus_cycler(focus_cycler);
    672   if (focus_cycler)
    673     focus_cycler->AddWidget(this);
    674 }
    675 
    676 internal::FocusCycler* ShelfWidget::GetFocusCycler() {
    677   return delegate_view_->focus_cycler();
    678 }
    679 
    680 void ShelfWidget::ShutdownStatusAreaWidget() {
    681   if (status_area_widget_)
    682     status_area_widget_->Shutdown();
    683   status_area_widget_ = NULL;
    684 }
    685 
    686 void ShelfWidget::ForceUndimming(bool force) {
    687   delegate_view_->ForceUndimming(force);
    688 }
    689 
    690 void ShelfWidget::OnWidgetActivationChanged(views::Widget* widget,
    691                                             bool active) {
    692   activating_as_fallback_ = false;
    693   if (active)
    694     delegate_view_->SetPaneFocusAndFocusDefault();
    695   else
    696     delegate_view_->GetFocusManager()->ClearFocus();
    697 }
    698 
    699 int ShelfWidget::GetDimmingAlphaForTest() {
    700   if (delegate_view_)
    701     return delegate_view_->GetDimmingAlphaForTest();
    702   return -1;
    703 }
    704 
    705 gfx::Rect ShelfWidget::GetDimmerBoundsForTest() {
    706   if (delegate_view_)
    707     return delegate_view_->GetDimmerBoundsForTest();
    708   return gfx::Rect();
    709 }
    710 
    711 void ShelfWidget::DisableDimmingAnimationsForTest() {
    712   DCHECK(delegate_view_);
    713   return delegate_view_->disable_dimming_animations_for_test();
    714 }
    715 
    716 void ShelfWidget::WillDeleteShelf() {
    717   shelf_layout_manager_->RemoveObserver(this);
    718   shelf_layout_manager_ = NULL;
    719 }
    720 
    721 }  // namespace ash
    722