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.
5 #include "ash/shelf/shelf_widget.h"
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"
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;
48 // The time to dim and un-dim.
49 const int kTimeToDimMs
= 3000; // Slow in dimming.
50 const int kTimeToUnDimMs
= 200; // Fast in activating.
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
{
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();
63 // Called by |DimmerEventFilter| when the mouse |hovered| state changes.
64 void SetHovered(bool hovered
);
66 // Force the dimmer to be undimmed.
67 void ForceUndimming(bool force
);
69 // views::WidgetDelegate overrides:
70 virtual views::Widget
* GetWidget() override
{
71 return View::GetWidget();
73 virtual const views::Widget
* GetWidget() const override
{
74 return View::GetWidget();
77 // ash::BackgroundAnimatorDelegate overrides:
78 virtual void UpdateBackground(int alpha
) override
{
83 // views::View overrides:
84 virtual void OnPaintBackground(gfx::Canvas
* canvas
) override
;
86 // A function to test the current alpha used.
87 int get_dimming_alpha_for_test() { return alpha_
; }
90 // This class monitors mouse events to see if it is on top of the shelf.
91 class DimmerEventFilter
: public ui::EventHandler
{
93 explicit DimmerEventFilter(DimmerView
* owner
);
94 virtual ~DimmerEventFilter();
96 // Overridden from ui::EventHandler:
97 virtual void OnMouseEvent(ui::MouseEvent
* event
) override
;
98 virtual void OnTouchEvent(ui::TouchEvent
* event
) override
;
104 // TRUE if the mouse is inside the shelf.
107 // TRUE if a touch event is inside the shelf.
110 DISALLOW_COPY_AND_ASSIGN(DimmerEventFilter
);
114 ash::ShelfWidget
* shelf_
;
116 // The alpha to use for covering the shelf.
119 // True if the event filter claims that we should not be dimmed.
122 // True if someone forces us not to be dimmed (e.g. a menu is open).
125 // True if animations should be suppressed for a test.
126 bool disable_dimming_animations_for_test_
;
128 // The animator for the background transitions.
129 ash::BackgroundAnimator background_animator_
;
131 // Notification of entering / exiting of the shelf area by mouse.
132 scoped_ptr
<DimmerEventFilter
> event_filter_
;
134 DISALLOW_COPY_AND_ASSIGN(DimmerView
);
137 DimmerView::DimmerView(ash::ShelfWidget
* shelf_widget
,
138 bool disable_dimming_animations_for_test
)
139 : shelf_(shelf_widget
),
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
148 background_animator_
.SetPaintsBackground(false,
149 ash::BACKGROUND_CHANGE_IMMEDIATE
);
153 DimmerView::~DimmerView() {
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
);
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_
);
176 void DimmerView::OnPaintBackground(gfx::Canvas
* canvas
) {
178 ui::ResourceBundle
& rb
= ui::ResourceBundle::GetSharedInstance();
179 gfx::ImageSkia shelf_background
=
180 *rb
.GetImageNamed(IDR_ASH_SHELF_DIMMING
).ToImageSkia();
182 if (shelf_
->GetAlignment() != ash::SHELF_ALIGNMENT_BOTTOM
) {
183 shelf_background
= gfx::ImageSkiaOperations::CreateRotatedImage(
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
));
191 paint
.setAlpha(alpha_
);
192 canvas
->DrawImageInt(shelf_background
,
195 shelf_background
.width(),
196 shelf_background
.height(),
205 DimmerView::DimmerEventFilter::DimmerEventFilter(DimmerView
* owner
)
207 mouse_inside_(false),
208 touch_inside_(false) {
209 ash::Shell::GetInstance()->AddPreTargetHandler(this);
212 DimmerView::DimmerEventFilter::~DimmerEventFilter() {
213 ash::Shell::GetInstance()->RemovePreTargetHandler(this);
216 void DimmerView::DimmerEventFilter::OnMouseEvent(ui::MouseEvent
* event
) {
217 if (event
->type() != ui::ET_MOUSE_MOVED
&&
218 event
->type() != ui::ET_MOUSE_DRAGGED
)
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
;
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());
232 if (mouse_inside_
|| touch_inside_
!= mouse_inside_
|| touch_inside
)
233 owner_
->SetHovered(mouse_inside_
|| touch_inside
);
234 touch_inside_
= touch_inside
;
237 using ash::ShelfLayoutManager
;
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
{
245 ShelfWindowTargeter(aura::Window
* container
,
246 ShelfLayoutManager
* shelf
)
247 : wm::EasyResizeWindowTargeter(container
, gfx::Insets(), gfx::Insets()),
249 WillChangeVisibilityState(shelf_
->visibility_state());
250 shelf_
->AddObserver(this);
253 virtual ~ShelfWindowTargeter() {
254 // |shelf_| may have been destroyed by this time.
256 shelf_
->RemoveObserver(this);
260 gfx::Insets
GetInsetsForAlignment(int distance
,
261 ash::ShelfAlignment 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);
273 return gfx::Insets();
276 // ash::ShelfLayoutManagerObserver:
277 virtual void WillDeleteShelf() override
{
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
294 touch_insets
= GetInsetsForAlignment(
295 -ShelfLayoutManager::kWorkspaceAreaAutoHideInset
,
296 shelf_
->GetAlignment());
299 set_mouse_extend(mouse_insets
);
300 set_touch_extend(touch_insets
);
303 ShelfLayoutManager
* shelf_
;
305 DISALLOW_COPY_AND_ASSIGN(ShelfWindowTargeter
);
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
{
319 explicit DelegateView(ShelfWidget
* shelf
);
320 virtual ~DelegateView();
322 void set_focus_cycler(FocusCycler
* focus_cycler
) {
323 focus_cycler_
= focus_cycler
;
325 FocusCycler
* focus_cycler() { return focus_cycler_
; }
327 ui::Layer
* opaque_background() { return &opaque_background_
; }
328 ui::Layer
* opaque_foreground() { return &opaque_foreground_
; }
330 // Set if the shelf area is dimmed (eg when a window is maximized).
331 void SetDimmed(bool dimmed
);
332 bool GetDimmed() const;
334 void SetParentLayer(ui::Layer
* layer
);
336 // views::View overrides:
337 virtual void OnPaintBackground(gfx::Canvas
* canvas
) override
;
339 // views::WidgetDelegateView overrides:
340 virtual views::Widget
* GetWidget() override
{
341 return View::GetWidget();
343 virtual const views::Widget
* GetWidget() const override
{
344 return View::GetWidget();
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
;
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
;
362 // BackgroundAnimatorDelegate overrides:
363 virtual void UpdateBackground(int alpha
) override
;
365 // Force the shelf to be presented in an undimmed state.
366 void ForceUndimming(bool force
);
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();
372 // A function to test the bounds of the dimming bar. Returns gfx::Rect() if
373 // the dimmer is inactive.
374 gfx::Rect
GetDimmerBoundsForTest();
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;
384 scoped_ptr
<views::Widget
> dimmer_
;
385 FocusCycler
* focus_cycler_
;
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_
;
394 // The view which does the dimming.
395 DimmerView
* dimmer_view_
;
397 // True if dimming animations should be turned off.
398 bool disable_dimming_animations_for_test_
;
400 DISALLOW_COPY_AND_ASSIGN(DelegateView
);
403 ShelfWidget::DelegateView::DelegateView(ShelfWidget
* shelf
)
407 opaque_background_(ui::LAYER_SOLID_COLOR
),
408 opaque_foreground_(ui::LAYER_SOLID_COLOR
),
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
);
420 ShelfWidget::DelegateView::~DelegateView() {
421 // Make sure that the dimmer goes away since it might have set an observer.
425 void ShelfWidget::DelegateView::SetDimmed(bool value
) {
426 if (value
== (dimmer_
.get() != NULL
))
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");
447 shelf_
->GetNativeView()->AddObserver(this);
449 // Some unit tests will come here with a destroyed window.
450 if (shelf_
->GetNativeView())
451 shelf_
->GetNativeView()->RemoveObserver(this);
457 bool ShelfWidget::DelegateView::GetDimmed() const {
458 return dimmer_
.get() && dimmer_
->IsVisible();
461 void ShelfWidget::DelegateView::SetParentLayer(ui::Layer
* layer
) {
462 layer
->Add(&opaque_background_
);
463 layer
->Add(&opaque_foreground_
);
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(
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());
481 paint
.setAlpha(alpha_
);
482 canvas
->DrawImageInt(shelf_background
,
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()
492 SHELF_ALIGNMENT_BOTTOM
== shelf_
->GetAlignment()
493 ? width() - dock_bounds
.width()
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
);
508 canvas
->DrawImageInt(
512 shelf_corner
.width(),
513 shelf_corner
.height(),
514 dock_bounds
.x() > 0 ? dock_bounds
.x() : dock_bounds
.width() - height(),
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
,
525 shelf_background
.height() - 1,
526 shelf_background
.width(),
528 dock_bounds
.x() > 0 ? dock_bounds
.x() + height() : 0,
530 dock_bounds
.width() - height(),
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
);
544 bool ShelfWidget::DelegateView::CanActivate() const {
545 // Allow to activate as fallback.
546 if (shelf_
->activating_as_fallback_
)
548 // Allow to activate from the focus cycler.
549 if (focus_cycler_
&& focus_cycler_
->widget_activating() == GetWidget())
551 // Disallow activating in other cases, especially when using mouse.
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());
561 child_at(i
)->SetBounds(child_at(i
)->x(), child_at(i
)->y(),
562 width(), child_at(i
)->height());
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_
);
573 void ShelfWidget::DelegateView::OnBoundsChanged(const gfx::Rect
& old_bounds
) {
574 opaque_background_
.SetBounds(GetLocalBounds());
575 opaque_foreground_
.SetBounds(GetLocalBounds());
577 dimmer_
->SetBounds(GetBoundsInScreen());
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());
590 void ShelfWidget::DelegateView::ForceUndimming(bool force
) {
592 dimmer_view_
->ForceUndimming(force
);
595 int ShelfWidget::DelegateView::GetDimmingAlphaForTest() {
597 return dimmer_view_
->get_dimming_alpha_for_test();
601 gfx::Rect
ShelfWidget::DelegateView::GetDimmerBoundsForTest() {
603 return dimmer_view_
->GetBoundsInScreen();
607 void ShelfWidget::DelegateView::UpdateBackground(int alpha
) {
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_
;
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());
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();
638 Shell::GetInstance()->focus_cycler()->AddWidget(status_area_widget_
);
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_
);
646 status_container
->SetLayoutManager(
647 new StatusAreaLayoutManager(status_container
, this));
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_
)));
654 views::Widget::AddObserver(this);
657 ShelfWidget::~ShelfWidget() {
658 RemoveObserver(this);
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
));
674 opaque_background
->SetOpacity(target_opacity
);
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
,
682 delegate_view_
->SchedulePaint();
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
;
691 return SHELF_BACKGROUND_DEFAULT
;
694 void ShelfWidget::HideShelfBehindBlackBar(bool hide
, int animation_time_ms
) {
695 if (IsShelfHiddenBehindBlackBar() == hide
)
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
);
708 opaque_foreground
->SetOpacity(target_opacity
);
711 bool ShelfWidget::IsShelfHiddenBehindBlackBar() const {
712 return delegate_view_
->opaque_foreground()->GetTargetOpacity() != 0.0f
;
716 bool ShelfWidget::ShelfAlignmentAllowed() {
717 if (Shell::GetInstance()->system_tray_delegate()->IsUserSupervised())
720 user::LoginStatus login_status
=
721 Shell::GetInstance()->system_tray_delegate()->GetUserLoginStatus();
723 switch (login_status
) {
724 case user::LOGGED_IN_USER
:
725 case user::LOGGED_IN_OWNER
:
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
:
741 ShelfAlignment
ShelfWidget::GetAlignment() const {
742 return shelf_layout_manager_
->GetAlignment();
745 void ShelfWidget::SetAlignment(ShelfAlignment alignment
) {
747 shelf_
->SetAlignment(alignment
);
748 status_area_widget_
->SetShelfAlignment(alignment
);
749 delegate_view_
->SchedulePaint();
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.
757 shelf_
->SchedulePaint();
758 status_area_widget_
->SchedulePaint();
761 bool ShelfWidget::GetDimsShelf() const {
762 return delegate_view_
->GetDimmed();
765 void ShelfWidget::CreateShelf() {
769 Shell
* shell
= Shell::GetInstance();
770 // This needs to be called before shelf_model().
771 ShelfDelegate
* shelf_delegate
= shell
->GetShelfDelegate();
773 return; // Not ready to create Shelf.
776 new Shelf(shell
->shelf_model(), shell
->GetShelfDelegate(), this));
777 SetFocusCycler(shell
->focus_cycler());
779 // Inform the root window controller.
780 RootWindowController::ForWindow(window_container_
)->OnShelfCreated();
783 shell
->session_state_delegate()->IsActiveUserSessionStarted());
784 shelf_layout_manager_
->LayoutShelf();
788 bool ShelfWidget::IsShelfVisible() const {
789 return shelf_
.get() && shelf_
->IsVisible();
792 void ShelfWidget::SetShelfVisibility(bool visible
) {
794 shelf_
->SetVisible(visible
);
797 void ShelfWidget::SetFocusCycler(FocusCycler
* focus_cycler
) {
798 delegate_view_
->set_focus_cycler(focus_cycler
);
800 focus_cycler
->AddWidget(this);
803 FocusCycler
* ShelfWidget::GetFocusCycler() {
804 return delegate_view_
->focus_cycler();
807 void ShelfWidget::ShutdownStatusAreaWidget() {
808 if (status_area_widget_
)
809 status_area_widget_
->Shutdown();
810 status_area_widget_
= NULL
;
813 void ShelfWidget::ForceUndimming(bool force
) {
814 delegate_view_
->ForceUndimming(force
);
817 void ShelfWidget::OnWidgetActivationChanged(views::Widget
* widget
,
819 activating_as_fallback_
= false;
821 delegate_view_
->SetPaneFocusAndFocusDefault();
823 delegate_view_
->GetFocusManager()->ClearFocus();
826 int ShelfWidget::GetDimmingAlphaForTest() {
828 return delegate_view_
->GetDimmingAlphaForTest();
832 gfx::Rect
ShelfWidget::GetDimmerBoundsForTest() {
834 return delegate_view_
->GetDimmerBoundsForTest();
838 void ShelfWidget::DisableDimmingAnimationsForTest() {
839 DCHECK(delegate_view_
);
840 return delegate_view_
->disable_dimming_animations_for_test();
843 void ShelfWidget::WillDeleteShelf() {
844 shelf_layout_manager_
->RemoveObserver(this);
845 shelf_layout_manager_
= NULL
;