Home | History | Annotate | Download | only in dock
      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