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