Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / ash / shelf / shelf_widget.cc
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   ui::Layer* opaque_foreground() { return &opaque_foreground_; }
329
330   // Set if the shelf area is dimmed (eg when a window is maximized).
331   void SetDimmed(bool dimmed);
332   bool GetDimmed() const;
333
334   void SetParentLayer(ui::Layer* layer);
335
336   // views::View overrides:
337   virtual void OnPaintBackground(gfx::Canvas* canvas) OVERRIDE;
338
339   // views::WidgetDelegateView overrides:
340   virtual views::Widget* GetWidget() OVERRIDE {
341     return View::GetWidget();
342   }
343   virtual const views::Widget* GetWidget() const OVERRIDE {
344     return View::GetWidget();
345   }
346
347   virtual bool CanActivate() const OVERRIDE;
348   virtual void Layout() OVERRIDE;
349   virtual void ReorderChildLayers(ui::Layer* parent_layer) OVERRIDE;
350   // This will be called when the parent local bounds change.
351   virtual void OnBoundsChanged(const gfx::Rect& old_bounds) OVERRIDE;
352
353   // aura::WindowObserver overrides:
354   // This will be called when the shelf itself changes its absolute position.
355   // Since the |dimmer_| panel needs to be placed in screen coordinates it needs
356   // to be repositioned. The difference to the OnBoundsChanged call above is
357   // that this gets also triggered when the shelf only moves.
358   virtual void OnWindowBoundsChanged(aura::Window* window,
359                                      const gfx::Rect& old_bounds,
360                                      const gfx::Rect& new_bounds) OVERRIDE;
361
362   // BackgroundAnimatorDelegate overrides:
363   virtual void UpdateBackground(int alpha) OVERRIDE;
364
365   // Force the shelf to be presented in an undimmed state.
366   void ForceUndimming(bool force);
367
368   // A function to test the current alpha used by the dimming bar. If there is
369   // no dimmer active, the function will return -1.
370   int GetDimmingAlphaForTest();
371
372   // A function to test the bounds of the dimming bar. Returns gfx::Rect() if
373   // the dimmer is inactive.
374   gfx::Rect GetDimmerBoundsForTest();
375
376   // Disable dimming animations for running tests. This needs to be called
377   // prior to the creation of of the |dimmer_|.
378   void disable_dimming_animations_for_test() {
379     disable_dimming_animations_for_test_ = true;
380   }
381
382  private:
383   ShelfWidget* shelf_;
384   scoped_ptr<views::Widget> dimmer_;
385   FocusCycler* focus_cycler_;
386   int alpha_;
387   // A black background layer which is shown when a maximized window is visible.
388   ui::Layer opaque_background_;
389   // A black foreground layer which is shown while transitioning between users.
390   // Note: Since the back- and foreground layers have different functions they
391   // can be used simultaneously - so no repurposing possible.
392   ui::Layer opaque_foreground_;
393
394   // The view which does the dimming.
395   DimmerView* dimmer_view_;
396
397   // True if dimming animations should be turned off.
398   bool disable_dimming_animations_for_test_;
399
400   DISALLOW_COPY_AND_ASSIGN(DelegateView);
401 };
402
403 ShelfWidget::DelegateView::DelegateView(ShelfWidget* shelf)
404     : shelf_(shelf),
405       focus_cycler_(NULL),
406       alpha_(0),
407       opaque_background_(ui::LAYER_SOLID_COLOR),
408       opaque_foreground_(ui::LAYER_SOLID_COLOR),
409       dimmer_view_(NULL),
410       disable_dimming_animations_for_test_(false) {
411   set_allow_deactivate_on_esc(true);
412   opaque_background_.SetColor(SK_ColorBLACK);
413   opaque_background_.SetBounds(GetLocalBounds());
414   opaque_background_.SetOpacity(0.0f);
415   opaque_foreground_.SetColor(SK_ColorBLACK);
416   opaque_foreground_.SetBounds(GetLocalBounds());
417   opaque_foreground_.SetOpacity(0.0f);
418 }
419
420 ShelfWidget::DelegateView::~DelegateView() {
421   // Make sure that the dimmer goes away since it might have set an observer.
422   SetDimmed(false);
423 }
424
425 void ShelfWidget::DelegateView::SetDimmed(bool value) {
426   if (value == (dimmer_.get() != NULL))
427     return;
428
429   if (value) {
430     dimmer_.reset(new views::Widget);
431     views::Widget::InitParams params(
432         views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
433     params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
434     params.activatable = views::Widget::InitParams::ACTIVATABLE_NO;
435     params.accept_events = false;
436     params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
437     params.parent = shelf_->GetNativeView();
438     dimmer_->Init(params);
439     dimmer_->GetNativeWindow()->SetName("ShelfDimmer");
440     dimmer_->SetBounds(shelf_->GetWindowBoundsInScreen());
441     // The shelf should not take focus when it is initially shown.
442     dimmer_->set_focus_on_creation(false);
443     dimmer_view_ = new DimmerView(shelf_, disable_dimming_animations_for_test_);
444     dimmer_->SetContentsView(dimmer_view_);
445     dimmer_->GetNativeView()->SetName("ShelfDimmerView");
446     dimmer_->Show();
447     shelf_->GetNativeView()->AddObserver(this);
448   } else {
449     // Some unit tests will come here with a destroyed window.
450     if (shelf_->GetNativeView())
451       shelf_->GetNativeView()->RemoveObserver(this);
452     dimmer_view_ = NULL;
453     dimmer_.reset(NULL);
454   }
455 }
456
457 bool ShelfWidget::DelegateView::GetDimmed() const {
458   return dimmer_.get() && dimmer_->IsVisible();
459 }
460
461 void ShelfWidget::DelegateView::SetParentLayer(ui::Layer* layer) {
462   layer->Add(&opaque_background_);
463   layer->Add(&opaque_foreground_);
464   ReorderLayers();
465 }
466
467 void ShelfWidget::DelegateView::OnPaintBackground(gfx::Canvas* canvas) {
468   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
469   gfx::ImageSkia shelf_background =
470       *rb.GetImageSkiaNamed(IDR_ASH_SHELF_BACKGROUND);
471   if (SHELF_ALIGNMENT_BOTTOM != shelf_->GetAlignment())
472     shelf_background = gfx::ImageSkiaOperations::CreateRotatedImage(
473         shelf_background,
474         shelf_->shelf_layout_manager()->SelectValueForShelfAlignment(
475             SkBitmapOperations::ROTATION_90_CW,
476             SkBitmapOperations::ROTATION_90_CW,
477             SkBitmapOperations::ROTATION_270_CW,
478             SkBitmapOperations::ROTATION_180_CW));
479   const gfx::Rect dock_bounds(shelf_->shelf_layout_manager()->dock_bounds());
480   SkPaint paint;
481   paint.setAlpha(alpha_);
482   canvas->DrawImageInt(shelf_background,
483                        0,
484                        0,
485                        shelf_background.width(),
486                        shelf_background.height(),
487                        (SHELF_ALIGNMENT_BOTTOM == shelf_->GetAlignment() &&
488                         dock_bounds.x() == 0 && dock_bounds.width() > 0)
489                            ? dock_bounds.width()
490                            : 0,
491                        0,
492                        SHELF_ALIGNMENT_BOTTOM == shelf_->GetAlignment()
493                            ? width() - dock_bounds.width()
494                            : width(),
495                        height(),
496                        false,
497                        paint);
498   if (SHELF_ALIGNMENT_BOTTOM == shelf_->GetAlignment() &&
499       dock_bounds.width() > 0) {
500     // The part of the shelf background that is in the corner below the docked
501     // windows close to the work area is an arched gradient that blends
502     // vertically oriented docked background and horizontal shelf.
503     gfx::ImageSkia shelf_corner = *rb.GetImageSkiaNamed(IDR_ASH_SHELF_CORNER);
504     if (dock_bounds.x() == 0) {
505       shelf_corner = gfx::ImageSkiaOperations::CreateRotatedImage(
506           shelf_corner, SkBitmapOperations::ROTATION_90_CW);
507     }
508     canvas->DrawImageInt(
509         shelf_corner,
510         0,
511         0,
512         shelf_corner.width(),
513         shelf_corner.height(),
514         dock_bounds.x() > 0 ? dock_bounds.x() : dock_bounds.width() - height(),
515         0,
516         height(),
517         height(),
518         false,
519         paint);
520     // The part of the shelf background that is just below the docked windows
521     // is drawn using the last (lowest) 1-pixel tall strip of the image asset.
522     // This avoids showing the border 3D shadow between the shelf and the dock.
523     canvas->DrawImageInt(shelf_background,
524                          0,
525                          shelf_background.height() - 1,
526                          shelf_background.width(),
527                          1,
528                          dock_bounds.x() > 0 ? dock_bounds.x() + height() : 0,
529                          0,
530                          dock_bounds.width() - height(),
531                          height(),
532                          false,
533                          paint);
534   }
535   gfx::Rect black_rect =
536       shelf_->shelf_layout_manager()->SelectValueForShelfAlignment(
537           gfx::Rect(0, height() - kNumBlackPixels, width(), kNumBlackPixels),
538           gfx::Rect(0, 0, kNumBlackPixels, height()),
539           gfx::Rect(width() - kNumBlackPixels, 0, kNumBlackPixels, height()),
540           gfx::Rect(0, 0, width(), kNumBlackPixels));
541   canvas->FillRect(black_rect, SK_ColorBLACK);
542 }
543
544 bool ShelfWidget::DelegateView::CanActivate() const {
545   // Allow to activate as fallback.
546   if (shelf_->activating_as_fallback_)
547     return true;
548   // Allow to activate from the focus cycler.
549   if (focus_cycler_ && focus_cycler_->widget_activating() == GetWidget())
550     return true;
551   // Disallow activating in other cases, especially when using mouse.
552   return false;
553 }
554
555 void ShelfWidget::DelegateView::Layout() {
556   for(int i = 0; i < child_count(); ++i) {
557     if (shelf_->shelf_layout_manager()->IsHorizontalAlignment()) {
558       child_at(i)->SetBounds(child_at(i)->x(), child_at(i)->y(),
559                              child_at(i)->width(), height());
560     } else {
561       child_at(i)->SetBounds(child_at(i)->x(), child_at(i)->y(),
562                              width(), child_at(i)->height());
563     }
564   }
565 }
566
567 void ShelfWidget::DelegateView::ReorderChildLayers(ui::Layer* parent_layer) {
568   views::View::ReorderChildLayers(parent_layer);
569   parent_layer->StackAtBottom(&opaque_background_);
570   parent_layer->StackAtTop(&opaque_foreground_);
571 }
572
573 void ShelfWidget::DelegateView::OnBoundsChanged(const gfx::Rect& old_bounds) {
574   opaque_background_.SetBounds(GetLocalBounds());
575   opaque_foreground_.SetBounds(GetLocalBounds());
576   if (dimmer_)
577     dimmer_->SetBounds(GetBoundsInScreen());
578 }
579
580 void ShelfWidget::DelegateView::OnWindowBoundsChanged(
581     aura::Window* window,
582     const gfx::Rect& old_bounds,
583     const gfx::Rect& new_bounds) {
584   // Coming here the shelf got repositioned and since the |dimmer_| is placed
585   // in screen coordinates and not relative to the parent it needs to be
586   // repositioned accordingly.
587   dimmer_->SetBounds(GetBoundsInScreen());
588 }
589
590 void ShelfWidget::DelegateView::ForceUndimming(bool force) {
591   if (GetDimmed())
592     dimmer_view_->ForceUndimming(force);
593 }
594
595 int ShelfWidget::DelegateView::GetDimmingAlphaForTest() {
596   if (GetDimmed())
597     return dimmer_view_->get_dimming_alpha_for_test();
598   return -1;
599 }
600
601 gfx::Rect ShelfWidget::DelegateView::GetDimmerBoundsForTest() {
602   if (GetDimmed())
603     return dimmer_view_->GetBoundsInScreen();
604   return gfx::Rect();
605 }
606
607 void ShelfWidget::DelegateView::UpdateBackground(int alpha) {
608   alpha_ = alpha;
609   SchedulePaint();
610 }
611
612 ShelfWidget::ShelfWidget(aura::Window* shelf_container,
613                          aura::Window* status_container,
614                          WorkspaceController* workspace_controller)
615     : delegate_view_(new DelegateView(this)),
616       background_animator_(delegate_view_, 0, kShelfBackgroundAlpha),
617       activating_as_fallback_(false),
618       window_container_(shelf_container) {
619   views::Widget::InitParams params(
620       views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
621   params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
622   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
623   params.parent = shelf_container;
624   params.delegate = delegate_view_;
625   Init(params);
626
627   // The shelf should not take focus when initially shown.
628   set_focus_on_creation(false);
629   SetContentsView(delegate_view_);
630   delegate_view_->SetParentLayer(GetLayer());
631
632   status_area_widget_ = new StatusAreaWidget(status_container);
633   status_area_widget_->CreateTrayViews();
634   if (Shell::GetInstance()->session_state_delegate()->
635           IsActiveUserSessionStarted()) {
636     status_area_widget_->Show();
637   }
638   Shell::GetInstance()->focus_cycler()->AddWidget(status_area_widget_);
639
640   shelf_layout_manager_ = new ShelfLayoutManager(this);
641   shelf_layout_manager_->AddObserver(this);
642   shelf_container->SetLayoutManager(shelf_layout_manager_);
643   shelf_layout_manager_->set_workspace_controller(workspace_controller);
644   workspace_controller->SetShelf(shelf_layout_manager_);
645
646   status_container->SetLayoutManager(
647       new StatusAreaLayoutManager(status_container, this));
648
649   shelf_container->SetEventTargeter(scoped_ptr<ui::EventTargeter>(new
650       ShelfWindowTargeter(shelf_container, shelf_layout_manager_)));
651   status_container->SetEventTargeter(scoped_ptr<ui::EventTargeter>(new
652       ShelfWindowTargeter(status_container, shelf_layout_manager_)));
653
654   views::Widget::AddObserver(this);
655 }
656
657 ShelfWidget::~ShelfWidget() {
658   RemoveObserver(this);
659 }
660
661 void ShelfWidget::SetPaintsBackground(
662     ShelfBackgroundType background_type,
663     BackgroundAnimatorChangeType change_type) {
664   ui::Layer* opaque_background = delegate_view_->opaque_background();
665   float target_opacity =
666       (background_type == SHELF_BACKGROUND_MAXIMIZED) ? 1.0f : 0.0f;
667   scoped_ptr<ui::ScopedLayerAnimationSettings> opaque_background_animation;
668   if (change_type != BACKGROUND_CHANGE_IMMEDIATE) {
669     opaque_background_animation.reset(new ui::ScopedLayerAnimationSettings(
670         opaque_background->GetAnimator()));
671     opaque_background_animation->SetTransitionDuration(
672         base::TimeDelta::FromMilliseconds(kTimeToSwitchBackgroundMs));
673   }
674   opaque_background->SetOpacity(target_opacity);
675
676   // TODO(mukai): use ui::Layer on both opaque_background and normal background
677   // retire background_animator_ at all. It would be simpler.
678   // See also DockedBackgroundWidget::SetPaintsBackground.
679   background_animator_.SetPaintsBackground(
680       background_type != SHELF_BACKGROUND_DEFAULT,
681       change_type);
682   delegate_view_->SchedulePaint();
683 }
684
685 ShelfBackgroundType ShelfWidget::GetBackgroundType() const {
686   if (delegate_view_->opaque_background()->GetTargetOpacity() == 1.0f)
687     return SHELF_BACKGROUND_MAXIMIZED;
688   if (background_animator_.paints_background())
689     return SHELF_BACKGROUND_OVERLAP;
690
691   return SHELF_BACKGROUND_DEFAULT;
692 }
693
694 void ShelfWidget::HideShelfBehindBlackBar(bool hide, int animation_time_ms) {
695   if (IsShelfHiddenBehindBlackBar() == hide)
696     return;
697
698   ui::Layer* opaque_foreground = delegate_view_->opaque_foreground();
699   float target_opacity = hide ? 1.0f : 0.0f;
700   scoped_ptr<ui::ScopedLayerAnimationSettings> opaque_foreground_animation;
701   opaque_foreground_animation.reset(new ui::ScopedLayerAnimationSettings(
702       opaque_foreground->GetAnimator()));
703   opaque_foreground_animation->SetTransitionDuration(
704       base::TimeDelta::FromMilliseconds(animation_time_ms));
705   opaque_foreground_animation->SetPreemptionStrategy(
706       ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS);
707
708   opaque_foreground->SetOpacity(target_opacity);
709 }
710
711 bool ShelfWidget::IsShelfHiddenBehindBlackBar() const {
712   return delegate_view_->opaque_foreground()->GetTargetOpacity() != 0.0f;
713 }
714
715 // static
716 bool ShelfWidget::ShelfAlignmentAllowed() {
717   if (Shell::GetInstance()->system_tray_delegate()->IsUserSupervised())
718     return false;
719
720   user::LoginStatus login_status =
721       Shell::GetInstance()->system_tray_delegate()->GetUserLoginStatus();
722
723   switch (login_status) {
724     case user::LOGGED_IN_USER:
725     case user::LOGGED_IN_OWNER:
726       return true;
727     case user::LOGGED_IN_LOCKED:
728     case user::LOGGED_IN_PUBLIC:
729     case user::LOGGED_IN_SUPERVISED:
730     case user::LOGGED_IN_GUEST:
731     case user::LOGGED_IN_RETAIL_MODE:
732     case user::LOGGED_IN_KIOSK_APP:
733     case user::LOGGED_IN_NONE:
734       return false;
735   }
736
737   DCHECK(false);
738   return false;
739 }
740
741 ShelfAlignment ShelfWidget::GetAlignment() const {
742   return shelf_layout_manager_->GetAlignment();
743 }
744
745 void ShelfWidget::SetAlignment(ShelfAlignment alignment) {
746   if (shelf_)
747     shelf_->SetAlignment(alignment);
748   status_area_widget_->SetShelfAlignment(alignment);
749   delegate_view_->SchedulePaint();
750 }
751
752 void ShelfWidget::SetDimsShelf(bool dimming) {
753   delegate_view_->SetDimmed(dimming);
754   // Repaint all children, allowing updates to reflect dimmed state eg:
755   // status area background, app list button and overflow button.
756   if (shelf_)
757     shelf_->SchedulePaint();
758   status_area_widget_->SchedulePaint();
759 }
760
761 bool ShelfWidget::GetDimsShelf() const {
762   return delegate_view_->GetDimmed();
763 }
764
765 void ShelfWidget::CreateShelf() {
766   if (shelf_)
767     return;
768
769   Shell* shell = Shell::GetInstance();
770   // This needs to be called before shelf_model().
771   ShelfDelegate* shelf_delegate = shell->GetShelfDelegate();
772   if (!shelf_delegate)
773     return;  // Not ready to create Shelf.
774
775   shelf_.reset(
776       new Shelf(shell->shelf_model(), shell->GetShelfDelegate(), this));
777   SetFocusCycler(shell->focus_cycler());
778
779   // Inform the root window controller.
780   RootWindowController::ForWindow(window_container_)->OnShelfCreated();
781
782   shelf_->SetVisible(
783       shell->session_state_delegate()->IsActiveUserSessionStarted());
784   shelf_layout_manager_->LayoutShelf();
785   Show();
786 }
787
788 bool ShelfWidget::IsShelfVisible() const {
789   return shelf_.get() && shelf_->IsVisible();
790 }
791
792 void ShelfWidget::SetShelfVisibility(bool visible) {
793   if (shelf_)
794     shelf_->SetVisible(visible);
795 }
796
797 void ShelfWidget::SetFocusCycler(FocusCycler* focus_cycler) {
798   delegate_view_->set_focus_cycler(focus_cycler);
799   if (focus_cycler)
800     focus_cycler->AddWidget(this);
801 }
802
803 FocusCycler* ShelfWidget::GetFocusCycler() {
804   return delegate_view_->focus_cycler();
805 }
806
807 void ShelfWidget::ShutdownStatusAreaWidget() {
808   if (status_area_widget_)
809     status_area_widget_->Shutdown();
810   status_area_widget_ = NULL;
811 }
812
813 void ShelfWidget::ForceUndimming(bool force) {
814   delegate_view_->ForceUndimming(force);
815 }
816
817 void ShelfWidget::OnWidgetActivationChanged(views::Widget* widget,
818                                             bool active) {
819   activating_as_fallback_ = false;
820   if (active)
821     delegate_view_->SetPaneFocusAndFocusDefault();
822   else
823     delegate_view_->GetFocusManager()->ClearFocus();
824 }
825
826 int ShelfWidget::GetDimmingAlphaForTest() {
827   if (delegate_view_)
828     return delegate_view_->GetDimmingAlphaForTest();
829   return -1;
830 }
831
832 gfx::Rect ShelfWidget::GetDimmerBoundsForTest() {
833   if (delegate_view_)
834     return delegate_view_->GetDimmerBoundsForTest();
835   return gfx::Rect();
836 }
837
838 void ShelfWidget::DisableDimmingAnimationsForTest() {
839   DCHECK(delegate_view_);
840   return delegate_view_->disable_dimming_animations_for_test();
841 }
842
843 void ShelfWidget::WillDeleteShelf() {
844   shelf_layout_manager_->RemoveObserver(this);
845   shelf_layout_manager_ = NULL;
846 }
847
848 }  // namespace ash