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/accelerators/accelerator_commands.h"
14 #include "ash/ash_switches.h"
15 #include "ash/root_window_controller.h"
16 #include "ash/screen_util.h"
17 #include "ash/session_state_delegate.h"
18 #include "ash/shelf/shelf.h"
19 #include "ash/shelf/shelf_bezel_event_filter.h"
20 #include "ash/shelf/shelf_constants.h"
21 #include "ash/shelf/shelf_layout_manager_observer.h"
22 #include "ash/shelf/shelf_widget.h"
23 #include "ash/shell.h"
24 #include "ash/shell_window_ids.h"
25 #include "ash/system/status_area_widget.h"
26 #include "ash/wm/gestures/shelf_gesture_handler.h"
27 #include "ash/wm/lock_state_controller.h"
28 #include "ash/wm/mru_window_tracker.h"
29 #include "ash/wm/window_animations.h"
30 #include "ash/wm/window_state.h"
31 #include "ash/wm/window_util.h"
32 #include "ash/wm/workspace_controller.h"
33 #include "base/auto_reset.h"
34 #include "base/command_line.h"
35 #include "base/command_line.h"
36 #include "base/i18n/rtl.h"
37 #include "base/strings/string_number_conversions.h"
38 #include "base/strings/string_util.h"
39 #include "ui/aura/client/cursor_client.h"
40 #include "ui/aura/window_event_dispatcher.h"
41 #include "ui/base/ui_base_switches.h"
42 #include "ui/compositor/layer.h"
43 #include "ui/compositor/layer_animation_observer.h"
44 #include "ui/compositor/layer_animator.h"
45 #include "ui/compositor/scoped_layer_animation_settings.h"
46 #include "ui/events/event.h"
47 #include "ui/events/event_handler.h"
48 #include "ui/gfx/screen.h"
49 #include "ui/views/widget/widget.h"
50 #include "ui/wm/public/activation_client.h"
55 // Delay before showing the shelf. 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 ui::Layer
* GetLayer(views::Widget
* widget
) {
76 return widget
->GetNativeView()->layer();
79 bool IsDraggingTrayEnabled() {
80 static bool dragging_tray_allowed
= CommandLine::ForCurrentProcess()->
81 HasSwitch(ash::switches::kAshEnableTrayDragging
);
82 return dragging_tray_allowed
;
88 const int ShelfLayoutManager::kWorkspaceAreaVisibleInset
= 2;
91 const int ShelfLayoutManager::kWorkspaceAreaAutoHideInset
= 5;
94 const int ShelfLayoutManager::kAutoHideSize
= 3;
97 const int ShelfLayoutManager::kShelfItemInset
= 3;
99 // ShelfLayoutManager::AutoHideEventFilter -------------------------------------
101 // Notifies ShelfLayoutManager any time the mouse moves.
102 class ShelfLayoutManager::AutoHideEventFilter
: public ui::EventHandler
{
104 explicit AutoHideEventFilter(ShelfLayoutManager
* shelf
);
105 virtual ~AutoHideEventFilter();
107 // Returns true if the last mouse event was a mouse drag.
108 bool in_mouse_drag() const { return in_mouse_drag_
; }
110 // Overridden from ui::EventHandler:
111 virtual void OnMouseEvent(ui::MouseEvent
* event
) OVERRIDE
;
112 virtual void OnGestureEvent(ui::GestureEvent
* event
) OVERRIDE
;
115 ShelfLayoutManager
* shelf_
;
117 ShelfGestureHandler gesture_handler_
;
118 DISALLOW_COPY_AND_ASSIGN(AutoHideEventFilter
);
121 ShelfLayoutManager::AutoHideEventFilter::AutoHideEventFilter(
122 ShelfLayoutManager
* shelf
)
124 in_mouse_drag_(false) {
125 Shell::GetInstance()->AddPreTargetHandler(this);
128 ShelfLayoutManager::AutoHideEventFilter::~AutoHideEventFilter() {
129 Shell::GetInstance()->RemovePreTargetHandler(this);
132 void ShelfLayoutManager::AutoHideEventFilter::OnMouseEvent(
133 ui::MouseEvent
* event
) {
134 // This also checks IsShelfWindow() to make sure we don't attempt to hide the
135 // shelf if the mouse down occurs on the shelf.
136 in_mouse_drag_
= (event
->type() == ui::ET_MOUSE_DRAGGED
||
137 (in_mouse_drag_
&& event
->type() != ui::ET_MOUSE_RELEASED
&&
138 event
->type() != ui::ET_MOUSE_CAPTURE_CHANGED
)) &&
139 !shelf_
->IsShelfWindow(static_cast<aura::Window
*>(event
->target()));
140 if (event
->type() == ui::ET_MOUSE_MOVED
)
141 shelf_
->UpdateAutoHideState();
145 void ShelfLayoutManager::AutoHideEventFilter::OnGestureEvent(
146 ui::GestureEvent
* event
) {
147 if (shelf_
->IsShelfWindow(static_cast<aura::Window
*>(event
->target()))) {
148 if (gesture_handler_
.ProcessGestureEvent(*event
))
149 event
->StopPropagation();
153 // ShelfLayoutManager:UpdateShelfObserver --------------------------------------
155 // UpdateShelfObserver is used to delay updating the background until the
156 // animation completes.
157 class ShelfLayoutManager::UpdateShelfObserver
158 : public ui::ImplicitAnimationObserver
{
160 explicit UpdateShelfObserver(ShelfLayoutManager
* shelf
) : shelf_(shelf
) {
161 shelf_
->update_shelf_observer_
= this;
168 virtual void OnImplicitAnimationsCompleted() OVERRIDE
{
170 shelf_
->UpdateShelfBackground(BACKGROUND_CHANGE_ANIMATE
);
175 virtual ~UpdateShelfObserver() {
177 shelf_
->update_shelf_observer_
= NULL
;
180 // Shelf we're in. NULL if deleted before we're deleted.
181 ShelfLayoutManager
* shelf_
;
183 DISALLOW_COPY_AND_ASSIGN(UpdateShelfObserver
);
186 // ShelfLayoutManager ----------------------------------------------------------
188 ShelfLayoutManager::ShelfLayoutManager(ShelfWidget
* shelf
)
189 : root_window_(shelf
->GetNativeView()->GetRootWindow()),
190 updating_bounds_(false),
191 force_shelf_always_visibile_(
192 Shell::GetInstance()->IsMaximizeModeWindowManagerEnabled()),
193 auto_hide_behavior_(SHELF_AUTO_HIDE_BEHAVIOR_NEVER
),
194 alignment_(SHELF_ALIGNMENT_BOTTOM
),
196 workspace_controller_(NULL
),
197 window_overlaps_shelf_(false),
198 mouse_over_shelf_when_auto_hide_timer_started_(false),
199 bezel_event_filter_(new ShelfBezelEventFilter(this)),
200 gesture_drag_status_(GESTURE_DRAG_NONE
),
201 gesture_drag_amount_(0.f
),
202 gesture_drag_auto_hide_state_(SHELF_AUTO_HIDE_SHOWN
),
203 update_shelf_observer_(NULL
),
204 duration_override_in_ms_(0) {
205 Shell::GetInstance()->AddShellObserver(this);
206 Shell::GetInstance()->lock_state_controller()->AddObserver(this);
207 aura::client::GetActivationClient(root_window_
)->AddObserver(this);
208 Shell::GetInstance()->session_state_delegate()->AddSessionStateObserver(this);
211 ShelfLayoutManager::~ShelfLayoutManager() {
212 if (update_shelf_observer_
)
213 update_shelf_observer_
->Detach();
215 FOR_EACH_OBSERVER(ShelfLayoutManagerObserver
, observers_
, WillDeleteShelf());
216 Shell::GetInstance()->RemoveShellObserver(this);
217 Shell::GetInstance()->lock_state_controller()->RemoveObserver(this);
218 aura::client::GetActivationClient(root_window_
)->RemoveObserver(this);
219 Shell::GetInstance()->
220 session_state_delegate()->RemoveSessionStateObserver(this);
223 void ShelfLayoutManager::SetAutoHideBehavior(ShelfAutoHideBehavior behavior
) {
224 if (auto_hide_behavior_
== behavior
)
226 auto_hide_behavior_
= behavior
;
227 UpdateVisibilityState();
228 FOR_EACH_OBSERVER(ShelfLayoutManagerObserver
, observers_
,
229 OnAutoHideBehaviorChanged(root_window_
,
230 auto_hide_behavior_
));
233 void ShelfLayoutManager::PrepareForShutdown() {
234 // Clear all event filters, otherwise sometimes those filters may catch
235 // synthesized mouse event and cause crashes during the shutdown.
236 set_workspace_controller(NULL
);
237 auto_hide_event_filter_
.reset();
238 bezel_event_filter_
.reset();
241 bool ShelfLayoutManager::IsVisible() const {
242 // status_area_widget() may be NULL during the shutdown.
243 return shelf_
->status_area_widget() &&
244 shelf_
->status_area_widget()->IsVisible() &&
245 (state_
.visibility_state
== SHELF_VISIBLE
||
246 (state_
.visibility_state
== SHELF_AUTO_HIDE
&&
247 state_
.auto_hide_state
== SHELF_AUTO_HIDE_SHOWN
));
250 bool ShelfLayoutManager::SetAlignment(ShelfAlignment alignment
) {
251 if (alignment_
== alignment
)
254 // This should not be called during the lock screen transitions.
255 DCHECK(!Shell::GetInstance()->session_state_delegate()->IsScreenLocked());
256 alignment_
= alignment
;
257 shelf_
->SetAlignment(alignment
);
262 ShelfAlignment
ShelfLayoutManager::GetAlignment() const {
263 // When the screen is locked, the shelf is forced into bottom alignment.
264 if (Shell::GetInstance()->session_state_delegate()->IsScreenLocked())
265 return SHELF_ALIGNMENT_BOTTOM
;
269 gfx::Rect
ShelfLayoutManager::GetIdealBounds() {
271 ScreenUtil::GetDisplayBoundsInParent(shelf_
->GetNativeView()));
272 int width
= 0, height
= 0;
273 GetShelfSize(&width
, &height
);
274 return SelectValueForShelfAlignment(
275 gfx::Rect(bounds
.x(), bounds
.bottom() - height
, bounds
.width(), height
),
276 gfx::Rect(bounds
.x(), bounds
.y(), width
, bounds
.height()),
277 gfx::Rect(bounds
.right() - width
, bounds
.y(), width
, bounds
.height()),
278 gfx::Rect(bounds
.x(), bounds
.y(), bounds
.width(), height
));
281 void ShelfLayoutManager::LayoutShelf() {
282 TargetBounds target_bounds
;
283 CalculateTargetBounds(state_
, &target_bounds
);
284 UpdateBoundsAndOpacity(target_bounds
, false, NULL
);
286 if (shelf_
->shelf()) {
287 // This is not part of UpdateBoundsAndOpacity() because
288 // SetShelfViewBounds() sets the bounds immediately and does not animate.
289 // The height of the ShelfView for a horizontal shelf and the width of
290 // the ShelfView for a vertical shelf are set when |shelf_|'s bounds
291 // are changed via UpdateBoundsAndOpacity(). This sets the origin and the
292 // dimension in the other direction.
293 shelf_
->shelf()->SetShelfViewBounds(
294 target_bounds
.shelf_bounds_in_shelf
);
298 ShelfVisibilityState
ShelfLayoutManager::CalculateShelfVisibility() {
299 switch(auto_hide_behavior_
) {
300 case SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS
:
301 return SHELF_AUTO_HIDE
;
302 case SHELF_AUTO_HIDE_BEHAVIOR_NEVER
:
303 return SHELF_VISIBLE
;
304 case SHELF_AUTO_HIDE_ALWAYS_HIDDEN
:
307 return SHELF_VISIBLE
;
310 void ShelfLayoutManager::UpdateVisibilityState() {
311 // Bail out early when there is no |workspace_controller_|, which happens
312 // during shutdown after PrepareForShutdown.
313 if (!workspace_controller_
)
316 if (Shell::GetInstance()->session_state_delegate()->IsScreenLocked() ||
317 force_shelf_always_visibile_
) {
318 SetState(SHELF_VISIBLE
);
320 // TODO(zelidrag): Verify shelf drag animation still shows on the device
321 // when we are in SHELF_AUTO_HIDE_ALWAYS_HIDDEN.
322 WorkspaceWindowState
window_state(workspace_controller_
->GetWindowState());
323 switch (window_state
) {
324 case WORKSPACE_WINDOW_STATE_FULL_SCREEN
: {
325 const aura::Window
* fullscreen_window
= GetRootWindowController(
326 root_window_
)->GetWindowForFullscreenMode();
327 if (fullscreen_window
&& wm::GetWindowState(fullscreen_window
)->
328 hide_shelf_when_fullscreen()) {
329 SetState(SHELF_HIDDEN
);
331 // The shelf is sometimes not hidden when in immersive fullscreen.
332 // Force the shelf to be auto hidden in this case.
333 SetState(SHELF_AUTO_HIDE
);
338 case WORKSPACE_WINDOW_STATE_MAXIMIZED
:
339 SetState(CalculateShelfVisibility());
342 case WORKSPACE_WINDOW_STATE_WINDOW_OVERLAPS_SHELF
:
343 case WORKSPACE_WINDOW_STATE_DEFAULT
:
344 SetState(CalculateShelfVisibility());
345 SetWindowOverlapsShelf(window_state
==
346 WORKSPACE_WINDOW_STATE_WINDOW_OVERLAPS_SHELF
);
352 void ShelfLayoutManager::UpdateAutoHideState() {
353 ShelfAutoHideState auto_hide_state
=
354 CalculateAutoHideState(state_
.visibility_state
);
355 if (auto_hide_state
!= state_
.auto_hide_state
) {
356 if (auto_hide_state
== SHELF_AUTO_HIDE_HIDDEN
) {
357 // Hides happen immediately.
358 SetState(state_
.visibility_state
);
360 if (!auto_hide_timer_
.IsRunning()) {
361 mouse_over_shelf_when_auto_hide_timer_started_
=
362 shelf_
->GetWindowBoundsInScreen().Contains(
363 Shell::GetScreen()->GetCursorScreenPoint());
365 auto_hide_timer_
.Start(
367 base::TimeDelta::FromMilliseconds(kAutoHideDelayMS
),
368 this, &ShelfLayoutManager::UpdateAutoHideStateNow
);
375 void ShelfLayoutManager::SetWindowOverlapsShelf(bool value
) {
376 window_overlaps_shelf_
= value
;
377 UpdateShelfBackground(BACKGROUND_CHANGE_ANIMATE
);
380 void ShelfLayoutManager::AddObserver(ShelfLayoutManagerObserver
* observer
) {
381 observers_
.AddObserver(observer
);
384 void ShelfLayoutManager::RemoveObserver(ShelfLayoutManagerObserver
* observer
) {
385 observers_
.RemoveObserver(observer
);
388 ////////////////////////////////////////////////////////////////////////////////
389 // ShelfLayoutManager, Gesture functions:
391 void ShelfLayoutManager::OnGestureEdgeSwipe(const ui::GestureEvent
& gesture
) {
392 if (force_shelf_always_visibile_
)
395 if (visibility_state() == SHELF_AUTO_HIDE
) {
396 gesture_drag_auto_hide_state_
= SHELF_AUTO_HIDE_SHOWN
;
397 gesture_drag_status_
= GESTURE_DRAG_COMPLETE_IN_PROGRESS
;
398 UpdateVisibilityState();
399 gesture_drag_status_
= GESTURE_DRAG_NONE
;
403 void ShelfLayoutManager::StartGestureDrag(const ui::GestureEvent
& gesture
) {
404 if (force_shelf_always_visibile_
)
406 gesture_drag_status_
= GESTURE_DRAG_IN_PROGRESS
;
407 gesture_drag_amount_
= 0.f
;
408 gesture_drag_auto_hide_state_
= visibility_state() == SHELF_AUTO_HIDE
?
409 auto_hide_state() : SHELF_AUTO_HIDE_SHOWN
;
410 UpdateShelfBackground(BACKGROUND_CHANGE_ANIMATE
);
413 ShelfLayoutManager::DragState
ShelfLayoutManager::UpdateGestureDrag(
414 const ui::GestureEvent
& gesture
) {
415 if (force_shelf_always_visibile_
)
417 bool horizontal
= IsHorizontalAlignment();
418 gesture_drag_amount_
+= horizontal
? gesture
.details().scroll_y() :
419 gesture
.details().scroll_x();
422 // Start reveling the status menu when:
423 // - dragging up on an already visible shelf
424 // - dragging up on a hidden shelf, but it is currently completely visible.
425 if (horizontal
&& gesture
.details().scroll_y() < 0) {
427 if (gesture_drag_auto_hide_state_
== SHELF_AUTO_HIDE_HIDDEN
&& shelf_
)
428 min_height
= shelf_
->GetContentsView()->GetPreferredSize().height();
430 if (min_height
< shelf_
->GetWindowBoundsInScreen().height() &&
431 gesture
.root_location().x() >=
432 shelf_
->status_area_widget()->GetWindowBoundsInScreen().x() &&
433 IsDraggingTrayEnabled())
440 void ShelfLayoutManager::CompleteGestureDrag(const ui::GestureEvent
& gesture
) {
441 if (force_shelf_always_visibile_
)
443 bool horizontal
= IsHorizontalAlignment();
444 bool should_change
= false;
445 if (gesture
.type() == ui::ET_GESTURE_SCROLL_END
) {
446 // The visibility of the shelf changes only if the shelf was dragged X%
447 // along the correct axis. If the shelf was already visible, then the
448 // direction of the drag does not matter.
449 const float kDragHideThreshold
= 0.4f
;
450 gfx::Rect bounds
= GetIdealBounds();
451 float drag_ratio
= fabs(gesture_drag_amount_
) /
452 (horizontal
? bounds
.height() : bounds
.width());
453 if (gesture_drag_auto_hide_state_
== SHELF_AUTO_HIDE_SHOWN
) {
454 should_change
= drag_ratio
> kDragHideThreshold
;
456 bool correct_direction
= false;
457 switch (GetAlignment()) {
458 case SHELF_ALIGNMENT_BOTTOM
:
459 case SHELF_ALIGNMENT_RIGHT
:
460 correct_direction
= gesture_drag_amount_
< 0;
462 case SHELF_ALIGNMENT_LEFT
:
463 case SHELF_ALIGNMENT_TOP
:
464 correct_direction
= gesture_drag_amount_
> 0;
467 should_change
= correct_direction
&& drag_ratio
> kDragHideThreshold
;
469 } else if (gesture
.type() == ui::ET_SCROLL_FLING_START
) {
470 if (gesture_drag_auto_hide_state_
== SHELF_AUTO_HIDE_SHOWN
) {
471 should_change
= horizontal
? fabs(gesture
.details().velocity_y()) > 0 :
472 fabs(gesture
.details().velocity_x()) > 0;
474 should_change
= SelectValueForShelfAlignment(
475 gesture
.details().velocity_y() < 0,
476 gesture
.details().velocity_x() > 0,
477 gesture
.details().velocity_x() < 0,
478 gesture
.details().velocity_y() > 0);
484 if (!should_change
) {
489 shelf_
->Deactivate();
490 shelf_
->status_area_widget()->Deactivate();
492 gesture_drag_auto_hide_state_
=
493 gesture_drag_auto_hide_state_
== SHELF_AUTO_HIDE_SHOWN
?
494 SHELF_AUTO_HIDE_HIDDEN
: SHELF_AUTO_HIDE_SHOWN
;
495 ShelfAutoHideBehavior new_auto_hide_behavior
=
496 gesture_drag_auto_hide_state_
== SHELF_AUTO_HIDE_SHOWN
?
497 SHELF_AUTO_HIDE_BEHAVIOR_NEVER
: SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS
;
499 // When in fullscreen and the shelf is forced to be auto hidden, the auto hide
500 // behavior affects neither the visibility state nor the auto hide state. Set
501 // |gesture_drag_status_| to GESTURE_DRAG_COMPLETE_IN_PROGRESS to set the auto
502 // hide state to |gesture_drag_auto_hide_state_|.
503 gesture_drag_status_
= GESTURE_DRAG_COMPLETE_IN_PROGRESS
;
504 if (auto_hide_behavior_
!= new_auto_hide_behavior
)
505 SetAutoHideBehavior(new_auto_hide_behavior
);
507 UpdateVisibilityState();
508 gesture_drag_status_
= GESTURE_DRAG_NONE
;
511 void ShelfLayoutManager::CancelGestureDrag() {
512 gesture_drag_status_
= GESTURE_DRAG_CANCEL_IN_PROGRESS
;
513 UpdateVisibilityState();
514 gesture_drag_status_
= GESTURE_DRAG_NONE
;
517 void ShelfLayoutManager::SetAnimationDurationOverride(
518 int duration_override_in_ms
) {
519 duration_override_in_ms_
= duration_override_in_ms
;
522 ////////////////////////////////////////////////////////////////////////////////
523 // ShelfLayoutManager, aura::LayoutManager implementation:
525 void ShelfLayoutManager::OnWindowResized() {
529 void ShelfLayoutManager::OnWindowAddedToLayout(aura::Window
* child
) {
532 void ShelfLayoutManager::OnWillRemoveWindowFromLayout(aura::Window
* child
) {
535 void ShelfLayoutManager::OnWindowRemovedFromLayout(aura::Window
* child
) {
538 void ShelfLayoutManager::OnChildWindowVisibilityChanged(aura::Window
* child
,
542 void ShelfLayoutManager::SetChildBounds(aura::Window
* child
,
543 const gfx::Rect
& requested_bounds
) {
544 SetChildBoundsDirect(child
, requested_bounds
);
545 // We may contain other widgets (such as frame maximize bubble) but they don't
546 // effect the layout in anyway.
547 if (!updating_bounds_
&&
548 ((shelf_
->GetNativeView() == child
) ||
549 (shelf_
->status_area_widget()->GetNativeView() == child
))) {
554 void ShelfLayoutManager::OnLockStateChanged(bool locked
) {
555 // Force the shelf to layout for alignment (bottom if locked, restore
556 // the previous alignment otherwise).
557 state_
.is_screen_locked
= locked
;
558 shelf_
->SetAlignment(locked
? SHELF_ALIGNMENT_BOTTOM
: alignment_
);
559 UpdateVisibilityState();
563 void ShelfLayoutManager::OnMaximizeModeStarted() {
564 DCHECK(!force_shelf_always_visibile_
);
565 force_shelf_always_visibile_
= true;
566 UpdateVisibilityState();
569 void ShelfLayoutManager::OnMaximizeModeEnded() {
570 DCHECK(force_shelf_always_visibile_
);
571 // Note: At this time Ash::Shell::IsMaximizeModeWindowManagerEnabled() will
572 // report true, even though it is in progress of shut down. To address this
573 // |force_shelf_always_visibile_| will be read.
574 force_shelf_always_visibile_
= false;
575 UpdateVisibilityState();
578 void ShelfLayoutManager::OnWindowActivated(aura::Window
* gained_active
,
579 aura::Window
* lost_active
) {
580 UpdateAutoHideStateNow();
583 bool ShelfLayoutManager::IsHorizontalAlignment() const {
584 return GetAlignment() == SHELF_ALIGNMENT_BOTTOM
||
585 GetAlignment() == SHELF_ALIGNMENT_TOP
;
589 ShelfLayoutManager
* ShelfLayoutManager::ForShelf(aura::Window
* window
) {
590 ShelfWidget
* shelf
= RootWindowController::ForShelf(window
)->shelf();
591 return shelf
? shelf
->shelf_layout_manager() : NULL
;
594 ////////////////////////////////////////////////////////////////////////////////
595 // ShelfLayoutManager, private:
597 ShelfLayoutManager::TargetBounds::TargetBounds() : opacity(0.0f
) {}
598 ShelfLayoutManager::TargetBounds::~TargetBounds() {}
600 void ShelfLayoutManager::SetState(ShelfVisibilityState visibility_state
) {
601 if (!shelf_
->GetNativeView())
605 state
.visibility_state
= visibility_state
;
606 state
.auto_hide_state
= CalculateAutoHideState(visibility_state
);
607 state
.window_state
= workspace_controller_
?
608 workspace_controller_
->GetWindowState() : WORKSPACE_WINDOW_STATE_DEFAULT
;
610 // Force an update because gesture drags affect the shelf bounds and we
611 // should animate back to the normal bounds at the end of a gesture.
613 (gesture_drag_status_
== GESTURE_DRAG_CANCEL_IN_PROGRESS
||
614 gesture_drag_status_
== GESTURE_DRAG_COMPLETE_IN_PROGRESS
);
616 if (!force_update
&& state_
.Equals(state
))
617 return; // Nothing changed.
619 FOR_EACH_OBSERVER(ShelfLayoutManagerObserver
, observers_
,
620 WillChangeVisibilityState(visibility_state
));
622 if (state
.visibility_state
== SHELF_AUTO_HIDE
) {
623 // When state is SHELF_AUTO_HIDE we need to track when the mouse is over the
624 // shelf to unhide it. AutoHideEventFilter does that for us.
625 if (!auto_hide_event_filter_
)
626 auto_hide_event_filter_
.reset(new AutoHideEventFilter(this));
628 auto_hide_event_filter_
.reset(NULL
);
633 State old_state
= state_
;
636 BackgroundAnimatorChangeType change_type
= BACKGROUND_CHANGE_ANIMATE
;
637 bool delay_background_change
= false;
639 // Do not animate the background when:
640 // - Going from a hidden / auto hidden shelf in fullscreen to a visible shelf
641 // in maximized mode.
642 // - Going from an auto hidden shelf in maximized mode to a visible shelf in
644 if (state
.visibility_state
== SHELF_VISIBLE
&&
645 state
.window_state
== WORKSPACE_WINDOW_STATE_MAXIMIZED
&&
646 old_state
.visibility_state
!= SHELF_VISIBLE
) {
647 change_type
= BACKGROUND_CHANGE_IMMEDIATE
;
649 // Delay the animation when the shelf was hidden, and has just been made
650 // visible (e.g. using a gesture-drag).
651 if (state
.visibility_state
== SHELF_VISIBLE
&&
652 old_state
.visibility_state
== SHELF_AUTO_HIDE
&&
653 old_state
.auto_hide_state
== SHELF_AUTO_HIDE_HIDDEN
) {
654 delay_background_change
= true;
658 if (delay_background_change
) {
659 if (update_shelf_observer_
)
660 update_shelf_observer_
->Detach();
661 // UpdateShelfBackground deletes itself when the animation is done.
662 update_shelf_observer_
= new UpdateShelfObserver(this);
664 UpdateShelfBackground(change_type
);
667 shelf_
->SetDimsShelf(
668 state
.visibility_state
== SHELF_VISIBLE
&&
669 state
.window_state
== WORKSPACE_WINDOW_STATE_MAXIMIZED
);
671 TargetBounds target_bounds
;
672 CalculateTargetBounds(state_
, &target_bounds
);
673 UpdateBoundsAndOpacity(target_bounds
, true,
674 delay_background_change
? update_shelf_observer_
: NULL
);
676 // OnAutoHideStateChanged Should be emitted when:
677 // - firstly state changed to auto-hide from other state
678 // - or, auto_hide_state has changed
679 if ((old_state
.visibility_state
!= state_
.visibility_state
&&
680 state_
.visibility_state
== SHELF_AUTO_HIDE
) ||
681 old_state
.auto_hide_state
!= state_
.auto_hide_state
) {
682 FOR_EACH_OBSERVER(ShelfLayoutManagerObserver
, observers_
,
683 OnAutoHideStateChanged(state_
.auto_hide_state
));
687 void ShelfLayoutManager::UpdateBoundsAndOpacity(
688 const TargetBounds
& target_bounds
,
690 ui::ImplicitAnimationObserver
* observer
) {
691 base::AutoReset
<bool> auto_reset_updating_bounds(&updating_bounds_
, true);
693 ui::ScopedLayerAnimationSettings
shelf_animation_setter(
694 GetLayer(shelf_
)->GetAnimator());
695 ui::ScopedLayerAnimationSettings
status_animation_setter(
696 GetLayer(shelf_
->status_area_widget())->GetAnimator());
698 int duration
= duration_override_in_ms_
? duration_override_in_ms_
:
699 kCrossFadeDurationMS
;
700 shelf_animation_setter
.SetTransitionDuration(
701 base::TimeDelta::FromMilliseconds(duration
));
702 shelf_animation_setter
.SetTweenType(gfx::Tween::EASE_OUT
);
703 shelf_animation_setter
.SetPreemptionStrategy(
704 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET
);
705 status_animation_setter
.SetTransitionDuration(
706 base::TimeDelta::FromMilliseconds(duration
));
707 status_animation_setter
.SetTweenType(gfx::Tween::EASE_OUT
);
708 status_animation_setter
.SetPreemptionStrategy(
709 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET
);
712 shelf_animation_setter
.SetTransitionDuration(base::TimeDelta());
713 status_animation_setter
.SetTransitionDuration(base::TimeDelta());
716 status_animation_setter
.AddObserver(observer
);
718 GetLayer(shelf_
)->SetOpacity(target_bounds
.opacity
);
719 shelf_
->SetBounds(ScreenUtil::ConvertRectToScreen(
720 shelf_
->GetNativeView()->parent(),
721 target_bounds
.shelf_bounds_in_root
));
723 GetLayer(shelf_
->status_area_widget())->SetOpacity(
724 target_bounds
.status_opacity
);
725 // TODO(harrym): Once status area widget is a child view of shelf
726 // this can be simplified.
727 gfx::Rect status_bounds
= target_bounds
.status_bounds_in_shelf
;
728 status_bounds
.set_x(status_bounds
.x() +
729 target_bounds
.shelf_bounds_in_root
.x());
730 status_bounds
.set_y(status_bounds
.y() +
731 target_bounds
.shelf_bounds_in_root
.y());
732 shelf_
->status_area_widget()->SetBounds(
733 ScreenUtil::ConvertRectToScreen(
734 shelf_
->status_area_widget()->GetNativeView()->parent(),
736 SessionStateDelegate
* session_state_delegate
=
737 Shell::GetInstance()->session_state_delegate();
738 if (!state_
.is_screen_locked
) {
740 // If user session is blocked (login to new user session or add user to
741 // the existing session - multi-profile) then give 100% of work area only if
742 // keyboard is not shown.
743 if (!session_state_delegate
->IsUserSessionBlocked() ||
744 !keyboard_bounds_
.IsEmpty()) {
745 insets
= target_bounds
.work_area_insets
;
747 Shell::GetInstance()->SetDisplayWorkAreaInsets(root_window_
, insets
);
751 void ShelfLayoutManager::StopAnimating() {
752 GetLayer(shelf_
)->GetAnimator()->StopAnimating();
753 GetLayer(shelf_
->status_area_widget())->GetAnimator()->StopAnimating();
756 void ShelfLayoutManager::GetShelfSize(int* width
, int* height
) {
757 *width
= *height
= 0;
758 gfx::Size
status_size(
759 shelf_
->status_area_widget()->GetWindowBoundsInScreen().size());
760 if (IsHorizontalAlignment())
761 *height
= kShelfSize
;
766 void ShelfLayoutManager::AdjustBoundsBasedOnAlignment(int inset
,
767 gfx::Rect
* bounds
) const {
768 bounds
->Inset(SelectValueForShelfAlignment(
769 gfx::Insets(0, 0, inset
, 0),
770 gfx::Insets(0, inset
, 0, 0),
771 gfx::Insets(0, 0, 0, inset
),
772 gfx::Insets(inset
, 0, 0, 0)));
775 void ShelfLayoutManager::CalculateTargetBounds(
777 TargetBounds
* target_bounds
) {
778 const gfx::Rect
available_bounds(GetAvailableBounds());
779 gfx::Rect
status_size(
780 shelf_
->status_area_widget()->GetWindowBoundsInScreen().size());
781 int shelf_width
= 0, shelf_height
= 0;
782 GetShelfSize(&shelf_width
, &shelf_height
);
783 if (IsHorizontalAlignment())
784 shelf_width
= available_bounds
.width();
786 shelf_height
= available_bounds
.height();
788 if (state
.visibility_state
== SHELF_AUTO_HIDE
&&
789 state
.auto_hide_state
== SHELF_AUTO_HIDE_HIDDEN
) {
790 // Auto-hidden shelf always starts with the default size. If a gesture-drag
791 // is in progress, then the call to UpdateTargetBoundsForGesture() below
792 // takes care of setting the height properly.
793 if (IsHorizontalAlignment())
794 shelf_height
= kAutoHideSize
;
796 shelf_width
= kAutoHideSize
;
797 } else if (state
.visibility_state
== SHELF_HIDDEN
||
798 !keyboard_bounds_
.IsEmpty()) {
799 if (IsHorizontalAlignment())
805 target_bounds
->shelf_bounds_in_root
= SelectValueForShelfAlignment(
806 gfx::Rect(available_bounds
.x(), available_bounds
.bottom() - shelf_height
,
807 available_bounds
.width(), shelf_height
),
808 gfx::Rect(available_bounds
.x(), available_bounds
.y(),
809 shelf_width
, available_bounds
.height()),
810 gfx::Rect(available_bounds
.right() - shelf_width
, available_bounds
.y(),
811 shelf_width
, available_bounds
.height()),
812 gfx::Rect(available_bounds
.x(), available_bounds
.y(),
813 available_bounds
.width(), shelf_height
));
815 if (IsHorizontalAlignment())
816 status_size
.set_height(kShelfSize
);
818 status_size
.set_width(kShelfSize
);
820 target_bounds
->status_bounds_in_shelf
= SelectValueForShelfAlignment(
821 gfx::Rect(base::i18n::IsRTL() ? 0 : shelf_width
- status_size
.width(),
822 0, status_size
.width(), status_size
.height()),
823 gfx::Rect(shelf_width
- status_size
.width(),
824 shelf_height
- status_size
.height(), status_size
.width(),
825 status_size
.height()),
826 gfx::Rect(0, shelf_height
- status_size
.height(),
827 status_size
.width(), status_size
.height()),
828 gfx::Rect(base::i18n::IsRTL() ? 0 : shelf_width
- status_size
.width(),
829 shelf_height
- status_size
.height(),
830 status_size
.width(), status_size
.height()));
832 target_bounds
->work_area_insets
= SelectValueForShelfAlignment(
833 gfx::Insets(0, 0, GetWorkAreaSize(state
, shelf_height
), 0),
834 gfx::Insets(0, GetWorkAreaSize(state
, shelf_width
), 0, 0),
835 gfx::Insets(0, 0, 0, GetWorkAreaSize(state
, shelf_width
)),
836 gfx::Insets(GetWorkAreaSize(state
, shelf_height
), 0, 0, 0));
838 // TODO(varkha): The functionality of managing insets for display areas
839 // should probably be pushed to a separate component. This would simplify or
840 // remove entirely the dependency on keyboard and dock.
842 // Also push in the work area inset for the keyboard if it is visible.
843 if (!keyboard_bounds_
.IsEmpty()) {
844 gfx::Insets
keyboard_insets(0, 0, keyboard_bounds_
.height(), 0);
845 target_bounds
->work_area_insets
+= keyboard_insets
;
848 // Also push in the work area inset for the dock if it is visible.
849 if (!dock_bounds_
.IsEmpty()) {
850 gfx::Insets
dock_insets(
851 0, (dock_bounds_
.x() > 0 ? 0 : dock_bounds_
.width()),
852 0, (dock_bounds_
.x() > 0 ? dock_bounds_
.width() : 0));
853 target_bounds
->work_area_insets
+= dock_insets
;
856 target_bounds
->opacity
=
857 (gesture_drag_status_
== GESTURE_DRAG_IN_PROGRESS
||
858 state
.visibility_state
== SHELF_VISIBLE
||
859 state
.visibility_state
== SHELF_AUTO_HIDE
) ? 1.0f
: 0.0f
;
860 target_bounds
->status_opacity
=
861 (state
.visibility_state
== SHELF_AUTO_HIDE
&&
862 state
.auto_hide_state
== SHELF_AUTO_HIDE_HIDDEN
&&
863 gesture_drag_status_
!= GESTURE_DRAG_IN_PROGRESS
) ?
864 0.0f
: target_bounds
->opacity
;
866 if (gesture_drag_status_
== GESTURE_DRAG_IN_PROGRESS
)
867 UpdateTargetBoundsForGesture(target_bounds
);
869 // This needs to happen after calling UpdateTargetBoundsForGesture(), because
870 // that can change the size of the shelf.
871 target_bounds
->shelf_bounds_in_shelf
= SelectValueForShelfAlignment(
873 shelf_width
- status_size
.width(),
874 target_bounds
->shelf_bounds_in_root
.height()),
875 gfx::Rect(0, 0, target_bounds
->shelf_bounds_in_root
.width(),
876 shelf_height
- status_size
.height()),
877 gfx::Rect(0, 0, target_bounds
->shelf_bounds_in_root
.width(),
878 shelf_height
- status_size
.height()),
880 shelf_width
- status_size
.width(),
881 target_bounds
->shelf_bounds_in_root
.height()));
884 void ShelfLayoutManager::UpdateTargetBoundsForGesture(
885 TargetBounds
* target_bounds
) const {
886 CHECK_EQ(GESTURE_DRAG_IN_PROGRESS
, gesture_drag_status_
);
887 bool horizontal
= IsHorizontalAlignment();
888 const gfx::Rect
& available_bounds(root_window_
->bounds());
889 int resistance_free_region
= 0;
891 if (gesture_drag_auto_hide_state_
== SHELF_AUTO_HIDE_HIDDEN
&&
892 visibility_state() == SHELF_AUTO_HIDE
&&
893 auto_hide_state() != SHELF_AUTO_HIDE_SHOWN
) {
894 // If the shelf was hidden when the drag started (and the state hasn't
895 // changed since then, e.g. because the tray-menu was shown because of the
896 // drag), then allow the drag some resistance-free region at first to make
897 // sure the shelf sticks with the finger until the shelf is visible.
898 resistance_free_region
= kShelfSize
- kAutoHideSize
;
901 bool resist
= SelectValueForShelfAlignment(
902 gesture_drag_amount_
< -resistance_free_region
,
903 gesture_drag_amount_
> resistance_free_region
,
904 gesture_drag_amount_
< -resistance_free_region
,
905 gesture_drag_amount_
> resistance_free_region
);
907 float translate
= 0.f
;
909 float diff
= fabsf(gesture_drag_amount_
) - resistance_free_region
;
910 diff
= std::min(diff
, sqrtf(diff
));
911 if (gesture_drag_amount_
< 0)
912 translate
= -resistance_free_region
- diff
;
914 translate
= resistance_free_region
+ diff
;
916 translate
= gesture_drag_amount_
;
920 // Move and size the shelf with the gesture.
921 int shelf_height
= target_bounds
->shelf_bounds_in_root
.height() - translate
;
922 shelf_height
= std::max(shelf_height
, kAutoHideSize
);
923 target_bounds
->shelf_bounds_in_root
.set_height(shelf_height
);
924 if (GetAlignment() == SHELF_ALIGNMENT_BOTTOM
) {
925 target_bounds
->shelf_bounds_in_root
.set_y(
926 available_bounds
.bottom() - shelf_height
);
929 target_bounds
->status_bounds_in_shelf
.set_y(0);
931 // Move and size the shelf with the gesture.
932 int shelf_width
= target_bounds
->shelf_bounds_in_root
.width();
933 bool right_aligned
= GetAlignment() == SHELF_ALIGNMENT_RIGHT
;
935 shelf_width
-= translate
;
937 shelf_width
+= translate
;
938 shelf_width
= std::max(shelf_width
, kAutoHideSize
);
939 target_bounds
->shelf_bounds_in_root
.set_width(shelf_width
);
941 target_bounds
->shelf_bounds_in_root
.set_x(
942 available_bounds
.right() - shelf_width
);
946 target_bounds
->status_bounds_in_shelf
.set_x(0);
948 target_bounds
->status_bounds_in_shelf
.set_x(
949 target_bounds
->shelf_bounds_in_root
.width() -
954 void ShelfLayoutManager::UpdateShelfBackground(
955 BackgroundAnimatorChangeType type
) {
956 const ShelfBackgroundType
background_type(GetShelfBackgroundType());
957 shelf_
->SetPaintsBackground(background_type
, type
);
958 FOR_EACH_OBSERVER(ShelfLayoutManagerObserver
, observers_
,
959 OnBackgroundUpdated(background_type
, type
));
962 ShelfBackgroundType
ShelfLayoutManager::GetShelfBackgroundType() const {
963 if (state_
.visibility_state
!= SHELF_AUTO_HIDE
&&
964 state_
.window_state
== WORKSPACE_WINDOW_STATE_MAXIMIZED
) {
965 return SHELF_BACKGROUND_MAXIMIZED
;
968 if (gesture_drag_status_
== GESTURE_DRAG_IN_PROGRESS
||
969 (!state_
.is_screen_locked
&& window_overlaps_shelf_
) ||
970 (state_
.visibility_state
== SHELF_AUTO_HIDE
)) {
971 return SHELF_BACKGROUND_OVERLAP
;
974 return SHELF_BACKGROUND_DEFAULT
;
977 void ShelfLayoutManager::UpdateAutoHideStateNow() {
978 SetState(state_
.visibility_state
);
980 // If the state did not change, the auto hide timer may still be running.
984 void ShelfLayoutManager::StopAutoHideTimer() {
985 auto_hide_timer_
.Stop();
986 mouse_over_shelf_when_auto_hide_timer_started_
= false;
989 gfx::Rect
ShelfLayoutManager::GetAutoHideShowShelfRegionInScreen() const {
990 gfx::Rect shelf_bounds_in_screen
= shelf_
->GetWindowBoundsInScreen();
991 gfx::Vector2d offset
= SelectValueForShelfAlignment(
992 gfx::Vector2d(0, shelf_bounds_in_screen
.height()),
993 gfx::Vector2d(-kMaxAutoHideShowShelfRegionSize
, 0),
994 gfx::Vector2d(shelf_bounds_in_screen
.width(), 0),
995 gfx::Vector2d(0, -kMaxAutoHideShowShelfRegionSize
));
997 gfx::Rect show_shelf_region_in_screen
= shelf_bounds_in_screen
;
998 show_shelf_region_in_screen
+= offset
;
999 if (IsHorizontalAlignment())
1000 show_shelf_region_in_screen
.set_height(kMaxAutoHideShowShelfRegionSize
);
1002 show_shelf_region_in_screen
.set_width(kMaxAutoHideShowShelfRegionSize
);
1004 // TODO: Figure out if we need any special handling when the keyboard is
1006 return show_shelf_region_in_screen
;
1009 ShelfAutoHideState
ShelfLayoutManager::CalculateAutoHideState(
1010 ShelfVisibilityState visibility_state
) const {
1011 if (force_shelf_always_visibile_
)
1012 return SHELF_AUTO_HIDE_SHOWN
;
1014 if (visibility_state
!= SHELF_AUTO_HIDE
|| !shelf_
)
1015 return SHELF_AUTO_HIDE_HIDDEN
;
1017 Shell
* shell
= Shell::GetInstance();
1018 if (shell
->GetAppListTargetVisibility())
1019 return SHELF_AUTO_HIDE_SHOWN
;
1021 if (shelf_
->status_area_widget() &&
1022 shelf_
->status_area_widget()->ShouldShowShelf())
1023 return SHELF_AUTO_HIDE_SHOWN
;
1025 if (shelf_
->shelf() && shelf_
->shelf()->IsShowingMenu())
1026 return SHELF_AUTO_HIDE_SHOWN
;
1028 if (shelf_
->shelf() && shelf_
->shelf()->IsShowingOverflowBubble())
1029 return SHELF_AUTO_HIDE_SHOWN
;
1031 if (shelf_
->IsActive() || shelf_
->status_area_widget()->IsActive())
1032 return SHELF_AUTO_HIDE_SHOWN
;
1034 const std::vector
<aura::Window
*> windows
=
1035 ash::MruWindowTracker::BuildWindowList(false);
1037 // Process the window list and check if there are any visible windows.
1038 bool visible_window
= false;
1039 for (size_t i
= 0; i
< windows
.size(); ++i
) {
1040 if (windows
[i
] && windows
[i
]->IsVisible() &&
1041 !wm::GetWindowState(windows
[i
])->IsMinimized() &&
1042 root_window_
== windows
[i
]->GetRootWindow()) {
1043 visible_window
= true;
1047 // If there are no visible windows do not hide the shelf.
1048 if (!visible_window
)
1049 return SHELF_AUTO_HIDE_SHOWN
;
1051 if (gesture_drag_status_
== GESTURE_DRAG_COMPLETE_IN_PROGRESS
)
1052 return gesture_drag_auto_hide_state_
;
1054 // Don't show if the user is dragging the mouse.
1055 if (auto_hide_event_filter_
.get() && auto_hide_event_filter_
->in_mouse_drag())
1056 return SHELF_AUTO_HIDE_HIDDEN
;
1058 // Ignore the mouse position if mouse events are disabled.
1059 aura::client::CursorClient
* cursor_client
= aura::client::GetCursorClient(
1060 shelf_
->GetNativeWindow()->GetRootWindow());
1061 if (!cursor_client
->IsMouseEventsEnabled())
1062 return SHELF_AUTO_HIDE_HIDDEN
;
1064 gfx::Rect shelf_region
= shelf_
->GetWindowBoundsInScreen();
1065 if (shelf_
->status_area_widget() &&
1066 shelf_
->status_area_widget()->IsMessageBubbleShown() &&
1068 // Increase the the hit test area to prevent the shelf from disappearing
1069 // when the mouse is over the bubble gap.
1070 ShelfAlignment alignment
= GetAlignment();
1071 shelf_region
.Inset(alignment
== SHELF_ALIGNMENT_RIGHT
?
1072 -kNotificationBubbleGapHeight
: 0,
1073 alignment
== SHELF_ALIGNMENT_BOTTOM
?
1074 -kNotificationBubbleGapHeight
: 0,
1075 alignment
== SHELF_ALIGNMENT_LEFT
?
1076 -kNotificationBubbleGapHeight
: 0,
1077 alignment
== SHELF_ALIGNMENT_TOP
?
1078 -kNotificationBubbleGapHeight
: 0);
1081 gfx::Point cursor_position_in_screen
=
1082 Shell::GetScreen()->GetCursorScreenPoint();
1083 if (shelf_region
.Contains(cursor_position_in_screen
))
1084 return SHELF_AUTO_HIDE_SHOWN
;
1086 // When the shelf is auto hidden and the shelf is on the boundary between two
1087 // displays, it is hard to trigger showing the shelf. For instance, if a
1088 // user's primary display is left of their secondary display, it is hard to
1089 // unautohide a left aligned shelf on the secondary display.
1090 // It is hard because:
1091 // - It is hard to stop the cursor in the shelf "light bar" and not overshoot.
1092 // - The cursor is warped to the other display if the cursor gets to the edge
1094 // Show the shelf if the cursor started on the shelf and the user overshot the
1095 // shelf slightly to make it easier to show the shelf in this situation. We
1096 // do not check |auto_hide_timer_|.IsRunning() because it returns false when
1097 // the timer's task is running.
1098 if ((state_
.auto_hide_state
== SHELF_AUTO_HIDE_SHOWN
||
1099 mouse_over_shelf_when_auto_hide_timer_started_
) &&
1100 GetAutoHideShowShelfRegionInScreen().Contains(
1101 cursor_position_in_screen
)) {
1102 return SHELF_AUTO_HIDE_SHOWN
;
1105 return SHELF_AUTO_HIDE_HIDDEN
;
1108 bool ShelfLayoutManager::IsShelfWindow(aura::Window
* window
) {
1111 return (shelf_
&& shelf_
->GetNativeWindow()->Contains(window
)) ||
1112 (shelf_
->status_area_widget() &&
1113 shelf_
->status_area_widget()->GetNativeWindow()->Contains(window
));
1116 int ShelfLayoutManager::GetWorkAreaSize(const State
& state
, int size
) const {
1117 if (state
.visibility_state
== SHELF_VISIBLE
)
1119 if (state
.visibility_state
== SHELF_AUTO_HIDE
)
1120 return kAutoHideSize
;
1124 gfx::Rect
ShelfLayoutManager::GetAvailableBounds() const {
1125 gfx::Rect
bounds(root_window_
->bounds());
1126 bounds
.set_height(bounds
.height() - keyboard_bounds_
.height());
1130 void ShelfLayoutManager::OnKeyboardBoundsChanging(const gfx::Rect
& new_bounds
) {
1131 bool keyboard_is_about_to_hide
= false;
1132 if (new_bounds
.IsEmpty() && !keyboard_bounds_
.IsEmpty())
1133 keyboard_is_about_to_hide
= true;
1135 keyboard_bounds_
= new_bounds
;
1138 SessionStateDelegate
* session_state_delegate
=
1139 Shell::GetInstance()->session_state_delegate();
1141 // On login screen if keyboard has been just hidden, update bounds just once
1142 // but ignore target_bounds.work_area_insets since shelf overlaps with login
1144 if (session_state_delegate
->IsUserSessionBlocked() &&
1145 keyboard_is_about_to_hide
) {
1146 Shell::GetInstance()->SetDisplayWorkAreaInsets(root_window_
, gfx::Insets());
1150 void ShelfLayoutManager::OnDockBoundsChanging(
1151 const gfx::Rect
& dock_bounds
,
1152 DockedWindowLayoutManagerObserver::Reason reason
) {
1153 // Skip shelf layout in case docked notification originates from this class.
1154 if (reason
== DISPLAY_INSETS_CHANGED
)
1156 if (dock_bounds_
!= dock_bounds
) {
1157 dock_bounds_
= dock_bounds
;
1159 UpdateVisibilityState();
1160 UpdateShelfBackground(BACKGROUND_CHANGE_ANIMATE
);
1164 void ShelfLayoutManager::OnLockStateEvent(LockStateObserver::EventType event
) {
1165 if (event
== EVENT_LOCK_ANIMATION_STARTED
) {
1166 // Enter the screen locked state as the animation starts to prevent
1167 // layout changes as the screen locks.
1168 state_
.is_screen_locked
= true;
1169 // Hide the status area widget (using auto hide animation).
1170 base::AutoReset
<ShelfVisibilityState
> state(&state_
.visibility_state
,
1172 TargetBounds target_bounds
;
1173 CalculateTargetBounds(state_
, &target_bounds
);
1174 UpdateBoundsAndOpacity(target_bounds
, true, NULL
);
1175 UpdateVisibilityState();
1179 void ShelfLayoutManager::SessionStateChanged(
1180 SessionStateDelegate::SessionState state
) {
1181 TargetBounds target_bounds
;
1182 CalculateTargetBounds(state_
, &target_bounds
);
1183 UpdateBoundsAndOpacity(target_bounds
, true, NULL
);
1184 UpdateVisibilityState();