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