blob: 8af81a8ad028adf419dc45061088012d8448ccc6 [file] [log] [blame]
[email protected]1b62b892012-01-17 17:08:151// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ae18b9112011-11-07 16:59:132// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]478c6c32013-03-09 02:50:585#include "ash/shelf/shelf_layout_manager.h"
[email protected]ae18b9112011-11-07 16:59:136
[email protected]c2d58b42012-05-30 08:11:297#include <algorithm>
[email protected]91d966a72012-09-06 03:42:278#include <cmath>
[email protected]c2d58b42012-05-30 08:11:299
[email protected]fd422702012-09-25 17:45:1410#include "ash/ash_switches.h"
[email protected]7634f962011-12-23 21:35:5211#include "ash/launcher/launcher.h"
[email protected]478c6c32013-03-09 02:50:5812#include "ash/launcher/launcher_types.h"
[email protected]88d71122012-10-18 07:11:0113#include "ash/root_window_controller.h"
[email protected]1a2145b2012-03-13 21:09:1714#include "ash/screen_ash.h"
[email protected]fcb123d2013-04-17 15:58:4915#include "ash/session_state_delegate.h"
[email protected]7841e1172013-05-07 03:53:3316#include "ash/shelf/shelf_layout_manager_observer.h"
[email protected]478c6c32013-03-09 02:50:5817#include "ash/shelf/shelf_widget.h"
[email protected]b65bdda2011-12-23 23:35:3118#include "ash/shell.h"
[email protected]c758fbf2012-03-25 22:53:5919#include "ash/shell_window_ids.h"
[email protected]6d6546e2012-05-30 23:12:0220#include "ash/system/status_area_widget.h"
[email protected]d3643b52013-05-01 16:00:4821#include "ash/wm/gestures/shelf_gesture_handler.h"
[email protected]2ee2f5d2013-01-10 23:37:1622#include "ash/wm/property_util.h"
[email protected]ca8f905b2013-01-22 21:53:2523#include "ash/wm/window_cycle_controller.h"
[email protected]700849f2013-04-30 17:49:2024#include "ash/wm/window_properties.h"
[email protected]ca8f905b2013-01-22 21:53:2525#include "ash/wm/window_util.h"
[email protected]f4bb9fde2012-08-03 19:33:5026#include "ash/wm/workspace_controller.h"
[email protected]ba38e002012-10-12 16:39:4127#include "ash/wm/workspace/workspace_animations.h"
[email protected]4bb16502011-12-06 14:44:5828#include "base/auto_reset.h"
[email protected]fd422702012-09-25 17:45:1429#include "base/command_line.h"
[email protected]e24b6092012-04-12 18:58:5130#include "base/i18n/rtl.h"
[email protected]8676f0472012-03-29 20:30:1231#include "ui/aura/client/activation_client.h"
[email protected]99f07e02011-12-07 00:02:5932#include "ui/aura/root_window.h"
[email protected]153472d72012-09-04 21:33:0233#include "ui/base/events/event.h"
[email protected]f9f017c2012-11-12 19:05:1734#include "ui/base/events/event_handler.h"
[email protected]116302fc2012-05-05 21:45:4135#include "ui/compositor/layer.h"
36#include "ui/compositor/layer_animation_observer.h"
37#include "ui/compositor/layer_animator.h"
38#include "ui/compositor/scoped_layer_animation_settings.h"
[email protected]b82c42c42012-04-25 20:03:4139#include "ui/gfx/screen.h"
[email protected]c13be0d2011-11-22 02:09:5840#include "ui/views/widget/widget.h"
[email protected]ae18b9112011-11-07 16:59:1341
[email protected]55f593352011-12-24 05:42:4642namespace ash {
[email protected]ae18b9112011-11-07 16:59:1343namespace internal {
44
45namespace {
46
[email protected]cadd8c42012-03-27 02:44:3147// Delay before showing the launcher. This is after the mouse stops moving.
48const int kAutoHideDelayMS = 200;
[email protected]27f6af62012-03-21 05:34:4049
[email protected]2e195f52012-09-22 00:24:4650// To avoid hiding the shelf when the mouse transitions from a message bubble
51// into the shelf, the hit test area is enlarged by this amount of pixels to
52// keep the shelf from hiding.
53const int kNotificationBubbleGapHeight = 6;
54
[email protected]ae18b9112011-11-07 16:59:1355ui::Layer* GetLayer(views::Widget* widget) {
56 return widget->GetNativeView()->layer();
57}
58
[email protected]fd422702012-09-25 17:45:1459bool IsDraggingTrayEnabled() {
60 static bool dragging_tray_allowed = CommandLine::ForCurrentProcess()->
61 HasSwitch(ash::switches::kAshEnableTrayDragging);
62 return dragging_tray_allowed;
63}
64
[email protected]ae18b9112011-11-07 16:59:1365} // namespace
66
[email protected]bbb59f82012-03-14 04:04:3567// static
[email protected]d3643b52013-05-01 16:00:4868const int ShelfLayoutManager::kWorkspaceAreaVisibleInset = 2;
69
70// static
71const int ShelfLayoutManager::kWorkspaceAreaAutoHideInset = 5;
[email protected]bbb59f82012-03-14 04:04:3572
[email protected]b1c37fc2012-03-22 03:36:1373// static
[email protected]7b675df612012-09-16 18:33:2074const int ShelfLayoutManager::kAutoHideSize = 3;
[email protected]b1c37fc2012-03-22 03:36:1375
[email protected]e4d9fe92012-09-10 14:04:4976// ShelfLayoutManager::AutoHideEventFilter -------------------------------------
77
[email protected]b1c37fc2012-03-22 03:36:1378// Notifies ShelfLayoutManager any time the mouse moves.
[email protected]f9f017c2012-11-12 19:05:1779class ShelfLayoutManager::AutoHideEventFilter : public ui::EventHandler {
[email protected]b1c37fc2012-03-22 03:36:1380 public:
81 explicit AutoHideEventFilter(ShelfLayoutManager* shelf);
82 virtual ~AutoHideEventFilter();
83
[email protected]5f1d99dc2012-04-12 21:42:3784 // Returns true if the last mouse event was a mouse drag.
85 bool in_mouse_drag() const { return in_mouse_drag_; }
86
[email protected]f9f017c2012-11-12 19:05:1787 // Overridden from ui::EventHandler:
[email protected]d44efe02012-12-18 06:08:1888 virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
[email protected]d3643b52013-05-01 16:00:4889 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
[email protected]b1c37fc2012-03-22 03:36:1390
91 private:
92 ShelfLayoutManager* shelf_;
[email protected]5f1d99dc2012-04-12 21:42:3793 bool in_mouse_drag_;
[email protected]d3643b52013-05-01 16:00:4894 ShelfGestureHandler gesture_handler_;
[email protected]b1c37fc2012-03-22 03:36:1395
96 DISALLOW_COPY_AND_ASSIGN(AutoHideEventFilter);
97};
98
99ShelfLayoutManager::AutoHideEventFilter::AutoHideEventFilter(
100 ShelfLayoutManager* shelf)
[email protected]5f1d99dc2012-04-12 21:42:37101 : shelf_(shelf),
102 in_mouse_drag_(false) {
[email protected]f9f017c2012-11-12 19:05:17103 Shell::GetInstance()->AddPreTargetHandler(this);
[email protected]b1c37fc2012-03-22 03:36:13104}
105
106ShelfLayoutManager::AutoHideEventFilter::~AutoHideEventFilter() {
[email protected]f9f017c2012-11-12 19:05:17107 Shell::GetInstance()->RemovePreTargetHandler(this);
[email protected]b1c37fc2012-03-22 03:36:13108}
109
[email protected]d44efe02012-12-18 06:08:18110void ShelfLayoutManager::AutoHideEventFilter::OnMouseEvent(
[email protected]ca7060982012-08-08 18:05:25111 ui::MouseEvent* event) {
[email protected]5f1d99dc2012-04-12 21:42:37112 // This also checks IsShelfWindow() to make sure we don't attempt to hide the
113 // shelf if the mouse down occurs on the shelf.
114 in_mouse_drag_ = (event->type() == ui::ET_MOUSE_DRAGGED ||
115 (in_mouse_drag_ && event->type() != ui::ET_MOUSE_RELEASED &&
116 event->type() != ui::ET_MOUSE_CAPTURE_CHANGED)) &&
[email protected]f9f017c2012-11-12 19:05:17117 !shelf_->IsShelfWindow(static_cast<aura::Window*>(event->target()));
[email protected]b1c37fc2012-03-22 03:36:13118 if (event->type() == ui::ET_MOUSE_MOVED)
119 shelf_->UpdateAutoHideState();
[email protected]d44efe02012-12-18 06:08:18120 return;
[email protected]b1c37fc2012-03-22 03:36:13121}
122
[email protected]d3643b52013-05-01 16:00:48123void ShelfLayoutManager::AutoHideEventFilter::OnGestureEvent(
124 ui::GestureEvent* event) {
[email protected]65767e62013-05-14 09:29:50125 if (shelf_->IsShelfWindow(static_cast<aura::Window*>(event->target()))) {
126 if (gesture_handler_.ProcessGestureEvent(*event))
127 event->StopPropagation();
128 }
[email protected]d3643b52013-05-01 16:00:48129}
130
[email protected]e4d9fe92012-09-10 14:04:49131// ShelfLayoutManager:UpdateShelfObserver --------------------------------------
132
133// UpdateShelfObserver is used to delay updating the background until the
134// animation completes.
135class ShelfLayoutManager::UpdateShelfObserver
136 : public ui::ImplicitAnimationObserver {
137 public:
138 explicit UpdateShelfObserver(ShelfLayoutManager* shelf) : shelf_(shelf) {
139 shelf_->update_shelf_observer_ = this;
140 }
141
142 void Detach() {
143 shelf_ = NULL;
144 }
145
146 virtual void OnImplicitAnimationsCompleted() OVERRIDE {
147 if (shelf_) {
[email protected]1fcfb992012-12-05 01:47:23148 shelf_->UpdateShelfBackground(BackgroundAnimator::CHANGE_ANIMATE);
[email protected]e4d9fe92012-09-10 14:04:49149 }
150 delete this;
151 }
152
153 private:
154 virtual ~UpdateShelfObserver() {
155 if (shelf_)
156 shelf_->update_shelf_observer_ = NULL;
157 }
158
159 // Shelf we're in. NULL if deleted before we're deleted.
160 ShelfLayoutManager* shelf_;
161
162 DISALLOW_COPY_AND_ASSIGN(UpdateShelfObserver);
163};
164
165// ShelfLayoutManager ----------------------------------------------------------
[email protected]4bb16502011-12-06 14:44:58166
[email protected]478c6c32013-03-09 02:50:58167ShelfLayoutManager::ShelfLayoutManager(ShelfWidget* shelf)
168 : root_window_(shelf->GetNativeView()->GetRootWindow()),
[email protected]8676f0472012-03-29 20:30:12169 in_layout_(false),
[email protected]eefd51b22012-09-25 20:26:24170 auto_hide_behavior_(SHELF_AUTO_HIDE_BEHAVIOR_NEVER),
[email protected]55444502012-05-10 15:43:53171 alignment_(SHELF_ALIGNMENT_BOTTOM),
[email protected]478c6c32013-03-09 02:50:58172 shelf_(shelf),
[email protected]f4bb9fde2012-08-03 19:33:50173 workspace_controller_(NULL),
[email protected]3c6abbe2012-08-30 23:48:57174 window_overlaps_shelf_(false),
175 gesture_drag_status_(GESTURE_DRAG_NONE),
[email protected]4982ee12012-09-04 22:16:10176 gesture_drag_amount_(0.f),
[email protected]ef80e4302012-12-04 19:37:31177 gesture_drag_auto_hide_state_(SHELF_AUTO_HIDE_SHOWN),
[email protected]e4d9fe92012-09-10 14:04:49178 update_shelf_observer_(NULL) {
[email protected]8e43cdf42012-05-11 17:03:31179 Shell::GetInstance()->AddShellObserver(this);
[email protected]e76310a92012-06-04 19:06:11180 aura::client::GetActivationClient(root_window_)->AddObserver(this);
[email protected]ae18b9112011-11-07 16:59:13181}
182
[email protected]4bb16502011-12-06 14:44:58183ShelfLayoutManager::~ShelfLayoutManager() {
[email protected]e4d9fe92012-09-10 14:04:49184 if (update_shelf_observer_)
185 update_shelf_observer_->Detach();
186
[email protected]7841e1172013-05-07 03:53:33187 FOR_EACH_OBSERVER(ShelfLayoutManagerObserver, observers_, WillDeleteShelf());
[email protected]8e43cdf42012-05-11 17:03:31188 Shell::GetInstance()->RemoveShellObserver(this);
[email protected]e76310a92012-06-04 19:06:11189 aura::client::GetActivationClient(root_window_)->RemoveObserver(this);
[email protected]ae18b9112011-11-07 16:59:13190}
191
[email protected]09f3fc82012-03-26 23:26:56192void ShelfLayoutManager::SetAutoHideBehavior(ShelfAutoHideBehavior behavior) {
193 if (auto_hide_behavior_ == behavior)
[email protected]c758fbf2012-03-25 22:53:59194 return;
[email protected]09f3fc82012-03-26 23:26:56195 auto_hide_behavior_ = behavior;
[email protected]c758fbf2012-03-25 22:53:59196 UpdateVisibilityState();
[email protected]7841e1172013-05-07 03:53:33197 FOR_EACH_OBSERVER(ShelfLayoutManagerObserver, observers_,
[email protected]cbc278f2012-07-10 03:40:21198 OnAutoHideStateChanged(state_.auto_hide_state));
[email protected]7841e1172013-05-07 03:53:33199 FOR_EACH_OBSERVER(ShelfLayoutManagerObserver, observers_,
[email protected]7ed98952013-04-02 23:04:50200 OnAutoHideBehaviorChanged(auto_hide_behavior_));
[email protected]c758fbf2012-03-25 22:53:59201}
202
[email protected]40429f02012-03-28 20:38:50203bool ShelfLayoutManager::IsVisible() const {
[email protected]478c6c32013-03-09 02:50:58204 return shelf_->status_area_widget()->IsVisible() &&
[email protected]ef80e4302012-12-04 19:37:31205 (state_.visibility_state == SHELF_VISIBLE ||
206 (state_.visibility_state == SHELF_AUTO_HIDE &&
207 state_.auto_hide_state == SHELF_AUTO_HIDE_SHOWN));
[email protected]40429f02012-03-28 20:38:50208}
209
[email protected]c2d58b42012-05-30 08:11:29210bool ShelfLayoutManager::SetAlignment(ShelfAlignment alignment) {
[email protected]55444502012-05-10 15:43:53211 if (alignment_ == alignment)
[email protected]c2d58b42012-05-30 08:11:29212 return false;
[email protected]55444502012-05-10 15:43:53213
214 alignment_ = alignment;
[email protected]478c6c32013-03-09 02:50:58215 if (shelf_->launcher())
216 shelf_->launcher()->SetAlignment(alignment);
217 shelf_->status_area_widget()->SetShelfAlignment(alignment);
[email protected]55444502012-05-10 15:43:53218 LayoutShelf();
[email protected]c2d58b42012-05-30 08:11:29219 return true;
[email protected]55444502012-05-10 15:43:53220}
221
222gfx::Rect ShelfLayoutManager::GetIdealBounds() {
[email protected]478c6c32013-03-09 02:50:58223 gfx::Rect bounds(
224 ScreenAsh::GetDisplayBoundsInParent(shelf_->GetNativeView()));
[email protected]55444502012-05-10 15:43:53225 int width = 0, height = 0;
226 GetShelfSize(&width, &height);
[email protected]8572c4872013-01-12 17:16:07227 return SelectValueForShelfAlignment(
228 gfx::Rect(bounds.x(), bounds.bottom() - height, bounds.width(), height),
229 gfx::Rect(bounds.x(), bounds.y(), width, bounds.height()),
230 gfx::Rect(bounds.right() - width, bounds.y(), width, bounds.height()),
231 gfx::Rect(bounds.x(), bounds.y(), bounds.width(), height));
[email protected]55444502012-05-10 15:43:53232}
233
[email protected]4bb16502011-12-06 14:44:58234void ShelfLayoutManager::LayoutShelf() {
[email protected]997ec9f2012-11-21 04:44:14235 base::AutoReset<bool> auto_reset_in_layout(&in_layout_, true);
[email protected]ae18b9112011-11-07 16:59:13236 StopAnimating();
237 TargetBounds target_bounds;
[email protected]27f6af62012-03-21 05:34:40238 CalculateTargetBounds(state_, &target_bounds);
[email protected]478c6c32013-03-09 02:50:58239 GetLayer(shelf_)->SetOpacity(target_bounds.opacity);
[email protected]14f5d0e2013-03-27 07:30:20240 shelf_->SetWidgetBounds(
[email protected]ec1930c32012-07-19 23:57:42241 ScreenAsh::ConvertRectToScreen(
[email protected]478c6c32013-03-09 02:50:58242 shelf_->GetNativeView()->parent(),
243 target_bounds.shelf_bounds_in_root));
244 if (shelf_->launcher())
245 shelf_->launcher()->SetLauncherViewBounds(
246 target_bounds.launcher_bounds_in_shelf);
247 GetLayer(shelf_->status_area_widget())->SetOpacity(target_bounds.opacity);
248 // TODO(harrym): Once status area widget is a child view of shelf
249 // this can be simplified.
250 gfx::Rect status_bounds = target_bounds.status_bounds_in_shelf;
251 status_bounds.set_x(status_bounds.x() +
252 target_bounds.shelf_bounds_in_root.x());
253 status_bounds.set_y(status_bounds.y() +
254 target_bounds.shelf_bounds_in_root.y());
255 shelf_->status_area_widget()->SetBounds(
256 ScreenAsh::ConvertRectToScreen(
257 shelf_->status_area_widget()->GetNativeView()->parent(),
258 status_bounds));
[email protected]2e236a52012-06-27 22:21:47259 Shell::GetInstance()->SetDisplayWorkAreaInsets(
[email protected]b913a3a2012-12-11 13:07:19260 root_window_, target_bounds.work_area_insets);
[email protected]128fd3732012-03-27 01:55:12261 UpdateHitTestBounds();
[email protected]ae18b9112011-11-07 16:59:13262}
263
[email protected]8e837ec2013-01-31 01:48:33264ShelfVisibilityState ShelfLayoutManager::CalculateShelfVisibility() {
265 switch(auto_hide_behavior_) {
266 case SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS:
267 return SHELF_AUTO_HIDE;
268 case SHELF_AUTO_HIDE_BEHAVIOR_NEVER:
269 return SHELF_VISIBLE;
270 case SHELF_AUTO_HIDE_ALWAYS_HIDDEN:
271 return SHELF_HIDDEN;
272 }
273 return SHELF_VISIBLE;
274}
275
276ShelfVisibilityState
277ShelfLayoutManager::CalculateShelfVisibilityWhileDragging() {
278 switch(auto_hide_behavior_) {
279 case SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS:
280 case SHELF_AUTO_HIDE_BEHAVIOR_NEVER:
281 return SHELF_AUTO_HIDE;
282 case SHELF_AUTO_HIDE_ALWAYS_HIDDEN:
283 return SHELF_HIDDEN;
284 }
285 return SHELF_VISIBLE;
286}
287
[email protected]c758fbf2012-03-25 22:53:59288void ShelfLayoutManager::UpdateVisibilityState() {
[email protected]fcb123d2013-04-17 15:58:49289 if (Shell::GetInstance()->session_state_delegate()->IsScreenLocked()) {
[email protected]ef80e4302012-12-04 19:37:31290 SetState(SHELF_VISIBLE);
[email protected]4982ee12012-09-04 22:16:10291 } else if (gesture_drag_status_ == GESTURE_DRAG_COMPLETE_IN_PROGRESS) {
[email protected]8e837ec2013-01-31 01:48:33292 // TODO(zelidrag): Verify shelf drag animation still shows on the device
293 // when we are in SHELF_AUTO_HIDE_ALWAYS_HIDDEN.
294 SetState(CalculateShelfVisibilityWhileDragging());
[email protected]c758fbf2012-03-25 22:53:59295 } else {
[email protected]f4bb9fde2012-08-03 19:33:50296 WorkspaceWindowState window_state(workspace_controller_->GetWindowState());
[email protected]c758fbf2012-03-25 22:53:59297 switch (window_state) {
[email protected]f4bb9fde2012-08-03 19:33:50298 case WORKSPACE_WINDOW_STATE_FULL_SCREEN:
[email protected]700849f2013-04-30 17:49:20299 {
300 aura::Window* fullscreen_window =
301 GetRootWindowController(root_window_)->GetFullscreenWindow();
302 if (fullscreen_window->GetProperty(kFullscreenUsesMinimalChromeKey)) {
303 DCHECK_NE(auto_hide_behavior_, SHELF_AUTO_HIDE_ALWAYS_HIDDEN);
304 SetState(SHELF_AUTO_HIDE);
305 } else {
306 SetState(SHELF_HIDDEN);
307 }
[email protected]c758fbf2012-03-25 22:53:59308 break;
[email protected]700849f2013-04-30 17:49:20309 }
[email protected]f4bb9fde2012-08-03 19:33:50310 case WORKSPACE_WINDOW_STATE_MAXIMIZED:
[email protected]8e837ec2013-01-31 01:48:33311 SetState(CalculateShelfVisibility());
[email protected]c758fbf2012-03-25 22:53:59312 break;
313
[email protected]f4bb9fde2012-08-03 19:33:50314 case WORKSPACE_WINDOW_STATE_WINDOW_OVERLAPS_SHELF:
315 case WORKSPACE_WINDOW_STATE_DEFAULT:
[email protected]8e837ec2013-01-31 01:48:33316 SetState(CalculateShelfVisibility());
[email protected]c758fbf2012-03-25 22:53:59317 SetWindowOverlapsShelf(window_state ==
[email protected]f4bb9fde2012-08-03 19:33:50318 WORKSPACE_WINDOW_STATE_WINDOW_OVERLAPS_SHELF);
[email protected]e4d9fe92012-09-10 14:04:49319 break;
[email protected]c758fbf2012-03-25 22:53:59320 }
321 }
322}
323
324void ShelfLayoutManager::UpdateAutoHideState() {
[email protected]ef80e4302012-12-04 19:37:31325 ShelfAutoHideState auto_hide_state =
[email protected]cadd8c42012-03-27 02:44:31326 CalculateAutoHideState(state_.visibility_state);
327 if (auto_hide_state != state_.auto_hide_state) {
[email protected]ef80e4302012-12-04 19:37:31328 if (auto_hide_state == SHELF_AUTO_HIDE_HIDDEN) {
[email protected]cadd8c42012-03-27 02:44:31329 // Hides happen immediately.
330 SetState(state_.visibility_state);
[email protected]7841e1172013-05-07 03:53:33331 FOR_EACH_OBSERVER(ShelfLayoutManagerObserver, observers_,
[email protected]cbc278f2012-07-10 03:40:21332 OnAutoHideStateChanged(auto_hide_state));
[email protected]cadd8c42012-03-27 02:44:31333 } else {
334 auto_hide_timer_.Stop();
[email protected]c758fbf2012-03-25 22:53:59335 auto_hide_timer_.Start(
336 FROM_HERE,
337 base::TimeDelta::FromMilliseconds(kAutoHideDelayMS),
338 this, &ShelfLayoutManager::UpdateAutoHideStateNow);
[email protected]7841e1172013-05-07 03:53:33339 FOR_EACH_OBSERVER(ShelfLayoutManagerObserver, observers_,
340 OnAutoHideStateChanged(
341 CalculateAutoHideState(state_.visibility_state)));
[email protected]c758fbf2012-03-25 22:53:59342 }
343 } else {
344 auto_hide_timer_.Stop();
345 }
346}
347
348void ShelfLayoutManager::SetWindowOverlapsShelf(bool value) {
349 window_overlaps_shelf_ = value;
[email protected]1fcfb992012-12-05 01:47:23350 UpdateShelfBackground(BackgroundAnimator::CHANGE_ANIMATE);
[email protected]c758fbf2012-03-25 22:53:59351}
352
[email protected]7841e1172013-05-07 03:53:33353void ShelfLayoutManager::AddObserver(ShelfLayoutManagerObserver* observer) {
[email protected]cbc278f2012-07-10 03:40:21354 observers_.AddObserver(observer);
355}
356
[email protected]7841e1172013-05-07 03:53:33357void ShelfLayoutManager::RemoveObserver(ShelfLayoutManagerObserver* observer) {
[email protected]cbc278f2012-07-10 03:40:21358 observers_.RemoveObserver(observer);
359}
360
[email protected]c758fbf2012-03-25 22:53:59361////////////////////////////////////////////////////////////////////////////////
[email protected]3c6abbe2012-08-30 23:48:57362// ShelfLayoutManager, Gesture dragging:
363
364void ShelfLayoutManager::StartGestureDrag(const ui::GestureEvent& gesture) {
365 gesture_drag_status_ = GESTURE_DRAG_IN_PROGRESS;
366 gesture_drag_amount_ = 0.f;
[email protected]ef80e4302012-12-04 19:37:31367 gesture_drag_auto_hide_state_ = visibility_state() == SHELF_AUTO_HIDE ?
368 auto_hide_state() : SHELF_AUTO_HIDE_SHOWN;
[email protected]1fcfb992012-12-05 01:47:23369 UpdateShelfBackground(BackgroundAnimator::CHANGE_ANIMATE);
[email protected]3c6abbe2012-08-30 23:48:57370}
371
[email protected]c8e2e832012-09-12 21:48:28372ShelfLayoutManager::DragState ShelfLayoutManager::UpdateGestureDrag(
373 const ui::GestureEvent& gesture) {
[email protected]8572c4872013-01-12 17:16:07374 bool horizontal = IsHorizontalAlignment();
[email protected]3c6abbe2012-08-30 23:48:57375 gesture_drag_amount_ += horizontal ? gesture.details().scroll_y() :
376 gesture.details().scroll_x();
377 LayoutShelf();
[email protected]c8e2e832012-09-12 21:48:28378
379 // Start reveling the status menu when:
380 // - dragging up on an already visible shelf
381 // - dragging up on a hidden shelf, but it is currently completely visible.
382 if (horizontal && gesture.details().scroll_y() < 0) {
383 int min_height = 0;
[email protected]478c6c32013-03-09 02:50:58384 if (gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_HIDDEN && shelf_)
385 min_height = shelf_->GetContentsView()->GetPreferredSize().height();
[email protected]c8e2e832012-09-12 21:48:28386
[email protected]478c6c32013-03-09 02:50:58387 if (min_height < shelf_->GetWindowBoundsInScreen().height() &&
[email protected]88d71122012-10-18 07:11:01388 gesture.root_location().x() >=
[email protected]478c6c32013-03-09 02:50:58389 shelf_->status_area_widget()->GetWindowBoundsInScreen().x() &&
[email protected]fd422702012-09-25 17:45:14390 IsDraggingTrayEnabled())
[email protected]c8e2e832012-09-12 21:48:28391 return DRAG_TRAY;
392 }
393
394 return DRAG_SHELF;
[email protected]3c6abbe2012-08-30 23:48:57395}
396
[email protected]4982ee12012-09-04 22:16:10397void ShelfLayoutManager::CompleteGestureDrag(const ui::GestureEvent& gesture) {
[email protected]8572c4872013-01-12 17:16:07398 bool horizontal = IsHorizontalAlignment();
[email protected]4982ee12012-09-04 22:16:10399 bool should_change = false;
[email protected]3c6abbe2012-08-30 23:48:57400 if (gesture.type() == ui::ET_GESTURE_SCROLL_END) {
[email protected]9bf222b2012-11-28 02:21:16401 // The visibility of the shelf changes only if the shelf was dragged X%
402 // along the correct axis. If the shelf was already visible, then the
403 // direction of the drag does not matter.
[email protected]3c6abbe2012-08-30 23:48:57404 const float kDragHideThreshold = 0.4f;
405 gfx::Rect bounds = GetIdealBounds();
[email protected]9bf222b2012-11-28 02:21:16406 float drag_ratio = fabs(gesture_drag_amount_) /
407 (horizontal ? bounds.height() : bounds.width());
[email protected]ef80e4302012-12-04 19:37:31408 if (gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_SHOWN) {
[email protected]9bf222b2012-11-28 02:21:16409 should_change = drag_ratio > kDragHideThreshold;
410 } else {
411 bool correct_direction = false;
[email protected]1fcfb992012-12-05 01:47:23412 switch (alignment_) {
[email protected]9bf222b2012-11-28 02:21:16413 case SHELF_ALIGNMENT_BOTTOM:
414 case SHELF_ALIGNMENT_RIGHT:
415 correct_direction = gesture_drag_amount_ < 0;
416 break;
417 case SHELF_ALIGNMENT_LEFT:
[email protected]8572c4872013-01-12 17:16:07418 case SHELF_ALIGNMENT_TOP:
[email protected]9bf222b2012-11-28 02:21:16419 correct_direction = gesture_drag_amount_ > 0;
420 break;
421 }
422 should_change = correct_direction && drag_ratio > kDragHideThreshold;
423 }
[email protected]3c6abbe2012-08-30 23:48:57424 } else if (gesture.type() == ui::ET_SCROLL_FLING_START) {
[email protected]ef80e4302012-12-04 19:37:31425 if (gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_SHOWN) {
[email protected]9bf222b2012-11-28 02:21:16426 should_change = horizontal ? fabs(gesture.details().velocity_y()) > 0 :
427 fabs(gesture.details().velocity_x()) > 0;
428 } else {
[email protected]8572c4872013-01-12 17:16:07429 should_change = SelectValueForShelfAlignment(
430 gesture.details().velocity_y() < 0,
431 gesture.details().velocity_x() > 0,
432 gesture.details().velocity_x() < 0,
433 gesture.details().velocity_y() > 0);
[email protected]9bf222b2012-11-28 02:21:16434 }
[email protected]3c6abbe2012-08-30 23:48:57435 } else {
436 NOTREACHED();
437 }
438
[email protected]4982ee12012-09-04 22:16:10439 if (!should_change) {
[email protected]3c6abbe2012-08-30 23:48:57440 CancelGestureDrag();
441 return;
442 }
443
[email protected]4982ee12012-09-04 22:16:10444 gesture_drag_auto_hide_state_ =
[email protected]ef80e4302012-12-04 19:37:31445 gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_SHOWN ?
446 SHELF_AUTO_HIDE_HIDDEN : SHELF_AUTO_HIDE_SHOWN;
[email protected]478c6c32013-03-09 02:50:58447 if (shelf_)
448 shelf_->Deactivate();
449 shelf_->status_area_widget()->Deactivate();
[email protected]ef80e4302012-12-04 19:37:31450 if (gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_HIDDEN &&
[email protected]e10392c2012-09-11 21:13:08451 auto_hide_behavior_ != SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS) {
452 gesture_drag_status_ = GESTURE_DRAG_NONE;
[email protected]3c6abbe2012-08-30 23:48:57453 SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
[email protected]ef80e4302012-12-04 19:37:31454 } else if (gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_SHOWN &&
[email protected]e10392c2012-09-11 21:13:08455 auto_hide_behavior_ != SHELF_AUTO_HIDE_BEHAVIOR_NEVER) {
456 gesture_drag_status_ = GESTURE_DRAG_NONE;
457 SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
458 } else {
459 gesture_drag_status_ = GESTURE_DRAG_COMPLETE_IN_PROGRESS;
[email protected]3c6abbe2012-08-30 23:48:57460 UpdateVisibilityState();
[email protected]e10392c2012-09-11 21:13:08461 gesture_drag_status_ = GESTURE_DRAG_NONE;
462 }
[email protected]c3371c22013-04-18 04:42:23463 LayoutShelf();
[email protected]3c6abbe2012-08-30 23:48:57464}
465
466void ShelfLayoutManager::CancelGestureDrag() {
[email protected]e10392c2012-09-11 21:13:08467 gesture_drag_status_ = GESTURE_DRAG_NONE;
[email protected]3c6abbe2012-08-30 23:48:57468 ui::ScopedLayerAnimationSettings
[email protected]478c6c32013-03-09 02:50:58469 launcher_settings(GetLayer(shelf_)->GetAnimator()),
470 status_settings(GetLayer(shelf_->status_area_widget())->GetAnimator());
[email protected]3c6abbe2012-08-30 23:48:57471 LayoutShelf();
472 UpdateVisibilityState();
[email protected]1fcfb992012-12-05 01:47:23473 UpdateShelfBackground(BackgroundAnimator::CHANGE_ANIMATE);
[email protected]3c6abbe2012-08-30 23:48:57474}
475
476////////////////////////////////////////////////////////////////////////////////
[email protected]c758fbf2012-03-25 22:53:59477// ShelfLayoutManager, aura::LayoutManager implementation:
478
479void ShelfLayoutManager::OnWindowResized() {
480 LayoutShelf();
481}
482
483void ShelfLayoutManager::OnWindowAddedToLayout(aura::Window* child) {
484}
485
486void ShelfLayoutManager::OnWillRemoveWindowFromLayout(aura::Window* child) {
487}
488
[email protected]fa893ab62012-04-20 01:26:51489void ShelfLayoutManager::OnWindowRemovedFromLayout(aura::Window* child) {
490}
491
[email protected]c758fbf2012-03-25 22:53:59492void ShelfLayoutManager::OnChildWindowVisibilityChanged(aura::Window* child,
493 bool visible) {
494}
495
496void ShelfLayoutManager::SetChildBounds(aura::Window* child,
497 const gfx::Rect& requested_bounds) {
498 SetChildBoundsDirect(child, requested_bounds);
[email protected]9d9b3202012-09-09 22:39:32499 // We may contain other widgets (such as frame maximize bubble) but they don't
500 // effect the layout in anyway.
501 if (!in_layout_ &&
[email protected]478c6c32013-03-09 02:50:58502 ((shelf_->GetNativeView() == child) ||
503 (shelf_->status_area_widget()->GetNativeView() == child))) {
[email protected]c758fbf2012-03-25 22:53:59504 LayoutShelf();
[email protected]9d9b3202012-09-09 22:39:32505 }
[email protected]c758fbf2012-03-25 22:53:59506}
507
[email protected]8e43cdf42012-05-11 17:03:31508void ShelfLayoutManager::OnLockStateChanged(bool locked) {
509 UpdateVisibilityState();
510}
511
[email protected]1ae361652012-12-12 22:39:51512void ShelfLayoutManager::OnWindowActivated(aura::Window* gained_active,
513 aura::Window* lost_active) {
[email protected]e76310a92012-06-04 19:06:11514 UpdateAutoHideStateNow();
[email protected]8676f0472012-03-29 20:30:12515}
516
[email protected]1fcfb992012-12-05 01:47:23517bool ShelfLayoutManager::IsHorizontalAlignment() const {
[email protected]8572c4872013-01-12 17:16:07518 return alignment_ == SHELF_ALIGNMENT_BOTTOM ||
519 alignment_ == SHELF_ALIGNMENT_TOP;
[email protected]1fcfb992012-12-05 01:47:23520}
521
522// static
523ShelfLayoutManager* ShelfLayoutManager::ForLauncher(aura::Window* window) {
[email protected]478c6c32013-03-09 02:50:58524 ShelfWidget* shelf = RootWindowController::ForLauncher(window)->shelf();
525 return shelf ? shelf->shelf_layout_manager() : NULL;
[email protected]1fcfb992012-12-05 01:47:23526}
527
[email protected]c758fbf2012-03-25 22:53:59528////////////////////////////////////////////////////////////////////////////////
529// ShelfLayoutManager, private:
530
[email protected]9e52129b92012-08-09 16:14:30531ShelfLayoutManager::TargetBounds::TargetBounds() : opacity(0.0f) {}
[email protected]478c6c32013-03-09 02:50:58532ShelfLayoutManager::TargetBounds::~TargetBounds() {}
[email protected]9e52129b92012-08-09 16:14:30533
[email protected]ef80e4302012-12-04 19:37:31534void ShelfLayoutManager::SetState(ShelfVisibilityState visibility_state) {
[email protected]b920e7d2013-04-19 03:29:35535 if (!shelf_->GetNativeView())
536 return;
537
[email protected]27f6af62012-03-21 05:34:40538 State state;
[email protected]c758fbf2012-03-25 22:53:59539 state.visibility_state = visibility_state;
[email protected]b1c37fc2012-03-22 03:36:13540 state.auto_hide_state = CalculateAutoHideState(visibility_state);
[email protected]fcb123d2013-04-17 15:58:49541 state.is_screen_locked =
542 Shell::GetInstance()->session_state_delegate()->IsScreenLocked();
[email protected]306768162012-02-02 02:04:41543
[email protected]b7d08122012-09-16 18:24:46544 // It's possible for SetState() when a window becomes maximized but the state
545 // won't have changed value. Do the dimming check before the early exit.
[email protected]478c6c32013-03-09 02:50:58546 if (workspace_controller_) {
547 shelf_->SetDimsShelf(
[email protected]ef80e4302012-12-04 19:37:31548 (state.visibility_state == SHELF_VISIBLE) &&
[email protected]b7d08122012-09-16 18:24:46549 workspace_controller_->GetWindowState() ==
550 WORKSPACE_WINDOW_STATE_MAXIMIZED);
551 }
552
[email protected]27f6af62012-03-21 05:34:40553 if (state_.Equals(state))
[email protected]ae18b9112011-11-07 16:59:13554 return; // Nothing changed.
555
[email protected]7841e1172013-05-07 03:53:33556 FOR_EACH_OBSERVER(ShelfLayoutManagerObserver, observers_,
[email protected]cbc278f2012-07-10 03:40:21557 WillChangeVisibilityState(visibility_state));
558
[email protected]ef80e4302012-12-04 19:37:31559 if (state.visibility_state == SHELF_AUTO_HIDE) {
560 // When state is SHELF_AUTO_HIDE we need to track when the mouse is over the
[email protected]b1c37fc2012-03-22 03:36:13561 // launcher to unhide the shelf. AutoHideEventFilter does that for us.
[email protected]7f7f65c2013-04-17 16:47:13562 if (!event_filter_)
[email protected]b1c37fc2012-03-22 03:36:13563 event_filter_.reset(new AutoHideEventFilter(this));
564 } else {
565 event_filter_.reset(NULL);
566 }
567
568 auto_hide_timer_.Stop();
569
[email protected]27f6af62012-03-21 05:34:40570 // Animating the background when transitioning from auto-hide & hidden to
[email protected]e4d9fe92012-09-10 14:04:49571 // visible is janky. Update the background immediately in this case.
[email protected]1fcfb992012-12-05 01:47:23572 BackgroundAnimator::ChangeType change_type =
[email protected]ef80e4302012-12-04 19:37:31573 (state_.visibility_state == SHELF_AUTO_HIDE &&
574 state_.auto_hide_state == SHELF_AUTO_HIDE_HIDDEN &&
575 state.visibility_state == SHELF_VISIBLE) ?
[email protected]1fcfb992012-12-05 01:47:23576 BackgroundAnimator::CHANGE_IMMEDIATE : BackgroundAnimator::CHANGE_ANIMATE;
[email protected]ae18b9112011-11-07 16:59:13577 StopAnimating();
[email protected]e10392c2012-09-11 21:13:08578
579 State old_state = state_;
[email protected]27f6af62012-03-21 05:34:40580 state_ = state;
[email protected]ae18b9112011-11-07 16:59:13581 TargetBounds target_bounds;
[email protected]27f6af62012-03-21 05:34:40582 CalculateTargetBounds(state_, &target_bounds);
[email protected]478c6c32013-03-09 02:50:58583
584 ui::ScopedLayerAnimationSettings launcher_animation_setter(
585 GetLayer(shelf_)->GetAnimator());
586 launcher_animation_setter.SetTransitionDuration(
587 base::TimeDelta::FromMilliseconds(kWorkspaceSwitchTimeMS));
588 launcher_animation_setter.SetTweenType(ui::Tween::EASE_OUT);
589 GetLayer(shelf_)->SetBounds(
590 target_bounds.shelf_bounds_in_root);
591 GetLayer(shelf_)->SetOpacity(target_bounds.opacity);
[email protected]306768162012-02-02 02:04:41592 ui::ScopedLayerAnimationSettings status_animation_setter(
[email protected]478c6c32013-03-09 02:50:58593 GetLayer(shelf_->status_area_widget())->GetAnimator());
[email protected]27f6af62012-03-21 05:34:40594 status_animation_setter.SetTransitionDuration(
[email protected]c96b9812012-10-17 16:04:04595 base::TimeDelta::FromMilliseconds(kWorkspaceSwitchTimeMS));
[email protected]27f6af62012-03-21 05:34:40596 status_animation_setter.SetTweenType(ui::Tween::EASE_OUT);
[email protected]e10392c2012-09-11 21:13:08597
[email protected]ef80e4302012-12-04 19:37:31598 // Delay updating the background when going from SHELF_AUTO_HIDE_SHOWN to
599 // SHELF_AUTO_HIDE_HIDDEN until the shelf animates out. Otherwise during the
[email protected]e4d9fe92012-09-10 14:04:49600 // animation you see the background change.
[email protected]e10392c2012-09-11 21:13:08601 // Also delay the animation when the shelf was hidden, and has just been made
602 // visible (e.g. using a gesture-drag).
603 bool delay_shelf_update =
[email protected]ef80e4302012-12-04 19:37:31604 state.visibility_state == SHELF_AUTO_HIDE &&
605 state.auto_hide_state == SHELF_AUTO_HIDE_HIDDEN &&
606 old_state.visibility_state == SHELF_AUTO_HIDE;
[email protected]e10392c2012-09-11 21:13:08607
[email protected]ef80e4302012-12-04 19:37:31608 if (state.visibility_state == SHELF_VISIBLE &&
609 old_state.visibility_state == SHELF_AUTO_HIDE &&
610 old_state.auto_hide_state == SHELF_AUTO_HIDE_HIDDEN)
[email protected]e10392c2012-09-11 21:13:08611 delay_shelf_update = true;
612
[email protected]e4d9fe92012-09-10 14:04:49613 if (delay_shelf_update) {
614 if (update_shelf_observer_)
615 update_shelf_observer_->Detach();
616 // UpdateShelfBackground deletes itself when the animation is done.
617 update_shelf_observer_ = new UpdateShelfObserver(this);
618 status_animation_setter.AddObserver(update_shelf_observer_);
619 }
[email protected]478c6c32013-03-09 02:50:58620 ui::Layer* layer = GetLayer(shelf_->status_area_widget());
621 // TODO(harrym): Remove when status_area is view (crbug.com/180422).
622 gfx::Rect status_bounds = target_bounds.status_bounds_in_shelf;
623 status_bounds.set_x(status_bounds.x() +
624 target_bounds.shelf_bounds_in_root.x());
625 status_bounds.set_y(status_bounds.y() +
626 target_bounds.shelf_bounds_in_root.y());
627 layer->SetBounds(status_bounds);
[email protected]88d71122012-10-18 07:11:01628 layer->SetOpacity(target_bounds.opacity);
[email protected]2e236a52012-06-27 22:21:47629 Shell::GetInstance()->SetDisplayWorkAreaInsets(
[email protected]b913a3a2012-12-11 13:07:19630 root_window_, target_bounds.work_area_insets);
[email protected]128fd3732012-03-27 01:55:12631 UpdateHitTestBounds();
[email protected]e4d9fe92012-09-10 14:04:49632 if (!delay_shelf_update)
633 UpdateShelfBackground(change_type);
[email protected]27f6af62012-03-21 05:34:40634}
[email protected]63ef21592012-03-21 01:15:40635
[email protected]4bb16502011-12-06 14:44:58636void ShelfLayoutManager::StopAnimating() {
[email protected]478c6c32013-03-09 02:50:58637 GetLayer(shelf_)->GetAnimator()->StopAnimating();
638 GetLayer(shelf_->status_area_widget())->GetAnimator()->StopAnimating();
[email protected]ae18b9112011-11-07 16:59:13639}
640
[email protected]55444502012-05-10 15:43:53641void ShelfLayoutManager::GetShelfSize(int* width, int* height) {
642 *width = *height = 0;
[email protected]478c6c32013-03-09 02:50:58643 gfx::Size status_size(
644 shelf_->status_area_widget()->GetWindowBoundsInScreen().size());
[email protected]8572c4872013-01-12 17:16:07645 if (IsHorizontalAlignment())
[email protected]478c6c32013-03-09 02:50:58646 *height = std::max(kLauncherPreferredSize, status_size.height());
[email protected]0ab08e52012-05-19 00:04:21647 else
[email protected]478c6c32013-03-09 02:50:58648 *width = std::max(kLauncherPreferredSize, status_size.width());
[email protected]55444502012-05-10 15:43:53649}
650
651void ShelfLayoutManager::AdjustBoundsBasedOnAlignment(int inset,
652 gfx::Rect* bounds) const {
[email protected]8572c4872013-01-12 17:16:07653 bounds->Inset(SelectValueForShelfAlignment(
654 gfx::Insets(0, 0, inset, 0),
655 gfx::Insets(0, inset, 0, 0),
656 gfx::Insets(0, 0, 0, inset),
657 gfx::Insets(inset, 0, 0, 0)));
[email protected]55444502012-05-10 15:43:53658}
659
[email protected]27f6af62012-03-21 05:34:40660void ShelfLayoutManager::CalculateTargetBounds(
661 const State& state,
[email protected]55444502012-05-10 15:43:53662 TargetBounds* target_bounds) {
[email protected]5416f282013-04-29 20:52:48663 const gfx::Rect available_bounds(GetAvailableBounds());
[email protected]478c6c32013-03-09 02:50:58664 gfx::Rect status_size(
665 shelf_->status_area_widget()->GetWindowBoundsInScreen().size());
[email protected]55444502012-05-10 15:43:53666 int shelf_width = 0, shelf_height = 0;
667 GetShelfSize(&shelf_width, &shelf_height);
[email protected]478c6c32013-03-09 02:50:58668 if (IsHorizontalAlignment())
669 shelf_width = available_bounds.width();
670 else
671 shelf_height = available_bounds.height();
672
673 if (state.visibility_state == SHELF_AUTO_HIDE &&
674 state.auto_hide_state == SHELF_AUTO_HIDE_HIDDEN) {
[email protected]17da26a82013-04-09 21:20:32675 // Auto-hidden shelf always starts with the default size. If a gesture-drag
676 // is in progress, then the call to UpdateTargetBoundsForGesture() below
677 // takes care of setting the height properly.
678 if (IsHorizontalAlignment())
679 shelf_height = kAutoHideSize;
680 else
681 shelf_width = kAutoHideSize;
[email protected]5416f282013-04-29 20:52:48682 } else if (state.visibility_state == SHELF_HIDDEN ||
683 !keyboard_bounds_.IsEmpty()) {
[email protected]478c6c32013-03-09 02:50:58684 if (IsHorizontalAlignment())
685 shelf_height = 0;
686 else
687 shelf_width = 0;
[email protected]27f6af62012-03-21 05:34:40688 }
[email protected]17da26a82013-04-09 21:20:32689
[email protected]478c6c32013-03-09 02:50:58690 target_bounds->shelf_bounds_in_root = SelectValueForShelfAlignment(
691 gfx::Rect(available_bounds.x(), available_bounds.bottom() - shelf_height,
692 available_bounds.width(), shelf_height),
693 gfx::Rect(available_bounds.x(), available_bounds.y(),
694 shelf_width, available_bounds.height()),
695 gfx::Rect(available_bounds.right() - shelf_width, available_bounds.y(),
696 shelf_width, available_bounds.height()),
697 gfx::Rect(available_bounds.x(), available_bounds.y(),
698 available_bounds.width(), shelf_height));
699
700 int status_inset = (kLauncherPreferredSize -
701 PrimaryAxisValue(status_size.height(), status_size.width()));
702
703 target_bounds->status_bounds_in_shelf = SelectValueForShelfAlignment(
704 gfx::Rect(base::i18n::IsRTL() ? 0 : shelf_width - status_size.width(),
705 status_inset, status_size.width(), status_size.height()),
706 gfx::Rect(shelf_width - (status_size.width() + status_inset),
707 shelf_height - status_size.height(), status_size.width(),
708 status_size.height()),
709 gfx::Rect(status_inset, shelf_height - status_size.height(),
710 status_size.width(), status_size.height()),
711 gfx::Rect(base::i18n::IsRTL() ? 0 : shelf_width - status_size.width(),
712 shelf_height - (status_size.height() + status_inset),
713 status_size.width(), status_size.height()));
714
[email protected]478c6c32013-03-09 02:50:58715 target_bounds->work_area_insets = SelectValueForShelfAlignment(
716 gfx::Insets(0, 0, GetWorkAreaSize(state, shelf_height), 0),
717 gfx::Insets(0, GetWorkAreaSize(state, shelf_width), 0, 0),
718 gfx::Insets(0, 0, 0, GetWorkAreaSize(state, shelf_width)),
719 gfx::Insets(GetWorkAreaSize(state, shelf_height), 0, 0, 0));
720
[email protected]5416f282013-04-29 20:52:48721 // Also push in the work area inset for the keyboard if it is visible.
722 if (!keyboard_bounds_.IsEmpty()) {
723 target_bounds->work_area_insets.Set(
724 target_bounds->work_area_insets.top(),
725 target_bounds->work_area_insets.left(),
726 target_bounds->work_area_insets.bottom() + keyboard_bounds_.height(),
727 target_bounds->work_area_insets.right());
728 }
729
[email protected]27f6af62012-03-21 05:34:40730 target_bounds->opacity =
[email protected]3c6abbe2012-08-30 23:48:57731 (gesture_drag_status_ != GESTURE_DRAG_NONE ||
[email protected]ef80e4302012-12-04 19:37:31732 state.visibility_state == SHELF_VISIBLE ||
733 state.visibility_state == SHELF_AUTO_HIDE) ? 1.0f : 0.0f;
[email protected]17da26a82013-04-09 21:20:32734
[email protected]3c6abbe2012-08-30 23:48:57735 if (gesture_drag_status_ == GESTURE_DRAG_IN_PROGRESS)
736 UpdateTargetBoundsForGesture(target_bounds);
[email protected]17da26a82013-04-09 21:20:32737
738 // This needs to happen after calling UpdateTargetBoundsForGesture(), because
739 // that can change the size of the shelf.
740 target_bounds->launcher_bounds_in_shelf = SelectValueForShelfAlignment(
741 gfx::Rect(base::i18n::IsRTL() ? status_size.width() : 0, 0,
742 shelf_width - status_size.width(),
743 target_bounds->shelf_bounds_in_root.height()),
744 gfx::Rect(0, 0, shelf_width, shelf_height - status_size.height()),
745 gfx::Rect(0, 0, shelf_width, shelf_height - status_size.height()),
746 gfx::Rect(base::i18n::IsRTL() ? status_size.width() : 0, 0,
747 shelf_width - status_size.width(),
748 target_bounds->shelf_bounds_in_root.height()));
[email protected]3c6abbe2012-08-30 23:48:57749}
750
751void ShelfLayoutManager::UpdateTargetBoundsForGesture(
752 TargetBounds* target_bounds) const {
753 CHECK_EQ(GESTURE_DRAG_IN_PROGRESS, gesture_drag_status_);
[email protected]8572c4872013-01-12 17:16:07754 bool horizontal = IsHorizontalAlignment();
[email protected]7d1d2d22013-03-24 04:25:57755 const gfx::Rect& available_bounds(root_window_->bounds());
[email protected]407ffd32012-09-11 17:47:36756 int resistance_free_region = 0;
[email protected]3c6abbe2012-08-30 23:48:57757
[email protected]ef80e4302012-12-04 19:37:31758 if (gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_HIDDEN &&
759 visibility_state() == SHELF_AUTO_HIDE &&
760 auto_hide_state() != SHELF_AUTO_HIDE_SHOWN) {
[email protected]c8e2e832012-09-12 21:48:28761 // If the shelf was hidden when the drag started (and the state hasn't
762 // changed since then, e.g. because the tray-menu was shown because of the
763 // drag), then allow the drag some resistance-free region at first to make
764 // sure the shelf sticks with the finger until the shelf is visible.
[email protected]7d1d2d22013-03-24 04:25:57765 resistance_free_region = kLauncherPreferredSize - kAutoHideSize;
[email protected]91d966a72012-09-06 03:42:27766 }
767
[email protected]8572c4872013-01-12 17:16:07768 bool resist = SelectValueForShelfAlignment(
769 gesture_drag_amount_ < -resistance_free_region,
770 gesture_drag_amount_ > resistance_free_region,
771 gesture_drag_amount_ < -resistance_free_region,
772 gesture_drag_amount_ > resistance_free_region);
[email protected]91d966a72012-09-06 03:42:27773
774 float translate = 0.f;
775 if (resist) {
776 float diff = fabsf(gesture_drag_amount_) - resistance_free_region;
[email protected]407ffd32012-09-11 17:47:36777 diff = std::min(diff, sqrtf(diff));
[email protected]91d966a72012-09-06 03:42:27778 if (gesture_drag_amount_ < 0)
779 translate = -resistance_free_region - diff;
780 else
781 translate = resistance_free_region + diff;
[email protected]4982ee12012-09-04 22:16:10782 } else {
[email protected]91d966a72012-09-06 03:42:27783 translate = gesture_drag_amount_;
[email protected]4982ee12012-09-04 22:16:10784 }
785
[email protected]3c6abbe2012-08-30 23:48:57786 if (horizontal) {
[email protected]7d1d2d22013-03-24 04:25:57787 // Move and size the launcher with the gesture.
[email protected]17da26a82013-04-09 21:20:32788 int shelf_height = target_bounds->shelf_bounds_in_root.height() - translate;
789 shelf_height = std::max(shelf_height, kAutoHideSize);
790 target_bounds->shelf_bounds_in_root.set_height(shelf_height);
[email protected]7d1d2d22013-03-24 04:25:57791 if (alignment_ == SHELF_ALIGNMENT_BOTTOM) {
[email protected]17da26a82013-04-09 21:20:32792 target_bounds->shelf_bounds_in_root.set_y(
793 available_bounds.bottom() - shelf_height);
[email protected]91d966a72012-09-06 03:42:27794 }
[email protected]7d1d2d22013-03-24 04:25:57795
796 // The statusbar should be in the center of the shelf.
797 gfx::Rect status_y = target_bounds->shelf_bounds_in_root;
798 status_y.set_y(0);
799 status_y.ClampToCenteredSize(
800 target_bounds->status_bounds_in_shelf.size());
801 target_bounds->status_bounds_in_shelf.set_y(status_y.y());
802 } else {
803 // Move and size the launcher with the gesture.
[email protected]17da26a82013-04-09 21:20:32804 int shelf_width = target_bounds->shelf_bounds_in_root.width() - translate;
805 shelf_width = std::max(shelf_width, kAutoHideSize);
806 target_bounds->shelf_bounds_in_root.set_width(shelf_width);
[email protected]7d1d2d22013-03-24 04:25:57807 if (alignment_ == SHELF_ALIGNMENT_RIGHT) {
[email protected]17da26a82013-04-09 21:20:32808 target_bounds->shelf_bounds_in_root.set_y(
809 available_bounds.right() - shelf_width);
[email protected]7d1d2d22013-03-24 04:25:57810 }
811
812 // The statusbar should be in the center of the shelf.
813 gfx::Rect status_x = target_bounds->shelf_bounds_in_root;
814 status_x.set_x(0);
815 status_x.ClampToCenteredSize(
816 target_bounds->status_bounds_in_shelf.size());
817 target_bounds->status_bounds_in_shelf.set_x(status_x.x());
[email protected]3c6abbe2012-08-30 23:48:57818 }
[email protected]ae18b9112011-11-07 16:59:13819}
820
[email protected]a160baec2012-03-21 20:52:15821void ShelfLayoutManager::UpdateShelfBackground(
822 BackgroundAnimator::ChangeType type) {
823 bool launcher_paints = GetLauncherPaintsBackground();
[email protected]478c6c32013-03-09 02:50:58824 shelf_->SetPaintsBackground(launcher_paints, type);
[email protected]a160baec2012-03-21 20:52:15825}
826
827bool ShelfLayoutManager::GetLauncherPaintsBackground() const {
[email protected]3c6abbe2012-08-30 23:48:57828 return gesture_drag_status_ != GESTURE_DRAG_NONE ||
829 (!state_.is_screen_locked && window_overlaps_shelf_) ||
[email protected]ef80e4302012-12-04 19:37:31830 (state_.visibility_state == SHELF_AUTO_HIDE) ;
[email protected]ae18b9112011-11-07 16:59:13831}
832
[email protected]b1c37fc2012-03-22 03:36:13833void ShelfLayoutManager::UpdateAutoHideStateNow() {
834 SetState(state_.visibility_state);
835}
836
[email protected]ef80e4302012-12-04 19:37:31837ShelfAutoHideState ShelfLayoutManager::CalculateAutoHideState(
838 ShelfVisibilityState visibility_state) const {
[email protected]478c6c32013-03-09 02:50:58839 if (visibility_state != SHELF_AUTO_HIDE || !shelf_)
[email protected]ef80e4302012-12-04 19:37:31840 return SHELF_AUTO_HIDE_HIDDEN;
[email protected]b1c37fc2012-03-22 03:36:13841
[email protected]4982ee12012-09-04 22:16:10842 if (gesture_drag_status_ == GESTURE_DRAG_COMPLETE_IN_PROGRESS)
843 return gesture_drag_auto_hide_state_;
[email protected]3c6abbe2012-08-30 23:48:57844
[email protected]b1c37fc2012-03-22 03:36:13845 Shell* shell = Shell::GetInstance();
[email protected]7510d1082012-03-30 21:58:34846 if (shell->GetAppListTargetVisibility())
[email protected]ef80e4302012-12-04 19:37:31847 return SHELF_AUTO_HIDE_SHOWN;
[email protected]7510d1082012-03-30 21:58:34848
[email protected]478c6c32013-03-09 02:50:58849 if (shelf_->status_area_widget() &&
850 shelf_->status_area_widget()->ShouldShowLauncher())
[email protected]ef80e4302012-12-04 19:37:31851 return SHELF_AUTO_HIDE_SHOWN;
[email protected]b1c37fc2012-03-22 03:36:13852
[email protected]478c6c32013-03-09 02:50:58853 if (shelf_->launcher() && shelf_->launcher()->IsShowingMenu())
[email protected]ef80e4302012-12-04 19:37:31854 return SHELF_AUTO_HIDE_SHOWN;
[email protected]e9992b12012-03-27 00:11:27855
[email protected]478c6c32013-03-09 02:50:58856 if (shelf_->launcher() && shelf_->launcher()->IsShowingOverflowBubble())
[email protected]ef80e4302012-12-04 19:37:31857 return SHELF_AUTO_HIDE_SHOWN;
[email protected]3475f5e2012-07-12 22:10:32858
[email protected]478c6c32013-03-09 02:50:58859 if (shelf_->IsActive() || shelf_->status_area_widget()->IsActive())
[email protected]ef80e4302012-12-04 19:37:31860 return SHELF_AUTO_HIDE_SHOWN;
[email protected]8676f0472012-03-29 20:30:12861
[email protected]5f1d99dc2012-04-12 21:42:37862 // Don't show if the user is dragging the mouse.
863 if (event_filter_.get() && event_filter_->in_mouse_drag())
[email protected]ef80e4302012-12-04 19:37:31864 return SHELF_AUTO_HIDE_HIDDEN;
[email protected]5f1d99dc2012-04-12 21:42:37865
[email protected]478c6c32013-03-09 02:50:58866 gfx::Rect shelf_region = shelf_->GetWindowBoundsInScreen();
867 if (shelf_->status_area_widget() &&
868 shelf_->status_area_widget()->IsMessageBubbleShown() &&
[email protected]2e195f52012-09-22 00:24:46869 IsVisible()) {
870 // Increase the the hit test area to prevent the shelf from disappearing
871 // when the mouse is over the bubble gap.
872 shelf_region.Inset(alignment_ == SHELF_ALIGNMENT_RIGHT ?
873 -kNotificationBubbleGapHeight : 0,
874 alignment_ == SHELF_ALIGNMENT_BOTTOM ?
875 -kNotificationBubbleGapHeight : 0,
876 alignment_ == SHELF_ALIGNMENT_LEFT ?
877 -kNotificationBubbleGapHeight : 0,
[email protected]8572c4872013-01-12 17:16:07878 alignment_ == SHELF_ALIGNMENT_TOP ?
879 -kNotificationBubbleGapHeight : 0);
[email protected]2e195f52012-09-22 00:24:46880 }
[email protected]ca8f905b2013-01-22 21:53:25881
882 if (shelf_region.Contains(Shell::GetScreen()->GetCursorScreenPoint()))
883 return SHELF_AUTO_HIDE_SHOWN;
884
885 const std::vector<aura::Window*> windows =
[email protected]3f540b42013-03-26 07:43:18886 ash::WindowCycleController::BuildWindowList(NULL, false);
[email protected]ca8f905b2013-01-22 21:53:25887
888 // Process the window list and check if there are any visible windows.
889 for (size_t i = 0; i < windows.size(); ++i) {
890 if (windows[i] && windows[i]->IsVisible() &&
[email protected]0dd07722013-04-12 23:07:43891 !ash::wm::IsWindowMinimized(windows[i]) &&
892 root_window_ == windows[i]->GetRootWindow())
[email protected]ca8f905b2013-01-22 21:53:25893 return SHELF_AUTO_HIDE_HIDDEN;
894 }
895
896 // If there are no visible windows do not hide the shelf.
897 return SHELF_AUTO_HIDE_SHOWN;
[email protected]b1c37fc2012-03-22 03:36:13898}
899
[email protected]128fd3732012-03-27 01:55:12900void ShelfLayoutManager::UpdateHitTestBounds() {
[email protected]d3643b52013-05-01 16:00:48901 gfx::Insets mouse_insets;
902 gfx::Insets touch_insets;
[email protected]ef80e4302012-12-04 19:37:31903 if (state_.visibility_state == SHELF_VISIBLE) {
[email protected]128fd3732012-03-27 01:55:12904 // Let clicks at the very top of the launcher through so windows can be
905 // resized with the bottom-right corner and bottom edge.
[email protected]d3643b52013-05-01 16:00:48906 mouse_insets = GetInsetsForAlignment(kWorkspaceAreaVisibleInset);
907 } else if (state_.visibility_state == SHELF_AUTO_HIDE) {
908 // Extend the touch hit target out a bit to allow users to drag shelf out
909 // while hidden.
910 touch_insets = GetInsetsForAlignment(-kWorkspaceAreaAutoHideInset);
[email protected]128fd3732012-03-27 01:55:12911 }
[email protected]d3643b52013-05-01 16:00:48912
913 if (shelf_ && shelf_->GetNativeWindow())
914 shelf_->GetNativeWindow()->SetHitTestBoundsOverrideOuter(mouse_insets,
915 touch_insets);
916 shelf_->status_area_widget()->GetNativeWindow()->
917 SetHitTestBoundsOverrideOuter(mouse_insets, touch_insets);
[email protected]128fd3732012-03-27 01:55:12918}
919
[email protected]5f1d99dc2012-04-12 21:42:37920bool ShelfLayoutManager::IsShelfWindow(aura::Window* window) {
921 if (!window)
922 return false;
[email protected]bb0c7cd42013-05-20 23:39:45923 return (shelf_ && shelf_->GetNativeWindow()->Contains(window)) ||
924 (shelf_->status_area_widget() &&
925 shelf_->status_area_widget()->GetNativeWindow()->Contains(window));
[email protected]5f1d99dc2012-04-12 21:42:37926}
927
[email protected]55444502012-05-10 15:43:53928int ShelfLayoutManager::GetWorkAreaSize(const State& state, int size) const {
[email protected]ef80e4302012-12-04 19:37:31929 if (state.visibility_state == SHELF_VISIBLE)
[email protected]55444502012-05-10 15:43:53930 return size;
[email protected]ef80e4302012-12-04 19:37:31931 if (state.visibility_state == SHELF_AUTO_HIDE)
[email protected]55444502012-05-10 15:43:53932 return kAutoHideSize;
933 return 0;
934}
935
[email protected]5416f282013-04-29 20:52:48936gfx::Rect ShelfLayoutManager::GetAvailableBounds() const {
937 gfx::Rect bounds(root_window_->bounds());
938 bounds.set_height(bounds.height() - keyboard_bounds_.height());
939 return bounds;
940}
941
942void ShelfLayoutManager::OnKeyboardBoundsChanging(
943 const gfx::Rect& keyboard_bounds) {
944 keyboard_bounds_ = keyboard_bounds;
945 OnWindowResized();
946}
947
[email protected]d3643b52013-05-01 16:00:48948gfx::Insets ShelfLayoutManager::GetInsetsForAlignment(int distance) const {
949 switch (alignment_) {
950 case SHELF_ALIGNMENT_BOTTOM:
951 return gfx::Insets(distance, 0, 0, 0);
952 case SHELF_ALIGNMENT_LEFT:
953 return gfx::Insets(0, 0, 0, distance);
954 case SHELF_ALIGNMENT_RIGHT:
955 return gfx::Insets(0, distance, 0, 0);
956 case SHELF_ALIGNMENT_TOP:
957 return gfx::Insets(0, 0, distance, 0);
958 }
959 NOTREACHED();
960 return gfx::Insets();
961}
962
[email protected]55f593352011-12-24 05:42:46963} // namespace internal
964} // namespace ash