Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / ash / shelf / shelf_widget.cc
blobf912011365f934f25a5be883108fd0fcb12ada19
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"
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;
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 {
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();
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 {
79 alpha_ = alpha;
80 SchedulePaint();
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_; }
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();
96 // Overridden from ui::EventHandler:
97 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
98 virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE;
100 private:
101 // The owning class.
102 DimmerView* owner_;
104 // TRUE if the mouse is inside the shelf.
105 bool mouse_inside_;
107 // TRUE if a touch event is inside the shelf.
108 bool touch_inside_;
110 DISALLOW_COPY_AND_ASSIGN(DimmerEventFilter);
113 // The owning shelf.
114 ash::ShelfWidget* shelf_;
116 // The alpha to use for covering the shelf.
117 int alpha_;
119 // True if the event filter claims that we should not be dimmed.
120 bool is_hovered_;
122 // True if someone forces us not to be dimmed (e.g. a menu is open).
123 bool force_hovered_;
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),
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);
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) {
177 SkPaint paint;
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(
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));
191 paint.setAlpha(alpha_);
192 canvas->DrawImageInt(shelf_background,
195 shelf_background.width(),
196 shelf_background.height(),
199 width(),
200 height(),
201 false,
202 paint);
205 DimmerView::DimmerEventFilter::DimmerEventFilter(DimmerView* owner)
206 : owner_(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)
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;
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 {
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);
253 virtual ~ShelfWindowTargeter() {
254 // |shelf_| may have been destroyed by this time.
255 if (shelf_)
256 shelf_->RemoveObserver(this);
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);
272 NOTREACHED();
273 return gfx::Insets();
276 // ash::ShelfLayoutManagerObserver:
277 virtual void WillDeleteShelf() OVERRIDE {
278 shelf_ = NULL;
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());
299 set_mouse_extend(mouse_insets);
300 set_touch_extend(touch_insets);
303 ShelfLayoutManager* shelf_;
305 DISALLOW_COPY_AND_ASSIGN(ShelfWindowTargeter);
308 } // namespace
310 namespace ash {
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();
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;
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_;
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)
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);
420 ShelfWidget::DelegateView::~DelegateView() {
421 // Make sure that the dimmer goes away since it might have set an observer.
422 SetDimmed(false);
425 void ShelfWidget::DelegateView::SetDimmed(bool value) {
426 if (value == (dimmer_.get() != NULL))
427 return;
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);
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_);
464 ReorderLayers();
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,
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,
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);
508 canvas->DrawImageInt(
509 shelf_corner,
512 shelf_corner.width(),
513 shelf_corner.height(),
514 dock_bounds.x() > 0 ? dock_bounds.x() : dock_bounds.width() - height(),
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,
525 shelf_background.height() - 1,
526 shelf_background.width(),
528 dock_bounds.x() > 0 ? dock_bounds.x() + height() : 0,
530 dock_bounds.width() - height(),
531 height(),
532 false,
533 paint);
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_)
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;
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());
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());
576 if (dimmer_)
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) {
591 if (GetDimmed())
592 dimmer_view_->ForceUndimming(force);
595 int ShelfWidget::DelegateView::GetDimmingAlphaForTest() {
596 if (GetDimmed())
597 return dimmer_view_->get_dimming_alpha_for_test();
598 return -1;
601 gfx::Rect ShelfWidget::DelegateView::GetDimmerBoundsForTest() {
602 if (GetDimmed())
603 return dimmer_view_->GetBoundsInScreen();
604 return gfx::Rect();
607 void ShelfWidget::DelegateView::UpdateBackground(int alpha) {
608 alpha_ = alpha;
609 SchedulePaint();
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);
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,
681 change_type);
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)
696 return;
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;
715 // static
716 bool ShelfWidget::ShelfAlignmentAllowed() {
717 user::LoginStatus login_status =
718 Shell::GetInstance()->system_tray_delegate()->GetUserLoginStatus();
720 switch (login_status) {
721 case user::LOGGED_IN_USER:
722 case user::LOGGED_IN_OWNER:
723 return true;
724 case user::LOGGED_IN_LOCKED:
725 case user::LOGGED_IN_PUBLIC:
726 case user::LOGGED_IN_SUPERVISED:
727 case user::LOGGED_IN_GUEST:
728 case user::LOGGED_IN_RETAIL_MODE:
729 case user::LOGGED_IN_KIOSK_APP:
730 case user::LOGGED_IN_NONE:
731 return false;
734 DCHECK(false);
735 return false;
738 ShelfAlignment ShelfWidget::GetAlignment() const {
739 return shelf_layout_manager_->GetAlignment();
742 void ShelfWidget::SetAlignment(ShelfAlignment alignment) {
743 if (shelf_)
744 shelf_->SetAlignment(alignment);
745 status_area_widget_->SetShelfAlignment(alignment);
746 delegate_view_->SchedulePaint();
749 void ShelfWidget::SetDimsShelf(bool dimming) {
750 delegate_view_->SetDimmed(dimming);
751 // Repaint all children, allowing updates to reflect dimmed state eg:
752 // status area background, app list button and overflow button.
753 if (shelf_)
754 shelf_->SchedulePaint();
755 status_area_widget_->SchedulePaint();
758 bool ShelfWidget::GetDimsShelf() const {
759 return delegate_view_->GetDimmed();
762 void ShelfWidget::CreateShelf() {
763 if (shelf_)
764 return;
766 Shell* shell = Shell::GetInstance();
767 // This needs to be called before shelf_model().
768 ShelfDelegate* shelf_delegate = shell->GetShelfDelegate();
769 if (!shelf_delegate)
770 return; // Not ready to create Shelf.
772 shelf_.reset(
773 new Shelf(shell->shelf_model(), shell->GetShelfDelegate(), this));
774 SetFocusCycler(shell->focus_cycler());
776 // Inform the root window controller.
777 RootWindowController::ForWindow(window_container_)->OnShelfCreated();
779 shelf_->SetVisible(
780 shell->session_state_delegate()->IsActiveUserSessionStarted());
781 shelf_layout_manager_->LayoutShelf();
782 Show();
785 bool ShelfWidget::IsShelfVisible() const {
786 return shelf_.get() && shelf_->IsVisible();
789 void ShelfWidget::SetShelfVisibility(bool visible) {
790 if (shelf_)
791 shelf_->SetVisible(visible);
794 void ShelfWidget::SetFocusCycler(FocusCycler* focus_cycler) {
795 delegate_view_->set_focus_cycler(focus_cycler);
796 if (focus_cycler)
797 focus_cycler->AddWidget(this);
800 FocusCycler* ShelfWidget::GetFocusCycler() {
801 return delegate_view_->focus_cycler();
804 void ShelfWidget::ShutdownStatusAreaWidget() {
805 if (status_area_widget_)
806 status_area_widget_->Shutdown();
807 status_area_widget_ = NULL;
810 void ShelfWidget::ForceUndimming(bool force) {
811 delegate_view_->ForceUndimming(force);
814 void ShelfWidget::OnWidgetActivationChanged(views::Widget* widget,
815 bool active) {
816 activating_as_fallback_ = false;
817 if (active)
818 delegate_view_->SetPaneFocusAndFocusDefault();
819 else
820 delegate_view_->GetFocusManager()->ClearFocus();
823 int ShelfWidget::GetDimmingAlphaForTest() {
824 if (delegate_view_)
825 return delegate_view_->GetDimmingAlphaForTest();
826 return -1;
829 gfx::Rect ShelfWidget::GetDimmerBoundsForTest() {
830 if (delegate_view_)
831 return delegate_view_->GetDimmerBoundsForTest();
832 return gfx::Rect();
835 void ShelfWidget::DisableDimmingAnimationsForTest() {
836 DCHECK(delegate_view_);
837 return delegate_view_->disable_dimming_animations_for_test();
840 void ShelfWidget::WillDeleteShelf() {
841 shelf_layout_manager_->RemoveObserver(this);
842 shelf_layout_manager_ = NULL;
845 } // namespace ash