Allow YCM to use a custom output_dir from GYP_GENERATOR_FLAGS env variable.
[chromium-blink-merge.git] / ash / shelf / shelf_layout_manager.cc
blob789c884c5ce5b495e08ff7cb02dd677495b5d3a1
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_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"
52 namespace ash {
53 namespace {
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.
65 // For instance:
66 // - Primary display is left of secondary display.
67 // - Shelf is left aligned
68 // - This ShelfLayoutManager manages the shelf for the secondary display.
69 // |kMaxAutoHideShowShelfRegionSize| refers to the maximum size of the region
70 // from the right edge of the primary display which can trigger showing the
71 // auto hidden shelf. The region is used to make it easier to trigger showing
72 // the auto hidden shelf when the shelf is on the boundary between displays.
73 const int kMaxAutoHideShowShelfRegionSize = 10;
75 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;
85 } // namespace
87 // static
88 const int ShelfLayoutManager::kWorkspaceAreaVisibleInset = 2;
90 // static
91 const int ShelfLayoutManager::kWorkspaceAreaAutoHideInset = 5;
93 // static
94 const int ShelfLayoutManager::kAutoHideSize = 3;
96 // static
97 const int ShelfLayoutManager::kShelfItemInset = 3;
99 // ShelfLayoutManager::AutoHideEventFilter -------------------------------------
101 // Notifies ShelfLayoutManager any time the mouse moves.
102 class ShelfLayoutManager::AutoHideEventFilter : public ui::EventHandler {
103 public:
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;
114 private:
115 ShelfLayoutManager* shelf_;
116 bool in_mouse_drag_;
117 ShelfGestureHandler gesture_handler_;
118 DISALLOW_COPY_AND_ASSIGN(AutoHideEventFilter);
121 ShelfLayoutManager::AutoHideEventFilter::AutoHideEventFilter(
122 ShelfLayoutManager* shelf)
123 : shelf_(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();
142 return;
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 {
159 public:
160 explicit UpdateShelfObserver(ShelfLayoutManager* shelf) : shelf_(shelf) {
161 shelf_->update_shelf_observer_ = this;
164 void Detach() {
165 shelf_ = NULL;
168 virtual void OnImplicitAnimationsCompleted() OVERRIDE {
169 if (shelf_)
170 shelf_->UpdateShelfBackground(BACKGROUND_CHANGE_ANIMATE);
171 delete this;
174 private:
175 virtual ~UpdateShelfObserver() {
176 if (shelf_)
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),
195 shelf_(shelf),
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)
225 return;
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)
252 return false;
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);
258 LayoutShelf();
259 return true;
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;
266 return alignment_;
269 gfx::Rect ShelfLayoutManager::GetIdealBounds() {
270 gfx::Rect bounds(
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:
305 return SHELF_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_)
314 return;
316 if (Shell::GetInstance()->session_state_delegate()->IsScreenLocked() ||
317 force_shelf_always_visibile_) {
318 SetState(SHELF_VISIBLE);
319 } else {
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);
330 } else {
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);
335 break;
338 case WORKSPACE_WINDOW_STATE_MAXIMIZED:
339 SetState(CalculateShelfVisibility());
340 break;
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);
347 break;
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);
359 } else {
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(
366 FROM_HERE,
367 base::TimeDelta::FromMilliseconds(kAutoHideDelayMS),
368 this, &ShelfLayoutManager::UpdateAutoHideStateNow);
370 } else {
371 StopAutoHideTimer();
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_)
393 return;
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_)
405 return;
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_)
416 return DRAG_SHELF;
417 bool horizontal = IsHorizontalAlignment();
418 gesture_drag_amount_ += horizontal ? gesture.details().scroll_y() :
419 gesture.details().scroll_x();
420 LayoutShelf();
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) {
426 int min_height = 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())
434 return DRAG_TRAY;
437 return DRAG_SHELF;
440 void ShelfLayoutManager::CompleteGestureDrag(const ui::GestureEvent& gesture) {
441 if (force_shelf_always_visibile_)
442 return;
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;
455 } else {
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;
461 break;
462 case SHELF_ALIGNMENT_LEFT:
463 case SHELF_ALIGNMENT_TOP:
464 correct_direction = gesture_drag_amount_ > 0;
465 break;
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;
473 } else {
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);
480 } else {
481 NOTREACHED();
484 if (!should_change) {
485 CancelGestureDrag();
486 return;
488 if (shelf_) {
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);
506 else
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() {
526 LayoutShelf();
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,
539 bool visible) {
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))) {
550 LayoutShelf();
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();
560 LayoutShelf();
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;
588 // static
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())
602 return;
604 State state;
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.
612 bool force_update =
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));
627 } else {
628 auto_hide_event_filter_.reset(NULL);
631 StopAutoHideTimer();
633 State old_state = state_;
634 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
643 // maximized mode.
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;
648 } else {
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);
663 } else {
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,
689 bool animate,
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());
697 if (animate) {
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);
710 } else {
711 StopAnimating();
712 shelf_animation_setter.SetTransitionDuration(base::TimeDelta());
713 status_animation_setter.SetTransitionDuration(base::TimeDelta());
715 if (observer)
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(),
735 status_bounds));
736 SessionStateDelegate* session_state_delegate =
737 Shell::GetInstance()->session_state_delegate();
738 if (!state_.is_screen_locked) {
739 gfx::Insets insets;
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;
762 else
763 *width = 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(
776 const State& state,
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();
785 else
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;
795 else
796 shelf_width = kAutoHideSize;
797 } else if (state.visibility_state == SHELF_HIDDEN ||
798 !keyboard_bounds_.IsEmpty()) {
799 if (IsHorizontalAlignment())
800 shelf_height = 0;
801 else
802 shelf_width = 0;
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);
817 else
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(
872 gfx::Rect(0, 0,
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()),
879 gfx::Rect(0, 0,
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;
908 if (resist) {
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;
913 else
914 translate = resistance_free_region + diff;
915 } else {
916 translate = gesture_drag_amount_;
919 if (horizontal) {
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);
930 } else {
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;
934 if (right_aligned)
935 shelf_width -= translate;
936 else
937 shelf_width += translate;
938 shelf_width = std::max(shelf_width, kAutoHideSize);
939 target_bounds->shelf_bounds_in_root.set_width(shelf_width);
940 if (right_aligned) {
941 target_bounds->shelf_bounds_in_root.set_x(
942 available_bounds.right() - shelf_width);
945 if (right_aligned)
946 target_bounds->status_bounds_in_shelf.set_x(0);
947 else
948 target_bounds->status_bounds_in_shelf.set_x(
949 target_bounds->shelf_bounds_in_root.width() -
950 kShelfSize);
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.
981 StopAutoHideTimer();
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);
1001 else
1002 show_shelf_region_in_screen.set_width(kMaxAutoHideShowShelfRegionSize);
1004 // TODO: Figure out if we need any special handling when the keyboard is
1005 // visible.
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;
1044 break;
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() &&
1067 IsVisible()) {
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
1093 // of the display.
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) {
1109 if (!window)
1110 return false;
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)
1118 return size;
1119 if (state.visibility_state == SHELF_AUTO_HIDE)
1120 return kAutoHideSize;
1121 return 0;
1124 gfx::Rect ShelfLayoutManager::GetAvailableBounds() const {
1125 gfx::Rect bounds(root_window_->bounds());
1126 bounds.set_height(bounds.height() - keyboard_bounds_.height());
1127 return bounds;
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;
1136 OnWindowResized();
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
1143 // window.
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)
1155 return;
1156 if (dock_bounds_ != dock_bounds) {
1157 dock_bounds_ = dock_bounds;
1158 OnWindowResized();
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,
1171 SHELF_HIDDEN);
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();
1187 } // namespace ash