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