• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/snap_to_pixel_layout_manager.h"
12 #include "ash/wm/dock/dock_types.h"
13 #include "ash/wm/dock/docked_window_layout_manager_observer.h"
14 #include "ash/wm/window_state_observer.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/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 
27 namespace aura {
28 class Window;
29 }
30 
31 namespace gfx {
32 class Point;
33 }
34 
35 namespace views {
36 class Widget;
37 }
38 
39 namespace ash {
40 class DockedBackgroundWidget;
41 class DockedWindowLayoutManagerObserver;
42 class DockedWindowResizerTest;
43 class Shelf;
44 class ShelfLayoutManager;
45 class WorkspaceController;
46 
47 struct WindowWithHeight {
WindowWithHeightWindowWithHeight48   explicit WindowWithHeight(aura::Window* window) :
49     window_(window),
50     height_(window->bounds().height()) { }
windowWindowWithHeight51   aura::Window* window() { return window_; }
windowWindowWithHeight52   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.
69 class ASH_EXPORT DockedWindowLayoutManager
70     : public SnapToPixelLayoutManager,
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 
shelf()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 
dock_container()123   aura::Window* dock_container() const { return dock_container_; }
124 
125   // Returns current bounding rectangle of docked windows area.
docked_bounds()126   const gfx::Rect& docked_bounds() const { return docked_bounds_; }
127 
128   // Returns last known coordinates of |dragged_window_| after Relayout.
dragged_bounds()129   const gfx::Rect dragged_bounds() const { return dragged_bounds_;}
130 
131   // Returns true if currently dragged window is docked at the screen edge.
is_dragged_window_docked()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   // SnapLayoutManager:
138   virtual void OnWindowResized() OVERRIDE;
139   virtual void OnWindowAddedToLayout(aura::Window* child) OVERRIDE;
OnWillRemoveWindowFromLayout(aura::Window * child)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