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