Finish refactoring of DomCodeToUsLayoutKeyboardCode().
[chromium-blink-merge.git] / ash / shelf / shelf_layout_manager.cc
blob75e273b3cd6118af3531735fe5536f263d47734c
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/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/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/keyboard/keyboard_util.h"
50 #include "ui/views/widget/widget.h"
51 #include "ui/wm/public/activation_client.h"
53 namespace ash {
54 namespace {
56 // Delay before showing the shelf. This is after the mouse stops moving.
57 const int kAutoHideDelayMS = 200;
59 // To avoid hiding the shelf when the mouse transitions from a message bubble
60 // into the shelf, the hit test area is enlarged by this amount of pixels to
61 // keep the shelf from hiding.
62 const int kNotificationBubbleGapHeight = 6;
64 // The maximum size of the region on the display opposing the shelf managed by
65 // this ShelfLayoutManager which can trigger showing the shelf.
66 // For instance:
67 // - Primary display is left of secondary display.
68 // - Shelf is left aligned
69 // - This ShelfLayoutManager manages the shelf for the secondary display.
70 // |kMaxAutoHideShowShelfRegionSize| refers to the maximum size of the region
71 // from the right edge of the primary display which can trigger showing the
72 // auto hidden shelf. The region is used to make it easier to trigger showing
73 // the auto hidden shelf when the shelf is on the boundary between displays.
74 const int kMaxAutoHideShowShelfRegionSize = 10;
76 ui::Layer* GetLayer(views::Widget* widget) {
77 return widget->GetNativeView()->layer();
80 } // namespace
82 // static
83 const int ShelfLayoutManager::kWorkspaceAreaVisibleInset = 2;
85 // static
86 const int ShelfLayoutManager::kWorkspaceAreaAutoHideInset = 5;
88 // static
89 const int ShelfLayoutManager::kAutoHideSize = 3;
91 // static
92 const int ShelfLayoutManager::kShelfItemInset = 3;
94 // ShelfLayoutManager::AutoHideEventFilter -------------------------------------
96 // Notifies ShelfLayoutManager any time the mouse moves.
97 class ShelfLayoutManager::AutoHideEventFilter : public ui::EventHandler {
98 public:
99 explicit AutoHideEventFilter(ShelfLayoutManager* shelf);
100 ~AutoHideEventFilter() override;
102 // Returns true if the last mouse event was a mouse drag.
103 bool in_mouse_drag() const { return in_mouse_drag_; }
105 // Overridden from ui::EventHandler:
106 void OnMouseEvent(ui::MouseEvent* event) override;
107 void OnGestureEvent(ui::GestureEvent* event) override;
109 private:
110 ShelfLayoutManager* shelf_;
111 bool in_mouse_drag_;
112 ShelfGestureHandler gesture_handler_;
113 DISALLOW_COPY_AND_ASSIGN(AutoHideEventFilter);
116 ShelfLayoutManager::AutoHideEventFilter::AutoHideEventFilter(
117 ShelfLayoutManager* shelf)
118 : shelf_(shelf),
119 in_mouse_drag_(false) {
120 Shell::GetInstance()->AddPreTargetHandler(this);
123 ShelfLayoutManager::AutoHideEventFilter::~AutoHideEventFilter() {
124 Shell::GetInstance()->RemovePreTargetHandler(this);
127 void ShelfLayoutManager::AutoHideEventFilter::OnMouseEvent(
128 ui::MouseEvent* event) {
129 // This also checks IsShelfWindow() to make sure we don't attempt to hide the
130 // shelf if the mouse down occurs on the shelf.
131 in_mouse_drag_ = (event->type() == ui::ET_MOUSE_DRAGGED ||
132 (in_mouse_drag_ && event->type() != ui::ET_MOUSE_RELEASED &&
133 event->type() != ui::ET_MOUSE_CAPTURE_CHANGED)) &&
134 !shelf_->IsShelfWindow(static_cast<aura::Window*>(event->target()));
135 if (event->type() == ui::ET_MOUSE_MOVED)
136 shelf_->UpdateAutoHideState();
137 return;
140 void ShelfLayoutManager::AutoHideEventFilter::OnGestureEvent(
141 ui::GestureEvent* event) {
142 aura::Window* target_window = static_cast<aura::Window*>(event->target());
143 if (shelf_->IsShelfWindow(target_window)) {
144 if (gesture_handler_.ProcessGestureEvent(*event, target_window))
145 event->StopPropagation();
149 // ShelfLayoutManager:UpdateShelfObserver --------------------------------------
151 // UpdateShelfObserver is used to delay updating the background until the
152 // animation completes.
153 class ShelfLayoutManager::UpdateShelfObserver
154 : public ui::ImplicitAnimationObserver {
155 public:
156 explicit UpdateShelfObserver(ShelfLayoutManager* shelf) : shelf_(shelf) {
157 shelf_->update_shelf_observer_ = this;
160 void Detach() {
161 shelf_ = NULL;
164 void OnImplicitAnimationsCompleted() override {
165 if (shelf_)
166 shelf_->UpdateShelfBackground(BACKGROUND_CHANGE_ANIMATE);
167 delete this;
170 private:
171 ~UpdateShelfObserver() override {
172 if (shelf_)
173 shelf_->update_shelf_observer_ = NULL;
176 // Shelf we're in. NULL if deleted before we're deleted.
177 ShelfLayoutManager* shelf_;
179 DISALLOW_COPY_AND_ASSIGN(UpdateShelfObserver);
182 // ShelfLayoutManager ----------------------------------------------------------
184 ShelfLayoutManager::ShelfLayoutManager(ShelfWidget* shelf)
185 : SnapToPixelLayoutManager(shelf->GetNativeView()->parent()),
186 root_window_(shelf->GetNativeView()->GetRootWindow()),
187 updating_bounds_(false),
188 auto_hide_behavior_(SHELF_AUTO_HIDE_BEHAVIOR_NEVER),
189 alignment_(SHELF_ALIGNMENT_BOTTOM),
190 shelf_(shelf),
191 workspace_controller_(NULL),
192 window_overlaps_shelf_(false),
193 mouse_over_shelf_when_auto_hide_timer_started_(false),
194 bezel_event_filter_(new ShelfBezelEventFilter(this)),
195 gesture_drag_status_(GESTURE_DRAG_NONE),
196 gesture_drag_amount_(0.f),
197 gesture_drag_auto_hide_state_(SHELF_AUTO_HIDE_SHOWN),
198 update_shelf_observer_(NULL),
199 duration_override_in_ms_(0) {
200 Shell::GetInstance()->AddShellObserver(this);
201 Shell::GetInstance()->lock_state_controller()->AddObserver(this);
202 aura::client::GetActivationClient(root_window_)->AddObserver(this);
203 Shell::GetInstance()->session_state_delegate()->AddSessionStateObserver(this);
206 ShelfLayoutManager::~ShelfLayoutManager() {
207 if (update_shelf_observer_)
208 update_shelf_observer_->Detach();
210 FOR_EACH_OBSERVER(ShelfLayoutManagerObserver, observers_, WillDeleteShelf());
211 Shell::GetInstance()->RemoveShellObserver(this);
212 Shell::GetInstance()->lock_state_controller()->RemoveObserver(this);
213 Shell::GetInstance()->
214 session_state_delegate()->RemoveSessionStateObserver(this);
217 void ShelfLayoutManager::SetAutoHideBehavior(ShelfAutoHideBehavior behavior) {
218 if (auto_hide_behavior_ == behavior)
219 return;
220 auto_hide_behavior_ = behavior;
221 UpdateVisibilityState();
222 FOR_EACH_OBSERVER(ShelfLayoutManagerObserver, observers_,
223 OnAutoHideBehaviorChanged(root_window_,
224 auto_hide_behavior_));
227 void ShelfLayoutManager::PrepareForShutdown() {
228 // Clear all event filters, otherwise sometimes those filters may catch
229 // synthesized mouse event and cause crashes during the shutdown.
230 set_workspace_controller(NULL);
231 auto_hide_event_filter_.reset();
232 bezel_event_filter_.reset();
233 // Stop observing window change, otherwise we can attempt to update a
234 // partially destructed shelf.
235 aura::client::GetActivationClient(root_window_)->RemoveObserver(this);
238 bool ShelfLayoutManager::IsVisible() const {
239 // status_area_widget() may be NULL during the shutdown.
240 return shelf_->status_area_widget() &&
241 shelf_->status_area_widget()->IsVisible() &&
242 (state_.visibility_state == SHELF_VISIBLE ||
243 (state_.visibility_state == SHELF_AUTO_HIDE &&
244 state_.auto_hide_state == SHELF_AUTO_HIDE_SHOWN));
247 bool ShelfLayoutManager::SetAlignment(ShelfAlignment alignment) {
248 if (alignment_ == alignment)
249 return false;
251 alignment_ = alignment;
252 // The shelf will itself move to the bottom while locked or obscured by user
253 // login. If a request is sent to move while being obscured, we postpone the
254 // move until the user session is resumed.
255 if (IsAlignmentLocked())
256 return false;
258 // This should not be called during the lock screen transitions.
259 shelf_->SetAlignment(alignment);
260 LayoutShelf();
261 return true;
264 ShelfAlignment ShelfLayoutManager::GetAlignment() const {
265 // When the screen is locked or a user gets added, the shelf is forced into
266 // bottom alignment.
267 if (IsAlignmentLocked())
268 return SHELF_ALIGNMENT_BOTTOM;
269 return alignment_;
272 gfx::Rect ShelfLayoutManager::GetIdealBounds() {
273 gfx::Rect bounds(
274 ScreenUtil::GetDisplayBoundsInParent(shelf_->GetNativeView()));
275 int width = 0, height = 0;
276 GetShelfSize(&width, &height);
277 return SelectValueForShelfAlignment(
278 gfx::Rect(bounds.x(), bounds.bottom() - height, bounds.width(), height),
279 gfx::Rect(bounds.x(), bounds.y(), width, bounds.height()),
280 gfx::Rect(bounds.right() - width, bounds.y(), width, bounds.height()),
281 gfx::Rect(bounds.x(), bounds.y(), bounds.width(), height));
284 void ShelfLayoutManager::LayoutShelf() {
285 TargetBounds target_bounds;
286 CalculateTargetBounds(state_, &target_bounds);
287 UpdateBoundsAndOpacity(target_bounds, false, NULL);
289 if (shelf_->shelf()) {
290 // This is not part of UpdateBoundsAndOpacity() because
291 // SetShelfViewBounds() sets the bounds immediately and does not animate.
292 // The height of the ShelfView for a horizontal shelf and the width of
293 // the ShelfView for a vertical shelf are set when |shelf_|'s bounds
294 // are changed via UpdateBoundsAndOpacity(). This sets the origin and the
295 // dimension in the other direction.
296 shelf_->shelf()->SetShelfViewBounds(
297 target_bounds.shelf_bounds_in_shelf);
298 // Update insets in ShelfWindowTargeter when shelf bounds change.
299 FOR_EACH_OBSERVER(ShelfLayoutManagerObserver, observers_,
300 WillChangeVisibilityState(visibility_state()));
304 ShelfVisibilityState ShelfLayoutManager::CalculateShelfVisibility() {
305 switch(auto_hide_behavior_) {
306 case SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS:
307 #if defined(OS_WIN)
308 // Disable shelf auto-hide behavior on screen sides in Metro mode.
309 if (GetAlignment() != SHELF_ALIGNMENT_BOTTOM)
310 return SHELF_VISIBLE;
311 #endif
312 return SHELF_AUTO_HIDE;
313 case SHELF_AUTO_HIDE_BEHAVIOR_NEVER:
314 return SHELF_VISIBLE;
315 case SHELF_AUTO_HIDE_ALWAYS_HIDDEN:
316 return SHELF_HIDDEN;
318 return SHELF_VISIBLE;
321 void ShelfLayoutManager::UpdateVisibilityState() {
322 // Bail out early when there is no |workspace_controller_|, which happens
323 // during shutdown after PrepareForShutdown.
324 if (!workspace_controller_)
325 return;
327 if (state_.is_screen_locked || state_.is_adding_user_screen) {
328 SetState(SHELF_VISIBLE);
329 } else {
330 // TODO(zelidrag): Verify shelf drag animation still shows on the device
331 // when we are in SHELF_AUTO_HIDE_ALWAYS_HIDDEN.
332 WorkspaceWindowState window_state(workspace_controller_->GetWindowState());
333 switch (window_state) {
334 case WORKSPACE_WINDOW_STATE_FULL_SCREEN: {
335 const aura::Window* fullscreen_window = GetRootWindowController(
336 root_window_)->GetWindowForFullscreenMode();
337 if (fullscreen_window && wm::GetWindowState(fullscreen_window)->
338 hide_shelf_when_fullscreen()) {
339 SetState(SHELF_HIDDEN);
340 } else {
341 // The shelf is sometimes not hidden when in immersive fullscreen.
342 // Force the shelf to be auto hidden in this case.
343 SetState(SHELF_AUTO_HIDE);
345 break;
348 case WORKSPACE_WINDOW_STATE_MAXIMIZED:
349 SetState(CalculateShelfVisibility());
350 break;
352 case WORKSPACE_WINDOW_STATE_WINDOW_OVERLAPS_SHELF:
353 case WORKSPACE_WINDOW_STATE_DEFAULT:
354 SetState(CalculateShelfVisibility());
355 SetWindowOverlapsShelf(window_state ==
356 WORKSPACE_WINDOW_STATE_WINDOW_OVERLAPS_SHELF);
357 break;
362 void ShelfLayoutManager::UpdateAutoHideState() {
363 ShelfAutoHideState auto_hide_state =
364 CalculateAutoHideState(state_.visibility_state);
365 if (auto_hide_state != state_.auto_hide_state) {
366 if (auto_hide_state == SHELF_AUTO_HIDE_HIDDEN) {
367 // Hides happen immediately.
368 SetState(state_.visibility_state);
369 } else {
370 if (!auto_hide_timer_.IsRunning()) {
371 mouse_over_shelf_when_auto_hide_timer_started_ =
372 shelf_->GetWindowBoundsInScreen().Contains(
373 Shell::GetScreen()->GetCursorScreenPoint());
375 auto_hide_timer_.Start(
376 FROM_HERE,
377 base::TimeDelta::FromMilliseconds(kAutoHideDelayMS),
378 this, &ShelfLayoutManager::UpdateAutoHideStateNow);
380 } else {
381 StopAutoHideTimer();
385 void ShelfLayoutManager::SetWindowOverlapsShelf(bool value) {
386 window_overlaps_shelf_ = value;
387 UpdateShelfBackground(BACKGROUND_CHANGE_ANIMATE);
390 void ShelfLayoutManager::AddObserver(ShelfLayoutManagerObserver* observer) {
391 observers_.AddObserver(observer);
394 void ShelfLayoutManager::RemoveObserver(ShelfLayoutManagerObserver* observer) {
395 observers_.RemoveObserver(observer);
398 ////////////////////////////////////////////////////////////////////////////////
399 // ShelfLayoutManager, Gesture functions:
401 void ShelfLayoutManager::OnGestureEdgeSwipe(const ui::GestureEvent& gesture) {
402 if (visibility_state() == SHELF_AUTO_HIDE) {
403 gesture_drag_auto_hide_state_ = SHELF_AUTO_HIDE_SHOWN;
404 gesture_drag_status_ = GESTURE_DRAG_COMPLETE_IN_PROGRESS;
405 UpdateVisibilityState();
406 gesture_drag_status_ = GESTURE_DRAG_NONE;
410 void ShelfLayoutManager::StartGestureDrag(const ui::GestureEvent& gesture) {
411 gesture_drag_status_ = GESTURE_DRAG_IN_PROGRESS;
412 gesture_drag_amount_ = 0.f;
413 gesture_drag_auto_hide_state_ = visibility_state() == SHELF_AUTO_HIDE ?
414 auto_hide_state() : SHELF_AUTO_HIDE_SHOWN;
415 UpdateShelfBackground(BACKGROUND_CHANGE_ANIMATE);
418 void ShelfLayoutManager::UpdateGestureDrag(
419 const ui::GestureEvent& gesture) {
420 bool horizontal = IsHorizontalAlignment();
421 gesture_drag_amount_ += horizontal ? gesture.details().scroll_y() :
422 gesture.details().scroll_x();
423 LayoutShelf();
426 void ShelfLayoutManager::CompleteGestureDrag(const ui::GestureEvent& gesture) {
427 bool horizontal = IsHorizontalAlignment();
428 bool should_change = false;
429 if (gesture.type() == ui::ET_GESTURE_SCROLL_END) {
430 // The visibility of the shelf changes only if the shelf was dragged X%
431 // along the correct axis. If the shelf was already visible, then the
432 // direction of the drag does not matter.
433 const float kDragHideThreshold = 0.4f;
434 gfx::Rect bounds = GetIdealBounds();
435 float drag_ratio = fabs(gesture_drag_amount_) /
436 (horizontal ? bounds.height() : bounds.width());
437 if (gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_SHOWN) {
438 should_change = drag_ratio > kDragHideThreshold;
439 } else {
440 bool correct_direction = false;
441 switch (GetAlignment()) {
442 case SHELF_ALIGNMENT_BOTTOM:
443 case SHELF_ALIGNMENT_RIGHT:
444 correct_direction = gesture_drag_amount_ < 0;
445 break;
446 case SHELF_ALIGNMENT_LEFT:
447 case SHELF_ALIGNMENT_TOP:
448 correct_direction = gesture_drag_amount_ > 0;
449 break;
451 should_change = correct_direction && drag_ratio > kDragHideThreshold;
453 } else if (gesture.type() == ui::ET_SCROLL_FLING_START) {
454 if (gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_SHOWN) {
455 should_change = horizontal ? fabs(gesture.details().velocity_y()) > 0 :
456 fabs(gesture.details().velocity_x()) > 0;
457 } else {
458 should_change = SelectValueForShelfAlignment(
459 gesture.details().velocity_y() < 0,
460 gesture.details().velocity_x() > 0,
461 gesture.details().velocity_x() < 0,
462 gesture.details().velocity_y() > 0);
464 } else {
465 NOTREACHED();
468 if (!should_change) {
469 CancelGestureDrag();
470 return;
472 if (shelf_) {
473 shelf_->Deactivate();
474 shelf_->status_area_widget()->Deactivate();
476 gesture_drag_auto_hide_state_ =
477 gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_SHOWN ?
478 SHELF_AUTO_HIDE_HIDDEN : SHELF_AUTO_HIDE_SHOWN;
479 ShelfAutoHideBehavior new_auto_hide_behavior =
480 gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_SHOWN ?
481 SHELF_AUTO_HIDE_BEHAVIOR_NEVER : SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS;
483 // When in fullscreen and the shelf is forced to be auto hidden, the auto hide
484 // behavior affects neither the visibility state nor the auto hide state. Set
485 // |gesture_drag_status_| to GESTURE_DRAG_COMPLETE_IN_PROGRESS to set the auto
486 // hide state to |gesture_drag_auto_hide_state_|.
487 gesture_drag_status_ = GESTURE_DRAG_COMPLETE_IN_PROGRESS;
488 if (auto_hide_behavior_ != new_auto_hide_behavior)
489 SetAutoHideBehavior(new_auto_hide_behavior);
490 else
491 UpdateVisibilityState();
492 gesture_drag_status_ = GESTURE_DRAG_NONE;
495 void ShelfLayoutManager::CancelGestureDrag() {
496 gesture_drag_status_ = GESTURE_DRAG_CANCEL_IN_PROGRESS;
497 UpdateVisibilityState();
498 gesture_drag_status_ = GESTURE_DRAG_NONE;
501 void ShelfLayoutManager::SetAnimationDurationOverride(
502 int duration_override_in_ms) {
503 duration_override_in_ms_ = duration_override_in_ms;
506 ////////////////////////////////////////////////////////////////////////////////
507 // ShelfLayoutManager, aura::LayoutManager implementation:
509 void ShelfLayoutManager::OnWindowResized() {
510 LayoutShelf();
513 void ShelfLayoutManager::SetChildBounds(aura::Window* child,
514 const gfx::Rect& requested_bounds) {
515 SnapToPixelLayoutManager::SetChildBounds(child, requested_bounds);
516 // We may contain other widgets (such as frame maximize bubble) but they don't
517 // effect the layout in anyway.
518 if (!updating_bounds_ &&
519 ((shelf_->GetNativeView() == child) ||
520 (shelf_->status_area_widget()->GetNativeView() == child))) {
521 LayoutShelf();
525 void ShelfLayoutManager::OnLockStateChanged(bool locked) {
526 // Force the shelf to layout for alignment (bottom if locked, restore
527 // the previous alignment otherwise).
528 state_.is_screen_locked = locked;
529 UpdateShelfVisibilityAfterLoginUIChange();
532 void ShelfLayoutManager::OnWindowActivated(
533 aura::client::ActivationChangeObserver::ActivationReason reason,
534 aura::Window* gained_active,
535 aura::Window* lost_active) {
536 UpdateAutoHideStateNow();
539 bool ShelfLayoutManager::IsHorizontalAlignment() const {
540 return GetAlignment() == SHELF_ALIGNMENT_BOTTOM ||
541 GetAlignment() == SHELF_ALIGNMENT_TOP;
544 // static
545 ShelfLayoutManager* ShelfLayoutManager::ForShelf(aura::Window* window) {
546 ShelfWidget* shelf = RootWindowController::ForShelf(window)->shelf();
547 return shelf ? shelf->shelf_layout_manager() : NULL;
550 ////////////////////////////////////////////////////////////////////////////////
551 // ShelfLayoutManager, private:
553 ShelfLayoutManager::TargetBounds::TargetBounds() : opacity(0.0f) {}
554 ShelfLayoutManager::TargetBounds::~TargetBounds() {}
556 void ShelfLayoutManager::SetState(ShelfVisibilityState visibility_state) {
557 if (!shelf_->GetNativeView())
558 return;
560 State state;
561 state.visibility_state = visibility_state;
562 state.auto_hide_state = CalculateAutoHideState(visibility_state);
563 state.window_state = workspace_controller_ ?
564 workspace_controller_->GetWindowState() : WORKSPACE_WINDOW_STATE_DEFAULT;
565 // Preserve the log in screen states.
566 state.is_adding_user_screen = state_.is_adding_user_screen;
567 state.is_screen_locked = state_.is_screen_locked;
569 // Force an update because gesture drags affect the shelf bounds and we
570 // should animate back to the normal bounds at the end of a gesture.
571 bool force_update =
572 (gesture_drag_status_ == GESTURE_DRAG_CANCEL_IN_PROGRESS ||
573 gesture_drag_status_ == GESTURE_DRAG_COMPLETE_IN_PROGRESS);
575 if (!force_update && state_.Equals(state))
576 return; // Nothing changed.
578 FOR_EACH_OBSERVER(ShelfLayoutManagerObserver, observers_,
579 WillChangeVisibilityState(visibility_state));
581 if (state.visibility_state == SHELF_AUTO_HIDE) {
582 // When state is SHELF_AUTO_HIDE we need to track when the mouse is over the
583 // shelf to unhide it. AutoHideEventFilter does that for us.
584 if (!auto_hide_event_filter_)
585 auto_hide_event_filter_.reset(new AutoHideEventFilter(this));
586 } else {
587 auto_hide_event_filter_.reset(NULL);
590 StopAutoHideTimer();
592 State old_state = state_;
593 state_ = state;
595 BackgroundAnimatorChangeType change_type = BACKGROUND_CHANGE_ANIMATE;
596 bool delay_background_change = false;
598 // Do not animate the background when:
599 // - Going from a hidden / auto hidden shelf in fullscreen to a visible shelf
600 // in maximized mode.
601 // - Going from an auto hidden shelf in maximized mode to a visible shelf in
602 // maximized mode.
603 if (state.visibility_state == SHELF_VISIBLE &&
604 state.window_state == WORKSPACE_WINDOW_STATE_MAXIMIZED &&
605 old_state.visibility_state != SHELF_VISIBLE) {
606 change_type = BACKGROUND_CHANGE_IMMEDIATE;
607 } else {
608 // Delay the animation when the shelf was hidden, and has just been made
609 // visible (e.g. using a gesture-drag).
610 if (state.visibility_state == SHELF_VISIBLE &&
611 old_state.visibility_state == SHELF_AUTO_HIDE &&
612 old_state.auto_hide_state == SHELF_AUTO_HIDE_HIDDEN) {
613 delay_background_change = true;
617 if (delay_background_change) {
618 if (update_shelf_observer_)
619 update_shelf_observer_->Detach();
620 // UpdateShelfBackground deletes itself when the animation is done.
621 update_shelf_observer_ = new UpdateShelfObserver(this);
622 } else {
623 UpdateShelfBackground(change_type);
626 shelf_->SetDimsShelf(
627 state.visibility_state == SHELF_VISIBLE &&
628 state.window_state == WORKSPACE_WINDOW_STATE_MAXIMIZED);
630 TargetBounds target_bounds;
631 CalculateTargetBounds(state_, &target_bounds);
632 UpdateBoundsAndOpacity(target_bounds, true,
633 delay_background_change ? update_shelf_observer_ : NULL);
635 // OnAutoHideStateChanged Should be emitted when:
636 // - firstly state changed to auto-hide from other state
637 // - or, auto_hide_state has changed
638 if ((old_state.visibility_state != state_.visibility_state &&
639 state_.visibility_state == SHELF_AUTO_HIDE) ||
640 old_state.auto_hide_state != state_.auto_hide_state) {
641 FOR_EACH_OBSERVER(ShelfLayoutManagerObserver, observers_,
642 OnAutoHideStateChanged(state_.auto_hide_state));
646 void ShelfLayoutManager::UpdateBoundsAndOpacity(
647 const TargetBounds& target_bounds,
648 bool animate,
649 ui::ImplicitAnimationObserver* observer) {
650 base::AutoReset<bool> auto_reset_updating_bounds(&updating_bounds_, true);
652 ui::ScopedLayerAnimationSettings shelf_animation_setter(
653 GetLayer(shelf_)->GetAnimator());
654 ui::ScopedLayerAnimationSettings status_animation_setter(
655 GetLayer(shelf_->status_area_widget())->GetAnimator());
656 if (animate) {
657 int duration = duration_override_in_ms_ ? duration_override_in_ms_ :
658 kCrossFadeDurationMS;
659 shelf_animation_setter.SetTransitionDuration(
660 base::TimeDelta::FromMilliseconds(duration));
661 shelf_animation_setter.SetTweenType(gfx::Tween::EASE_OUT);
662 shelf_animation_setter.SetPreemptionStrategy(
663 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
664 status_animation_setter.SetTransitionDuration(
665 base::TimeDelta::FromMilliseconds(duration));
666 status_animation_setter.SetTweenType(gfx::Tween::EASE_OUT);
667 status_animation_setter.SetPreemptionStrategy(
668 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
669 } else {
670 StopAnimating();
671 shelf_animation_setter.SetTransitionDuration(base::TimeDelta());
672 status_animation_setter.SetTransitionDuration(base::TimeDelta());
674 if (observer)
675 status_animation_setter.AddObserver(observer);
677 GetLayer(shelf_)->SetOpacity(target_bounds.opacity);
678 shelf_->SetBounds(ScreenUtil::ConvertRectToScreen(
679 shelf_->GetNativeView()->parent(),
680 target_bounds.shelf_bounds_in_root));
682 GetLayer(shelf_->status_area_widget())->SetOpacity(
683 target_bounds.status_opacity);
685 // Having a window which is visible but does not have an opacity is an
686 // illegal state. We therefore hide the shelf here if required.
687 if (!target_bounds.status_opacity)
688 shelf_->status_area_widget()->Hide();
689 // Setting visibility during an animation causes the visibility property to
690 // animate. Override the animation settings to immediately set the
691 // visibility property. Opacity will still animate.
693 // TODO(harrym): Once status area widget is a child view of shelf
694 // this can be simplified.
695 gfx::Rect status_bounds = target_bounds.status_bounds_in_shelf;
696 status_bounds.set_x(status_bounds.x() +
697 target_bounds.shelf_bounds_in_root.x());
698 status_bounds.set_y(status_bounds.y() +
699 target_bounds.shelf_bounds_in_root.y());
700 shelf_->status_area_widget()->SetBounds(
701 ScreenUtil::ConvertRectToScreen(
702 shelf_->status_area_widget()->GetNativeView()->parent(),
703 status_bounds));
704 if (!state_.is_screen_locked) {
705 gfx::Insets insets;
706 // If user session is blocked (login to new user session or add user to
707 // the existing session - multi-profile) then give 100% of work area only
708 // if keyboard is not shown.
709 if (!state_.is_adding_user_screen || !keyboard_bounds_.IsEmpty()) {
710 insets = target_bounds.work_area_insets;
712 Shell::GetInstance()->SetDisplayWorkAreaInsets(root_window_, insets);
716 // Setting visibility during an animation causes the visibility property to
717 // animate. Set the visibility property without an animation.
718 if (target_bounds.status_opacity)
719 shelf_->status_area_widget()->Show();
722 void ShelfLayoutManager::StopAnimating() {
723 GetLayer(shelf_)->GetAnimator()->StopAnimating();
724 GetLayer(shelf_->status_area_widget())->GetAnimator()->StopAnimating();
727 void ShelfLayoutManager::GetShelfSize(int* width, int* height) {
728 *width = *height = 0;
729 gfx::Size status_size(
730 shelf_->status_area_widget()->GetWindowBoundsInScreen().size());
731 if (IsHorizontalAlignment())
732 *height = kShelfSize;
733 else
734 *width = kShelfSize;
737 void ShelfLayoutManager::AdjustBoundsBasedOnAlignment(int inset,
738 gfx::Rect* bounds) const {
739 bounds->Inset(SelectValueForShelfAlignment(
740 gfx::Insets(0, 0, inset, 0),
741 gfx::Insets(0, inset, 0, 0),
742 gfx::Insets(0, 0, 0, inset),
743 gfx::Insets(inset, 0, 0, 0)));
746 void ShelfLayoutManager::CalculateTargetBounds(
747 const State& state,
748 TargetBounds* target_bounds) {
749 gfx::Rect available_bounds =
750 ScreenUtil::GetShelfDisplayBoundsInScreen(root_window_);
751 available_bounds =
752 ScreenUtil::ConvertRectFromScreen(root_window_, available_bounds);
754 gfx::Rect status_size(
755 shelf_->status_area_widget()->GetWindowBoundsInScreen().size());
756 int shelf_width = 0, shelf_height = 0;
757 GetShelfSize(&shelf_width, &shelf_height);
758 if (IsHorizontalAlignment())
759 shelf_width = available_bounds.width();
760 else
761 shelf_height = available_bounds.height();
763 if (state.visibility_state == SHELF_AUTO_HIDE &&
764 state.auto_hide_state == SHELF_AUTO_HIDE_HIDDEN) {
765 // Auto-hidden shelf always starts with the default size. If a gesture-drag
766 // is in progress, then the call to UpdateTargetBoundsForGesture() below
767 // takes care of setting the height properly.
768 if (IsHorizontalAlignment())
769 shelf_height = kAutoHideSize;
770 else
771 shelf_width = kAutoHideSize;
772 } else if (state.visibility_state == SHELF_HIDDEN ||
773 (!keyboard_bounds_.IsEmpty() && !keyboard::IsKeyboardOverscrollEnabled()))
775 if (IsHorizontalAlignment())
776 shelf_height = 0;
777 else
778 shelf_width = 0;
781 int bottom_shelf_vertical_offset = available_bounds.bottom();
782 if (keyboard_bounds_.IsEmpty())
783 bottom_shelf_vertical_offset -= shelf_height;
784 else
785 bottom_shelf_vertical_offset -= keyboard_bounds_.height();
787 target_bounds->shelf_bounds_in_root = SelectValueForShelfAlignment(
788 gfx::Rect(available_bounds.x(), bottom_shelf_vertical_offset,
789 available_bounds.width(), shelf_height),
790 gfx::Rect(available_bounds.x(), available_bounds.y(),
791 shelf_width, available_bounds.height()),
792 gfx::Rect(available_bounds.right() - shelf_width, available_bounds.y(),
793 shelf_width, available_bounds.height()),
794 gfx::Rect(available_bounds.x(), available_bounds.y(),
795 available_bounds.width(), shelf_height));
797 if (IsHorizontalAlignment())
798 status_size.set_height(kShelfSize);
799 else
800 status_size.set_width(kShelfSize);
802 target_bounds->status_bounds_in_shelf = SelectValueForShelfAlignment(
803 gfx::Rect(base::i18n::IsRTL() ? 0 : shelf_width - status_size.width(),
804 0, status_size.width(), status_size.height()),
805 gfx::Rect(shelf_width - status_size.width(),
806 shelf_height - status_size.height(), status_size.width(),
807 status_size.height()),
808 gfx::Rect(0, shelf_height - status_size.height(),
809 status_size.width(), status_size.height()),
810 gfx::Rect(base::i18n::IsRTL() ? 0 : shelf_width - status_size.width(),
811 shelf_height - status_size.height(),
812 status_size.width(), status_size.height()));
814 target_bounds->work_area_insets = SelectValueForShelfAlignment(
815 gfx::Insets(0, 0, GetWorkAreaSize(state, shelf_height), 0),
816 gfx::Insets(0, GetWorkAreaSize(state, shelf_width), 0, 0),
817 gfx::Insets(0, 0, 0, GetWorkAreaSize(state, shelf_width)),
818 gfx::Insets(GetWorkAreaSize(state, shelf_height), 0, 0, 0));
820 // TODO(varkha): The functionality of managing insets for display areas
821 // should probably be pushed to a separate component. This would simplify or
822 // remove entirely the dependency on keyboard and dock.
824 if (!keyboard_bounds_.IsEmpty() && !keyboard::IsKeyboardOverscrollEnabled()) {
825 // Also push in the work area inset for the keyboard if it is visible.
826 gfx::Insets keyboard_insets(0, 0, keyboard_bounds_.height(), 0);
827 target_bounds->work_area_insets += keyboard_insets;
830 // Also push in the work area inset for the dock if it is visible.
831 if (!dock_bounds_.IsEmpty()) {
832 gfx::Insets dock_insets(
833 0, (dock_bounds_.x() > 0 ? 0 : dock_bounds_.width()),
834 0, (dock_bounds_.x() > 0 ? dock_bounds_.width() : 0));
835 target_bounds->work_area_insets += dock_insets;
838 target_bounds->opacity =
839 (gesture_drag_status_ == GESTURE_DRAG_IN_PROGRESS ||
840 state.visibility_state == SHELF_VISIBLE ||
841 state.visibility_state == SHELF_AUTO_HIDE) ? 1.0f : 0.0f;
842 target_bounds->status_opacity =
843 (state.visibility_state == SHELF_AUTO_HIDE &&
844 state.auto_hide_state == SHELF_AUTO_HIDE_HIDDEN &&
845 gesture_drag_status_ != GESTURE_DRAG_IN_PROGRESS) ?
846 0.0f : target_bounds->opacity;
848 if (gesture_drag_status_ == GESTURE_DRAG_IN_PROGRESS)
849 UpdateTargetBoundsForGesture(target_bounds);
851 // This needs to happen after calling UpdateTargetBoundsForGesture(), because
852 // that can change the size of the shelf.
853 target_bounds->shelf_bounds_in_shelf = SelectValueForShelfAlignment(
854 gfx::Rect(0, 0,
855 shelf_width - status_size.width(),
856 target_bounds->shelf_bounds_in_root.height()),
857 gfx::Rect(0, 0, target_bounds->shelf_bounds_in_root.width(),
858 shelf_height - status_size.height()),
859 gfx::Rect(0, 0, target_bounds->shelf_bounds_in_root.width(),
860 shelf_height - status_size.height()),
861 gfx::Rect(0, 0,
862 shelf_width - status_size.width(),
863 target_bounds->shelf_bounds_in_root.height()));
865 user_work_area_bounds_ = available_bounds;
866 user_work_area_bounds_.Subtract(target_bounds->shelf_bounds_in_root);
867 user_work_area_bounds_.Subtract(keyboard_bounds_);
870 void ShelfLayoutManager::UpdateTargetBoundsForGesture(
871 TargetBounds* target_bounds) const {
872 CHECK_EQ(GESTURE_DRAG_IN_PROGRESS, gesture_drag_status_);
873 bool horizontal = IsHorizontalAlignment();
874 const gfx::Rect& available_bounds(root_window_->bounds());
875 int resistance_free_region = 0;
877 if (gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_HIDDEN &&
878 visibility_state() == SHELF_AUTO_HIDE &&
879 auto_hide_state() != SHELF_AUTO_HIDE_SHOWN) {
880 // If the shelf was hidden when the drag started (and the state hasn't
881 // changed since then, e.g. because the tray-menu was shown because of the
882 // drag), then allow the drag some resistance-free region at first to make
883 // sure the shelf sticks with the finger until the shelf is visible.
884 resistance_free_region = kShelfSize - kAutoHideSize;
887 bool resist = SelectValueForShelfAlignment(
888 gesture_drag_amount_ < -resistance_free_region,
889 gesture_drag_amount_ > resistance_free_region,
890 gesture_drag_amount_ < -resistance_free_region,
891 gesture_drag_amount_ > resistance_free_region);
893 float translate = 0.f;
894 if (resist) {
895 float diff = fabsf(gesture_drag_amount_) - resistance_free_region;
896 diff = std::min(diff, sqrtf(diff));
897 if (gesture_drag_amount_ < 0)
898 translate = -resistance_free_region - diff;
899 else
900 translate = resistance_free_region + diff;
901 } else {
902 translate = gesture_drag_amount_;
905 if (horizontal) {
906 // Move and size the shelf with the gesture.
907 int shelf_height = target_bounds->shelf_bounds_in_root.height() - translate;
908 shelf_height = std::max(shelf_height, kAutoHideSize);
909 target_bounds->shelf_bounds_in_root.set_height(shelf_height);
910 if (GetAlignment() == SHELF_ALIGNMENT_BOTTOM) {
911 target_bounds->shelf_bounds_in_root.set_y(
912 available_bounds.bottom() - shelf_height);
915 target_bounds->status_bounds_in_shelf.set_y(0);
916 } else {
917 // Move and size the shelf with the gesture.
918 int shelf_width = target_bounds->shelf_bounds_in_root.width();
919 bool right_aligned = GetAlignment() == SHELF_ALIGNMENT_RIGHT;
920 if (right_aligned)
921 shelf_width -= translate;
922 else
923 shelf_width += translate;
924 shelf_width = std::max(shelf_width, kAutoHideSize);
925 target_bounds->shelf_bounds_in_root.set_width(shelf_width);
926 if (right_aligned) {
927 target_bounds->shelf_bounds_in_root.set_x(
928 available_bounds.right() - shelf_width);
931 if (right_aligned)
932 target_bounds->status_bounds_in_shelf.set_x(0);
933 else
934 target_bounds->status_bounds_in_shelf.set_x(
935 target_bounds->shelf_bounds_in_root.width() -
936 kShelfSize);
940 void ShelfLayoutManager::UpdateShelfBackground(
941 BackgroundAnimatorChangeType type) {
942 const ShelfBackgroundType background_type(GetShelfBackgroundType());
943 shelf_->SetPaintsBackground(background_type, type);
944 FOR_EACH_OBSERVER(ShelfLayoutManagerObserver, observers_,
945 OnBackgroundUpdated(background_type, type));
948 ShelfBackgroundType ShelfLayoutManager::GetShelfBackgroundType() const {
949 if (state_.visibility_state != SHELF_AUTO_HIDE &&
950 state_.window_state == WORKSPACE_WINDOW_STATE_MAXIMIZED) {
951 return SHELF_BACKGROUND_MAXIMIZED;
954 if (gesture_drag_status_ == GESTURE_DRAG_IN_PROGRESS ||
955 (!state_.is_screen_locked && !state_.is_adding_user_screen &&
956 window_overlaps_shelf_) ||
957 (state_.visibility_state == SHELF_AUTO_HIDE)) {
958 return SHELF_BACKGROUND_OVERLAP;
961 return SHELF_BACKGROUND_DEFAULT;
964 void ShelfLayoutManager::UpdateAutoHideStateNow() {
965 SetState(state_.visibility_state);
967 // If the state did not change, the auto hide timer may still be running.
968 StopAutoHideTimer();
971 void ShelfLayoutManager::StopAutoHideTimer() {
972 auto_hide_timer_.Stop();
973 mouse_over_shelf_when_auto_hide_timer_started_ = false;
976 gfx::Rect ShelfLayoutManager::GetAutoHideShowShelfRegionInScreen() const {
977 gfx::Rect shelf_bounds_in_screen = shelf_->GetWindowBoundsInScreen();
978 gfx::Vector2d offset = SelectValueForShelfAlignment(
979 gfx::Vector2d(0, shelf_bounds_in_screen.height()),
980 gfx::Vector2d(-kMaxAutoHideShowShelfRegionSize, 0),
981 gfx::Vector2d(shelf_bounds_in_screen.width(), 0),
982 gfx::Vector2d(0, -kMaxAutoHideShowShelfRegionSize));
984 gfx::Rect show_shelf_region_in_screen = shelf_bounds_in_screen;
985 show_shelf_region_in_screen += offset;
986 if (IsHorizontalAlignment())
987 show_shelf_region_in_screen.set_height(kMaxAutoHideShowShelfRegionSize);
988 else
989 show_shelf_region_in_screen.set_width(kMaxAutoHideShowShelfRegionSize);
991 // TODO: Figure out if we need any special handling when the keyboard is
992 // visible.
993 return show_shelf_region_in_screen;
996 ShelfAutoHideState ShelfLayoutManager::CalculateAutoHideState(
997 ShelfVisibilityState visibility_state) const {
998 if (visibility_state != SHELF_AUTO_HIDE || !shelf_)
999 return SHELF_AUTO_HIDE_HIDDEN;
1001 Shell* shell = Shell::GetInstance();
1002 // Unhide the shelf only on the active screen when the AppList is shown
1003 // (crbug.com/312445).
1004 if (shell->GetAppListTargetVisibility()) {
1005 aura::Window* active_window = wm::GetActiveWindow();
1006 aura::Window* shelf_window = shelf_->GetNativeWindow();
1007 if (active_window && shelf_window &&
1008 active_window->GetRootWindow() == shelf_window->GetRootWindow()) {
1009 return SHELF_AUTO_HIDE_SHOWN;
1013 if (shelf_->status_area_widget() &&
1014 shelf_->status_area_widget()->ShouldShowShelf())
1015 return SHELF_AUTO_HIDE_SHOWN;
1017 if (shelf_->shelf() && shelf_->shelf()->IsShowingMenu())
1018 return SHELF_AUTO_HIDE_SHOWN;
1020 if (shelf_->shelf() && shelf_->shelf()->IsShowingOverflowBubble())
1021 return SHELF_AUTO_HIDE_SHOWN;
1023 if (shelf_->IsActive() ||
1024 (shelf_->status_area_widget() &&
1025 shelf_->status_area_widget()->IsActive()))
1026 return SHELF_AUTO_HIDE_SHOWN;
1028 const std::vector<aura::Window*> windows =
1029 shell->mru_window_tracker()->BuildWindowListIgnoreModal();
1031 // Process the window list and check if there are any visible windows.
1032 bool visible_window = false;
1033 for (size_t i = 0; i < windows.size(); ++i) {
1034 if (windows[i] && windows[i]->IsVisible() &&
1035 !wm::GetWindowState(windows[i])->IsMinimized() &&
1036 root_window_ == windows[i]->GetRootWindow()) {
1037 visible_window = true;
1038 break;
1041 // If there are no visible windows do not hide the shelf.
1042 if (!visible_window)
1043 return SHELF_AUTO_HIDE_SHOWN;
1045 if (gesture_drag_status_ == GESTURE_DRAG_COMPLETE_IN_PROGRESS)
1046 return gesture_drag_auto_hide_state_;
1048 // Don't show if the user is dragging the mouse.
1049 if (auto_hide_event_filter_.get() && auto_hide_event_filter_->in_mouse_drag())
1050 return SHELF_AUTO_HIDE_HIDDEN;
1052 // Ignore the mouse position if mouse events are disabled.
1053 aura::client::CursorClient* cursor_client = aura::client::GetCursorClient(
1054 shelf_->GetNativeWindow()->GetRootWindow());
1055 if (!cursor_client->IsMouseEventsEnabled())
1056 return SHELF_AUTO_HIDE_HIDDEN;
1058 gfx::Rect shelf_region = shelf_->GetWindowBoundsInScreen();
1059 if (shelf_->status_area_widget() &&
1060 shelf_->status_area_widget()->IsMessageBubbleShown() &&
1061 IsVisible()) {
1062 // Increase the the hit test area to prevent the shelf from disappearing
1063 // when the mouse is over the bubble gap.
1064 ShelfAlignment alignment = GetAlignment();
1065 shelf_region.Inset(alignment == SHELF_ALIGNMENT_RIGHT ?
1066 -kNotificationBubbleGapHeight : 0,
1067 alignment == SHELF_ALIGNMENT_BOTTOM ?
1068 -kNotificationBubbleGapHeight : 0,
1069 alignment == SHELF_ALIGNMENT_LEFT ?
1070 -kNotificationBubbleGapHeight : 0,
1071 alignment == SHELF_ALIGNMENT_TOP ?
1072 -kNotificationBubbleGapHeight : 0);
1075 gfx::Point cursor_position_in_screen =
1076 Shell::GetScreen()->GetCursorScreenPoint();
1077 if (shelf_region.Contains(cursor_position_in_screen))
1078 return SHELF_AUTO_HIDE_SHOWN;
1080 // When the shelf is auto hidden and the shelf is on the boundary between two
1081 // displays, it is hard to trigger showing the shelf. For instance, if a
1082 // user's primary display is left of their secondary display, it is hard to
1083 // unautohide a left aligned shelf on the secondary display.
1084 // It is hard because:
1085 // - It is hard to stop the cursor in the shelf "light bar" and not overshoot.
1086 // - The cursor is warped to the other display if the cursor gets to the edge
1087 // of the display.
1088 // Show the shelf if the cursor started on the shelf and the user overshot the
1089 // shelf slightly to make it easier to show the shelf in this situation. We
1090 // do not check |auto_hide_timer_|.IsRunning() because it returns false when
1091 // the timer's task is running.
1092 if ((state_.auto_hide_state == SHELF_AUTO_HIDE_SHOWN ||
1093 mouse_over_shelf_when_auto_hide_timer_started_) &&
1094 GetAutoHideShowShelfRegionInScreen().Contains(
1095 cursor_position_in_screen)) {
1096 return SHELF_AUTO_HIDE_SHOWN;
1099 return SHELF_AUTO_HIDE_HIDDEN;
1102 bool ShelfLayoutManager::IsShelfWindow(aura::Window* window) {
1103 if (!window)
1104 return false;
1105 return (shelf_ && shelf_->GetNativeWindow()->Contains(window)) ||
1106 (shelf_->status_area_widget() &&
1107 shelf_->status_area_widget()->GetNativeWindow()->Contains(window));
1110 int ShelfLayoutManager::GetWorkAreaSize(const State& state, int size) const {
1111 if (state.visibility_state == SHELF_VISIBLE)
1112 return size;
1113 if (state.visibility_state == SHELF_AUTO_HIDE)
1114 return kAutoHideSize;
1115 return 0;
1118 void ShelfLayoutManager::OnKeyboardBoundsChanging(const gfx::Rect& new_bounds) {
1119 bool keyboard_is_about_to_hide = false;
1120 if (new_bounds.IsEmpty() && !keyboard_bounds_.IsEmpty())
1121 keyboard_is_about_to_hide = true;
1123 keyboard_bounds_ = new_bounds;
1124 OnWindowResized();
1126 SessionStateDelegate* session_state_delegate =
1127 Shell::GetInstance()->session_state_delegate();
1129 // On login screen if keyboard has been just hidden, update bounds just once
1130 // but ignore target_bounds.work_area_insets since shelf overlaps with login
1131 // window.
1132 if (session_state_delegate->IsUserSessionBlocked() &&
1133 keyboard_is_about_to_hide) {
1134 Shell::GetInstance()->SetDisplayWorkAreaInsets(root_window_, gfx::Insets());
1138 void ShelfLayoutManager::OnDockBoundsChanging(
1139 const gfx::Rect& dock_bounds,
1140 DockedWindowLayoutManagerObserver::Reason reason) {
1141 // Skip shelf layout in case docked notification originates from this class.
1142 if (reason == DISPLAY_INSETS_CHANGED)
1143 return;
1144 if (dock_bounds_ != dock_bounds) {
1145 dock_bounds_ = dock_bounds;
1146 OnWindowResized();
1147 UpdateVisibilityState();
1148 UpdateShelfBackground(BACKGROUND_CHANGE_ANIMATE);
1152 void ShelfLayoutManager::OnLockStateEvent(LockStateObserver::EventType event) {
1153 if (event == EVENT_LOCK_ANIMATION_STARTED) {
1154 // Enter the screen locked state and update the visibility to avoid an odd
1155 // animation when transitioning the orientation from L/R to bottom.
1156 state_.is_screen_locked = true;
1157 UpdateShelfVisibilityAfterLoginUIChange();
1161 void ShelfLayoutManager::SessionStateChanged(
1162 SessionStateDelegate::SessionState state) {
1163 // Check transition changes to/from the add user to session and change the
1164 // shelf alignment accordingly
1165 bool add_user = state == SessionStateDelegate::SESSION_STATE_LOGIN_SECONDARY;
1166 if (add_user != state_.is_adding_user_screen) {
1167 state_.is_adding_user_screen = add_user;
1168 UpdateShelfVisibilityAfterLoginUIChange();
1169 return;
1171 TargetBounds target_bounds;
1172 CalculateTargetBounds(state_, &target_bounds);
1173 UpdateBoundsAndOpacity(target_bounds, true, NULL);
1174 UpdateVisibilityState();
1177 void ShelfLayoutManager::UpdateShelfVisibilityAfterLoginUIChange() {
1178 shelf_->SetAlignment(GetAlignment());
1179 UpdateVisibilityState();
1180 LayoutShelf();
1183 bool ShelfLayoutManager::IsAlignmentLocked() const {
1184 if (state_.is_screen_locked)
1185 return true;
1186 // The session state becomes active at the start of transitioning to a user
1187 // session, however the session is considered blocked until the full UI is
1188 // ready. Exit early to allow for proper layout.
1189 SessionStateDelegate* session_state_delegate =
1190 Shell::GetInstance()->session_state_delegate();
1191 if (session_state_delegate->GetSessionState() ==
1192 SessionStateDelegate::SESSION_STATE_ACTIVE) {
1193 return false;
1195 if (session_state_delegate->IsUserSessionBlocked() ||
1196 state_.is_adding_user_screen) {
1197 return true;
1199 return false;
1202 } // namespace ash