Revert 221932 "Refactor KeySystems code to call a function to po..."
[chromium-blink-merge.git] / ash / shelf / shelf_layout_manager.cc
blobc3cf7f99fc944fd701a41c5a4b18b1c768546a7e
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_layout_manager.h"
7 #include <algorithm>
8 #include <cmath>
9 #include <cstring>
10 #include <string>
11 #include <vector>
13 #include "ash/ash_switches.h"
14 #include "ash/launcher/launcher.h"
15 #include "ash/launcher/launcher_types.h"
16 #include "ash/root_window_controller.h"
17 #include "ash/screen_ash.h"
18 #include "ash/session_state_delegate.h"
19 #include "ash/shelf/shelf_bezel_event_filter.h"
20 #include "ash/shelf/shelf_layout_manager_observer.h"
21 #include "ash/shelf/shelf_widget.h"
22 #include "ash/shell.h"
23 #include "ash/shell_window_ids.h"
24 #include "ash/system/status_area_widget.h"
25 #include "ash/wm/gestures/shelf_gesture_handler.h"
26 #include "ash/wm/mru_window_tracker.h"
27 #include "ash/wm/window_animations.h"
28 #include "ash/wm/window_properties.h"
29 #include "ash/wm/window_util.h"
30 #include "ash/wm/workspace_controller.h"
31 #include "base/auto_reset.h"
32 #include "base/command_line.h"
33 #include "base/command_line.h"
34 #include "base/i18n/rtl.h"
35 #include "base/strings/string_number_conversions.h"
36 #include "base/strings/string_util.h"
37 #include "ui/aura/client/activation_client.h"
38 #include "ui/aura/client/cursor_client.h"
39 #include "ui/aura/root_window.h"
40 #include "ui/base/events/event.h"
41 #include "ui/base/events/event_handler.h"
42 #include "ui/base/ui_base_switches.h"
43 #include "ui/compositor/layer.h"
44 #include "ui/compositor/layer_animation_observer.h"
45 #include "ui/compositor/layer_animator.h"
46 #include "ui/compositor/scoped_layer_animation_settings.h"
47 #include "ui/gfx/screen.h"
48 #include "ui/views/widget/widget.h"
50 namespace ash {
51 namespace internal {
53 namespace {
55 // Delay before showing the launcher. This is after the mouse stops moving.
56 const int kAutoHideDelayMS = 200;
58 // To avoid hiding the shelf when the mouse transitions from a message bubble
59 // into the shelf, the hit test area is enlarged by this amount of pixels to
60 // keep the shelf from hiding.
61 const int kNotificationBubbleGapHeight = 6;
63 // The maximum size of the region on the display opposing the shelf managed by
64 // this ShelfLayoutManager which can trigger showing the shelf.
65 // For instance:
66 // - Primary display is left of secondary display.
67 // - Shelf is left aligned
68 // - This ShelfLayoutManager manages the shelf for the secondary display.
69 // |kMaxAutoHideShowShelfRegionSize| refers to the maximum size of the region
70 // from the right edge of the primary display which can trigger showing the
71 // auto hidden shelf. The region is used to make it easier to trigger showing
72 // the auto hidden shelf when the shelf is on the boundary between displays.
73 const int kMaxAutoHideShowShelfRegionSize = 10;
75 // Const inset from the edget of the shelf to the edget of the status area.
76 const int kStatusAreaInset = 3;
78 ui::Layer* GetLayer(views::Widget* widget) {
79 return widget->GetNativeView()->layer();
82 bool IsDraggingTrayEnabled() {
83 static bool dragging_tray_allowed = CommandLine::ForCurrentProcess()->
84 HasSwitch(ash::switches::kAshEnableTrayDragging);
85 return dragging_tray_allowed;
88 } // namespace
90 // static
91 const int ShelfLayoutManager::kWorkspaceAreaVisibleInset = 2;
93 // static
94 const int ShelfLayoutManager::kWorkspaceAreaAutoHideInset = 5;
96 // static
97 const int ShelfLayoutManager::kAutoHideSize = 3;
99 // static
100 const int ShelfLayoutManager::kShelfSize = 47;
102 int ShelfLayoutManager::GetPreferredShelfSize() {
103 return ash::switches::UseAlternateShelfLayout() ?
104 ShelfLayoutManager::kShelfSize : kLauncherPreferredSize;
107 // ShelfLayoutManager::AutoHideEventFilter -------------------------------------
109 // Notifies ShelfLayoutManager any time the mouse moves.
110 class ShelfLayoutManager::AutoHideEventFilter : public ui::EventHandler {
111 public:
112 explicit AutoHideEventFilter(ShelfLayoutManager* shelf);
113 virtual ~AutoHideEventFilter();
115 // Returns true if the last mouse event was a mouse drag.
116 bool in_mouse_drag() const { return in_mouse_drag_; }
118 // Overridden from ui::EventHandler:
119 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
120 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
122 private:
123 ShelfLayoutManager* shelf_;
124 bool in_mouse_drag_;
125 ShelfGestureHandler gesture_handler_;
126 DISALLOW_COPY_AND_ASSIGN(AutoHideEventFilter);
129 ShelfLayoutManager::AutoHideEventFilter::AutoHideEventFilter(
130 ShelfLayoutManager* shelf)
131 : shelf_(shelf),
132 in_mouse_drag_(false) {
133 Shell::GetInstance()->AddPreTargetHandler(this);
136 ShelfLayoutManager::AutoHideEventFilter::~AutoHideEventFilter() {
137 Shell::GetInstance()->RemovePreTargetHandler(this);
140 void ShelfLayoutManager::AutoHideEventFilter::OnMouseEvent(
141 ui::MouseEvent* event) {
142 // This also checks IsShelfWindow() to make sure we don't attempt to hide the
143 // shelf if the mouse down occurs on the shelf.
144 in_mouse_drag_ = (event->type() == ui::ET_MOUSE_DRAGGED ||
145 (in_mouse_drag_ && event->type() != ui::ET_MOUSE_RELEASED &&
146 event->type() != ui::ET_MOUSE_CAPTURE_CHANGED)) &&
147 !shelf_->IsShelfWindow(static_cast<aura::Window*>(event->target()));
148 if (event->type() == ui::ET_MOUSE_MOVED)
149 shelf_->UpdateAutoHideState();
150 return;
153 void ShelfLayoutManager::AutoHideEventFilter::OnGestureEvent(
154 ui::GestureEvent* event) {
155 if (shelf_->IsShelfWindow(static_cast<aura::Window*>(event->target()))) {
156 if (gesture_handler_.ProcessGestureEvent(*event))
157 event->StopPropagation();
161 // ShelfLayoutManager:UpdateShelfObserver --------------------------------------
163 // UpdateShelfObserver is used to delay updating the background until the
164 // animation completes.
165 class ShelfLayoutManager::UpdateShelfObserver
166 : public ui::ImplicitAnimationObserver {
167 public:
168 explicit UpdateShelfObserver(ShelfLayoutManager* shelf) : shelf_(shelf) {
169 shelf_->update_shelf_observer_ = this;
172 void Detach() {
173 shelf_ = NULL;
176 virtual void OnImplicitAnimationsCompleted() OVERRIDE {
177 if (shelf_) {
178 shelf_->UpdateShelfBackground(BackgroundAnimator::CHANGE_ANIMATE);
180 delete this;
183 private:
184 virtual ~UpdateShelfObserver() {
185 if (shelf_)
186 shelf_->update_shelf_observer_ = NULL;
189 // Shelf we're in. NULL if deleted before we're deleted.
190 ShelfLayoutManager* shelf_;
192 DISALLOW_COPY_AND_ASSIGN(UpdateShelfObserver);
195 // ShelfLayoutManager ----------------------------------------------------------
197 ShelfLayoutManager::ShelfLayoutManager(ShelfWidget* shelf)
198 : root_window_(shelf->GetNativeView()->GetRootWindow()),
199 updating_bounds_(false),
200 auto_hide_behavior_(SHELF_AUTO_HIDE_BEHAVIOR_NEVER),
201 alignment_(SHELF_ALIGNMENT_BOTTOM),
202 shelf_(shelf),
203 workspace_controller_(NULL),
204 window_overlaps_shelf_(false),
205 mouse_over_shelf_when_auto_hide_timer_started_(false),
206 bezel_event_filter_(new ShelfBezelEventFilter(this)),
207 gesture_drag_status_(GESTURE_DRAG_NONE),
208 gesture_drag_amount_(0.f),
209 gesture_drag_auto_hide_state_(SHELF_AUTO_HIDE_SHOWN),
210 update_shelf_observer_(NULL) {
211 Shell::GetInstance()->AddShellObserver(this);
212 aura::client::GetActivationClient(root_window_)->AddObserver(this);
215 ShelfLayoutManager::~ShelfLayoutManager() {
216 if (update_shelf_observer_)
217 update_shelf_observer_->Detach();
219 FOR_EACH_OBSERVER(ShelfLayoutManagerObserver, observers_, WillDeleteShelf());
220 Shell::GetInstance()->RemoveShellObserver(this);
221 aura::client::GetActivationClient(root_window_)->RemoveObserver(this);
224 void ShelfLayoutManager::SetAutoHideBehavior(ShelfAutoHideBehavior behavior) {
225 if (auto_hide_behavior_ == behavior)
226 return;
227 auto_hide_behavior_ = behavior;
228 UpdateVisibilityState();
229 FOR_EACH_OBSERVER(ShelfLayoutManagerObserver, observers_,
230 OnAutoHideBehaviorChanged(root_window_,
231 auto_hide_behavior_));
234 void ShelfLayoutManager::PrepareForShutdown() {
235 // Clear all event filters, otherwise sometimes those filters may catch
236 // synthesized mouse event and cause crashes during the shutdown.
237 set_workspace_controller(NULL);
238 auto_hide_event_filter_.reset();
239 bezel_event_filter_.reset();
242 bool ShelfLayoutManager::IsVisible() const {
243 // status_area_widget() may be NULL during the shutdown.
244 return shelf_->status_area_widget() &&
245 shelf_->status_area_widget()->IsVisible() &&
246 (state_.visibility_state == SHELF_VISIBLE ||
247 (state_.visibility_state == SHELF_AUTO_HIDE &&
248 state_.auto_hide_state == SHELF_AUTO_HIDE_SHOWN));
251 bool ShelfLayoutManager::SetAlignment(ShelfAlignment alignment) {
252 if (alignment_ == alignment)
253 return false;
255 alignment_ = alignment;
256 shelf_->SetAlignment(alignment);
257 LayoutShelf();
258 return true;
261 gfx::Rect ShelfLayoutManager::GetIdealBounds() {
262 gfx::Rect bounds(
263 ScreenAsh::GetDisplayBoundsInParent(shelf_->GetNativeView()));
264 int width = 0, height = 0;
265 GetShelfSize(&width, &height);
266 return SelectValueForShelfAlignment(
267 gfx::Rect(bounds.x(), bounds.bottom() - height, bounds.width(), height),
268 gfx::Rect(bounds.x(), bounds.y(), width, bounds.height()),
269 gfx::Rect(bounds.right() - width, bounds.y(), width, bounds.height()),
270 gfx::Rect(bounds.x(), bounds.y(), bounds.width(), height));
273 void ShelfLayoutManager::LayoutShelf() {
274 TargetBounds target_bounds;
275 CalculateTargetBounds(state_, &target_bounds);
276 UpdateBoundsAndOpacity(target_bounds, false, NULL);
278 if (shelf_->launcher()) {
279 // This is not part of UpdateBoundsAndOpacity() because
280 // SetLauncherViewBounds() sets the bounds immediately and does not animate.
281 // The height of the LauncherView for a horizontal shelf and the width of
282 // the LauncherView for a vertical shelf are set when |shelf_|'s bounds
283 // are changed via UpdateBoundsAndOpacity(). This sets the origin and the
284 // dimension in the other direction.
285 shelf_->launcher()->SetLauncherViewBounds(
286 target_bounds.launcher_bounds_in_shelf);
290 ShelfVisibilityState ShelfLayoutManager::CalculateShelfVisibility() {
291 switch(auto_hide_behavior_) {
292 case SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS:
293 return SHELF_AUTO_HIDE;
294 case SHELF_AUTO_HIDE_BEHAVIOR_NEVER:
295 return SHELF_VISIBLE;
296 case SHELF_AUTO_HIDE_ALWAYS_HIDDEN:
297 return SHELF_HIDDEN;
299 return SHELF_VISIBLE;
302 void ShelfLayoutManager::UpdateVisibilityState() {
303 if (Shell::GetInstance()->session_state_delegate()->IsScreenLocked()) {
304 SetState(SHELF_VISIBLE);
305 } else {
306 // TODO(zelidrag): Verify shelf drag animation still shows on the device
307 // when we are in SHELF_AUTO_HIDE_ALWAYS_HIDDEN.
308 WorkspaceWindowState window_state(workspace_controller_->GetWindowState());
309 switch (window_state) {
310 case WORKSPACE_WINDOW_STATE_FULL_SCREEN:
311 if (FullscreenWithMinimalChrome()) {
312 SetState(SHELF_AUTO_HIDE);
313 } else {
314 SetState(SHELF_HIDDEN);
316 break;
317 case WORKSPACE_WINDOW_STATE_MAXIMIZED:
318 SetState(CalculateShelfVisibility());
319 break;
320 case WORKSPACE_WINDOW_STATE_WINDOW_OVERLAPS_SHELF:
321 case WORKSPACE_WINDOW_STATE_DEFAULT:
322 SetState(CalculateShelfVisibility());
323 SetWindowOverlapsShelf(window_state ==
324 WORKSPACE_WINDOW_STATE_WINDOW_OVERLAPS_SHELF);
325 break;
330 void ShelfLayoutManager::UpdateAutoHideState() {
331 ShelfAutoHideState auto_hide_state =
332 CalculateAutoHideState(state_.visibility_state);
333 if (auto_hide_state != state_.auto_hide_state) {
334 if (auto_hide_state == SHELF_AUTO_HIDE_HIDDEN) {
335 // Hides happen immediately.
336 SetState(state_.visibility_state);
337 } else {
338 if (!auto_hide_timer_.IsRunning()) {
339 mouse_over_shelf_when_auto_hide_timer_started_ =
340 shelf_->GetWindowBoundsInScreen().Contains(
341 Shell::GetScreen()->GetCursorScreenPoint());
343 auto_hide_timer_.Start(
344 FROM_HERE,
345 base::TimeDelta::FromMilliseconds(kAutoHideDelayMS),
346 this, &ShelfLayoutManager::UpdateAutoHideStateNow);
348 } else {
349 StopAutoHideTimer();
353 void ShelfLayoutManager::SetWindowOverlapsShelf(bool value) {
354 window_overlaps_shelf_ = value;
355 UpdateShelfBackground(BackgroundAnimator::CHANGE_ANIMATE);
358 void ShelfLayoutManager::AddObserver(ShelfLayoutManagerObserver* observer) {
359 observers_.AddObserver(observer);
362 void ShelfLayoutManager::RemoveObserver(ShelfLayoutManagerObserver* observer) {
363 observers_.RemoveObserver(observer);
366 ////////////////////////////////////////////////////////////////////////////////
367 // ShelfLayoutManager, Gesture dragging:
369 void ShelfLayoutManager::StartGestureDrag(const ui::GestureEvent& gesture) {
370 gesture_drag_status_ = GESTURE_DRAG_IN_PROGRESS;
371 gesture_drag_amount_ = 0.f;
372 gesture_drag_auto_hide_state_ = visibility_state() == SHELF_AUTO_HIDE ?
373 auto_hide_state() : SHELF_AUTO_HIDE_SHOWN;
374 UpdateShelfBackground(BackgroundAnimator::CHANGE_ANIMATE);
377 ShelfLayoutManager::DragState ShelfLayoutManager::UpdateGestureDrag(
378 const ui::GestureEvent& gesture) {
379 bool horizontal = IsHorizontalAlignment();
380 gesture_drag_amount_ += horizontal ? gesture.details().scroll_y() :
381 gesture.details().scroll_x();
382 LayoutShelf();
384 // Start reveling the status menu when:
385 // - dragging up on an already visible shelf
386 // - dragging up on a hidden shelf, but it is currently completely visible.
387 if (horizontal && gesture.details().scroll_y() < 0) {
388 int min_height = 0;
389 if (gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_HIDDEN && shelf_)
390 min_height = shelf_->GetContentsView()->GetPreferredSize().height();
392 if (min_height < shelf_->GetWindowBoundsInScreen().height() &&
393 gesture.root_location().x() >=
394 shelf_->status_area_widget()->GetWindowBoundsInScreen().x() &&
395 IsDraggingTrayEnabled())
396 return DRAG_TRAY;
399 return DRAG_SHELF;
402 void ShelfLayoutManager::CompleteGestureDrag(const ui::GestureEvent& gesture) {
403 bool horizontal = IsHorizontalAlignment();
404 bool should_change = false;
405 if (gesture.type() == ui::ET_GESTURE_SCROLL_END) {
406 // The visibility of the shelf changes only if the shelf was dragged X%
407 // along the correct axis. If the shelf was already visible, then the
408 // direction of the drag does not matter.
409 const float kDragHideThreshold = 0.4f;
410 gfx::Rect bounds = GetIdealBounds();
411 float drag_ratio = fabs(gesture_drag_amount_) /
412 (horizontal ? bounds.height() : bounds.width());
413 if (gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_SHOWN) {
414 should_change = drag_ratio > kDragHideThreshold;
415 } else {
416 bool correct_direction = false;
417 switch (alignment_) {
418 case SHELF_ALIGNMENT_BOTTOM:
419 case SHELF_ALIGNMENT_RIGHT:
420 correct_direction = gesture_drag_amount_ < 0;
421 break;
422 case SHELF_ALIGNMENT_LEFT:
423 case SHELF_ALIGNMENT_TOP:
424 correct_direction = gesture_drag_amount_ > 0;
425 break;
427 should_change = correct_direction && drag_ratio > kDragHideThreshold;
429 } else if (gesture.type() == ui::ET_SCROLL_FLING_START) {
430 if (gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_SHOWN) {
431 should_change = horizontal ? fabs(gesture.details().velocity_y()) > 0 :
432 fabs(gesture.details().velocity_x()) > 0;
433 } else {
434 should_change = SelectValueForShelfAlignment(
435 gesture.details().velocity_y() < 0,
436 gesture.details().velocity_x() > 0,
437 gesture.details().velocity_x() < 0,
438 gesture.details().velocity_y() > 0);
440 } else {
441 NOTREACHED();
444 if (!should_change) {
445 CancelGestureDrag();
446 return;
448 if (shelf_) {
449 shelf_->Deactivate();
450 shelf_->status_area_widget()->Deactivate();
452 gesture_drag_auto_hide_state_ =
453 gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_SHOWN ?
454 SHELF_AUTO_HIDE_HIDDEN : SHELF_AUTO_HIDE_SHOWN;
455 ShelfAutoHideBehavior new_auto_hide_behavior =
456 gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_SHOWN ?
457 SHELF_AUTO_HIDE_BEHAVIOR_NEVER : SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS;
459 // In fullscreen with minimal chrome, the auto hide behavior affects neither
460 // the visibility state nor the auto hide state. Set |gesture_drag_status_|
461 // to GESTURE_DRAG_COMPLETE_IN_PROGRESS to set the auto hide state to
462 // |gesture_drag_auto_hide_state_|.
463 gesture_drag_status_ = GESTURE_DRAG_COMPLETE_IN_PROGRESS;
464 if (auto_hide_behavior_ != new_auto_hide_behavior)
465 SetAutoHideBehavior(new_auto_hide_behavior);
466 else
467 UpdateVisibilityState();
468 gesture_drag_status_ = GESTURE_DRAG_NONE;
471 void ShelfLayoutManager::CancelGestureDrag() {
472 gesture_drag_status_ = GESTURE_DRAG_CANCEL_IN_PROGRESS;
473 UpdateVisibilityState();
474 gesture_drag_status_ = GESTURE_DRAG_NONE;
477 ////////////////////////////////////////////////////////////////////////////////
478 // ShelfLayoutManager, aura::LayoutManager implementation:
480 void ShelfLayoutManager::OnWindowResized() {
481 LayoutShelf();
484 void ShelfLayoutManager::OnWindowAddedToLayout(aura::Window* child) {
487 void ShelfLayoutManager::OnWillRemoveWindowFromLayout(aura::Window* child) {
490 void ShelfLayoutManager::OnWindowRemovedFromLayout(aura::Window* child) {
493 void ShelfLayoutManager::OnChildWindowVisibilityChanged(aura::Window* child,
494 bool visible) {
497 void ShelfLayoutManager::SetChildBounds(aura::Window* child,
498 const gfx::Rect& requested_bounds) {
499 SetChildBoundsDirect(child, requested_bounds);
500 // We may contain other widgets (such as frame maximize bubble) but they don't
501 // effect the layout in anyway.
502 if (!updating_bounds_ &&
503 ((shelf_->GetNativeView() == child) ||
504 (shelf_->status_area_widget()->GetNativeView() == child))) {
505 LayoutShelf();
509 void ShelfLayoutManager::OnLockStateChanged(bool locked) {
510 UpdateVisibilityState();
513 void ShelfLayoutManager::OnWindowActivated(aura::Window* gained_active,
514 aura::Window* lost_active) {
515 UpdateAutoHideStateNow();
518 bool ShelfLayoutManager::IsHorizontalAlignment() const {
519 return alignment_ == SHELF_ALIGNMENT_BOTTOM ||
520 alignment_ == SHELF_ALIGNMENT_TOP;
523 bool ShelfLayoutManager::FullscreenWithMinimalChrome() const {
524 RootWindowController* controller = GetRootWindowController(root_window_);
525 if (!controller)
526 return false;
527 const aura::Window* window = controller->GetTopmostFullscreenWindow();
528 if (!window)
529 return false;
530 if (!window->GetProperty(kFullscreenUsesMinimalChromeKey))
531 return false;
532 return true;
535 // static
536 ShelfLayoutManager* ShelfLayoutManager::ForLauncher(aura::Window* window) {
537 ShelfWidget* shelf = RootWindowController::ForLauncher(window)->shelf();
538 return shelf ? shelf->shelf_layout_manager() : NULL;
541 ////////////////////////////////////////////////////////////////////////////////
542 // ShelfLayoutManager, private:
544 ShelfLayoutManager::TargetBounds::TargetBounds() : opacity(0.0f) {}
545 ShelfLayoutManager::TargetBounds::~TargetBounds() {}
547 void ShelfLayoutManager::SetState(ShelfVisibilityState visibility_state) {
548 if (!shelf_->GetNativeView())
549 return;
551 State state;
552 state.visibility_state = visibility_state;
553 state.auto_hide_state = CalculateAutoHideState(visibility_state);
554 state.is_screen_locked =
555 Shell::GetInstance()->session_state_delegate()->IsScreenLocked();
556 state.window_state = workspace_controller_ ?
557 workspace_controller_->GetWindowState() : WORKSPACE_WINDOW_STATE_DEFAULT;
559 // Force an update because gesture drags affect the shelf bounds and we
560 // should animate back to the normal bounds at the end of a gesture.
561 bool force_update =
562 (gesture_drag_status_ == GESTURE_DRAG_CANCEL_IN_PROGRESS ||
563 gesture_drag_status_ == GESTURE_DRAG_COMPLETE_IN_PROGRESS);
565 if (!force_update && state_.Equals(state))
566 return; // Nothing changed.
568 FOR_EACH_OBSERVER(ShelfLayoutManagerObserver, observers_,
569 WillChangeVisibilityState(visibility_state));
571 if (state.visibility_state == SHELF_AUTO_HIDE) {
572 // When state is SHELF_AUTO_HIDE we need to track when the mouse is over the
573 // launcher to unhide the shelf. AutoHideEventFilter does that for us.
574 if (!auto_hide_event_filter_)
575 auto_hide_event_filter_.reset(new AutoHideEventFilter(this));
576 } else {
577 auto_hide_event_filter_.reset(NULL);
580 StopAutoHideTimer();
582 State old_state = state_;
583 state_ = state;
585 BackgroundAnimator::ChangeType change_type =
586 BackgroundAnimator::CHANGE_ANIMATE;
587 bool delay_background_change = false;
589 // Do not animate the background when:
590 // - Going from a hidden / auto hidden shelf in fullscreen to a visible shelf
591 // in maximized mode.
592 // - Going from an auto hidden shelf in maximized mode to a visible shelf in
593 // maximized mode.
594 if (state.visibility_state == SHELF_VISIBLE &&
595 state.window_state == WORKSPACE_WINDOW_STATE_MAXIMIZED &&
596 old_state.visibility_state != SHELF_VISIBLE) {
597 change_type = BackgroundAnimator::CHANGE_IMMEDIATE;
598 } else {
599 // Delay the animation when the shelf was hidden, and has just been made
600 // visible (e.g. using a gesture-drag).
601 if (state.visibility_state == SHELF_VISIBLE &&
602 old_state.visibility_state == SHELF_AUTO_HIDE &&
603 old_state.auto_hide_state == SHELF_AUTO_HIDE_HIDDEN) {
604 delay_background_change = true;
608 if (delay_background_change) {
609 if (update_shelf_observer_)
610 update_shelf_observer_->Detach();
611 // UpdateShelfBackground deletes itself when the animation is done.
612 update_shelf_observer_ = new UpdateShelfObserver(this);
613 } else {
614 UpdateShelfBackground(change_type);
617 shelf_->SetDimsShelf(
618 state.visibility_state == SHELF_VISIBLE &&
619 state.window_state == WORKSPACE_WINDOW_STATE_MAXIMIZED);
621 TargetBounds target_bounds;
622 CalculateTargetBounds(state_, &target_bounds);
623 UpdateBoundsAndOpacity(target_bounds, true,
624 delay_background_change ? update_shelf_observer_ : NULL);
626 // OnAutoHideStateChanged Should be emitted when:
627 // - firstly state changed to auto-hide from other state
628 // - or, auto_hide_state has changed
629 if ((old_state.visibility_state != state_.visibility_state &&
630 state_.visibility_state == SHELF_AUTO_HIDE) ||
631 old_state.auto_hide_state != state_.auto_hide_state) {
632 FOR_EACH_OBSERVER(ShelfLayoutManagerObserver, observers_,
633 OnAutoHideStateChanged(state_.auto_hide_state));
637 void ShelfLayoutManager::UpdateBoundsAndOpacity(
638 const TargetBounds& target_bounds,
639 bool animate,
640 ui::ImplicitAnimationObserver* observer) {
641 base::AutoReset<bool> auto_reset_updating_bounds(&updating_bounds_, true);
643 ui::ScopedLayerAnimationSettings launcher_animation_setter(
644 GetLayer(shelf_)->GetAnimator());
645 ui::ScopedLayerAnimationSettings status_animation_setter(
646 GetLayer(shelf_->status_area_widget())->GetAnimator());
647 if (animate) {
648 launcher_animation_setter.SetTransitionDuration(
649 base::TimeDelta::FromMilliseconds(kCrossFadeDurationMS));
650 launcher_animation_setter.SetTweenType(ui::Tween::EASE_OUT);
651 launcher_animation_setter.SetPreemptionStrategy(
652 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
653 status_animation_setter.SetTransitionDuration(
654 base::TimeDelta::FromMilliseconds(kCrossFadeDurationMS));
655 status_animation_setter.SetTweenType(ui::Tween::EASE_OUT);
656 status_animation_setter.SetPreemptionStrategy(
657 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
658 } else {
659 StopAnimating();
660 launcher_animation_setter.SetTransitionDuration(base::TimeDelta());
661 status_animation_setter.SetTransitionDuration(base::TimeDelta());
663 if (observer)
664 status_animation_setter.AddObserver(observer);
666 GetLayer(shelf_)->SetOpacity(target_bounds.opacity);
667 shelf_->SetBounds(ScreenAsh::ConvertRectToScreen(
668 shelf_->GetNativeView()->parent(),
669 target_bounds.shelf_bounds_in_root));
671 GetLayer(shelf_->status_area_widget())->SetOpacity(
672 target_bounds.status_opacity);
673 // TODO(harrym): Once status area widget is a child view of shelf
674 // this can be simplified.
675 gfx::Rect status_bounds = target_bounds.status_bounds_in_shelf;
676 status_bounds.set_x(status_bounds.x() +
677 target_bounds.shelf_bounds_in_root.x());
678 status_bounds.set_y(status_bounds.y() +
679 target_bounds.shelf_bounds_in_root.y());
680 shelf_->status_area_widget()->SetBounds(
681 ScreenAsh::ConvertRectToScreen(
682 shelf_->status_area_widget()->GetNativeView()->parent(),
683 status_bounds));
684 Shell::GetInstance()->SetDisplayWorkAreaInsets(
685 root_window_, target_bounds.work_area_insets);
686 UpdateHitTestBounds();
689 void ShelfLayoutManager::StopAnimating() {
690 GetLayer(shelf_)->GetAnimator()->StopAnimating();
691 GetLayer(shelf_->status_area_widget())->GetAnimator()->StopAnimating();
694 void ShelfLayoutManager::GetShelfSize(int* width, int* height) {
695 *width = *height = 0;
696 gfx::Size status_size(
697 shelf_->status_area_widget()->GetWindowBoundsInScreen().size());
698 if (IsHorizontalAlignment())
699 *height = GetPreferredShelfSize();
700 else
701 *width = GetPreferredShelfSize();
704 void ShelfLayoutManager::AdjustBoundsBasedOnAlignment(int inset,
705 gfx::Rect* bounds) const {
706 bounds->Inset(SelectValueForShelfAlignment(
707 gfx::Insets(0, 0, inset, 0),
708 gfx::Insets(0, inset, 0, 0),
709 gfx::Insets(0, 0, 0, inset),
710 gfx::Insets(inset, 0, 0, 0)));
713 void ShelfLayoutManager::CalculateTargetBounds(
714 const State& state,
715 TargetBounds* target_bounds) {
716 const gfx::Rect available_bounds(GetAvailableBounds());
717 gfx::Rect status_size(
718 shelf_->status_area_widget()->GetWindowBoundsInScreen().size());
719 int shelf_width = 0, shelf_height = 0;
720 GetShelfSize(&shelf_width, &shelf_height);
721 if (IsHorizontalAlignment())
722 shelf_width = available_bounds.width();
723 else
724 shelf_height = available_bounds.height();
726 if (state.visibility_state == SHELF_AUTO_HIDE &&
727 state.auto_hide_state == SHELF_AUTO_HIDE_HIDDEN) {
728 // Auto-hidden shelf always starts with the default size. If a gesture-drag
729 // is in progress, then the call to UpdateTargetBoundsForGesture() below
730 // takes care of setting the height properly.
731 if (IsHorizontalAlignment())
732 shelf_height = kAutoHideSize;
733 else
734 shelf_width = kAutoHideSize;
735 } else if (state.visibility_state == SHELF_HIDDEN ||
736 !keyboard_bounds_.IsEmpty()) {
737 if (IsHorizontalAlignment())
738 shelf_height = 0;
739 else
740 shelf_width = 0;
743 target_bounds->shelf_bounds_in_root = SelectValueForShelfAlignment(
744 gfx::Rect(available_bounds.x(), available_bounds.bottom() - shelf_height,
745 available_bounds.width(), shelf_height),
746 gfx::Rect(available_bounds.x(), available_bounds.y(),
747 shelf_width, available_bounds.height()),
748 gfx::Rect(available_bounds.right() - shelf_width, available_bounds.y(),
749 shelf_width, available_bounds.height()),
750 gfx::Rect(available_bounds.x(), available_bounds.y(),
751 available_bounds.width(), shelf_height));
753 int status_inset = std::max(0, GetPreferredShelfSize() -
754 PrimaryAxisValue(status_size.height(), status_size.width()));
756 if (ash::switches::UseAlternateShelfLayout())
757 status_inset = kStatusAreaInset;
759 target_bounds->status_bounds_in_shelf = SelectValueForShelfAlignment(
760 gfx::Rect(base::i18n::IsRTL() ? 0 : shelf_width - status_size.width(),
761 status_inset, status_size.width(), status_size.height()),
762 gfx::Rect(shelf_width - (status_size.width() + status_inset),
763 shelf_height - status_size.height(), status_size.width(),
764 status_size.height()),
765 gfx::Rect(status_inset, shelf_height - status_size.height(),
766 status_size.width(), status_size.height()),
767 gfx::Rect(base::i18n::IsRTL() ? 0 : shelf_width - status_size.width(),
768 shelf_height - (status_size.height() + status_inset),
769 status_size.width(), status_size.height()));
771 target_bounds->work_area_insets = SelectValueForShelfAlignment(
772 gfx::Insets(0, 0, GetWorkAreaSize(state, shelf_height), 0),
773 gfx::Insets(0, GetWorkAreaSize(state, shelf_width), 0, 0),
774 gfx::Insets(0, 0, 0, GetWorkAreaSize(state, shelf_width)),
775 gfx::Insets(GetWorkAreaSize(state, shelf_height), 0, 0, 0));
777 // TODO(varkha): The functionality of managing insets for display areas
778 // should probably be pushed to a separate component. This would simplify or
779 // remove entirely the dependency on keyboard and dock.
781 // Also push in the work area inset for the keyboard if it is visible.
782 if (!keyboard_bounds_.IsEmpty()) {
783 gfx::Insets keyboard_insets(0, 0, keyboard_bounds_.height(), 0);
784 target_bounds->work_area_insets += keyboard_insets;
787 // Also push in the work area inset for the dock if it is visible.
788 if (!dock_bounds_.IsEmpty()) {
789 gfx::Insets dock_insets(
790 0, (dock_bounds_.x() > 0 ? 0 : dock_bounds_.width()),
791 0, (dock_bounds_.x() > 0 ? dock_bounds_.width() : 0));
792 target_bounds->work_area_insets += dock_insets;
795 target_bounds->opacity =
796 (gesture_drag_status_ == GESTURE_DRAG_IN_PROGRESS ||
797 state.visibility_state == SHELF_VISIBLE ||
798 state.visibility_state == SHELF_AUTO_HIDE) ? 1.0f : 0.0f;
799 target_bounds->status_opacity =
800 (state.visibility_state == SHELF_AUTO_HIDE &&
801 state.auto_hide_state == SHELF_AUTO_HIDE_HIDDEN &&
802 gesture_drag_status_ != GESTURE_DRAG_IN_PROGRESS) ?
803 0.0f : target_bounds->opacity;
805 if (gesture_drag_status_ == GESTURE_DRAG_IN_PROGRESS)
806 UpdateTargetBoundsForGesture(target_bounds);
808 // This needs to happen after calling UpdateTargetBoundsForGesture(), because
809 // that can change the size of the shelf.
810 target_bounds->launcher_bounds_in_shelf = SelectValueForShelfAlignment(
811 gfx::Rect(base::i18n::IsRTL() ? status_size.width() : 0, 0,
812 shelf_width - status_size.width(),
813 target_bounds->shelf_bounds_in_root.height()),
814 gfx::Rect(0, 0, target_bounds->shelf_bounds_in_root.width(),
815 shelf_height - status_size.height()),
816 gfx::Rect(0, 0, target_bounds->shelf_bounds_in_root.width(),
817 shelf_height - status_size.height()),
818 gfx::Rect(base::i18n::IsRTL() ? status_size.width() : 0, 0,
819 shelf_width - status_size.width(),
820 target_bounds->shelf_bounds_in_root.height()));
823 void ShelfLayoutManager::UpdateTargetBoundsForGesture(
824 TargetBounds* target_bounds) const {
825 CHECK_EQ(GESTURE_DRAG_IN_PROGRESS, gesture_drag_status_);
826 bool horizontal = IsHorizontalAlignment();
827 const gfx::Rect& available_bounds(root_window_->bounds());
828 int resistance_free_region = 0;
830 if (gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_HIDDEN &&
831 visibility_state() == SHELF_AUTO_HIDE &&
832 auto_hide_state() != SHELF_AUTO_HIDE_SHOWN) {
833 // If the shelf was hidden when the drag started (and the state hasn't
834 // changed since then, e.g. because the tray-menu was shown because of the
835 // drag), then allow the drag some resistance-free region at first to make
836 // sure the shelf sticks with the finger until the shelf is visible.
837 resistance_free_region = GetPreferredShelfSize() - kAutoHideSize;
840 bool resist = SelectValueForShelfAlignment(
841 gesture_drag_amount_ < -resistance_free_region,
842 gesture_drag_amount_ > resistance_free_region,
843 gesture_drag_amount_ < -resistance_free_region,
844 gesture_drag_amount_ > resistance_free_region);
846 float translate = 0.f;
847 if (resist) {
848 float diff = fabsf(gesture_drag_amount_) - resistance_free_region;
849 diff = std::min(diff, sqrtf(diff));
850 if (gesture_drag_amount_ < 0)
851 translate = -resistance_free_region - diff;
852 else
853 translate = resistance_free_region + diff;
854 } else {
855 translate = gesture_drag_amount_;
858 if (horizontal) {
859 // Move and size the launcher with the gesture.
860 int shelf_height = target_bounds->shelf_bounds_in_root.height() - translate;
861 shelf_height = std::max(shelf_height, kAutoHideSize);
862 target_bounds->shelf_bounds_in_root.set_height(shelf_height);
863 if (alignment_ == SHELF_ALIGNMENT_BOTTOM) {
864 target_bounds->shelf_bounds_in_root.set_y(
865 available_bounds.bottom() - shelf_height);
868 if (ash::switches::UseAlternateShelfLayout()) {
869 target_bounds->status_bounds_in_shelf.set_y(kStatusAreaInset);
870 } else {
871 // The statusbar should be in the center of the shelf.
872 gfx::Rect status_y = target_bounds->shelf_bounds_in_root;
873 status_y.set_y(0);
874 status_y.ClampToCenteredSize(
875 target_bounds->status_bounds_in_shelf.size());
876 target_bounds->status_bounds_in_shelf.set_y(status_y.y());
878 } else {
879 // Move and size the launcher with the gesture.
880 int shelf_width = target_bounds->shelf_bounds_in_root.width();
881 if (alignment_ == SHELF_ALIGNMENT_RIGHT)
882 shelf_width -= translate;
883 else
884 shelf_width += translate;
885 shelf_width = std::max(shelf_width, kAutoHideSize);
886 target_bounds->shelf_bounds_in_root.set_width(shelf_width);
887 if (alignment_ == SHELF_ALIGNMENT_RIGHT) {
888 target_bounds->shelf_bounds_in_root.set_x(
889 available_bounds.right() - shelf_width);
892 if (ash::switches::UseAlternateShelfLayout()) {
893 if (alignment_ == SHELF_ALIGNMENT_RIGHT) {
894 target_bounds->status_bounds_in_shelf.set_x(kStatusAreaInset);
895 } else {
896 target_bounds->status_bounds_in_shelf.set_x(
897 available_bounds.right() - shelf_width + kStatusAreaInset);
899 } else {
900 // The statusbar should be in the center of the shelf.
901 gfx::Rect status_x = target_bounds->shelf_bounds_in_root;
902 status_x.set_x(0);
903 status_x.ClampToCenteredSize(
904 target_bounds->status_bounds_in_shelf.size());
905 target_bounds->status_bounds_in_shelf.set_x(status_x.x());
910 void ShelfLayoutManager::UpdateShelfBackground(
911 BackgroundAnimator::ChangeType type) {
912 shelf_->SetPaintsBackground(GetShelfBackgroundType(), type);
915 ShelfBackgroundType ShelfLayoutManager::GetShelfBackgroundType() const {
916 if (state_.visibility_state != SHELF_AUTO_HIDE &&
917 state_.window_state == WORKSPACE_WINDOW_STATE_MAXIMIZED) {
918 return SHELF_BACKGROUND_MAXIMIZED;
921 if (gesture_drag_status_ == GESTURE_DRAG_IN_PROGRESS ||
922 (!state_.is_screen_locked && window_overlaps_shelf_) ||
923 (state_.visibility_state == SHELF_AUTO_HIDE)) {
924 return SHELF_BACKGROUND_OVERLAP;
927 return SHELF_BACKGROUND_DEFAULT;
930 void ShelfLayoutManager::UpdateAutoHideStateNow() {
931 SetState(state_.visibility_state);
933 // If the state did not change, the auto hide timer may still be running.
934 StopAutoHideTimer();
937 void ShelfLayoutManager::StopAutoHideTimer() {
938 auto_hide_timer_.Stop();
939 mouse_over_shelf_when_auto_hide_timer_started_ = false;
942 gfx::Rect ShelfLayoutManager::GetAutoHideShowShelfRegionInScreen() const {
943 gfx::Rect shelf_bounds_in_screen = shelf_->GetWindowBoundsInScreen();
944 gfx::Vector2d offset = SelectValueForShelfAlignment(
945 gfx::Vector2d(0, shelf_bounds_in_screen.height()),
946 gfx::Vector2d(-kMaxAutoHideShowShelfRegionSize, 0),
947 gfx::Vector2d(shelf_bounds_in_screen.width(), 0),
948 gfx::Vector2d(0, -kMaxAutoHideShowShelfRegionSize));
950 gfx::Rect show_shelf_region_in_screen = shelf_bounds_in_screen;
951 show_shelf_region_in_screen += offset;
952 if (IsHorizontalAlignment())
953 show_shelf_region_in_screen.set_height(kMaxAutoHideShowShelfRegionSize);
954 else
955 show_shelf_region_in_screen.set_width(kMaxAutoHideShowShelfRegionSize);
957 // TODO: Figure out if we need any special handling when the keyboard is
958 // visible.
959 return show_shelf_region_in_screen;
962 ShelfAutoHideState ShelfLayoutManager::CalculateAutoHideState(
963 ShelfVisibilityState visibility_state) const {
964 if (visibility_state != SHELF_AUTO_HIDE || !shelf_)
965 return SHELF_AUTO_HIDE_HIDDEN;
967 Shell* shell = Shell::GetInstance();
968 if (shell->GetAppListTargetVisibility())
969 return SHELF_AUTO_HIDE_SHOWN;
971 if (shelf_->status_area_widget() &&
972 shelf_->status_area_widget()->ShouldShowLauncher())
973 return SHELF_AUTO_HIDE_SHOWN;
975 if (shelf_->launcher() && shelf_->launcher()->IsShowingMenu())
976 return SHELF_AUTO_HIDE_SHOWN;
978 if (shelf_->launcher() && shelf_->launcher()->IsShowingOverflowBubble())
979 return SHELF_AUTO_HIDE_SHOWN;
981 if (shelf_->IsActive() || shelf_->status_area_widget()->IsActive())
982 return SHELF_AUTO_HIDE_SHOWN;
984 const std::vector<aura::Window*> windows =
985 ash::MruWindowTracker::BuildWindowList(false);
987 // Process the window list and check if there are any visible windows.
988 bool visible_window = false;
989 for (size_t i = 0; i < windows.size(); ++i) {
990 if (windows[i] && windows[i]->IsVisible() &&
991 !ash::wm::IsWindowMinimized(windows[i]) &&
992 root_window_ == windows[i]->GetRootWindow()) {
993 visible_window = true;
994 break;
997 // If there are no visible windows do not hide the shelf.
998 if (!visible_window)
999 return SHELF_AUTO_HIDE_SHOWN;
1001 if (gesture_drag_status_ == GESTURE_DRAG_COMPLETE_IN_PROGRESS)
1002 return gesture_drag_auto_hide_state_;
1004 // Don't show if the user is dragging the mouse.
1005 if (auto_hide_event_filter_.get() && auto_hide_event_filter_->in_mouse_drag())
1006 return SHELF_AUTO_HIDE_HIDDEN;
1008 // Ignore the mouse position if mouse events are disabled.
1009 aura::client::CursorClient* cursor_client = aura::client::GetCursorClient(
1010 shelf_->GetNativeWindow()->GetRootWindow());
1011 if (!cursor_client->IsMouseEventsEnabled())
1012 return SHELF_AUTO_HIDE_HIDDEN;
1014 gfx::Rect shelf_region = shelf_->GetWindowBoundsInScreen();
1015 if (shelf_->status_area_widget() &&
1016 shelf_->status_area_widget()->IsMessageBubbleShown() &&
1017 IsVisible()) {
1018 // Increase the the hit test area to prevent the shelf from disappearing
1019 // when the mouse is over the bubble gap.
1020 shelf_region.Inset(alignment_ == SHELF_ALIGNMENT_RIGHT ?
1021 -kNotificationBubbleGapHeight : 0,
1022 alignment_ == SHELF_ALIGNMENT_BOTTOM ?
1023 -kNotificationBubbleGapHeight : 0,
1024 alignment_ == SHELF_ALIGNMENT_LEFT ?
1025 -kNotificationBubbleGapHeight : 0,
1026 alignment_ == SHELF_ALIGNMENT_TOP ?
1027 -kNotificationBubbleGapHeight : 0);
1030 gfx::Point cursor_position_in_screen =
1031 Shell::GetScreen()->GetCursorScreenPoint();
1032 if (shelf_region.Contains(cursor_position_in_screen))
1033 return SHELF_AUTO_HIDE_SHOWN;
1035 // When the shelf is auto hidden and the shelf is on the boundary between two
1036 // displays, it is hard to trigger showing the shelf. For instance, if a
1037 // user's primary display is left of their secondary display, it is hard to
1038 // unautohide a left aligned shelf on the secondary display.
1039 // It is hard because:
1040 // - It is hard to stop the cursor in the shelf "light bar" and not overshoot.
1041 // - The cursor is warped to the other display if the cursor gets to the edge
1042 // of the display.
1043 // Show the shelf if the cursor started on the shelf and the user overshot the
1044 // shelf slightly to make it easier to show the shelf in this situation. We
1045 // do not check |auto_hide_timer_|.IsRunning() because it returns false when
1046 // the timer's task is running.
1047 if ((state_.auto_hide_state == SHELF_AUTO_HIDE_SHOWN ||
1048 mouse_over_shelf_when_auto_hide_timer_started_) &&
1049 GetAutoHideShowShelfRegionInScreen().Contains(
1050 cursor_position_in_screen)) {
1051 return SHELF_AUTO_HIDE_SHOWN;
1054 return SHELF_AUTO_HIDE_HIDDEN;
1057 void ShelfLayoutManager::UpdateHitTestBounds() {
1058 gfx::Insets mouse_insets;
1059 gfx::Insets touch_insets;
1060 if (state_.visibility_state == SHELF_VISIBLE) {
1061 // Let clicks at the very top of the launcher through so windows can be
1062 // resized with the bottom-right corner and bottom edge.
1063 mouse_insets = GetInsetsForAlignment(kWorkspaceAreaVisibleInset);
1064 } else if (state_.visibility_state == SHELF_AUTO_HIDE) {
1065 // Extend the touch hit target out a bit to allow users to drag shelf out
1066 // while hidden.
1067 touch_insets = GetInsetsForAlignment(-kWorkspaceAreaAutoHideInset);
1070 if (shelf_ && shelf_->GetNativeWindow())
1071 shelf_->GetNativeWindow()->SetHitTestBoundsOverrideOuter(mouse_insets,
1072 touch_insets);
1073 shelf_->status_area_widget()->GetNativeWindow()->
1074 SetHitTestBoundsOverrideOuter(mouse_insets, touch_insets);
1077 bool ShelfLayoutManager::IsShelfWindow(aura::Window* window) {
1078 if (!window)
1079 return false;
1080 return (shelf_ && shelf_->GetNativeWindow()->Contains(window)) ||
1081 (shelf_->status_area_widget() &&
1082 shelf_->status_area_widget()->GetNativeWindow()->Contains(window));
1085 int ShelfLayoutManager::GetWorkAreaSize(const State& state, int size) const {
1086 if (state.visibility_state == SHELF_VISIBLE)
1087 return size;
1088 if (state.visibility_state == SHELF_AUTO_HIDE)
1089 return kAutoHideSize;
1090 return 0;
1093 gfx::Rect ShelfLayoutManager::GetAvailableBounds() const {
1094 gfx::Rect bounds(root_window_->bounds());
1095 bounds.set_height(bounds.height() - keyboard_bounds_.height());
1096 return bounds;
1099 void ShelfLayoutManager::OnKeyboardBoundsChanging(
1100 const gfx::Rect& keyboard_bounds) {
1101 keyboard_bounds_ = keyboard_bounds;
1102 OnWindowResized();
1105 void ShelfLayoutManager::OnDockBoundsChanging(
1106 const gfx::Rect& dock_bounds) {
1107 if (dock_bounds_ != dock_bounds) {
1108 dock_bounds_ = dock_bounds;
1109 OnWindowResized();
1113 gfx::Insets ShelfLayoutManager::GetInsetsForAlignment(int distance) const {
1114 switch (alignment_) {
1115 case SHELF_ALIGNMENT_BOTTOM:
1116 return gfx::Insets(distance, 0, 0, 0);
1117 case SHELF_ALIGNMENT_LEFT:
1118 return gfx::Insets(0, 0, 0, distance);
1119 case SHELF_ALIGNMENT_RIGHT:
1120 return gfx::Insets(0, distance, 0, 0);
1121 case SHELF_ALIGNMENT_TOP:
1122 return gfx::Insets(0, 0, distance, 0);
1124 NOTREACHED();
1125 return gfx::Insets();
1128 } // namespace internal
1129 } // namespace ash