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