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. 4 5 #ifndef ASH_SHELF_SHELF_LAYOUT_MANAGER_H_ 6 #define ASH_SHELF_SHELF_LAYOUT_MANAGER_H_ 7 8 #include <vector> 9 10 #include "ash/ash_export.h" 11 #include "ash/session/session_state_observer.h" 12 #include "ash/shelf/background_animator.h" 13 #include "ash/shelf/shelf.h" 14 #include "ash/shelf/shelf_types.h" 15 #include "ash/shell_observer.h" 16 #include "ash/snap_to_pixel_layout_manager.h" 17 #include "ash/system/status_area_widget.h" 18 #include "ash/wm/dock/docked_window_layout_manager_observer.h" 19 #include "ash/wm/lock_state_observer.h" 20 #include "ash/wm/workspace/workspace_types.h" 21 #include "base/basictypes.h" 22 #include "base/compiler_specific.h" 23 #include "base/logging.h" 24 #include "base/observer_list.h" 25 #include "base/timer/timer.h" 26 #include "ui/gfx/insets.h" 27 #include "ui/gfx/rect.h" 28 #include "ui/keyboard/keyboard_controller.h" 29 #include "ui/keyboard/keyboard_controller_observer.h" 30 #include "ui/wm/public/activation_change_observer.h" 31 32 namespace aura { 33 class RootWindow; 34 } 35 36 namespace ui { 37 class GestureEvent; 38 class ImplicitAnimationObserver; 39 } 40 41 namespace ash { 42 class PanelLayoutManagerTest; 43 class ScreenAsh; 44 class ShelfBezelEventFilter; 45 class ShelfLayoutManagerObserver; 46 class ShelfLayoutManagerTest; 47 class ShelfWidget; 48 class StatusAreaWidget; 49 class WorkspaceController; 50 FORWARD_DECLARE_TEST(AshPopupAlignmentDelegateTest, AutoHide); 51 FORWARD_DECLARE_TEST(WebNotificationTrayTest, PopupAndFullscreen); 52 53 // ShelfLayoutManager is the layout manager responsible for the shelf and 54 // status widgets. The shelf is given the total available width and told the 55 // width of the status area. This allows the shelf to draw the background and 56 // layout to the status area. 57 // To respond to bounds changes in the status area StatusAreaLayoutManager works 58 // closely with ShelfLayoutManager. 59 class ASH_EXPORT ShelfLayoutManager 60 : public ash::ShellObserver, 61 public aura::client::ActivationChangeObserver, 62 public DockedWindowLayoutManagerObserver, 63 public keyboard::KeyboardControllerObserver, 64 public LockStateObserver, 65 public SnapToPixelLayoutManager, 66 public SessionStateObserver { 67 public: 68 69 // We reserve a small area on the edge of the workspace area to ensure that 70 // the resize handle at the edge of the window can be hit. 71 static const int kWorkspaceAreaVisibleInset; 72 73 // When autohidden we extend the touch hit target onto the screen so that the 74 // user can drag the shelf out. 75 static const int kWorkspaceAreaAutoHideInset; 76 77 // Size of the shelf when auto-hidden. 78 static const int kAutoHideSize; 79 80 // Inset between the inner edge of the shelf (towards centre of screen), and 81 // the shelf items, notifications, status area etc. 82 static const int kShelfItemInset; 83 84 explicit ShelfLayoutManager(ShelfWidget* shelf); 85 virtual ~ShelfLayoutManager(); 86 87 // Sets the ShelfAutoHideBehavior. See enum description for details. 88 void SetAutoHideBehavior(ShelfAutoHideBehavior behavior); 89 ShelfAutoHideBehavior auto_hide_behavior() const { 90 return auto_hide_behavior_; 91 } 92 93 // Sets the alignment. Returns true if the alignment is changed. Otherwise, 94 // returns false. 95 bool SetAlignment(ShelfAlignment alignment); 96 // Returns the desired alignment for the current state, either the user's 97 // set alignment (alignment_) or SHELF_ALIGNMENT_BOTTOM when the screen 98 // is locked. 99 ShelfAlignment GetAlignment() const; 100 101 void set_workspace_controller(WorkspaceController* controller) { 102 workspace_controller_ = controller; 103 } 104 105 bool updating_bounds() const { return updating_bounds_; } 106 107 // Clears internal data for shutdown process. 108 void PrepareForShutdown(); 109 110 // Returns whether the shelf and its contents (shelf, status) are visible 111 // on the screen. 112 bool IsVisible() const; 113 114 // Returns the ideal bounds of the shelf assuming it is visible. 115 gfx::Rect GetIdealBounds(); 116 117 // Returns the docked area bounds. 118 const gfx::Rect& dock_bounds() const { return dock_bounds_; } 119 120 // Stops any animations and sets the bounds of the shelf and status 121 // widgets. 122 void LayoutShelf(); 123 124 // Returns shelf visibility state based on current value of auto hide 125 // behavior setting. 126 ShelfVisibilityState CalculateShelfVisibility(); 127 128 // Updates the visibility state. 129 void UpdateVisibilityState(); 130 131 // Invoked by the shelf when the auto-hide state may have changed. 132 void UpdateAutoHideState(); 133 134 ShelfVisibilityState visibility_state() const { 135 return state_.visibility_state; 136 } 137 ShelfAutoHideState auto_hide_state() const { return state_.auto_hide_state; } 138 139 ShelfWidget* shelf_widget() { return shelf_; } 140 141 // Sets whether any windows overlap the shelf. If a window overlaps the shelf 142 // the shelf renders slightly differently. 143 void SetWindowOverlapsShelf(bool value); 144 bool window_overlaps_shelf() const { return window_overlaps_shelf_; } 145 146 void AddObserver(ShelfLayoutManagerObserver* observer); 147 void RemoveObserver(ShelfLayoutManagerObserver* observer); 148 149 // Gesture related functions: 150 void OnGestureEdgeSwipe(const ui::GestureEvent& gesture); 151 void StartGestureDrag(const ui::GestureEvent& gesture); 152 enum DragState { 153 DRAG_SHELF, 154 DRAG_TRAY 155 }; 156 // Returns DRAG_SHELF if the gesture should continue to drag the entire shelf. 157 // Returns DRAG_TRAY if the gesture can start dragging the tray-bubble from 158 // this point on. 159 DragState UpdateGestureDrag(const ui::GestureEvent& gesture); 160 void CompleteGestureDrag(const ui::GestureEvent& gesture); 161 void CancelGestureDrag(); 162 163 // Set an animation duration override for the show / hide animation of the 164 // shelf. Specifying 0 leads to use the default. 165 void SetAnimationDurationOverride(int duration_override_in_ms); 166 167 // Overridden from SnapLayoutManager: 168 virtual void OnWindowResized() OVERRIDE; 169 virtual void SetChildBounds(aura::Window* child, 170 const gfx::Rect& requested_bounds) OVERRIDE; 171 172 // Overridden from ash::ShellObserver: 173 virtual void OnLockStateChanged(bool locked) OVERRIDE; 174 175 // Overriden from aura::client::ActivationChangeObserver: 176 virtual void OnWindowActivated(aura::Window* gained_active, 177 aura::Window* lost_active) OVERRIDE; 178 179 // Overridden from ash::LockStateObserver: 180 virtual void OnLockStateEvent(LockStateObserver::EventType event) OVERRIDE; 181 182 // Overridden from ash::SessionStateObserver: 183 virtual void SessionStateChanged( 184 SessionStateDelegate::SessionState state) OVERRIDE; 185 186 // TODO(harrym|oshima): These templates will be moved to 187 // new Shelf class. 188 // A helper function that provides a shortcut for choosing 189 // values specific to a shelf alignment. 190 template<typename T> 191 T SelectValueForShelfAlignment(T bottom, T left, T right, T top) const { 192 switch (GetAlignment()) { 193 case SHELF_ALIGNMENT_BOTTOM: 194 return bottom; 195 case SHELF_ALIGNMENT_LEFT: 196 return left; 197 case SHELF_ALIGNMENT_RIGHT: 198 return right; 199 case SHELF_ALIGNMENT_TOP: 200 return top; 201 } 202 NOTREACHED(); 203 return right; 204 } 205 206 template<typename T> 207 T PrimaryAxisValue(T horizontal, T vertical) const { 208 return IsHorizontalAlignment() ? horizontal : vertical; 209 } 210 211 // Is the shelf's alignment horizontal? 212 bool IsHorizontalAlignment() const; 213 214 // Returns a ShelfLayoutManager on the display which has a shelf for 215 // given |window|. See RootWindowController::ForShelf for more info. 216 static ShelfLayoutManager* ForShelf(aura::Window* window); 217 218 private: 219 class AutoHideEventFilter; 220 class UpdateShelfObserver; 221 friend class ash::ScreenAsh; 222 friend class PanelLayoutManagerTest; 223 friend class ShelfLayoutManagerTest; 224 FRIEND_TEST_ALL_PREFIXES(ash::AshPopupAlignmentDelegateTest, AutoHide); 225 FRIEND_TEST_ALL_PREFIXES(ash::WebNotificationTrayTest, PopupAndFullscreen); 226 227 struct TargetBounds { 228 TargetBounds(); 229 ~TargetBounds(); 230 231 float opacity; 232 float status_opacity; 233 gfx::Rect shelf_bounds_in_root; 234 gfx::Rect shelf_bounds_in_shelf; 235 gfx::Rect status_bounds_in_shelf; 236 gfx::Insets work_area_insets; 237 }; 238 239 struct State { 240 State() : visibility_state(SHELF_VISIBLE), 241 auto_hide_state(SHELF_AUTO_HIDE_HIDDEN), 242 window_state(WORKSPACE_WINDOW_STATE_DEFAULT), 243 is_screen_locked(false) {} 244 245 // Returns true if the two states are considered equal. As 246 // |auto_hide_state| only matters if |visibility_state| is 247 // |SHELF_AUTO_HIDE|, Equals() ignores the |auto_hide_state| as 248 // appropriate. 249 bool Equals(const State& other) const { 250 return other.visibility_state == visibility_state && 251 (visibility_state != SHELF_AUTO_HIDE || 252 other.auto_hide_state == auto_hide_state) && 253 other.window_state == window_state && 254 other.is_screen_locked == is_screen_locked; 255 } 256 257 ShelfVisibilityState visibility_state; 258 ShelfAutoHideState auto_hide_state; 259 WorkspaceWindowState window_state; 260 bool is_screen_locked; 261 }; 262 263 // Sets the visibility of the shelf to |state|. 264 void SetState(ShelfVisibilityState visibility_state); 265 266 // Updates the bounds and opacity of the shelf and status widgets. 267 // If |observer| is specified, it will be called back when the animations, if 268 // any, are complete. 269 void UpdateBoundsAndOpacity(const TargetBounds& target_bounds, 270 bool animate, 271 ui::ImplicitAnimationObserver* observer); 272 273 // Stops any animations and progresses them to the end. 274 void StopAnimating(); 275 276 // Returns the width (if aligned to the side) or height (if aligned to the 277 // bottom). 278 void GetShelfSize(int* width, int* height); 279 280 // Insets |bounds| by |inset| on the edge the shelf is aligned to. 281 void AdjustBoundsBasedOnAlignment(int inset, gfx::Rect* bounds) const; 282 283 // Calculates the target bounds assuming visibility of |visible|. 284 void CalculateTargetBounds(const State& state, TargetBounds* target_bounds); 285 286 // Updates the target bounds if a gesture-drag is in progress. This is only 287 // used by |CalculateTargetBounds()|. 288 void UpdateTargetBoundsForGesture(TargetBounds* target_bounds) const; 289 290 // Updates the background of the shelf. 291 void UpdateShelfBackground(BackgroundAnimatorChangeType type); 292 293 // Returns how the shelf background is painted. 294 ShelfBackgroundType GetShelfBackgroundType() const; 295 296 // Updates the auto hide state immediately. 297 void UpdateAutoHideStateNow(); 298 299 // Stops the auto hide timer and clears 300 // |mouse_over_shelf_when_auto_hide_timer_started_|. 301 void StopAutoHideTimer(); 302 303 // Returns the bounds of an additional region which can trigger showing the 304 // shelf. This region exists to make it easier to trigger showing the shelf 305 // when the shelf is auto hidden and the shelf is on the boundary between 306 // two displays. 307 gfx::Rect GetAutoHideShowShelfRegionInScreen() const; 308 309 // Returns the AutoHideState. This value is determined from the shelf and 310 // tray. 311 ShelfAutoHideState CalculateAutoHideState( 312 ShelfVisibilityState visibility_state) const; 313 314 // Returns true if |window| is a descendant of the shelf. 315 bool IsShelfWindow(aura::Window* window); 316 317 int GetWorkAreaSize(const State& state, int size) const; 318 319 // Overridden from keyboard::KeyboardControllerObserver: 320 virtual void OnKeyboardBoundsChanging(const gfx::Rect& new_bounds) OVERRIDE; 321 322 // Overridden from DockedWindowLayoutManagerObserver: 323 virtual void OnDockBoundsChanging( 324 const gfx::Rect& dock_bounds, 325 DockedWindowLayoutManagerObserver::Reason reason) OVERRIDE; 326 327 // The RootWindow is cached so that we don't invoke Shell::GetInstance() from 328 // our destructor. We avoid that as at the time we're deleted Shell is being 329 // deleted too. 330 aura::Window* root_window_; 331 332 // True when inside UpdateBoundsAndOpacity() method. Used to prevent calling 333 // UpdateBoundsAndOpacity() again from SetChildBounds(). 334 bool updating_bounds_; 335 336 // See description above setter. 337 ShelfAutoHideBehavior auto_hide_behavior_; 338 339 // See description above getter. 340 ShelfAlignment alignment_; 341 342 // Current state. 343 State state_; 344 345 ShelfWidget* shelf_; 346 347 WorkspaceController* workspace_controller_; 348 349 // Do any windows overlap the shelf? This is maintained by WorkspaceManager. 350 bool window_overlaps_shelf_; 351 352 base::OneShotTimer<ShelfLayoutManager> auto_hide_timer_; 353 354 // Whether the mouse was over the shelf when the auto hide timer started. 355 // False when neither the auto hide timer nor the timer task are running. 356 bool mouse_over_shelf_when_auto_hide_timer_started_; 357 358 // EventFilter used to detect when user moves the mouse over the shelf to 359 // trigger showing the shelf. 360 scoped_ptr<AutoHideEventFilter> auto_hide_event_filter_; 361 362 // EventFilter used to detect when user issues a gesture on a bezel sensor. 363 scoped_ptr<ShelfBezelEventFilter> bezel_event_filter_; 364 365 ObserverList<ShelfLayoutManagerObserver> observers_; 366 367 // The shelf reacts to gesture-drags, and can be set to auto-hide for certain 368 // gestures. Some shelf behaviour (e.g. visibility state, background color 369 // etc.) are affected by various stages of the drag. The enum keeps track of 370 // the present status of the gesture drag. 371 enum GestureDragStatus { 372 GESTURE_DRAG_NONE, 373 GESTURE_DRAG_IN_PROGRESS, 374 GESTURE_DRAG_CANCEL_IN_PROGRESS, 375 GESTURE_DRAG_COMPLETE_IN_PROGRESS 376 }; 377 GestureDragStatus gesture_drag_status_; 378 379 // Tracks the amount of the drag. The value is only valid when 380 // |gesture_drag_status_| is set to GESTURE_DRAG_IN_PROGRESS. 381 float gesture_drag_amount_; 382 383 // Manage the auto-hide state during the gesture. 384 ShelfAutoHideState gesture_drag_auto_hide_state_; 385 386 // Used to delay updating shelf background. 387 UpdateShelfObserver* update_shelf_observer_; 388 389 // The bounds of the keyboard. 390 gfx::Rect keyboard_bounds_; 391 392 // The bounds of the dock. 393 gfx::Rect dock_bounds_; 394 395 // The show hide animation duration override or 0 for default. 396 int duration_override_in_ms_; 397 398 DISALLOW_COPY_AND_ASSIGN(ShelfLayoutManager); 399 }; 400 401 } // namespace ash 402 403 #endif // ASH_SHELF_SHELF_LAYOUT_MANAGER_H_ 404