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"
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"
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.
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
;
91 const int ShelfLayoutManager::kWorkspaceAreaVisibleInset
= 2;
94 const int ShelfLayoutManager::kWorkspaceAreaAutoHideInset
= 5;
97 const int ShelfLayoutManager::kAutoHideSize
= 3;
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
{
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
;
123 ShelfLayoutManager
* shelf_
;
125 ShelfGestureHandler gesture_handler_
;
126 DISALLOW_COPY_AND_ASSIGN(AutoHideEventFilter
);
129 ShelfLayoutManager::AutoHideEventFilter::AutoHideEventFilter(
130 ShelfLayoutManager
* 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();
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
{
168 explicit UpdateShelfObserver(ShelfLayoutManager
* shelf
) : shelf_(shelf
) {
169 shelf_
->update_shelf_observer_
= this;
176 virtual void OnImplicitAnimationsCompleted() OVERRIDE
{
178 shelf_
->UpdateShelfBackground(BackgroundAnimator::CHANGE_ANIMATE
);
184 virtual ~UpdateShelfObserver() {
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
),
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
)
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
)
255 alignment_
= alignment
;
256 shelf_
->SetAlignment(alignment
);
261 gfx::Rect
ShelfLayoutManager::GetIdealBounds() {
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
:
299 return SHELF_VISIBLE
;
302 void ShelfLayoutManager::UpdateVisibilityState() {
303 if (Shell::GetInstance()->session_state_delegate()->IsScreenLocked()) {
304 SetState(SHELF_VISIBLE
);
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
);
314 SetState(SHELF_HIDDEN
);
317 case WORKSPACE_WINDOW_STATE_MAXIMIZED
:
318 SetState(CalculateShelfVisibility());
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
);
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
);
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(
345 base::TimeDelta::FromMilliseconds(kAutoHideDelayMS
),
346 this, &ShelfLayoutManager::UpdateAutoHideStateNow
);
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();
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) {
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())
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
;
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;
422 case SHELF_ALIGNMENT_LEFT
:
423 case SHELF_ALIGNMENT_TOP
:
424 correct_direction
= gesture_drag_amount_
> 0;
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;
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);
444 if (!should_change
) {
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
);
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() {
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
,
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
))) {
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_
);
527 const aura::Window
* window
= controller
->GetTopmostFullscreenWindow();
530 if (!window
->GetProperty(kFullscreenUsesMinimalChromeKey
))
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())
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.
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));
577 auto_hide_event_filter_
.reset(NULL
);
582 State old_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
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
;
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);
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
,
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());
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
);
660 launcher_animation_setter
.SetTransitionDuration(base::TimeDelta());
661 status_animation_setter
.SetTransitionDuration(base::TimeDelta());
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(),
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();
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(
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();
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
;
734 shelf_width
= kAutoHideSize
;
735 } else if (state
.visibility_state
== SHELF_HIDDEN
||
736 !keyboard_bounds_
.IsEmpty()) {
737 if (IsHorizontalAlignment())
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
;
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
;
853 translate
= resistance_free_region
+ diff
;
855 translate
= gesture_drag_amount_
;
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
);
871 // The statusbar should be in the center of the shelf.
872 gfx::Rect status_y
= target_bounds
->shelf_bounds_in_root
;
874 status_y
.ClampToCenteredSize(
875 target_bounds
->status_bounds_in_shelf
.size());
876 target_bounds
->status_bounds_in_shelf
.set_y(status_y
.y());
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
;
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
);
896 target_bounds
->status_bounds_in_shelf
.set_x(
897 available_bounds
.right() - shelf_width
+ kStatusAreaInset
);
900 // The statusbar should be in the center of the shelf.
901 gfx::Rect status_x
= target_bounds
->shelf_bounds_in_root
;
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.
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
);
955 show_shelf_region_in_screen
.set_width(kMaxAutoHideShowShelfRegionSize
);
957 // TODO: Figure out if we need any special handling when the keyboard is
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;
997 // If there are no visible windows do not hide the shelf.
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() &&
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
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
1067 touch_insets
= GetInsetsForAlignment(-kWorkspaceAreaAutoHideInset
);
1070 if (shelf_
&& shelf_
->GetNativeWindow())
1071 shelf_
->GetNativeWindow()->SetHitTestBoundsOverrideOuter(mouse_insets
,
1073 shelf_
->status_area_widget()->GetNativeWindow()->
1074 SetHitTestBoundsOverrideOuter(mouse_insets
, touch_insets
);
1077 bool ShelfLayoutManager::IsShelfWindow(aura::Window
* window
) {
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
)
1088 if (state
.visibility_state
== SHELF_AUTO_HIDE
)
1089 return kAutoHideSize
;
1093 gfx::Rect
ShelfLayoutManager::GetAvailableBounds() const {
1094 gfx::Rect
bounds(root_window_
->bounds());
1095 bounds
.set_height(bounds
.height() - keyboard_bounds_
.height());
1099 void ShelfLayoutManager::OnKeyboardBoundsChanging(
1100 const gfx::Rect
& keyboard_bounds
) {
1101 keyboard_bounds_
= keyboard_bounds
;
1105 void ShelfLayoutManager::OnDockBoundsChanging(
1106 const gfx::Rect
& dock_bounds
) {
1107 if (dock_bounds_
!= dock_bounds
) {
1108 dock_bounds_
= dock_bounds
;
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);
1125 return gfx::Insets();
1128 } // namespace internal