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.
5 #ifndef ASH_WM_DOCK_DOCKED_WINDOW_LAYOUT_MANAGER_H_
6 #define ASH_WM_DOCK_DOCKED_WINDOW_LAYOUT_MANAGER_H_
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"
44 class DockedBackgroundWidget;
45 class DockedWindowLayoutManagerObserver;
46 class DockedWindowResizerTest;
47 class ShelfLayoutManager;
48 class WorkspaceController;
50 struct WindowWithHeight {
51 explicit WindowWithHeight(aura::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_;
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.
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));
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 {
81 // Maximum width of the docked windows area.
82 static const int kMaxDockWidth;
84 // Minimum width of the docked windows area.
85 static const int kMinDockWidth;
87 DockedWindowLayoutManager(aura::Window* dock_container,
88 WorkspaceController* workspace_controller);
89 virtual ~DockedWindowLayoutManager();
91 // Disconnects observers before container windows get destroyed.
94 // Management of the observer list.
95 virtual void AddObserver(DockedWindowLayoutManagerObserver* observer);
96 virtual void RemoveObserver(DockedWindowLayoutManagerObserver* observer);
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);
102 // Called by a DockedWindowResizer when a dragged window is docked.
103 void DockDraggedWindow(aura::Window* window);
105 // Called by a DockedWindowResizer when a dragged window is no longer docked.
106 void UndockDraggedWindow();
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);
113 Shelf* shelf() { return shelf_; }
114 void SetShelf(Shelf* shelf);
116 // Calculates if a window is touching the screen edges and returns edge.
117 DockedAlignment GetAlignmentOfWindow(const aura::Window* window) const;
119 // Used to snap docked windows to the side of screen during drag.
120 DockedAlignment CalculateAlignment() const;
122 // Returns true when a window can be docked. Windows cannot be docked at the
123 // edge used by the shelf or the edge opposite from existing dock.
124 bool CanDockWindow(aura::Window* window, SnapType edge);
126 aura::Window* dock_container() const { return dock_container_; }
128 // Returns current bounding rectangle of docked windows area.
129 const gfx::Rect& docked_bounds() const { return docked_bounds_; }
131 // Returns last known coordinates of |dragged_window_| after Relayout.
132 const gfx::Rect dragged_bounds() const { return dragged_bounds_;}
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_; }
137 // Updates docked layout when shelf bounds change.
138 void OnShelfBoundsChanged();
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;
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;
156 // ShelfLayoutManagerObserver:
157 virtual void OnBackgroundUpdated(
158 ShelfBackgroundType background_type,
159 BackgroundAnimatorChangeType change_type) OVERRIDE;
161 // wm::WindowStateObserver:
162 virtual void OnWindowShowTypeChanged(wm::WindowState* window_state,
163 wm::WindowShowType old_type) OVERRIDE;
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;
173 // aura::client::ActivationChangeObserver:
174 virtual void OnWindowActivated(aura::Window* gained_active,
175 aura::Window* lost_active) OVERRIDE;
178 class ShelfWindowObserver;
179 friend class DockedWindowLayoutManagerTest;
180 friend class DockedWindowResizerTest;
182 // Width of the gap between the docked windows and a workspace.
183 static const int kMinDockGap;
185 // Ideal (starting) width of the dock.
186 static const int kIdealWidth;
188 // Keep at most kMaxVisibleWindows visible in the dock and minimize the rest
189 // (except for |child|).
190 void MaybeMinimizeChildrenExcept(aura::Window* child);
192 // Minimize / restore window and relayout.
193 void MinimizeDockedWindow(wm::WindowState* window_state);
194 void RestoreDockedWindow(wm::WindowState* window_state);
196 // Record user-initiated |action| by |source| in UMA metrics.
197 void RecordUmaAction(DockedAction action, DockedActionSource source);
199 // Updates |docked_width_| and UMA histograms.
200 void UpdateDockedWidth(int width);
202 // Updates docked layout state when a window gets inside the dock.
203 void OnDraggedWindowDocked(aura::Window* window);
205 // Updates docked layout state when a window gets outside the dock.
206 void OnDraggedWindowUndocked();
208 // Returns true if there are any windows currently docked.
209 bool IsAnyWindowDocked();
211 // Returns DOCKED_ALIGNMENT_LEFT if the |window|'s left edge is closer to
212 // the |dock_container_|'s left edge than the |window|'s right edge to
213 // the |dock_container_|'s right edge. Returns DOCKED_ALIGNMENT_RIGHT
215 DockedAlignment GetEdgeNearestWindow(const aura::Window* window) const;
217 // Called whenever the window layout might change.
220 // Calculates target heights (and fills it in |visible_windows| array) such
221 // that the vertical space is fairly distributed among the windows taking
222 // into account their minimum and maximum size. Returns free vertical space
223 // (positive value) that remains after resizing all windows or deficit
224 // (negative value) if not all the windows fit.
225 int CalculateWindowHeightsAndRemainingRoom(
226 const gfx::Rect work_area,
227 std::vector<WindowWithHeight>* visible_windows);
229 // Calculate ideal width for the docked area. It will get used to adjust the
230 // dragged window or other windows as necessary.
231 int CalculateIdealWidth(const std::vector<WindowWithHeight>& visible_windows);
233 // Fan out windows evenly distributing the overlap or remaining free space.
234 // Adjust the widths of the windows trying to make them all same. If this
235 // is not possible, center the windows in the docked area.
236 void FanOutChildren(const gfx::Rect& work_area,
237 int ideal_docked_width,
239 std::vector<WindowWithHeight>* visible_windows);
241 // Updates |docked_bounds_| and workspace insets when bounds of docked windows
242 // area change. Passing |reason| to observers allows selectively skipping
244 void UpdateDockBounds(DockedWindowLayoutManagerObserver::Reason reason);
246 // Called whenever the window stacking order needs to be updated (e.g. focus
247 // changes or a window is moved).
248 void UpdateStacking(aura::Window* active_window);
250 // keyboard::KeyboardControllerObserver:
251 virtual void OnKeyboardBoundsChanging(
252 const gfx::Rect& keyboard_bounds) OVERRIDE;
254 // Parent window associated with this layout manager.
255 aura::Window* dock_container_;
256 // Protect against recursive calls to Relayout().
259 // A window that is being dragged (whether docked or not).
260 // Windows are tracked by docked layout manager only if they are docked;
261 // however we need to know if a window is being dragged in order to avoid
262 // positioning it or even considering it for layout.
263 aura::Window* dragged_window_;
265 // True if the window being dragged is currently docked.
266 bool is_dragged_window_docked_;
268 // Previously docked windows use a more relaxed dragging sorting algorithm
269 // that uses assumption that a window starts being dragged out of position
270 // that was previously established in Relayout. This allows easier reordering.
271 bool is_dragged_from_dock_;
273 // The shelf to respond to alignment changes.
276 // Workspace controller that can be checked for fullscreen mode.
277 WorkspaceController* workspace_controller_;
278 // Tracks if any window in the same root window is in fullscreen mode.
280 // Current width of the dock.
283 // Last bounds that were sent to observers.
284 gfx::Rect docked_bounds_;
286 // Target bounds of a docked window being dragged.
287 gfx::Rect dragged_bounds_;
289 // Side of the screen that the dock is positioned at.
290 DockedAlignment alignment_;
292 // The last active window. Used to maintain stacking order even if no windows
293 // are currently focused.
294 aura::Window* last_active_window_;
296 // Timestamp of the last user-initiated action that changed docked state.
297 // Used in UMA metrics.
298 base::Time last_action_time_;
300 // Observes shelf for bounds changes.
301 scoped_ptr<ShelfWindowObserver> shelf_observer_;
303 // Widget used to paint a background for the docked area.
304 scoped_ptr<DockedBackgroundWidget> background_widget_;
306 // Observers of dock bounds changes.
307 ObserverList<DockedWindowLayoutManagerObserver> observer_list_;
309 DISALLOW_COPY_AND_ASSIGN(DockedWindowLayoutManager);
312 } // namespace internal
315 #endif // ASH_WM_DOCK_DOCKED_WINDOW_LAYOUT_MANAGER_H_