Don't preload rarely seen large images
[chromium-blink-merge.git] / ash / shelf / shelf_widget.cc
blob95bc68942fe037c6299fadd5de03a2f1e22a551c
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"
43 namespace {
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 {
57 public:
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 {
76 alpha_ = alpha;
77 SchedulePaint();
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_; }
86 private:
87 // This class monitors mouse events to see if it is on top of the shelf.
88 class DimmerEventFilter : public ui::EventHandler {
89 public:
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;
97 private:
98 // The owning class.
99 DimmerView* owner_;
101 // TRUE if the mouse is inside the shelf.
102 bool mouse_inside_;
104 // TRUE if a touch event is inside the shelf.
105 bool touch_inside_;
107 DISALLOW_COPY_AND_ASSIGN(DimmerEventFilter);
110 // The owning shelf.
111 ash::ShelfWidget* shelf_;
113 // The alpha to use for covering the shelf.
114 int alpha_;
116 // True if the event filter claims that we should not be dimmed.
117 bool is_hovered_;
119 // True if someone forces us not to be dimmed (e.g. a menu is open).
120 bool force_hovered_;
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),
137 alpha_(kDimAlpha),
138 is_hovered_(false),
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
144 // animation.
145 background_animator_.SetPaintsBackground(false,
146 ash::BACKGROUND_CHANGE_IMMEDIATE);
147 SetHovered(false);
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) {
174 SkPaint paint;
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(
181 shelf_background,
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(),
196 width(),
197 height(),
198 false,
199 paint);
202 DimmerView::DimmerEventFilter::DimmerEventFilter(DimmerView* owner)
203 : owner_(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)
216 return;
218 gfx::Point screen_point(event->location());
219 ::wm::ConvertPointToScreen(static_cast<aura::Window*>(event->target()),
220 &screen_point);
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()),
233 &screen_point);
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 {
249 public:
250 ShelfWindowTargeter(aura::Window* container,
251 ShelfLayoutManager* shelf)
252 : wm::EasyResizeWindowTargeter(container, gfx::Insets(), gfx::Insets()),
253 shelf_(shelf) {
254 WillChangeVisibilityState(shelf_->visibility_state());
255 shelf_->AddObserver(this);
258 ~ShelfWindowTargeter() override {
259 // |shelf_| may have been destroyed by this time.
260 if (shelf_)
261 shelf_->RemoveObserver(this);
264 private:
265 gfx::Insets GetInsetsForAlignment(int distance,
266 ash::ShelfAlignment alignment) {
267 switch (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);
277 NOTREACHED();
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
295 // while hidden.
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);
310 } // namespace
312 namespace ash {
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 {
320 public:
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;
380 private:
381 ShelfWidget* shelf_;
382 scoped_ptr<views::Widget> dimmer_;
383 FocusCycler* focus_cycler_;
384 int alpha_;
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)
402 : shelf_(shelf),
403 focus_cycler_(NULL),
404 alpha_(0),
405 opaque_background_(ui::LAYER_SOLID_COLOR),
406 opaque_foreground_(ui::LAYER_SOLID_COLOR),
407 dimmer_view_(NULL),
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.
420 SetDimmed(false);
423 void ShelfWidget::DelegateView::SetDimmed(bool value) {
424 if (value == (dimmer_.get() != NULL))
425 return;
427 if (value) {
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");
444 dimmer_->Show();
445 shelf_->GetNativeView()->AddObserver(this);
446 } else {
447 // Some unit tests will come here with a destroyed window.
448 if (shelf_->GetNativeView())
449 shelf_->GetNativeView()->RemoveObserver(this);
450 dimmer_view_ = NULL;
451 dimmer_.reset(NULL);
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_);
462 ReorderLayers();
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(
471 shelf_background,
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());
478 SkPaint paint;
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()
488 : 0,
490 SHELF_ALIGNMENT_BOTTOM == shelf_->GetAlignment()
491 ? width() - dock_bounds.width()
492 : width(),
493 height(),
494 false,
495 paint);
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(
507 shelf_corner,
510 shelf_corner.width(),
511 shelf_corner.height(),
512 dock_bounds.x() > 0 ? dock_bounds.x() : dock_bounds.width() - height(),
514 height(),
515 height(),
516 false,
517 paint);
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(),
529 height(),
530 false,
531 paint);
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_)
545 return true;
546 // Allow to activate from the focus cycler.
547 if (focus_cycler_ && focus_cycler_->widget_activating() == GetWidget())
548 return true;
549 // Disallow activating in other cases, especially when using mouse.
550 return false;
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());
558 } else {
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());
574 if (dimmer_)
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) {
589 if (GetDimmed())
590 dimmer_view_->ForceUndimming(force);
593 int ShelfWidget::DelegateView::GetDimmingAlphaForTest() {
594 if (GetDimmed())
595 return dimmer_view_->get_dimming_alpha_for_test();
596 return -1;
599 gfx::Rect ShelfWidget::DelegateView::GetDimmerBoundsForTest() {
600 if (GetDimmed())
601 return dimmer_view_->GetBoundsInScreen();
602 return gfx::Rect();
605 void ShelfWidget::DelegateView::UpdateBackground(int alpha) {
606 alpha_ = alpha;
607 SchedulePaint();
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_;
623 Init(params);
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,
679 change_type);
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)
694 return;
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;
713 // static
714 bool ShelfWidget::ShelfAlignmentAllowed() {
715 if (Shell::GetInstance()->system_tray_delegate()->IsUserSupervised())
716 return false;
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:
727 return true;
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:
733 return false;
736 DCHECK(false);
737 return false;
740 ShelfAlignment ShelfWidget::GetAlignment() const {
741 return shelf_layout_manager_->GetAlignment();
744 void ShelfWidget::SetAlignment(ShelfAlignment alignment) {
745 if (shelf_)
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.
755 if (shelf_)
756 shelf_->SchedulePaint();
757 status_area_widget_->SchedulePaint();
760 bool ShelfWidget::GetDimsShelf() const {
761 return delegate_view_->GetDimmed();
764 void ShelfWidget::CreateShelf() {
765 if (shelf_)
766 return;
768 Shell* shell = Shell::GetInstance();
769 // This needs to be called before shelf_model().
770 ShelfDelegate* shelf_delegate = shell->GetShelfDelegate();
771 if (!shelf_delegate)
772 return; // Not ready to create Shelf.
774 shelf_.reset(
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();
781 shelf_->SetVisible(
782 shell->session_state_delegate()->IsActiveUserSessionStarted());
783 shelf_layout_manager_->LayoutShelf();
784 Show();
787 bool ShelfWidget::IsShelfVisible() const {
788 return shelf_.get() && shelf_->IsVisible();
791 void ShelfWidget::SetShelfVisibility(bool visible) {
792 if (shelf_)
793 shelf_->SetVisible(visible);
796 void ShelfWidget::SetFocusCycler(FocusCycler* focus_cycler) {
797 delegate_view_->set_focus_cycler(focus_cycler);
798 if (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,
817 bool active) {
818 activating_as_fallback_ = false;
819 if (active)
820 delegate_view_->SetPaneFocusAndFocusDefault();
821 else
822 delegate_view_->GetFocusManager()->ClearFocus();
825 int ShelfWidget::GetDimmingAlphaForTest() {
826 if (delegate_view_)
827 return delegate_view_->GetDimmingAlphaForTest();
828 return -1;
831 gfx::Rect ShelfWidget::GetDimmerBoundsForTest() {
832 if (delegate_view_)
833 return delegate_view_->GetDimmerBoundsForTest();
834 return gfx::Rect();
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;
847 } // namespace ash