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. 4 5 #include "ash/shelf/shelf_widget.h" 6 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" 41 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; 47 48 // The time to dim and un-dim. 49 const int kTimeToDimMs = 3000; // Slow in dimming. 50 const int kTimeToUnDimMs = 200; // Fast in activating. 51 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(); 62 63 // Called by |DimmerEventFilter| when the mouse |hovered| state changes. 64 void SetHovered(bool hovered); 65 66 // Force the dimmer to be undimmed. 67 void ForceUndimming(bool force); 68 69 // views::WidgetDelegate overrides: 70 virtual views::Widget* GetWidget() OVERRIDE { 71 return View::GetWidget(); 72 } 73 virtual const views::Widget* GetWidget() const OVERRIDE { 74 return View::GetWidget(); 75 } 76 77 // ash::BackgroundAnimatorDelegate overrides: 78 virtual void UpdateBackground(int alpha) OVERRIDE { 79 alpha_ = alpha; 80 SchedulePaint(); 81 } 82 83 // views::View overrides: 84 virtual void OnPaintBackground(gfx::Canvas* canvas) OVERRIDE; 85 86 // A function to test the current alpha used. 87 int get_dimming_alpha_for_test() { return alpha_; } 88 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(); 95 96 // Overridden from ui::EventHandler: 97 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE; 98 virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE; 99 100 private: 101 // The owning class. 102 DimmerView* owner_; 103 104 // TRUE if the mouse is inside the shelf. 105 bool mouse_inside_; 106 107 // TRUE if a touch event is inside the shelf. 108 bool touch_inside_; 109 110 DISALLOW_COPY_AND_ASSIGN(DimmerEventFilter); 111 }; 112 113 // The owning shelf. 114 ash::ShelfWidget* shelf_; 115 116 // The alpha to use for covering the shelf. 117 int alpha_; 118 119 // True if the event filter claims that we should not be dimmed. 120 bool is_hovered_; 121 122 // True if someone forces us not to be dimmed (e.g. a menu is open). 123 bool force_hovered_; 124 125 // True if animations should be suppressed for a test. 126 bool disable_dimming_animations_for_test_; 127 128 // The animator for the background transitions. 129 ash::BackgroundAnimator background_animator_; 130 131 // Notification of entering / exiting of the shelf area by mouse. 132 scoped_ptr<DimmerEventFilter> event_filter_; 133 134 DISALLOW_COPY_AND_ASSIGN(DimmerView); 135 }; 136 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); 151 } 152 153 DimmerView::~DimmerView() { 154 } 155 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); 166 } 167 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_); 174 } 175 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(); 181 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)); 190 } 191 paint.setAlpha(alpha_); 192 canvas->DrawImageInt(shelf_background, 193 0, 194 0, 195 shelf_background.width(), 196 shelf_background.height(), 197 0, 198 0, 199 width(), 200 height(), 201 false, 202 paint); 203 } 204 205 DimmerView::DimmerEventFilter::DimmerEventFilter(DimmerView* owner) 206 : owner_(owner), 207 mouse_inside_(false), 208 touch_inside_(false) { 209 ash::Shell::GetInstance()->AddPreTargetHandler(this); 210 } 211 212 DimmerView::DimmerEventFilter::~DimmerEventFilter() { 213 ash::Shell::GetInstance()->RemovePreTargetHandler(this); 214 } 215 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; 224 } 225 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()); 231 232 if (mouse_inside_ || touch_inside_ != mouse_inside_ || touch_inside) 233 owner_->SetHovered(mouse_inside_ || touch_inside); 234 touch_inside_ = touch_inside; 235 } 236 237 using ash::ShelfLayoutManager; 238 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); 251 } 252 253 virtual ~ShelfWindowTargeter() { 254 // |shelf_| may have been destroyed by this time. 255 if (shelf_) 256 shelf_->RemoveObserver(this); 257 } 258 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); 271 } 272 NOTREACHED(); 273 return gfx::Insets(); 274 } 275 276 // ash::ShelfLayoutManagerObserver: 277 virtual void WillDeleteShelf() OVERRIDE { 278 shelf_ = NULL; 279 } 280 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()); 297 } 298 299 set_mouse_extend(mouse_insets); 300 set_touch_extend(touch_insets); 301 } 302 303 ShelfLayoutManager* shelf_; 304 305 DISALLOW_COPY_AND_ASSIGN(ShelfWindowTargeter); 306 }; 307 308 } // namespace 309 310 namespace ash { 311 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(); 321 322 void set_focus_cycler(FocusCycler* focus_cycler) { 323 focus_cycler_ = focus_cycler; 324 } 325 FocusCycler* focus_cycler() { return focus_cycler_; } 326 327 ui::Layer* opaque_background() { return &opaque_background_; } 328 ui::Layer* opaque_foreground() { return &opaque_foreground_; } 329 330 // Set if the shelf area is dimmed (eg when a window is maximized). 331 void SetDimmed(bool dimmed); 332 bool GetDimmed() const; 333 334 void SetParentLayer(ui::Layer* layer); 335 336 // views::View overrides: 337 virtual void OnPaintBackground(gfx::Canvas* canvas) OVERRIDE; 338 339 // views::WidgetDelegateView overrides: 340 virtual views::Widget* GetWidget() OVERRIDE { 341 return View::GetWidget(); 342 } 343 virtual const views::Widget* GetWidget() const OVERRIDE { 344 return View::GetWidget(); 345 } 346 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; 352 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; 361 362 // BackgroundAnimatorDelegate overrides: 363 virtual void UpdateBackground(int alpha) OVERRIDE; 364 365 // Force the shelf to be presented in an undimmed state. 366 void ForceUndimming(bool force); 367 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(); 371 372 // A function to test the bounds of the dimming bar. Returns gfx::Rect() if 373 // the dimmer is inactive. 374 gfx::Rect GetDimmerBoundsForTest(); 375 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; 380 } 381 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_; 393 394 // The view which does the dimming. 395 DimmerView* dimmer_view_; 396 397 // True if dimming animations should be turned off. 398 bool disable_dimming_animations_for_test_; 399 400 DISALLOW_COPY_AND_ASSIGN(DelegateView); 401 }; 402 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); 418 } 419 420 ShelfWidget::DelegateView::~DelegateView() { 421 // Make sure that the dimmer goes away since it might have set an observer. 422 SetDimmed(false); 423 } 424 425 void ShelfWidget::DelegateView::SetDimmed(bool value) { 426 if (value == (dimmer_.get() != NULL)) 427 return; 428 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); 454 } 455 } 456 457 bool ShelfWidget::DelegateView::GetDimmed() const { 458 return dimmer_.get() && dimmer_->IsVisible(); 459 } 460 461 void ShelfWidget::DelegateView::SetParentLayer(ui::Layer* layer) { 462 layer->Add(&opaque_background_); 463 layer->Add(&opaque_foreground_); 464 ReorderLayers(); 465 } 466 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, 483 0, 484 0, 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, 491 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); 507 } 508 canvas->DrawImageInt( 509 shelf_corner, 510 0, 511 0, 512 shelf_corner.width(), 513 shelf_corner.height(), 514 dock_bounds.x() > 0 ? dock_bounds.x() : dock_bounds.width() - height(), 515 0, 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, 524 0, 525 shelf_background.height() - 1, 526 shelf_background.width(), 527 1, 528 dock_bounds.x() > 0 ? dock_bounds.x() + height() : 0, 529 0, 530 dock_bounds.width() - height(), 531 height(), 532 false, 533 paint); 534 } 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); 542 } 543 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; 553 } 554 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()); 563 } 564 } 565 } 566 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_); 571 } 572 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()); 578 } 579 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()); 588 } 589 590 void ShelfWidget::DelegateView::ForceUndimming(bool force) { 591 if (GetDimmed()) 592 dimmer_view_->ForceUndimming(force); 593 } 594 595 int ShelfWidget::DelegateView::GetDimmingAlphaForTest() { 596 if (GetDimmed()) 597 return dimmer_view_->get_dimming_alpha_for_test(); 598 return -1; 599 } 600 601 gfx::Rect ShelfWidget::DelegateView::GetDimmerBoundsForTest() { 602 if (GetDimmed()) 603 return dimmer_view_->GetBoundsInScreen(); 604 return gfx::Rect(); 605 } 606 607 void ShelfWidget::DelegateView::UpdateBackground(int alpha) { 608 alpha_ = alpha; 609 SchedulePaint(); 610 } 611 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); 626 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()); 631 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(); 637 } 638 Shell::GetInstance()->focus_cycler()->AddWidget(status_area_widget_); 639 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_); 645 646 status_container->SetLayoutManager( 647 new StatusAreaLayoutManager(status_container, this)); 648 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_))); 653 654 views::Widget::AddObserver(this); 655 } 656 657 ShelfWidget::~ShelfWidget() { 658 RemoveObserver(this); 659 } 660 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)); 673 } 674 opaque_background->SetOpacity(target_opacity); 675 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(); 683 } 684 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; 690 691 return SHELF_BACKGROUND_DEFAULT; 692 } 693 694 void ShelfWidget::HideShelfBehindBlackBar(bool hide, int animation_time_ms) { 695 if (IsShelfHiddenBehindBlackBar() == hide) 696 return; 697 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); 707 708 opaque_foreground->SetOpacity(target_opacity); 709 } 710 711 bool ShelfWidget::IsShelfHiddenBehindBlackBar() const { 712 return delegate_view_->opaque_foreground()->GetTargetOpacity() != 0.0f; 713 } 714 715 // static 716 bool ShelfWidget::ShelfAlignmentAllowed() { 717 if (Shell::GetInstance()->system_tray_delegate()->IsUserSupervised()) 718 return false; 719 720 user::LoginStatus login_status = 721 Shell::GetInstance()->system_tray_delegate()->GetUserLoginStatus(); 722 723 switch (login_status) { 724 case user::LOGGED_IN_USER: 725 case user::LOGGED_IN_OWNER: 726 return true; 727 case user::LOGGED_IN_LOCKED: 728 case user::LOGGED_IN_PUBLIC: 729 case user::LOGGED_IN_SUPERVISED: 730 case user::LOGGED_IN_GUEST: 731 case user::LOGGED_IN_RETAIL_MODE: 732 case user::LOGGED_IN_KIOSK_APP: 733 case user::LOGGED_IN_NONE: 734 return false; 735 } 736 737 DCHECK(false); 738 return false; 739 } 740 741 ShelfAlignment ShelfWidget::GetAlignment() const { 742 return shelf_layout_manager_->GetAlignment(); 743 } 744 745 void ShelfWidget::SetAlignment(ShelfAlignment alignment) { 746 if (shelf_) 747 shelf_->SetAlignment(alignment); 748 status_area_widget_->SetShelfAlignment(alignment); 749 delegate_view_->SchedulePaint(); 750 } 751 752 void ShelfWidget::SetDimsShelf(bool dimming) { 753 delegate_view_->SetDimmed(dimming); 754 // Repaint all children, allowing updates to reflect dimmed state eg: 755 // status area background, app list button and overflow button. 756 if (shelf_) 757 shelf_->SchedulePaint(); 758 status_area_widget_->SchedulePaint(); 759 } 760 761 bool ShelfWidget::GetDimsShelf() const { 762 return delegate_view_->GetDimmed(); 763 } 764 765 void ShelfWidget::CreateShelf() { 766 if (shelf_) 767 return; 768 769 Shell* shell = Shell::GetInstance(); 770 // This needs to be called before shelf_model(). 771 ShelfDelegate* shelf_delegate = shell->GetShelfDelegate(); 772 if (!shelf_delegate) 773 return; // Not ready to create Shelf. 774 775 shelf_.reset( 776 new Shelf(shell->shelf_model(), shell->GetShelfDelegate(), this)); 777 SetFocusCycler(shell->focus_cycler()); 778 779 // Inform the root window controller. 780 RootWindowController::ForWindow(window_container_)->OnShelfCreated(); 781 782 shelf_->SetVisible( 783 shell->session_state_delegate()->IsActiveUserSessionStarted()); 784 shelf_layout_manager_->LayoutShelf(); 785 Show(); 786 } 787 788 bool ShelfWidget::IsShelfVisible() const { 789 return shelf_.get() && shelf_->IsVisible(); 790 } 791 792 void ShelfWidget::SetShelfVisibility(bool visible) { 793 if (shelf_) 794 shelf_->SetVisible(visible); 795 } 796 797 void ShelfWidget::SetFocusCycler(FocusCycler* focus_cycler) { 798 delegate_view_->set_focus_cycler(focus_cycler); 799 if (focus_cycler) 800 focus_cycler->AddWidget(this); 801 } 802 803 FocusCycler* ShelfWidget::GetFocusCycler() { 804 return delegate_view_->focus_cycler(); 805 } 806 807 void ShelfWidget::ShutdownStatusAreaWidget() { 808 if (status_area_widget_) 809 status_area_widget_->Shutdown(); 810 status_area_widget_ = NULL; 811 } 812 813 void ShelfWidget::ForceUndimming(bool force) { 814 delegate_view_->ForceUndimming(force); 815 } 816 817 void ShelfWidget::OnWidgetActivationChanged(views::Widget* widget, 818 bool active) { 819 activating_as_fallback_ = false; 820 if (active) 821 delegate_view_->SetPaneFocusAndFocusDefault(); 822 else 823 delegate_view_->GetFocusManager()->ClearFocus(); 824 } 825 826 int ShelfWidget::GetDimmingAlphaForTest() { 827 if (delegate_view_) 828 return delegate_view_->GetDimmingAlphaForTest(); 829 return -1; 830 } 831 832 gfx::Rect ShelfWidget::GetDimmerBoundsForTest() { 833 if (delegate_view_) 834 return delegate_view_->GetDimmerBoundsForTest(); 835 return gfx::Rect(); 836 } 837 838 void ShelfWidget::DisableDimmingAnimationsForTest() { 839 DCHECK(delegate_view_); 840 return delegate_view_->disable_dimming_animations_for_test(); 841 } 842 843 void ShelfWidget::WillDeleteShelf() { 844 shelf_layout_manager_->RemoveObserver(this); 845 shelf_layout_manager_ = NULL; 846 } 847 848 } // namespace ash 849