Support HTTP/2 drafts 14 and 15 simultaneously.
[chromium-blink-merge.git] / ash / shelf / shelf_widget.cc
blob73bbeaa6e5aa7cf4de8c3185fc36294c5114573c
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 ~DimmerView() override;
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 views::Widget* GetWidget() override { return View::GetWidget(); }
71 const views::Widget* GetWidget() const override { return View::GetWidget(); }
73 // ash::BackgroundAnimatorDelegate overrides:
74 void UpdateBackground(int alpha) override {
75 alpha_ = alpha;
76 SchedulePaint();
79 // views::View overrides:
80 void OnPaintBackground(gfx::Canvas* canvas) override;
82 // A function to test the current alpha used.
83 int get_dimming_alpha_for_test() { return alpha_; }
85 private:
86 // This class monitors mouse events to see if it is on top of the shelf.
87 class DimmerEventFilter : public ui::EventHandler {
88 public:
89 explicit DimmerEventFilter(DimmerView* owner);
90 ~DimmerEventFilter() override;
92 // Overridden from ui::EventHandler:
93 void OnMouseEvent(ui::MouseEvent* event) override;
94 void OnTouchEvent(ui::TouchEvent* event) override;
96 private:
97 // The owning class.
98 DimmerView* owner_;
100 // TRUE if the mouse is inside the shelf.
101 bool mouse_inside_;
103 // TRUE if a touch event is inside the shelf.
104 bool touch_inside_;
106 DISALLOW_COPY_AND_ASSIGN(DimmerEventFilter);
109 // The owning shelf.
110 ash::ShelfWidget* shelf_;
112 // The alpha to use for covering the shelf.
113 int alpha_;
115 // True if the event filter claims that we should not be dimmed.
116 bool is_hovered_;
118 // True if someone forces us not to be dimmed (e.g. a menu is open).
119 bool force_hovered_;
121 // True if animations should be suppressed for a test.
122 bool disable_dimming_animations_for_test_;
124 // The animator for the background transitions.
125 ash::BackgroundAnimator background_animator_;
127 // Notification of entering / exiting of the shelf area by mouse.
128 scoped_ptr<DimmerEventFilter> event_filter_;
130 DISALLOW_COPY_AND_ASSIGN(DimmerView);
133 DimmerView::DimmerView(ash::ShelfWidget* shelf_widget,
134 bool disable_dimming_animations_for_test)
135 : shelf_(shelf_widget),
136 alpha_(kDimAlpha),
137 is_hovered_(false),
138 force_hovered_(false),
139 disable_dimming_animations_for_test_(disable_dimming_animations_for_test),
140 background_animator_(this, 0, kDimAlpha) {
141 event_filter_.reset(new DimmerEventFilter(this));
142 // Make sure it is undimmed at the beginning and then fire off the dimming
143 // animation.
144 background_animator_.SetPaintsBackground(false,
145 ash::BACKGROUND_CHANGE_IMMEDIATE);
146 SetHovered(false);
149 DimmerView::~DimmerView() {
152 void DimmerView::SetHovered(bool hovered) {
153 // Remember the hovered state so that we can correct the state once a
154 // possible force state has disappeared.
155 is_hovered_ = hovered;
156 // Undimm also if we were forced to by e.g. an open menu.
157 hovered |= force_hovered_;
158 background_animator_.SetDuration(hovered ? kTimeToUnDimMs : kTimeToDimMs);
159 background_animator_.SetPaintsBackground(!hovered,
160 disable_dimming_animations_for_test_ ?
161 ash::BACKGROUND_CHANGE_IMMEDIATE : ash::BACKGROUND_CHANGE_ANIMATE);
164 void DimmerView::ForceUndimming(bool force) {
165 bool previous = force_hovered_;
166 force_hovered_ = force;
167 // If the forced change does change the result we apply the change.
168 if (is_hovered_ || force_hovered_ != is_hovered_ || previous)
169 SetHovered(is_hovered_);
172 void DimmerView::OnPaintBackground(gfx::Canvas* canvas) {
173 SkPaint paint;
174 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
175 gfx::ImageSkia shelf_background =
176 *rb.GetImageNamed(IDR_ASH_SHELF_DIMMING).ToImageSkia();
178 if (shelf_->GetAlignment() != ash::SHELF_ALIGNMENT_BOTTOM) {
179 shelf_background = gfx::ImageSkiaOperations::CreateRotatedImage(
180 shelf_background,
181 shelf_->shelf_layout_manager()->SelectValueForShelfAlignment(
182 SkBitmapOperations::ROTATION_90_CW,
183 SkBitmapOperations::ROTATION_90_CW,
184 SkBitmapOperations::ROTATION_270_CW,
185 SkBitmapOperations::ROTATION_180_CW));
187 paint.setAlpha(alpha_);
188 canvas->DrawImageInt(shelf_background,
191 shelf_background.width(),
192 shelf_background.height(),
195 width(),
196 height(),
197 false,
198 paint);
201 DimmerView::DimmerEventFilter::DimmerEventFilter(DimmerView* owner)
202 : owner_(owner),
203 mouse_inside_(false),
204 touch_inside_(false) {
205 ash::Shell::GetInstance()->AddPreTargetHandler(this);
208 DimmerView::DimmerEventFilter::~DimmerEventFilter() {
209 ash::Shell::GetInstance()->RemovePreTargetHandler(this);
212 void DimmerView::DimmerEventFilter::OnMouseEvent(ui::MouseEvent* event) {
213 if (event->type() != ui::ET_MOUSE_MOVED &&
214 event->type() != ui::ET_MOUSE_DRAGGED)
215 return;
216 bool inside = owner_->GetBoundsInScreen().Contains(event->root_location());
217 if (mouse_inside_ || touch_inside_ != inside || touch_inside_)
218 owner_->SetHovered(inside || touch_inside_);
219 mouse_inside_ = inside;
222 void DimmerView::DimmerEventFilter::OnTouchEvent(ui::TouchEvent* event) {
223 bool touch_inside = false;
224 if (event->type() != ui::ET_TOUCH_RELEASED &&
225 event->type() != ui::ET_TOUCH_CANCELLED)
226 touch_inside = owner_->GetBoundsInScreen().Contains(event->root_location());
228 if (mouse_inside_ || touch_inside_ != mouse_inside_ || touch_inside)
229 owner_->SetHovered(mouse_inside_ || touch_inside);
230 touch_inside_ = touch_inside;
233 using ash::ShelfLayoutManager;
235 // ShelfWindowTargeter makes it easier to resize windows with the mouse when the
236 // window-edge slightly overlaps with the shelf edge. The targeter also makes it
237 // easier to drag the shelf out with touch while it is hidden.
238 class ShelfWindowTargeter : public wm::EasyResizeWindowTargeter,
239 public ash::ShelfLayoutManagerObserver {
240 public:
241 ShelfWindowTargeter(aura::Window* container,
242 ShelfLayoutManager* shelf)
243 : wm::EasyResizeWindowTargeter(container, gfx::Insets(), gfx::Insets()),
244 shelf_(shelf) {
245 WillChangeVisibilityState(shelf_->visibility_state());
246 shelf_->AddObserver(this);
249 ~ShelfWindowTargeter() override {
250 // |shelf_| may have been destroyed by this time.
251 if (shelf_)
252 shelf_->RemoveObserver(this);
255 private:
256 gfx::Insets GetInsetsForAlignment(int distance,
257 ash::ShelfAlignment alignment) {
258 switch (alignment) {
259 case ash::SHELF_ALIGNMENT_BOTTOM:
260 return gfx::Insets(distance, 0, 0, 0);
261 case ash::SHELF_ALIGNMENT_LEFT:
262 return gfx::Insets(0, 0, 0, distance);
263 case ash::SHELF_ALIGNMENT_RIGHT:
264 return gfx::Insets(0, distance, 0, 0);
265 case ash::SHELF_ALIGNMENT_TOP:
266 return gfx::Insets(0, 0, distance, 0);
268 NOTREACHED();
269 return gfx::Insets();
272 // ash::ShelfLayoutManagerObserver:
273 void WillDeleteShelf() override { shelf_ = NULL; }
275 void WillChangeVisibilityState(ash::ShelfVisibilityState new_state) override {
276 gfx::Insets mouse_insets;
277 gfx::Insets touch_insets;
278 if (new_state == ash::SHELF_VISIBLE) {
279 // Let clicks at the very top of the shelf through so windows can be
280 // resized with the bottom-right corner and bottom edge.
281 mouse_insets = GetInsetsForAlignment(
282 ShelfLayoutManager::kWorkspaceAreaVisibleInset,
283 shelf_->GetAlignment());
284 } else if (new_state == ash::SHELF_AUTO_HIDE) {
285 // Extend the touch hit target out a bit to allow users to drag shelf out
286 // while hidden.
287 touch_insets = GetInsetsForAlignment(
288 -ShelfLayoutManager::kWorkspaceAreaAutoHideInset,
289 shelf_->GetAlignment());
292 set_mouse_extend(mouse_insets);
293 set_touch_extend(touch_insets);
296 ShelfLayoutManager* shelf_;
298 DISALLOW_COPY_AND_ASSIGN(ShelfWindowTargeter);
301 } // namespace
303 namespace ash {
305 // The contents view of the Shelf. This view contains ShelfView and
306 // sizes it to the width of the shelf minus the size of the status area.
307 class ShelfWidget::DelegateView : public views::WidgetDelegate,
308 public views::AccessiblePaneView,
309 public BackgroundAnimatorDelegate,
310 public aura::WindowObserver {
311 public:
312 explicit DelegateView(ShelfWidget* shelf);
313 ~DelegateView() override;
315 void set_focus_cycler(FocusCycler* focus_cycler) {
316 focus_cycler_ = focus_cycler;
318 FocusCycler* focus_cycler() { return focus_cycler_; }
320 ui::Layer* opaque_background() { return &opaque_background_; }
321 ui::Layer* opaque_foreground() { return &opaque_foreground_; }
323 // Set if the shelf area is dimmed (eg when a window is maximized).
324 void SetDimmed(bool dimmed);
325 bool GetDimmed() const;
327 void SetParentLayer(ui::Layer* layer);
329 // views::View overrides:
330 void OnPaintBackground(gfx::Canvas* canvas) override;
332 // views::WidgetDelegateView overrides:
333 views::Widget* GetWidget() override { return View::GetWidget(); }
334 const views::Widget* GetWidget() const override { return View::GetWidget(); }
336 bool CanActivate() const override;
337 void Layout() override;
338 void ReorderChildLayers(ui::Layer* parent_layer) override;
339 // This will be called when the parent local bounds change.
340 void OnBoundsChanged(const gfx::Rect& old_bounds) override;
342 // aura::WindowObserver overrides:
343 // This will be called when the shelf itself changes its absolute position.
344 // Since the |dimmer_| panel needs to be placed in screen coordinates it needs
345 // to be repositioned. The difference to the OnBoundsChanged call above is
346 // that this gets also triggered when the shelf only moves.
347 void OnWindowBoundsChanged(aura::Window* window,
348 const gfx::Rect& old_bounds,
349 const gfx::Rect& new_bounds) override;
351 // BackgroundAnimatorDelegate overrides:
352 void UpdateBackground(int alpha) override;
354 // Force the shelf to be presented in an undimmed state.
355 void ForceUndimming(bool force);
357 // A function to test the current alpha used by the dimming bar. If there is
358 // no dimmer active, the function will return -1.
359 int GetDimmingAlphaForTest();
361 // A function to test the bounds of the dimming bar. Returns gfx::Rect() if
362 // the dimmer is inactive.
363 gfx::Rect GetDimmerBoundsForTest();
365 // Disable dimming animations for running tests. This needs to be called
366 // prior to the creation of of the |dimmer_|.
367 void disable_dimming_animations_for_test() {
368 disable_dimming_animations_for_test_ = true;
371 private:
372 ShelfWidget* shelf_;
373 scoped_ptr<views::Widget> dimmer_;
374 FocusCycler* focus_cycler_;
375 int alpha_;
376 // A black background layer which is shown when a maximized window is visible.
377 ui::Layer opaque_background_;
378 // A black foreground layer which is shown while transitioning between users.
379 // Note: Since the back- and foreground layers have different functions they
380 // can be used simultaneously - so no repurposing possible.
381 ui::Layer opaque_foreground_;
383 // The view which does the dimming.
384 DimmerView* dimmer_view_;
386 // True if dimming animations should be turned off.
387 bool disable_dimming_animations_for_test_;
389 DISALLOW_COPY_AND_ASSIGN(DelegateView);
392 ShelfWidget::DelegateView::DelegateView(ShelfWidget* shelf)
393 : shelf_(shelf),
394 focus_cycler_(NULL),
395 alpha_(0),
396 opaque_background_(ui::LAYER_SOLID_COLOR),
397 opaque_foreground_(ui::LAYER_SOLID_COLOR),
398 dimmer_view_(NULL),
399 disable_dimming_animations_for_test_(false) {
400 set_allow_deactivate_on_esc(true);
401 opaque_background_.SetColor(SK_ColorBLACK);
402 opaque_background_.SetBounds(GetLocalBounds());
403 opaque_background_.SetOpacity(0.0f);
404 opaque_foreground_.SetColor(SK_ColorBLACK);
405 opaque_foreground_.SetBounds(GetLocalBounds());
406 opaque_foreground_.SetOpacity(0.0f);
409 ShelfWidget::DelegateView::~DelegateView() {
410 // Make sure that the dimmer goes away since it might have set an observer.
411 SetDimmed(false);
414 void ShelfWidget::DelegateView::SetDimmed(bool value) {
415 if (value == (dimmer_.get() != NULL))
416 return;
418 if (value) {
419 dimmer_.reset(new views::Widget);
420 views::Widget::InitParams params(
421 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
422 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
423 params.activatable = views::Widget::InitParams::ACTIVATABLE_NO;
424 params.accept_events = false;
425 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
426 params.parent = shelf_->GetNativeView();
427 dimmer_->Init(params);
428 dimmer_->GetNativeWindow()->SetName("ShelfDimmer");
429 dimmer_->SetBounds(shelf_->GetWindowBoundsInScreen());
430 // The shelf should not take focus when it is initially shown.
431 dimmer_->set_focus_on_creation(false);
432 dimmer_view_ = new DimmerView(shelf_, disable_dimming_animations_for_test_);
433 dimmer_->SetContentsView(dimmer_view_);
434 dimmer_->GetNativeView()->SetName("ShelfDimmerView");
435 dimmer_->Show();
436 shelf_->GetNativeView()->AddObserver(this);
437 } else {
438 // Some unit tests will come here with a destroyed window.
439 if (shelf_->GetNativeView())
440 shelf_->GetNativeView()->RemoveObserver(this);
441 dimmer_view_ = NULL;
442 dimmer_.reset(NULL);
446 bool ShelfWidget::DelegateView::GetDimmed() const {
447 return dimmer_.get() && dimmer_->IsVisible();
450 void ShelfWidget::DelegateView::SetParentLayer(ui::Layer* layer) {
451 layer->Add(&opaque_background_);
452 layer->Add(&opaque_foreground_);
453 ReorderLayers();
456 void ShelfWidget::DelegateView::OnPaintBackground(gfx::Canvas* canvas) {
457 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
458 gfx::ImageSkia shelf_background =
459 *rb.GetImageSkiaNamed(IDR_ASH_SHELF_BACKGROUND);
460 if (SHELF_ALIGNMENT_BOTTOM != shelf_->GetAlignment())
461 shelf_background = gfx::ImageSkiaOperations::CreateRotatedImage(
462 shelf_background,
463 shelf_->shelf_layout_manager()->SelectValueForShelfAlignment(
464 SkBitmapOperations::ROTATION_90_CW,
465 SkBitmapOperations::ROTATION_90_CW,
466 SkBitmapOperations::ROTATION_270_CW,
467 SkBitmapOperations::ROTATION_180_CW));
468 const gfx::Rect dock_bounds(shelf_->shelf_layout_manager()->dock_bounds());
469 SkPaint paint;
470 paint.setAlpha(alpha_);
471 canvas->DrawImageInt(shelf_background,
474 shelf_background.width(),
475 shelf_background.height(),
476 (SHELF_ALIGNMENT_BOTTOM == shelf_->GetAlignment() &&
477 dock_bounds.x() == 0 && dock_bounds.width() > 0)
478 ? dock_bounds.width()
479 : 0,
481 SHELF_ALIGNMENT_BOTTOM == shelf_->GetAlignment()
482 ? width() - dock_bounds.width()
483 : width(),
484 height(),
485 false,
486 paint);
487 if (SHELF_ALIGNMENT_BOTTOM == shelf_->GetAlignment() &&
488 dock_bounds.width() > 0) {
489 // The part of the shelf background that is in the corner below the docked
490 // windows close to the work area is an arched gradient that blends
491 // vertically oriented docked background and horizontal shelf.
492 gfx::ImageSkia shelf_corner = *rb.GetImageSkiaNamed(IDR_ASH_SHELF_CORNER);
493 if (dock_bounds.x() == 0) {
494 shelf_corner = gfx::ImageSkiaOperations::CreateRotatedImage(
495 shelf_corner, SkBitmapOperations::ROTATION_90_CW);
497 canvas->DrawImageInt(
498 shelf_corner,
501 shelf_corner.width(),
502 shelf_corner.height(),
503 dock_bounds.x() > 0 ? dock_bounds.x() : dock_bounds.width() - height(),
505 height(),
506 height(),
507 false,
508 paint);
509 // The part of the shelf background that is just below the docked windows
510 // is drawn using the last (lowest) 1-pixel tall strip of the image asset.
511 // This avoids showing the border 3D shadow between the shelf and the dock.
512 canvas->DrawImageInt(shelf_background,
514 shelf_background.height() - 1,
515 shelf_background.width(),
517 dock_bounds.x() > 0 ? dock_bounds.x() + height() : 0,
519 dock_bounds.width() - height(),
520 height(),
521 false,
522 paint);
524 gfx::Rect black_rect =
525 shelf_->shelf_layout_manager()->SelectValueForShelfAlignment(
526 gfx::Rect(0, height() - kNumBlackPixels, width(), kNumBlackPixels),
527 gfx::Rect(0, 0, kNumBlackPixels, height()),
528 gfx::Rect(width() - kNumBlackPixels, 0, kNumBlackPixels, height()),
529 gfx::Rect(0, 0, width(), kNumBlackPixels));
530 canvas->FillRect(black_rect, SK_ColorBLACK);
533 bool ShelfWidget::DelegateView::CanActivate() const {
534 // Allow to activate as fallback.
535 if (shelf_->activating_as_fallback_)
536 return true;
537 // Allow to activate from the focus cycler.
538 if (focus_cycler_ && focus_cycler_->widget_activating() == GetWidget())
539 return true;
540 // Disallow activating in other cases, especially when using mouse.
541 return false;
544 void ShelfWidget::DelegateView::Layout() {
545 for(int i = 0; i < child_count(); ++i) {
546 if (shelf_->shelf_layout_manager()->IsHorizontalAlignment()) {
547 child_at(i)->SetBounds(child_at(i)->x(), child_at(i)->y(),
548 child_at(i)->width(), height());
549 } else {
550 child_at(i)->SetBounds(child_at(i)->x(), child_at(i)->y(),
551 width(), child_at(i)->height());
556 void ShelfWidget::DelegateView::ReorderChildLayers(ui::Layer* parent_layer) {
557 views::View::ReorderChildLayers(parent_layer);
558 parent_layer->StackAtBottom(&opaque_background_);
559 parent_layer->StackAtTop(&opaque_foreground_);
562 void ShelfWidget::DelegateView::OnBoundsChanged(const gfx::Rect& old_bounds) {
563 opaque_background_.SetBounds(GetLocalBounds());
564 opaque_foreground_.SetBounds(GetLocalBounds());
565 if (dimmer_)
566 dimmer_->SetBounds(GetBoundsInScreen());
569 void ShelfWidget::DelegateView::OnWindowBoundsChanged(
570 aura::Window* window,
571 const gfx::Rect& old_bounds,
572 const gfx::Rect& new_bounds) {
573 // Coming here the shelf got repositioned and since the |dimmer_| is placed
574 // in screen coordinates and not relative to the parent it needs to be
575 // repositioned accordingly.
576 dimmer_->SetBounds(GetBoundsInScreen());
579 void ShelfWidget::DelegateView::ForceUndimming(bool force) {
580 if (GetDimmed())
581 dimmer_view_->ForceUndimming(force);
584 int ShelfWidget::DelegateView::GetDimmingAlphaForTest() {
585 if (GetDimmed())
586 return dimmer_view_->get_dimming_alpha_for_test();
587 return -1;
590 gfx::Rect ShelfWidget::DelegateView::GetDimmerBoundsForTest() {
591 if (GetDimmed())
592 return dimmer_view_->GetBoundsInScreen();
593 return gfx::Rect();
596 void ShelfWidget::DelegateView::UpdateBackground(int alpha) {
597 alpha_ = alpha;
598 SchedulePaint();
601 ShelfWidget::ShelfWidget(aura::Window* shelf_container,
602 aura::Window* status_container,
603 WorkspaceController* workspace_controller)
604 : delegate_view_(new DelegateView(this)),
605 background_animator_(delegate_view_, 0, kShelfBackgroundAlpha),
606 activating_as_fallback_(false),
607 window_container_(shelf_container) {
608 views::Widget::InitParams params(
609 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
610 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
611 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
612 params.parent = shelf_container;
613 params.delegate = delegate_view_;
614 Init(params);
616 // The shelf should not take focus when initially shown.
617 set_focus_on_creation(false);
618 SetContentsView(delegate_view_);
619 delegate_view_->SetParentLayer(GetLayer());
621 status_area_widget_ = new StatusAreaWidget(status_container);
622 status_area_widget_->CreateTrayViews();
623 if (Shell::GetInstance()->session_state_delegate()->
624 IsActiveUserSessionStarted()) {
625 status_area_widget_->Show();
627 Shell::GetInstance()->focus_cycler()->AddWidget(status_area_widget_);
629 shelf_layout_manager_ = new ShelfLayoutManager(this);
630 shelf_layout_manager_->AddObserver(this);
631 shelf_container->SetLayoutManager(shelf_layout_manager_);
632 shelf_layout_manager_->set_workspace_controller(workspace_controller);
633 workspace_controller->SetShelf(shelf_layout_manager_);
635 status_container->SetLayoutManager(
636 new StatusAreaLayoutManager(status_container, this));
638 shelf_container->SetEventTargeter(scoped_ptr<ui::EventTargeter>(new
639 ShelfWindowTargeter(shelf_container, shelf_layout_manager_)));
640 status_container->SetEventTargeter(scoped_ptr<ui::EventTargeter>(new
641 ShelfWindowTargeter(status_container, shelf_layout_manager_)));
643 views::Widget::AddObserver(this);
646 ShelfWidget::~ShelfWidget() {
647 RemoveObserver(this);
650 void ShelfWidget::SetPaintsBackground(
651 ShelfBackgroundType background_type,
652 BackgroundAnimatorChangeType change_type) {
653 ui::Layer* opaque_background = delegate_view_->opaque_background();
654 float target_opacity =
655 (background_type == SHELF_BACKGROUND_MAXIMIZED) ? 1.0f : 0.0f;
656 scoped_ptr<ui::ScopedLayerAnimationSettings> opaque_background_animation;
657 if (change_type != BACKGROUND_CHANGE_IMMEDIATE) {
658 opaque_background_animation.reset(new ui::ScopedLayerAnimationSettings(
659 opaque_background->GetAnimator()));
660 opaque_background_animation->SetTransitionDuration(
661 base::TimeDelta::FromMilliseconds(kTimeToSwitchBackgroundMs));
663 opaque_background->SetOpacity(target_opacity);
665 // TODO(mukai): use ui::Layer on both opaque_background and normal background
666 // retire background_animator_ at all. It would be simpler.
667 // See also DockedBackgroundWidget::SetPaintsBackground.
668 background_animator_.SetPaintsBackground(
669 background_type != SHELF_BACKGROUND_DEFAULT,
670 change_type);
671 delegate_view_->SchedulePaint();
674 ShelfBackgroundType ShelfWidget::GetBackgroundType() const {
675 if (delegate_view_->opaque_background()->GetTargetOpacity() == 1.0f)
676 return SHELF_BACKGROUND_MAXIMIZED;
677 if (background_animator_.paints_background())
678 return SHELF_BACKGROUND_OVERLAP;
680 return SHELF_BACKGROUND_DEFAULT;
683 void ShelfWidget::HideShelfBehindBlackBar(bool hide, int animation_time_ms) {
684 if (IsShelfHiddenBehindBlackBar() == hide)
685 return;
687 ui::Layer* opaque_foreground = delegate_view_->opaque_foreground();
688 float target_opacity = hide ? 1.0f : 0.0f;
689 scoped_ptr<ui::ScopedLayerAnimationSettings> opaque_foreground_animation;
690 opaque_foreground_animation.reset(new ui::ScopedLayerAnimationSettings(
691 opaque_foreground->GetAnimator()));
692 opaque_foreground_animation->SetTransitionDuration(
693 base::TimeDelta::FromMilliseconds(animation_time_ms));
694 opaque_foreground_animation->SetPreemptionStrategy(
695 ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS);
697 opaque_foreground->SetOpacity(target_opacity);
700 bool ShelfWidget::IsShelfHiddenBehindBlackBar() const {
701 return delegate_view_->opaque_foreground()->GetTargetOpacity() != 0.0f;
704 // static
705 bool ShelfWidget::ShelfAlignmentAllowed() {
706 if (Shell::GetInstance()->system_tray_delegate()->IsUserSupervised())
707 return false;
709 user::LoginStatus login_status =
710 Shell::GetInstance()->system_tray_delegate()->GetUserLoginStatus();
712 switch (login_status) {
713 case user::LOGGED_IN_USER:
714 case user::LOGGED_IN_OWNER:
715 return true;
716 case user::LOGGED_IN_LOCKED:
717 case user::LOGGED_IN_PUBLIC:
718 case user::LOGGED_IN_SUPERVISED:
719 case user::LOGGED_IN_GUEST:
720 case user::LOGGED_IN_RETAIL_MODE:
721 case user::LOGGED_IN_KIOSK_APP:
722 case user::LOGGED_IN_NONE:
723 return false;
726 DCHECK(false);
727 return false;
730 ShelfAlignment ShelfWidget::GetAlignment() const {
731 return shelf_layout_manager_->GetAlignment();
734 void ShelfWidget::SetAlignment(ShelfAlignment alignment) {
735 if (shelf_)
736 shelf_->SetAlignment(alignment);
737 status_area_widget_->SetShelfAlignment(alignment);
738 delegate_view_->SchedulePaint();
741 void ShelfWidget::SetDimsShelf(bool dimming) {
742 delegate_view_->SetDimmed(dimming);
743 // Repaint all children, allowing updates to reflect dimmed state eg:
744 // status area background, app list button and overflow button.
745 if (shelf_)
746 shelf_->SchedulePaint();
747 status_area_widget_->SchedulePaint();
750 bool ShelfWidget::GetDimsShelf() const {
751 return delegate_view_->GetDimmed();
754 void ShelfWidget::CreateShelf() {
755 if (shelf_)
756 return;
758 Shell* shell = Shell::GetInstance();
759 // This needs to be called before shelf_model().
760 ShelfDelegate* shelf_delegate = shell->GetShelfDelegate();
761 if (!shelf_delegate)
762 return; // Not ready to create Shelf.
764 shelf_.reset(
765 new Shelf(shell->shelf_model(), shell->GetShelfDelegate(), this));
766 SetFocusCycler(shell->focus_cycler());
768 // Inform the root window controller.
769 RootWindowController::ForWindow(window_container_)->OnShelfCreated();
771 shelf_->SetVisible(
772 shell->session_state_delegate()->IsActiveUserSessionStarted());
773 shelf_layout_manager_->LayoutShelf();
774 Show();
777 bool ShelfWidget::IsShelfVisible() const {
778 return shelf_.get() && shelf_->IsVisible();
781 void ShelfWidget::SetShelfVisibility(bool visible) {
782 if (shelf_)
783 shelf_->SetVisible(visible);
786 void ShelfWidget::SetFocusCycler(FocusCycler* focus_cycler) {
787 delegate_view_->set_focus_cycler(focus_cycler);
788 if (focus_cycler)
789 focus_cycler->AddWidget(this);
792 FocusCycler* ShelfWidget::GetFocusCycler() {
793 return delegate_view_->focus_cycler();
796 void ShelfWidget::ShutdownStatusAreaWidget() {
797 if (status_area_widget_)
798 status_area_widget_->Shutdown();
799 status_area_widget_ = NULL;
802 void ShelfWidget::ForceUndimming(bool force) {
803 delegate_view_->ForceUndimming(force);
806 void ShelfWidget::OnWidgetActivationChanged(views::Widget* widget,
807 bool active) {
808 activating_as_fallback_ = false;
809 if (active)
810 delegate_view_->SetPaneFocusAndFocusDefault();
811 else
812 delegate_view_->GetFocusManager()->ClearFocus();
815 int ShelfWidget::GetDimmingAlphaForTest() {
816 if (delegate_view_)
817 return delegate_view_->GetDimmingAlphaForTest();
818 return -1;
821 gfx::Rect ShelfWidget::GetDimmerBoundsForTest() {
822 if (delegate_view_)
823 return delegate_view_->GetDimmerBoundsForTest();
824 return gfx::Rect();
827 void ShelfWidget::DisableDimmingAnimationsForTest() {
828 DCHECK(delegate_view_);
829 return delegate_view_->disable_dimming_animations_for_test();
832 void ShelfWidget::WillDeleteShelf() {
833 shelf_layout_manager_->RemoveObserver(this);
834 shelf_layout_manager_ = NULL;
837 } // namespace ash