1 // Copyright (c) 2013 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_WM_DOCK_DOCKED_WINDOW_LAYOUT_MANAGER_H_ 6 #define ASH_WM_DOCK_DOCKED_WINDOW_LAYOUT_MANAGER_H_ 7 8 #include "ash/ash_export.h" 9 #include "ash/shelf/shelf_layout_manager_observer.h" 10 #include "ash/shell_observer.h" 11 #include "ash/wm/dock/dock_types.h" 12 #include "ash/wm/dock/docked_window_layout_manager_observer.h" 13 #include "ash/wm/window_state_observer.h" 14 #include "ash/wm/workspace/snap_types.h" 15 #include "base/basictypes.h" 16 #include "base/compiler_specific.h" 17 #include "base/gtest_prod_util.h" 18 #include "base/memory/scoped_ptr.h" 19 #include "base/observer_list.h" 20 #include "base/time/time.h" 21 #include "ui/aura/client/activation_change_observer.h" 22 #include "ui/aura/layout_manager.h" 23 #include "ui/aura/window.h" 24 #include "ui/aura/window_observer.h" 25 #include "ui/gfx/rect.h" 26 #include "ui/keyboard/keyboard_controller_observer.h" 27 28 namespace aura { 29 class Window; 30 } 31 32 namespace gfx { 33 class Point; 34 } 35 36 namespace views { 37 class Widget; 38 } 39 40 namespace ash { 41 class Launcher; 42 43 namespace internal { 44 class DockedBackgroundWidget; 45 class DockedWindowLayoutManagerObserver; 46 class DockedWindowResizerTest; 47 class ShelfLayoutManager; 48 class WorkspaceController; 49 50 struct WindowWithHeight { 51 explicit WindowWithHeight(aura::Window* window) : 52 window_(window), 53 height_(window->bounds().height()) { } 54 aura::Window* window() { return window_; } 55 const aura::Window* window() const { return window_; } 56 aura::Window* window_; 57 int height_; 58 }; 59 60 // DockedWindowLayoutManager is responsible for organizing windows when they are 61 // docked to the side of a screen. It is associated with a specific container 62 // window (i.e. kShellWindowId_DockContainer) and controls the layout of any 63 // windows added to that container. 64 // 65 // The constructor takes a |dock_container| argument which is expected to set 66 // its layout manager to this instance, e.g.: 67 // dock_container->SetLayoutManager( 68 // new DockedWindowLayoutManager(dock_container)); 69 // 70 // TODO(varkha): extend BaseLayoutManager instead of LayoutManager to inherit 71 // common functionality. 72 class ASH_EXPORT DockedWindowLayoutManager 73 : public aura::LayoutManager, 74 public ash::ShellObserver, 75 public aura::WindowObserver, 76 public aura::client::ActivationChangeObserver, 77 public keyboard::KeyboardControllerObserver, 78 public ShelfLayoutManagerObserver, 79 public wm::WindowStateObserver { 80 public: 81 // Maximum width of the docked windows area. 82 static const int kMaxDockWidth; 83 84 // Minimum width of the docked windows area. 85 static const int kMinDockWidth; 86 87 DockedWindowLayoutManager(aura::Window* dock_container, 88 WorkspaceController* workspace_controller); 89 virtual ~DockedWindowLayoutManager(); 90 91 // Disconnects observers before container windows get destroyed. 92 void Shutdown(); 93 94 // Management of the observer list. 95 virtual void AddObserver(DockedWindowLayoutManagerObserver* observer); 96 virtual void RemoveObserver(DockedWindowLayoutManagerObserver* observer); 97 98 // Called by a DockedWindowResizer to update which window is being dragged. 99 // Starts observing the window unless it is a child. 100 void StartDragging(aura::Window* window); 101 102 // Called by a DockedWindowResizer when a dragged window is docked. 103 void DockDraggedWindow(aura::Window* window); 104 105 // Called by a DockedWindowResizer when a dragged window is no longer docked. 106 void UndockDraggedWindow(); 107 108 // Called by a DockedWindowResizer when a window is no longer being dragged. 109 // Stops observing the window unless it is a child. 110 // Records |action| by |source| in UMA. 111 void FinishDragging(DockedAction action, DockedActionSource source); 112 113 ash::Launcher* launcher() { return launcher_; } 114 void SetLauncher(ash::Launcher* launcher); 115 116 // Calculates if a window is touching the screen edges and returns edge. 117 DockedAlignment GetAlignmentOfWindow(const aura::Window* window) const; 118 119 // Used to snap docked windows to the side of screen during drag. 120 DockedAlignment CalculateAlignment() const; 121 122 // Returns true when a window can be docked. Windows cannot be docked at the 123 // edge used by the launcher shelf or the edge opposite from existing dock. 124 bool CanDockWindow(aura::Window* window, SnapType edge); 125 126 aura::Window* dock_container() const { return dock_container_; } 127 128 // Returns current bounding rectangle of docked windows area. 129 const gfx::Rect& docked_bounds() const { return docked_bounds_; } 130 131 // Returns last known coordinates of |dragged_window_| after Relayout. 132 const gfx::Rect dragged_bounds() const { return dragged_bounds_;} 133 134 // Returns true if currently dragged window is docked at the screen edge. 135 bool is_dragged_window_docked() const { return is_dragged_window_docked_; } 136 137 // Updates docked layout when launcher shelf bounds change. 138 void OnShelfBoundsChanged(); 139 140 // aura::LayoutManager: 141 virtual void OnWindowResized() OVERRIDE; 142 virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE; 143 virtual void OnWillRemoveWindowFromLayout(aura::Window* child) OVERRIDE {} 144 virtual void OnWindowRemovedFromLayout(aura::Window* child) OVERRIDE; 145 virtual void OnChildWindowVisibilityChanged(aura::Window* child, 146 bool visibile) OVERRIDE; 147 virtual void SetChildBounds(aura::Window* child, 148 const gfx::Rect& requested_bounds) OVERRIDE; 149 150 // ash::ShellObserver: 151 virtual void OnDisplayWorkAreaInsetsChanged() OVERRIDE; 152 virtual void OnFullscreenStateChanged(bool is_fullscreen, 153 aura::Window* root_window) OVERRIDE; 154 virtual void OnShelfAlignmentChanged(aura::Window* root_window) OVERRIDE; 155 156 // ShelfLayoutManagerObserver: 157 virtual void OnBackgroundUpdated( 158 ShelfBackgroundType background_type, 159 BackgroundAnimatorChangeType change_type) OVERRIDE; 160 161 // wm::WindowStateObserver: 162 virtual void OnWindowShowTypeChanged(wm::WindowState* window_state, 163 wm::WindowShowType old_type) OVERRIDE; 164 165 // aura::WindowObserver: 166 virtual void OnWindowBoundsChanged(aura::Window* window, 167 const gfx::Rect& old_bounds, 168 const gfx::Rect& new_bounds) OVERRIDE; 169 virtual void OnWindowVisibilityChanging(aura::Window* window, 170 bool visible) OVERRIDE; 171 virtual void OnWindowDestroying(aura::Window* window) OVERRIDE; 172 173 // aura::client::ActivationChangeObserver: 174 virtual void OnWindowActivated(aura::Window* gained_active, 175 aura::Window* lost_active) OVERRIDE; 176 177 private: 178 class ShelfWindowObserver; 179 friend class DockedWindowLayoutManagerTest; 180 friend class DockedWindowResizerTest; 181 182 // Width of the gap between the docked windows and a workspace. 183 static const int kMinDockGap; 184 185 // Ideal (starting) width of the dock. 186 static const int kIdealWidth; 187 188 // Keep at most kMaxVisibleWindows visible in the dock and minimize the rest 189 // (except for |child|). 190 void MaybeMinimizeChildrenExcept(aura::Window* child); 191 192 // Minimize / restore window and relayout. 193 void MinimizeDockedWindow(wm::WindowState* window_state); 194 void RestoreDockedWindow(wm::WindowState* window_state); 195 196 // Record user-initiated |action| by |source| in UMA metrics. 197 void RecordUmaAction(DockedAction action, DockedActionSource source); 198 199 // Updates |docked_width_| and UMA histograms. 200 void UpdateDockedWidth(int width); 201 202 // Updates docked layout state when a window gets inside the dock. 203 void OnDraggedWindowDocked(aura::Window* window); 204 205 // Updates docked layout state when a window gets outside the dock. 206 void OnDraggedWindowUndocked(); 207 208 // Returns true if there are any windows currently docked. 209 bool IsAnyWindowDocked(); 210 211 // Called whenever the window layout might change. 212 void Relayout(); 213 214 // Calculates target heights (and fills it in |visible_windows| array) such 215 // that the vertical space is fairly distributed among the windows taking 216 // into account their minimum and maximum size. Returns free vertical space 217 // (positive value) that remains after resizing all windows or deficit 218 // (negative value) if not all the windows fit. 219 int CalculateWindowHeightsAndRemainingRoom( 220 const gfx::Rect work_area, 221 std::vector<WindowWithHeight>* visible_windows); 222 223 // Calculate ideal width for the docked area. It will get used to adjust the 224 // dragged window or other windows as necessary. 225 int CalculateIdealWidth(const std::vector<WindowWithHeight>& visible_windows); 226 227 // Fan out windows evenly distributing the overlap or remaining free space. 228 // Adjust the widths of the windows trying to make them all same. If this 229 // is not possible, center the windows in the docked area. 230 void FanOutChildren(const gfx::Rect& work_area, 231 int ideal_docked_width, 232 int available_room, 233 std::vector<WindowWithHeight>* visible_windows); 234 235 // Updates |docked_bounds_| and workspace insets when bounds of docked windows 236 // area change. Passing |reason| to observers allows selectively skipping 237 // notifications. 238 void UpdateDockBounds(DockedWindowLayoutManagerObserver::Reason reason); 239 240 // Called whenever the window stacking order needs to be updated (e.g. focus 241 // changes or a window is moved). 242 void UpdateStacking(aura::Window* active_window); 243 244 // keyboard::KeyboardControllerObserver: 245 virtual void OnKeyboardBoundsChanging( 246 const gfx::Rect& keyboard_bounds) OVERRIDE; 247 248 // Parent window associated with this layout manager. 249 aura::Window* dock_container_; 250 // Protect against recursive calls to Relayout(). 251 bool in_layout_; 252 253 // A window that is being dragged (whether docked or not). 254 // Windows are tracked by docked layout manager only if they are docked; 255 // however we need to know if a window is being dragged in order to avoid 256 // positioning it or even considering it for layout. 257 aura::Window* dragged_window_; 258 259 // True if the window being dragged is currently docked. 260 bool is_dragged_window_docked_; 261 262 // Previously docked windows use a more relaxed dragging sorting algorithm 263 // that uses assumption that a window starts being dragged out of position 264 // that was previously established in Relayout. This allows easier reordering. 265 bool is_dragged_from_dock_; 266 267 // The launcher to respond to launcher alignment changes. 268 Launcher* launcher_; 269 270 // Workspace controller that can be checked for fullscreen mode. 271 WorkspaceController* workspace_controller_; 272 // Tracks if any window in the same root window is in fullscreen mode. 273 bool in_fullscreen_; 274 // Current width of the dock. 275 int docked_width_; 276 277 // Last bounds that were sent to observers. 278 gfx::Rect docked_bounds_; 279 280 // Target bounds of a docked window being dragged. 281 gfx::Rect dragged_bounds_; 282 283 // Side of the screen that the dock is positioned at. 284 DockedAlignment alignment_; 285 286 // The last active window. Used to maintain stacking order even if no windows 287 // are currently focused. 288 aura::Window* last_active_window_; 289 290 // Timestamp of the last user-initiated action that changed docked state. 291 // Used in UMA metrics. 292 base::Time last_action_time_; 293 294 // Observes launcher shelf for bounds changes. 295 scoped_ptr<ShelfWindowObserver> shelf_observer_; 296 297 // Widget used to paint a background for the docked area. 298 scoped_ptr<DockedBackgroundWidget> background_widget_; 299 300 // Observers of dock bounds changes. 301 ObserverList<DockedWindowLayoutManagerObserver> observer_list_; 302 303 DISALLOW_COPY_AND_ASSIGN(DockedWindowLayoutManager); 304 }; 305 306 } // namespace internal 307 } // namespace ash 308 309 #endif // ASH_WM_DOCK_DOCKED_WINDOW_LAYOUT_MANAGER_H_ 310