1 // Copyright (c) 2012 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_WORKSPACE_WINDOW_RESIZER_H_ 6 #define ASH_WM_WORKSPACE_WINDOW_RESIZER_H_ 7 8 #include <vector> 9 10 #include "ash/wm/window_resizer.h" 11 #include "ash/wm/workspace/magnetism_matcher.h" 12 #include "ash/wm/workspace/snap_types.h" 13 #include "base/compiler_specific.h" 14 #include "base/gtest_prod_util.h" 15 #include "base/memory/scoped_ptr.h" 16 #include "base/memory/weak_ptr.h" 17 #include "ui/aura/window_tracker.h" 18 19 namespace ash { 20 namespace wm { 21 class WindowState; 22 } 23 24 namespace internal { 25 26 class DockedWindowLayoutManager; 27 class PhantomWindowController; 28 class SnapSizer; 29 class WindowSize; 30 31 // WindowResizer implementation for workspaces. This enforces that windows are 32 // not allowed to vertically move or resize outside of the work area. As windows 33 // are moved outside the work area they are shrunk. We remember the height of 34 // the window before it was moved so that if the window is again moved up we 35 // attempt to restore the old height. 36 class ASH_EXPORT WorkspaceWindowResizer : public WindowResizer { 37 public: 38 // When dragging an attached window this is the min size we'll make sure is 39 // visible. In the vertical direction we take the max of this and that from 40 // the delegate. 41 static const int kMinOnscreenSize; 42 43 // Min height we'll force on screen when dragging the caption. 44 // TODO: this should come from a property on the window. 45 static const int kMinOnscreenHeight; 46 47 // Snap region when dragging close to the edges. That is, as the window gets 48 // this close to an edge of the screen it snaps to the edge. 49 static const int kScreenEdgeInset; 50 51 // Distance in pixels that the cursor must move past an edge for a window 52 // to move or resize beyond that edge. 53 static const int kStickyDistancePixels; 54 55 virtual ~WorkspaceWindowResizer(); 56 57 static WorkspaceWindowResizer* Create( 58 aura::Window* window, 59 const gfx::Point& location_in_parent, 60 int window_component, 61 aura::client::WindowMoveSource source, 62 const std::vector<aura::Window*>& attached_windows); 63 64 // WindowResizer: 65 virtual void Drag(const gfx::Point& location_in_parent, 66 int event_flags) OVERRIDE; 67 virtual void CompleteDrag(int event_flags) OVERRIDE; 68 virtual void RevertDrag() OVERRIDE; 69 virtual aura::Window* GetTarget() OVERRIDE; 70 virtual const gfx::Point& GetInitialLocation() const OVERRIDE; 71 72 private: 73 WorkspaceWindowResizer(const Details& details, 74 const std::vector<aura::Window*>& attached_windows); 75 76 private: 77 friend class WorkspaceWindowResizerTest; 78 79 // Returns the final bounds to place the window at. This differs from 80 // the current when snapping. 81 gfx::Rect GetFinalBounds(const gfx::Rect& bounds) const; 82 83 // Lays out the attached windows. |bounds| is the bounds of the main window. 84 void LayoutAttachedWindows(gfx::Rect* bounds); 85 86 // Calculates the new sizes of the attached windows, given that the main 87 // window has been resized (along the primary axis) by |delta|. 88 // |available_size| is the maximum length of the space that the attached 89 // windows are allowed to occupy (ie: the distance between the right/bottom 90 // edge of the primary window and the right/bottom of the desktop area). 91 // Populates |sizes| with the desired sizes of the attached windows, and 92 // returns the number of pixels that couldn't be allocated to the attached 93 // windows (due to min/max size constraints). 94 // Note the return value can be positive or negative, a negative value 95 // indicating that that many pixels couldn't be removed from the attached 96 // windows. 97 int CalculateAttachedSizes( 98 int delta, 99 int available_size, 100 std::vector<int>* sizes) const; 101 102 // Divides |amount| evenly between |sizes|. If |amount| is negative it 103 // indicates how many pixels |sizes| should be shrunk by. 104 // Returns how many pixels failed to be allocated/removed from |sizes|. 105 int GrowFairly(int amount, std::vector<WindowSize>& sizes) const; 106 107 // Calculate the ratio of pixels that each WindowSize in |sizes| should 108 // receive when growing or shrinking. 109 void CalculateGrowthRatios(const std::vector<WindowSize*>& sizes, 110 std::vector<float>* out_ratios) const; 111 112 // Adds a WindowSize to |sizes| for each attached window. 113 void CreateBucketsForAttached(std::vector<WindowSize>* sizes) const; 114 115 // If possible snaps the window to a neary window. Updates |bounds| if there 116 // was a close enough window. 117 void MagneticallySnapToOtherWindows(gfx::Rect* bounds); 118 119 // If possible snaps the resize to a neary window. Updates |bounds| if there 120 // was a close enough window. 121 void MagneticallySnapResizeToOtherWindows(gfx::Rect* bounds); 122 123 // Finds the neareset window to magentically snap to. Updates 124 // |magnetism_window_| and |magnetism_edge_| appropriately. |edges| is a 125 // bitmask of the MagnetismEdges to match again. Returns true if a match is 126 // found. 127 bool UpdateMagnetismWindow(const gfx::Rect& bounds, uint32 edges); 128 129 // Adjusts the bounds of the window: magnetically snapping, ensuring the 130 // window has enough on screen... |snap_size| is the distance from an edge of 131 // the work area before the window is snapped. A value of 0 results in no 132 // snapping. 133 void AdjustBoundsForMainWindow(int snap_size, gfx::Rect* bounds); 134 135 // Stick the window bounds to the work area during a move. 136 bool StickToWorkAreaOnMove(const gfx::Rect& work_area, 137 int sticky_size, 138 gfx::Rect* bounds) const; 139 140 // Stick the window bounds to the work area during a resize. 141 void StickToWorkAreaOnResize(const gfx::Rect& work_area, 142 int sticky_size, 143 gfx::Rect* bounds) const; 144 145 // Returns a coordinate along the primary axis. Used to share code for 146 // left/right multi window resize and top/bottom resize. 147 int PrimaryAxisSize(const gfx::Size& size) const; 148 int PrimaryAxisCoordinate(int x, int y) const; 149 150 // Updates the bounds of the phantom window for window snapping. 151 void UpdateSnapPhantomWindow(const gfx::Point& location, 152 const gfx::Rect& bounds); 153 154 // Restacks the windows z-order position so that one of the windows is at the 155 // top of the z-order, and the rest directly underneath it. 156 void RestackWindows(); 157 158 // Returns the SnapType for the specified point. SNAP_NONE is used if no 159 // snapping should be used. 160 SnapType GetSnapType(const gfx::Point& location) const; 161 162 // Docks the dragged window if |should_dock| and the window can be docked. 163 // Undocks the window if |should_dock| is false. 164 void SetDraggedWindowDocked(bool should_dock); 165 window()166 aura::Window* window() const { return details_.window; } 167 window_state()168 wm::WindowState* window_state() { return details_.window_state; } 169 170 const Details details_; 171 172 const std::vector<aura::Window*> attached_windows_; 173 174 bool did_lock_cursor_; 175 176 // Set to true once Drag() is invoked and the bounds of the window change. 177 bool did_move_or_resize_; 178 179 // True if the window initially had |bounds_changed_by_user_| set in state. 180 bool initial_bounds_changed_by_user_; 181 182 // The initial size of each of the windows in |attached_windows_| along the 183 // primary axis. 184 std::vector<int> initial_size_; 185 186 // Sum of the minimum sizes of the attached windows. 187 int total_min_; 188 189 // Sum of the sizes in |initial_size_|. 190 int total_initial_size_; 191 192 // Gives a previews of where the the window will end up. Only used if there 193 // is a grid and the caption is being dragged. 194 scoped_ptr<PhantomWindowController> snap_phantom_window_controller_; 195 196 // Used to determine the target position of a snap. 197 scoped_ptr<SnapSizer> snap_sizer_; 198 199 // Last SnapType. 200 SnapType snap_type_; 201 202 // Number of mouse moves since the last bounds change. Only used for phantom 203 // placement to track when the mouse is moved while pushed against the edge of 204 // the screen. 205 int num_mouse_moves_since_bounds_change_; 206 207 // The mouse location passed to Drag(). 208 gfx::Point last_mouse_location_; 209 210 // Window the drag has magnetically attached to. 211 aura::Window* magnetism_window_; 212 213 // Used to verify |magnetism_window_| is still valid. 214 aura::WindowTracker window_tracker_; 215 216 // If |magnetism_window_| is non-NULL this indicates how the two windows 217 // should attach. 218 MatchedEdge magnetism_edge_; 219 220 // Dock container window layout manager. 221 DockedWindowLayoutManager* dock_layout_; 222 223 // Used to determine if this has been deleted during a drag such as when a tab 224 // gets dragged into another browser window. 225 base::WeakPtrFactory<WorkspaceWindowResizer> weak_ptr_factory_; 226 227 // Current instance for use by the WorkspaceWindowResizerTest. 228 static WorkspaceWindowResizer* instance_; 229 230 DISALLOW_COPY_AND_ASSIGN(WorkspaceWindowResizer); 231 }; 232 233 } // namespace internal 234 } // namespace ash 235 236 #endif // ASH_WM_WORKSPACE_WINDOW_RESIZER_H_ 237