1 // Copyright 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/coordinate_conversion.h"
40 #include "ui/wm/core/easy_resize_window_targeter.h"
41 #include "ui/wm/public/activation_client.h"
44 // Size of black border at bottom (or side) of shelf.
45 const int kNumBlackPixels
= 3;
46 // Alpha to paint dimming image with.
47 const int kDimAlpha
= 128;
49 // The time to dim and un-dim.
50 const int kTimeToDimMs
= 3000; // Slow in dimming.
51 const int kTimeToUnDimMs
= 200; // Fast in activating.
53 // Class used to slightly dim shelf items when maximized and visible.
54 class DimmerView
: public views::View
,
55 public views::WidgetDelegate
,
56 ash::BackgroundAnimatorDelegate
{
58 // If |disable_dimming_animations_for_test| is set, all alpha animations will
59 // be performed instantly.
60 DimmerView(ash::ShelfWidget
* shelf_widget
,
61 bool disable_dimming_animations_for_test
);
62 ~DimmerView() override
;
64 // Called by |DimmerEventFilter| when the mouse |hovered| state changes.
65 void SetHovered(bool hovered
);
67 // Force the dimmer to be undimmed.
68 void ForceUndimming(bool force
);
70 // views::WidgetDelegate overrides:
71 views::Widget
* GetWidget() override
{ return View::GetWidget(); }
72 const views::Widget
* GetWidget() const override
{ return View::GetWidget(); }
74 // ash::BackgroundAnimatorDelegate overrides:
75 void UpdateBackground(int alpha
) override
{
80 // views::View overrides:
81 void OnPaintBackground(gfx::Canvas
* canvas
) override
;
83 // A function to test the current alpha used.
84 int get_dimming_alpha_for_test() { return alpha_
; }
87 // This class monitors mouse events to see if it is on top of the shelf.
88 class DimmerEventFilter
: public ui::EventHandler
{
90 explicit DimmerEventFilter(DimmerView
* owner
);
91 ~DimmerEventFilter() override
;
93 // Overridden from ui::EventHandler:
94 void OnMouseEvent(ui::MouseEvent
* event
) override
;
95 void OnTouchEvent(ui::TouchEvent
* event
) override
;
101 // TRUE if the mouse is inside the shelf.
104 // TRUE if a touch event is inside the shelf.
107 DISALLOW_COPY_AND_ASSIGN(DimmerEventFilter
);
111 ash::ShelfWidget
* shelf_
;
113 // The alpha to use for covering the shelf.
116 // True if the event filter claims that we should not be dimmed.
119 // True if someone forces us not to be dimmed (e.g. a menu is open).
122 // True if animations should be suppressed for a test.
123 bool disable_dimming_animations_for_test_
;
125 // The animator for the background transitions.
126 ash::BackgroundAnimator background_animator_
;
128 // Notification of entering / exiting of the shelf area by mouse.
129 scoped_ptr
<DimmerEventFilter
> event_filter_
;
131 DISALLOW_COPY_AND_ASSIGN(DimmerView
);
134 DimmerView::DimmerView(ash::ShelfWidget
* shelf_widget
,
135 bool disable_dimming_animations_for_test
)
136 : shelf_(shelf_widget
),
139 force_hovered_(false),
140 disable_dimming_animations_for_test_(disable_dimming_animations_for_test
),
141 background_animator_(this, 0, kDimAlpha
) {
142 event_filter_
.reset(new DimmerEventFilter(this));
143 // Make sure it is undimmed at the beginning and then fire off the dimming
145 background_animator_
.SetPaintsBackground(false,
146 ash::BACKGROUND_CHANGE_IMMEDIATE
);
150 DimmerView::~DimmerView() {
153 void DimmerView::SetHovered(bool hovered
) {
154 // Remember the hovered state so that we can correct the state once a
155 // possible force state has disappeared.
156 is_hovered_
= hovered
;
157 // Undimm also if we were forced to by e.g. an open menu.
158 hovered
|= force_hovered_
;
159 background_animator_
.SetDuration(hovered
? kTimeToUnDimMs
: kTimeToDimMs
);
160 background_animator_
.SetPaintsBackground(!hovered
,
161 disable_dimming_animations_for_test_
?
162 ash::BACKGROUND_CHANGE_IMMEDIATE
: ash::BACKGROUND_CHANGE_ANIMATE
);
165 void DimmerView::ForceUndimming(bool force
) {
166 bool previous
= force_hovered_
;
167 force_hovered_
= force
;
168 // If the forced change does change the result we apply the change.
169 if (is_hovered_
|| force_hovered_
!= is_hovered_
|| previous
)
170 SetHovered(is_hovered_
);
173 void DimmerView::OnPaintBackground(gfx::Canvas
* canvas
) {
175 ui::ResourceBundle
* rb
= &ui::ResourceBundle::GetSharedInstance();
176 gfx::ImageSkia shelf_background
=
177 *rb
->GetImageNamed(IDR_ASH_SHELF_DIMMING
).ToImageSkia();
179 if (shelf_
->GetAlignment() != ash::SHELF_ALIGNMENT_BOTTOM
) {
180 shelf_background
= gfx::ImageSkiaOperations::CreateRotatedImage(
182 shelf_
->shelf_layout_manager()->SelectValueForShelfAlignment(
183 SkBitmapOperations::ROTATION_90_CW
,
184 SkBitmapOperations::ROTATION_90_CW
,
185 SkBitmapOperations::ROTATION_270_CW
,
186 SkBitmapOperations::ROTATION_180_CW
));
188 paint
.setAlpha(alpha_
);
189 canvas
->DrawImageInt(shelf_background
,
192 shelf_background
.width(),
193 shelf_background
.height(),
202 DimmerView::DimmerEventFilter::DimmerEventFilter(DimmerView
* owner
)
204 mouse_inside_(false),
205 touch_inside_(false) {
206 ash::Shell::GetInstance()->AddPreTargetHandler(this);
209 DimmerView::DimmerEventFilter::~DimmerEventFilter() {
210 ash::Shell::GetInstance()->RemovePreTargetHandler(this);
213 void DimmerView::DimmerEventFilter::OnMouseEvent(ui::MouseEvent
* event
) {
214 if (event
->type() != ui::ET_MOUSE_MOVED
&&
215 event
->type() != ui::ET_MOUSE_DRAGGED
)
218 gfx::Point
screen_point(event
->location());
219 ::wm::ConvertPointToScreen(static_cast<aura::Window
*>(event
->target()),
221 bool inside
= owner_
->GetBoundsInScreen().Contains(screen_point
);
222 if (mouse_inside_
|| touch_inside_
!= inside
|| touch_inside_
)
223 owner_
->SetHovered(inside
|| touch_inside_
);
224 mouse_inside_
= inside
;
227 void DimmerView::DimmerEventFilter::OnTouchEvent(ui::TouchEvent
* event
) {
228 bool touch_inside
= false;
229 if (event
->type() != ui::ET_TOUCH_RELEASED
&&
230 event
->type() != ui::ET_TOUCH_CANCELLED
) {
231 gfx::Point
screen_point(event
->location());
232 ::wm::ConvertPointToScreen(static_cast<aura::Window
*>(event
->target()),
234 touch_inside
= owner_
->GetBoundsInScreen().Contains(screen_point
);
237 if (mouse_inside_
|| touch_inside_
!= mouse_inside_
|| touch_inside
)
238 owner_
->SetHovered(mouse_inside_
|| touch_inside
);
239 touch_inside_
= touch_inside
;
242 using ash::ShelfLayoutManager
;
244 // ShelfWindowTargeter makes it easier to resize windows with the mouse when the
245 // window-edge slightly overlaps with the shelf edge. The targeter also makes it
246 // easier to drag the shelf out with touch while it is hidden.
247 class ShelfWindowTargeter
: public wm::EasyResizeWindowTargeter
,
248 public ash::ShelfLayoutManagerObserver
{
250 ShelfWindowTargeter(aura::Window
* container
,
251 ShelfLayoutManager
* shelf
)
252 : wm::EasyResizeWindowTargeter(container
, gfx::Insets(), gfx::Insets()),
254 WillChangeVisibilityState(shelf_
->visibility_state());
255 shelf_
->AddObserver(this);
258 ~ShelfWindowTargeter() override
{
259 // |shelf_| may have been destroyed by this time.
261 shelf_
->RemoveObserver(this);
265 gfx::Insets
GetInsetsForAlignment(int distance
,
266 ash::ShelfAlignment alignment
) {
268 case ash::SHELF_ALIGNMENT_BOTTOM
:
269 return gfx::Insets(distance
, 0, 0, 0);
270 case ash::SHELF_ALIGNMENT_LEFT
:
271 return gfx::Insets(0, 0, 0, distance
);
272 case ash::SHELF_ALIGNMENT_RIGHT
:
273 return gfx::Insets(0, distance
, 0, 0);
274 case ash::SHELF_ALIGNMENT_TOP
:
275 return gfx::Insets(0, 0, distance
, 0);
278 return gfx::Insets();
281 // ash::ShelfLayoutManagerObserver:
282 void WillDeleteShelf() override
{ shelf_
= NULL
; }
284 void WillChangeVisibilityState(ash::ShelfVisibilityState new_state
) override
{
285 gfx::Insets mouse_insets
;
286 gfx::Insets touch_insets
;
287 if (new_state
== ash::SHELF_VISIBLE
) {
288 // Let clicks at the very top of the shelf through so windows can be
289 // resized with the bottom-right corner and bottom edge.
290 mouse_insets
= GetInsetsForAlignment(
291 ShelfLayoutManager::kWorkspaceAreaVisibleInset
,
292 shelf_
->GetAlignment());
293 } else if (new_state
== ash::SHELF_AUTO_HIDE
) {
294 // Extend the touch hit target out a bit to allow users to drag shelf out
296 touch_insets
= GetInsetsForAlignment(
297 -ShelfLayoutManager::kWorkspaceAreaAutoHideInset
,
298 shelf_
->GetAlignment());
301 set_mouse_extend(mouse_insets
);
302 set_touch_extend(touch_insets
);
305 ShelfLayoutManager
* shelf_
;
307 DISALLOW_COPY_AND_ASSIGN(ShelfWindowTargeter
);
314 // The contents view of the Shelf. This view contains ShelfView and
315 // sizes it to the width of the shelf minus the size of the status area.
316 class ShelfWidget::DelegateView
: public views::WidgetDelegate
,
317 public views::AccessiblePaneView
,
318 public BackgroundAnimatorDelegate
,
319 public aura::WindowObserver
{
321 explicit DelegateView(ShelfWidget
* shelf
);
322 ~DelegateView() override
;
324 void set_focus_cycler(FocusCycler
* focus_cycler
) {
325 focus_cycler_
= focus_cycler
;
327 FocusCycler
* focus_cycler() { return focus_cycler_
; }
329 ui::Layer
* opaque_background() { return &opaque_background_
; }
330 ui::Layer
* opaque_foreground() { return &opaque_foreground_
; }
332 // Set if the shelf area is dimmed (eg when a window is maximized).
333 void SetDimmed(bool dimmed
);
334 bool GetDimmed() const;
336 void SetParentLayer(ui::Layer
* layer
);
338 // views::View overrides:
339 void OnPaintBackground(gfx::Canvas
* canvas
) override
;
341 // views::WidgetDelegateView overrides:
342 views::Widget
* GetWidget() override
{ return View::GetWidget(); }
343 const views::Widget
* GetWidget() const override
{ return View::GetWidget(); }
345 bool CanActivate() const override
;
346 void Layout() override
;
347 void ReorderChildLayers(ui::Layer
* parent_layer
) override
;
348 // This will be called when the parent local bounds change.
349 void OnBoundsChanged(const gfx::Rect
& old_bounds
) override
;
351 // aura::WindowObserver overrides:
352 // This will be called when the shelf itself changes its absolute position.
353 // Since the |dimmer_| panel needs to be placed in screen coordinates it needs
354 // to be repositioned. The difference to the OnBoundsChanged call above is
355 // that this gets also triggered when the shelf only moves.
356 void OnWindowBoundsChanged(aura::Window
* window
,
357 const gfx::Rect
& old_bounds
,
358 const gfx::Rect
& new_bounds
) override
;
360 // BackgroundAnimatorDelegate overrides:
361 void UpdateBackground(int alpha
) override
;
363 // Force the shelf to be presented in an undimmed state.
364 void ForceUndimming(bool force
);
366 // A function to test the current alpha used by the dimming bar. If there is
367 // no dimmer active, the function will return -1.
368 int GetDimmingAlphaForTest();
370 // A function to test the bounds of the dimming bar. Returns gfx::Rect() if
371 // the dimmer is inactive.
372 gfx::Rect
GetDimmerBoundsForTest();
374 // Disable dimming animations for running tests. This needs to be called
375 // prior to the creation of of the |dimmer_|.
376 void disable_dimming_animations_for_test() {
377 disable_dimming_animations_for_test_
= true;
382 scoped_ptr
<views::Widget
> dimmer_
;
383 FocusCycler
* focus_cycler_
;
385 // A black background layer which is shown when a maximized window is visible.
386 ui::Layer opaque_background_
;
387 // A black foreground layer which is shown while transitioning between users.
388 // Note: Since the back- and foreground layers have different functions they
389 // can be used simultaneously - so no repurposing possible.
390 ui::Layer opaque_foreground_
;
392 // The view which does the dimming.
393 DimmerView
* dimmer_view_
;
395 // True if dimming animations should be turned off.
396 bool disable_dimming_animations_for_test_
;
398 DISALLOW_COPY_AND_ASSIGN(DelegateView
);
401 ShelfWidget::DelegateView::DelegateView(ShelfWidget
* shelf
)
405 opaque_background_(ui::LAYER_SOLID_COLOR
),
406 opaque_foreground_(ui::LAYER_SOLID_COLOR
),
408 disable_dimming_animations_for_test_(false) {
409 set_allow_deactivate_on_esc(true);
410 opaque_background_
.SetColor(SK_ColorBLACK
);
411 opaque_background_
.SetBounds(GetLocalBounds());
412 opaque_background_
.SetOpacity(0.0f
);
413 opaque_foreground_
.SetColor(SK_ColorBLACK
);
414 opaque_foreground_
.SetBounds(GetLocalBounds());
415 opaque_foreground_
.SetOpacity(0.0f
);
418 ShelfWidget::DelegateView::~DelegateView() {
419 // Make sure that the dimmer goes away since it might have set an observer.
423 void ShelfWidget::DelegateView::SetDimmed(bool value
) {
424 if (value
== (dimmer_
.get() != NULL
))
428 dimmer_
.reset(new views::Widget
);
429 views::Widget::InitParams
params(
430 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS
);
431 params
.opacity
= views::Widget::InitParams::TRANSLUCENT_WINDOW
;
432 params
.activatable
= views::Widget::InitParams::ACTIVATABLE_NO
;
433 params
.accept_events
= false;
434 params
.ownership
= views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
435 params
.parent
= shelf_
->GetNativeView();
436 dimmer_
->Init(params
);
437 dimmer_
->GetNativeWindow()->SetName("ShelfDimmer");
438 dimmer_
->SetBounds(shelf_
->GetWindowBoundsInScreen());
439 // The shelf should not take focus when it is initially shown.
440 dimmer_
->set_focus_on_creation(false);
441 dimmer_view_
= new DimmerView(shelf_
, disable_dimming_animations_for_test_
);
442 dimmer_
->SetContentsView(dimmer_view_
);
443 dimmer_
->GetNativeView()->SetName("ShelfDimmerView");
445 shelf_
->GetNativeView()->AddObserver(this);
447 // Some unit tests will come here with a destroyed window.
448 if (shelf_
->GetNativeView())
449 shelf_
->GetNativeView()->RemoveObserver(this);
455 bool ShelfWidget::DelegateView::GetDimmed() const {
456 return dimmer_
.get() && dimmer_
->IsVisible();
459 void ShelfWidget::DelegateView::SetParentLayer(ui::Layer
* layer
) {
460 layer
->Add(&opaque_background_
);
461 layer
->Add(&opaque_foreground_
);
465 void ShelfWidget::DelegateView::OnPaintBackground(gfx::Canvas
* canvas
) {
466 ui::ResourceBundle
* rb
= &ui::ResourceBundle::GetSharedInstance();
467 gfx::ImageSkia shelf_background
=
468 *rb
->GetImageSkiaNamed(IDR_ASH_SHELF_BACKGROUND
);
469 if (SHELF_ALIGNMENT_BOTTOM
!= shelf_
->GetAlignment())
470 shelf_background
= gfx::ImageSkiaOperations::CreateRotatedImage(
472 shelf_
->shelf_layout_manager()->SelectValueForShelfAlignment(
473 SkBitmapOperations::ROTATION_90_CW
,
474 SkBitmapOperations::ROTATION_90_CW
,
475 SkBitmapOperations::ROTATION_270_CW
,
476 SkBitmapOperations::ROTATION_180_CW
));
477 const gfx::Rect
dock_bounds(shelf_
->shelf_layout_manager()->dock_bounds());
479 paint
.setAlpha(alpha_
);
480 canvas
->DrawImageInt(shelf_background
,
483 shelf_background
.width(),
484 shelf_background
.height(),
485 (SHELF_ALIGNMENT_BOTTOM
== shelf_
->GetAlignment() &&
486 dock_bounds
.x() == 0 && dock_bounds
.width() > 0)
487 ? dock_bounds
.width()
490 SHELF_ALIGNMENT_BOTTOM
== shelf_
->GetAlignment()
491 ? width() - dock_bounds
.width()
496 if (SHELF_ALIGNMENT_BOTTOM
== shelf_
->GetAlignment() &&
497 dock_bounds
.width() > 0) {
498 // The part of the shelf background that is in the corner below the docked
499 // windows close to the work area is an arched gradient that blends
500 // vertically oriented docked background and horizontal shelf.
501 gfx::ImageSkia shelf_corner
= *rb
->GetImageSkiaNamed(IDR_ASH_SHELF_CORNER
);
502 if (dock_bounds
.x() == 0) {
503 shelf_corner
= gfx::ImageSkiaOperations::CreateRotatedImage(
504 shelf_corner
, SkBitmapOperations::ROTATION_90_CW
);
506 canvas
->DrawImageInt(
510 shelf_corner
.width(),
511 shelf_corner
.height(),
512 dock_bounds
.x() > 0 ? dock_bounds
.x() : dock_bounds
.width() - height(),
518 // The part of the shelf background that is just below the docked windows
519 // is drawn using the last (lowest) 1-pixel tall strip of the image asset.
520 // This avoids showing the border 3D shadow between the shelf and the dock.
521 canvas
->DrawImageInt(shelf_background
,
523 shelf_background
.height() - 1,
524 shelf_background
.width(),
526 dock_bounds
.x() > 0 ? dock_bounds
.x() + height() : 0,
528 dock_bounds
.width() - height(),
533 gfx::Rect black_rect
=
534 shelf_
->shelf_layout_manager()->SelectValueForShelfAlignment(
535 gfx::Rect(0, height() - kNumBlackPixels
, width(), kNumBlackPixels
),
536 gfx::Rect(0, 0, kNumBlackPixels
, height()),
537 gfx::Rect(width() - kNumBlackPixels
, 0, kNumBlackPixels
, height()),
538 gfx::Rect(0, 0, width(), kNumBlackPixels
));
539 canvas
->FillRect(black_rect
, SK_ColorBLACK
);
542 bool ShelfWidget::DelegateView::CanActivate() const {
543 // Allow to activate as fallback.
544 if (shelf_
->activating_as_fallback_
)
546 // Allow to activate from the focus cycler.
547 if (focus_cycler_
&& focus_cycler_
->widget_activating() == GetWidget())
549 // Disallow activating in other cases, especially when using mouse.
553 void ShelfWidget::DelegateView::Layout() {
554 for(int i
= 0; i
< child_count(); ++i
) {
555 if (shelf_
->shelf_layout_manager()->IsHorizontalAlignment()) {
556 child_at(i
)->SetBounds(child_at(i
)->x(), child_at(i
)->y(),
557 child_at(i
)->width(), height());
559 child_at(i
)->SetBounds(child_at(i
)->x(), child_at(i
)->y(),
560 width(), child_at(i
)->height());
565 void ShelfWidget::DelegateView::ReorderChildLayers(ui::Layer
* parent_layer
) {
566 views::View::ReorderChildLayers(parent_layer
);
567 parent_layer
->StackAtBottom(&opaque_background_
);
568 parent_layer
->StackAtTop(&opaque_foreground_
);
571 void ShelfWidget::DelegateView::OnBoundsChanged(const gfx::Rect
& old_bounds
) {
572 opaque_background_
.SetBounds(GetLocalBounds());
573 opaque_foreground_
.SetBounds(GetLocalBounds());
575 dimmer_
->SetBounds(GetBoundsInScreen());
578 void ShelfWidget::DelegateView::OnWindowBoundsChanged(
579 aura::Window
* window
,
580 const gfx::Rect
& old_bounds
,
581 const gfx::Rect
& new_bounds
) {
582 // Coming here the shelf got repositioned and since the |dimmer_| is placed
583 // in screen coordinates and not relative to the parent it needs to be
584 // repositioned accordingly.
585 dimmer_
->SetBounds(GetBoundsInScreen());
588 void ShelfWidget::DelegateView::ForceUndimming(bool force
) {
590 dimmer_view_
->ForceUndimming(force
);
593 int ShelfWidget::DelegateView::GetDimmingAlphaForTest() {
595 return dimmer_view_
->get_dimming_alpha_for_test();
599 gfx::Rect
ShelfWidget::DelegateView::GetDimmerBoundsForTest() {
601 return dimmer_view_
->GetBoundsInScreen();
605 void ShelfWidget::DelegateView::UpdateBackground(int alpha
) {
610 ShelfWidget::ShelfWidget(aura::Window
* shelf_container
,
611 aura::Window
* status_container
,
612 WorkspaceController
* workspace_controller
)
613 : delegate_view_(new DelegateView(this)),
614 background_animator_(delegate_view_
, 0, kShelfBackgroundAlpha
),
615 activating_as_fallback_(false),
616 window_container_(shelf_container
) {
617 views::Widget::InitParams
params(
618 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS
);
619 params
.opacity
= views::Widget::InitParams::TRANSLUCENT_WINDOW
;
620 params
.ownership
= views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
621 params
.parent
= shelf_container
;
622 params
.delegate
= delegate_view_
;
625 // The shelf should not take focus when initially shown.
626 set_focus_on_creation(false);
627 SetContentsView(delegate_view_
);
628 delegate_view_
->SetParentLayer(GetLayer());
630 status_area_widget_
= new StatusAreaWidget(status_container
);
631 status_area_widget_
->CreateTrayViews();
632 if (Shell::GetInstance()->session_state_delegate()->
633 IsActiveUserSessionStarted()) {
634 status_area_widget_
->Show();
636 Shell::GetInstance()->focus_cycler()->AddWidget(status_area_widget_
);
638 shelf_layout_manager_
= new ShelfLayoutManager(this);
639 shelf_layout_manager_
->AddObserver(this);
640 shelf_container
->SetLayoutManager(shelf_layout_manager_
);
641 shelf_layout_manager_
->set_workspace_controller(workspace_controller
);
642 workspace_controller
->SetShelf(shelf_layout_manager_
);
644 status_container
->SetLayoutManager(
645 new StatusAreaLayoutManager(status_container
, this));
647 shelf_container
->SetEventTargeter(scoped_ptr
<ui::EventTargeter
>(new
648 ShelfWindowTargeter(shelf_container
, shelf_layout_manager_
)));
649 status_container
->SetEventTargeter(scoped_ptr
<ui::EventTargeter
>(new
650 ShelfWindowTargeter(status_container
, shelf_layout_manager_
)));
652 views::Widget::AddObserver(this);
655 ShelfWidget::~ShelfWidget() {
656 RemoveObserver(this);
659 void ShelfWidget::SetPaintsBackground(
660 ShelfBackgroundType background_type
,
661 BackgroundAnimatorChangeType change_type
) {
662 ui::Layer
* opaque_background
= delegate_view_
->opaque_background();
663 float target_opacity
=
664 (background_type
== SHELF_BACKGROUND_MAXIMIZED
) ? 1.0f
: 0.0f
;
665 scoped_ptr
<ui::ScopedLayerAnimationSettings
> opaque_background_animation
;
666 if (change_type
!= BACKGROUND_CHANGE_IMMEDIATE
) {
667 opaque_background_animation
.reset(new ui::ScopedLayerAnimationSettings(
668 opaque_background
->GetAnimator()));
669 opaque_background_animation
->SetTransitionDuration(
670 base::TimeDelta::FromMilliseconds(kTimeToSwitchBackgroundMs
));
672 opaque_background
->SetOpacity(target_opacity
);
674 // TODO(mukai): use ui::Layer on both opaque_background and normal background
675 // retire background_animator_ at all. It would be simpler.
676 // See also DockedBackgroundWidget::SetPaintsBackground.
677 background_animator_
.SetPaintsBackground(
678 background_type
!= SHELF_BACKGROUND_DEFAULT
,
680 delegate_view_
->SchedulePaint();
683 ShelfBackgroundType
ShelfWidget::GetBackgroundType() const {
684 if (delegate_view_
->opaque_background()->GetTargetOpacity() == 1.0f
)
685 return SHELF_BACKGROUND_MAXIMIZED
;
686 if (background_animator_
.paints_background())
687 return SHELF_BACKGROUND_OVERLAP
;
689 return SHELF_BACKGROUND_DEFAULT
;
692 void ShelfWidget::HideShelfBehindBlackBar(bool hide
, int animation_time_ms
) {
693 if (IsShelfHiddenBehindBlackBar() == hide
)
696 ui::Layer
* opaque_foreground
= delegate_view_
->opaque_foreground();
697 float target_opacity
= hide
? 1.0f
: 0.0f
;
698 scoped_ptr
<ui::ScopedLayerAnimationSettings
> opaque_foreground_animation
;
699 opaque_foreground_animation
.reset(new ui::ScopedLayerAnimationSettings(
700 opaque_foreground
->GetAnimator()));
701 opaque_foreground_animation
->SetTransitionDuration(
702 base::TimeDelta::FromMilliseconds(animation_time_ms
));
703 opaque_foreground_animation
->SetPreemptionStrategy(
704 ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS
);
706 opaque_foreground
->SetOpacity(target_opacity
);
709 bool ShelfWidget::IsShelfHiddenBehindBlackBar() const {
710 return delegate_view_
->opaque_foreground()->GetTargetOpacity() != 0.0f
;
714 bool ShelfWidget::ShelfAlignmentAllowed() {
715 if (Shell::GetInstance()->system_tray_delegate()->IsUserSupervised())
718 user::LoginStatus login_status
=
719 Shell::GetInstance()->system_tray_delegate()->GetUserLoginStatus();
721 switch (login_status
) {
722 case user::LOGGED_IN_LOCKED
:
723 // Shelf alignment changes can be requested while being locked, but will
724 // be applied upon unlock.
725 case user::LOGGED_IN_USER
:
726 case user::LOGGED_IN_OWNER
:
728 case user::LOGGED_IN_PUBLIC
:
729 case user::LOGGED_IN_SUPERVISED
:
730 case user::LOGGED_IN_GUEST
:
731 case user::LOGGED_IN_KIOSK_APP
:
732 case user::LOGGED_IN_NONE
:
740 ShelfAlignment
ShelfWidget::GetAlignment() const {
741 return shelf_layout_manager_
->GetAlignment();
744 void ShelfWidget::SetAlignment(ShelfAlignment alignment
) {
746 shelf_
->SetAlignment(alignment
);
747 status_area_widget_
->SetShelfAlignment(alignment
);
748 delegate_view_
->SchedulePaint();
751 void ShelfWidget::SetDimsShelf(bool dimming
) {
752 delegate_view_
->SetDimmed(dimming
);
753 // Repaint all children, allowing updates to reflect dimmed state eg:
754 // status area background, app list button and overflow button.
756 shelf_
->SchedulePaint();
757 status_area_widget_
->SchedulePaint();
760 bool ShelfWidget::GetDimsShelf() const {
761 return delegate_view_
->GetDimmed();
764 void ShelfWidget::CreateShelf() {
768 Shell
* shell
= Shell::GetInstance();
769 // This needs to be called before shelf_model().
770 ShelfDelegate
* shelf_delegate
= shell
->GetShelfDelegate();
772 return; // Not ready to create Shelf.
775 new Shelf(shell
->shelf_model(), shell
->GetShelfDelegate(), this));
776 SetFocusCycler(shell
->focus_cycler());
778 // Inform the root window controller.
779 RootWindowController::ForWindow(window_container_
)->OnShelfCreated();
782 shell
->session_state_delegate()->IsActiveUserSessionStarted());
783 shelf_layout_manager_
->LayoutShelf();
787 bool ShelfWidget::IsShelfVisible() const {
788 return shelf_
.get() && shelf_
->IsVisible();
791 void ShelfWidget::SetShelfVisibility(bool visible
) {
793 shelf_
->SetVisible(visible
);
796 void ShelfWidget::SetFocusCycler(FocusCycler
* focus_cycler
) {
797 delegate_view_
->set_focus_cycler(focus_cycler
);
799 focus_cycler
->AddWidget(this);
802 FocusCycler
* ShelfWidget::GetFocusCycler() {
803 return delegate_view_
->focus_cycler();
806 void ShelfWidget::ShutdownStatusAreaWidget() {
807 if (status_area_widget_
)
808 status_area_widget_
->Shutdown();
809 status_area_widget_
= NULL
;
812 void ShelfWidget::ForceUndimming(bool force
) {
813 delegate_view_
->ForceUndimming(force
);
816 void ShelfWidget::OnWidgetActivationChanged(views::Widget
* widget
,
818 activating_as_fallback_
= false;
820 delegate_view_
->SetPaneFocusAndFocusDefault();
822 delegate_view_
->GetFocusManager()->ClearFocus();
825 int ShelfWidget::GetDimmingAlphaForTest() {
827 return delegate_view_
->GetDimmingAlphaForTest();
831 gfx::Rect
ShelfWidget::GetDimmerBoundsForTest() {
833 return delegate_view_
->GetDimmerBoundsForTest();
837 void ShelfWidget::DisableDimmingAnimationsForTest() {
838 DCHECK(delegate_view_
);
839 return delegate_view_
->disable_dimming_animations_for_test();
842 void ShelfWidget::WillDeleteShelf() {
843 shelf_layout_manager_
->RemoveObserver(this);
844 shelf_layout_manager_
= NULL
;