OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ash/wm/dock/docked_window_resizer.h" | 5 #include "ash/wm/dock/docked_window_resizer.h" |
6 | 6 |
7 #include "ash/ash_switches.h" | 7 #include "ash/ash_switches.h" |
| 8 #include "ash/display/display_controller.h" |
8 #include "ash/launcher/launcher.h" | 9 #include "ash/launcher/launcher.h" |
9 #include "ash/root_window_controller.h" | 10 #include "ash/root_window_controller.h" |
10 #include "ash/screen_ash.h" | 11 #include "ash/screen_ash.h" |
11 #include "ash/shelf/shelf_types.h" | 12 #include "ash/shelf/shelf_types.h" |
12 #include "ash/shelf/shelf_widget.h" | 13 #include "ash/shelf/shelf_widget.h" |
13 #include "ash/shell.h" | 14 #include "ash/shell.h" |
14 #include "ash/shell_window_ids.h" | 15 #include "ash/shell_window_ids.h" |
15 #include "ash/wm/coordinate_conversion.h" | 16 #include "ash/wm/coordinate_conversion.h" |
16 #include "ash/wm/dock/docked_window_layout_manager.h" | 17 #include "ash/wm/dock/docked_window_layout_manager.h" |
17 #include "ash/wm/property_util.h" | 18 #include "ash/wm/property_util.h" |
18 #include "ash/wm/window_properties.h" | 19 #include "ash/wm/window_properties.h" |
19 #include "ash/wm/workspace/magnetism_matcher.h" | 20 #include "ash/wm/workspace/magnetism_matcher.h" |
20 #include "ash/wm/workspace/phantom_window_controller.h" | |
21 #include "ash/wm/workspace/workspace_window_resizer.h" | 21 #include "ash/wm/workspace/workspace_window_resizer.h" |
22 #include "base/command_line.h" | 22 #include "base/command_line.h" |
23 #include "base/memory/weak_ptr.h" | 23 #include "base/memory/weak_ptr.h" |
24 #include "ui/aura/client/aura_constants.h" | 24 #include "ui/aura/client/aura_constants.h" |
25 #include "ui/aura/env.h" | 25 #include "ui/aura/env.h" |
26 #include "ui/aura/root_window.h" | 26 #include "ui/aura/root_window.h" |
27 #include "ui/aura/window.h" | 27 #include "ui/aura/window.h" |
28 #include "ui/aura/window_delegate.h" | 28 #include "ui/aura/window_delegate.h" |
29 #include "ui/base/hit_test.h" | 29 #include "ui/base/hit_test.h" |
30 #include "ui/base/ui_base_types.h" | 30 #include "ui/base/ui_base_types.h" |
31 #include "ui/gfx/screen.h" | 31 #include "ui/gfx/screen.h" |
32 #include "ui/views/widget/widget.h" | 32 #include "ui/views/widget/widget.h" |
33 | 33 |
34 namespace ash { | 34 namespace ash { |
35 namespace internal { | 35 namespace internal { |
36 | 36 |
37 namespace { | 37 namespace { |
38 | 38 |
39 DockedWindowLayoutManager* GetDockedLayoutManagerAtPoint( | 39 DockedWindowLayoutManager* GetDockedLayoutManagerAtPoint( |
40 const gfx::Point& point) { | 40 const gfx::Point& point) { |
| 41 gfx::Display display = ScreenAsh::FindDisplayContainingPoint(point); |
| 42 if (!display.is_valid()) |
| 43 return NULL; |
| 44 aura::RootWindow* root = Shell::GetInstance()->display_controller()-> |
| 45 GetRootWindowForDisplayId(display.id()); |
41 aura::Window* dock_container = Shell::GetContainer( | 46 aura::Window* dock_container = Shell::GetContainer( |
42 wm::GetRootWindowAt(point), | 47 root, kShellWindowId_DockedContainer); |
43 kShellWindowId_DockedContainer); | |
44 return static_cast<DockedWindowLayoutManager*>( | 48 return static_cast<DockedWindowLayoutManager*>( |
45 dock_container->layout_manager()); | 49 dock_container->layout_manager()); |
46 } | 50 } |
47 | 51 |
48 } // namespace | 52 } // namespace |
49 | 53 |
50 DockedWindowResizer::~DockedWindowResizer() { | 54 DockedWindowResizer::~DockedWindowResizer() { |
51 } | 55 } |
52 | 56 |
53 // static | 57 // static |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
85 base::WeakPtr<DockedWindowResizer> resizer(weak_ptr_factory_.GetWeakPtr()); | 89 base::WeakPtr<DockedWindowResizer> resizer(weak_ptr_factory_.GetWeakPtr()); |
86 next_window_resizer_->Drag(modified_location, event_flags); | 90 next_window_resizer_->Drag(modified_location, event_flags); |
87 if (!resizer) | 91 if (!resizer) |
88 return; | 92 return; |
89 | 93 |
90 if (set_tracked_by_workspace) | 94 if (set_tracked_by_workspace) |
91 SetTrackedByWorkspace(GetTarget(), tracked_by_workspace); | 95 SetTrackedByWorkspace(GetTarget(), tracked_by_workspace); |
92 | 96 |
93 DockedWindowLayoutManager* new_dock_layout = | 97 DockedWindowLayoutManager* new_dock_layout = |
94 GetDockedLayoutManagerAtPoint(last_location_); | 98 GetDockedLayoutManagerAtPoint(last_location_); |
95 if (new_dock_layout != dock_layout_) { | 99 if (new_dock_layout && new_dock_layout != dock_layout_) { |
96 // The window is being dragged to a new display. If the previous | 100 // The window is being dragged to a new display. If the previous |
97 // container is the current parent of the window it will be informed of | 101 // container is the current parent of the window it will be informed of |
98 // the end of drag when the window is reparented, otherwise let the | 102 // the end of drag when the window is reparented, otherwise let the |
99 // previous container know the drag is complete. If we told the | 103 // previous container know the drag is complete. If we told the |
100 // window's parent that the drag was complete it would begin | 104 // window's parent that the drag was complete it would begin |
101 // positioning the window. | 105 // positioning the window. |
102 if (is_docked_) | 106 if (is_docked_ && dock_layout_->is_dragged_window_docked()) |
103 dock_layout_->UndockDraggedWindow(); | 107 dock_layout_->UndockDraggedWindow(); |
104 if (dock_layout_ != initial_dock_layout_) | 108 if (dock_layout_ != initial_dock_layout_) |
105 dock_layout_->FinishDragging(); | 109 dock_layout_->FinishDragging(); |
106 is_docked_ = false; | 110 is_docked_ = false; |
107 dock_layout_ = new_dock_layout; | 111 dock_layout_ = new_dock_layout; |
108 // The window's initial layout manager already knows that the drag is | 112 // The window's initial layout manager already knows that the drag is |
109 // in progress for this window. | 113 // in progress for this window. |
110 if (new_dock_layout != initial_dock_layout_) | 114 if (new_dock_layout != initial_dock_layout_) |
111 new_dock_layout->StartDragging(GetTarget()); | 115 new_dock_layout->StartDragging(GetTarget()); |
112 } | 116 } |
113 | 117 // Window could get marked as docked by the SnapSizer, so update the state. |
114 // Show snapping animation when a window touches a screen edge or when | 118 is_docked_ = dock_layout_->is_dragged_window_docked(); |
115 // it is about to get docked. | |
116 DockedAlignment new_docked_alignment = GetDraggedWindowAlignment(); | |
117 if (new_docked_alignment != DOCKED_ALIGNMENT_NONE) { | |
118 if (!is_docked_) { | |
119 dock_layout_->DockDraggedWindow(GetTarget()); | |
120 is_docked_ = true; | |
121 } | |
122 UpdateSnapPhantomWindow(); | |
123 } else { | |
124 if (is_docked_) { | |
125 dock_layout_->UndockDraggedWindow(); | |
126 is_docked_ = false; | |
127 } | |
128 // Clear phantom window when a window gets undocked. | |
129 snap_phantom_window_controller_.reset(); | |
130 } | |
131 } | 119 } |
132 | 120 |
133 void DockedWindowResizer::CompleteDrag(int event_flags) { | 121 void DockedWindowResizer::CompleteDrag(int event_flags) { |
134 snap_phantom_window_controller_.reset(); | |
135 | |
136 // Temporarily clear kWindowTrackedByWorkspaceKey for panels so that they | 122 // Temporarily clear kWindowTrackedByWorkspaceKey for panels so that they |
137 // don't get forced into the workspace that may be shrunken because of docked | 123 // don't get forced into the workspace that may be shrunken because of docked |
138 // windows. | 124 // windows. |
139 bool tracked_by_workspace = GetTrackedByWorkspace(GetTarget()); | 125 bool tracked_by_workspace = GetTrackedByWorkspace(GetTarget()); |
140 bool set_tracked_by_workspace = was_docked_; | 126 bool set_tracked_by_workspace = was_docked_; |
141 if (set_tracked_by_workspace) | 127 if (set_tracked_by_workspace) |
142 SetTrackedByWorkspace(GetTarget(), false); | 128 SetTrackedByWorkspace(GetTarget(), false); |
143 // The root window can change when dragging into a different screen. | 129 // The root window can change when dragging into a different screen. |
144 next_window_resizer_->CompleteDrag(event_flags); | 130 next_window_resizer_->CompleteDrag(event_flags); |
145 FinishedDragging(); | 131 FinishedDragging(); |
146 if (set_tracked_by_workspace) | 132 if (set_tracked_by_workspace) |
147 SetTrackedByWorkspace(GetTarget(), tracked_by_workspace); | 133 SetTrackedByWorkspace(GetTarget(), tracked_by_workspace); |
148 } | 134 } |
149 | 135 |
150 void DockedWindowResizer::RevertDrag() { | 136 void DockedWindowResizer::RevertDrag() { |
151 snap_phantom_window_controller_.reset(); | |
152 | |
153 // Temporarily clear kWindowTrackedByWorkspaceKey for panels so that they | 137 // Temporarily clear kWindowTrackedByWorkspaceKey for panels so that they |
154 // don't get forced into the workspace that may be shrunken because of docked | 138 // don't get forced into the workspace that may be shrunken because of docked |
155 // windows. | 139 // windows. |
156 bool tracked_by_workspace = GetTrackedByWorkspace(GetTarget()); | 140 bool tracked_by_workspace = GetTrackedByWorkspace(GetTarget()); |
157 bool set_tracked_by_workspace = was_docked_; | 141 bool set_tracked_by_workspace = was_docked_; |
158 if (set_tracked_by_workspace) | 142 if (set_tracked_by_workspace) |
159 SetTrackedByWorkspace(GetTarget(), false); | 143 SetTrackedByWorkspace(GetTarget(), false); |
160 next_window_resizer_->RevertDrag(); | 144 next_window_resizer_->RevertDrag(); |
| 145 // Restore docked state to what it was before the drag if necessary. |
| 146 if (was_docked_ && !is_docked_) { |
| 147 dock_layout_->DockDraggedWindow(GetTarget()); |
| 148 is_docked_ = was_docked_; |
| 149 } |
161 FinishedDragging(); | 150 FinishedDragging(); |
162 if (set_tracked_by_workspace) | 151 if (set_tracked_by_workspace) |
163 SetTrackedByWorkspace(GetTarget(), tracked_by_workspace); | 152 SetTrackedByWorkspace(GetTarget(), tracked_by_workspace); |
164 } | 153 } |
165 | 154 |
166 aura::Window* DockedWindowResizer::GetTarget() { | 155 aura::Window* DockedWindowResizer::GetTarget() { |
167 return next_window_resizer_->GetTarget(); | 156 return next_window_resizer_->GetTarget(); |
168 } | 157 } |
169 | 158 |
170 const gfx::Point& DockedWindowResizer::GetInitialLocation() const { | 159 const gfx::Point& DockedWindowResizer::GetInitialLocation() const { |
(...skipping 14 matching lines...) Expand all Loading... |
185 aura::Window* dock_container = Shell::GetContainer( | 174 aura::Window* dock_container = Shell::GetContainer( |
186 details.window->GetRootWindow(), | 175 details.window->GetRootWindow(), |
187 kShellWindowId_DockedContainer); | 176 kShellWindowId_DockedContainer); |
188 dock_layout_ = static_cast<DockedWindowLayoutManager*>( | 177 dock_layout_ = static_cast<DockedWindowLayoutManager*>( |
189 dock_container->layout_manager()); | 178 dock_container->layout_manager()); |
190 initial_dock_layout_ = dock_layout_; | 179 initial_dock_layout_ = dock_layout_; |
191 was_docked_ = details.window->parent() == dock_container; | 180 was_docked_ = details.window->parent() == dock_container; |
192 is_docked_ = was_docked_; | 181 is_docked_ = was_docked_; |
193 } | 182 } |
194 | 183 |
195 DockedAlignment DockedWindowResizer::GetDraggedWindowAlignment() { | |
196 aura::Window* window = GetTarget(); | |
197 DockedWindowLayoutManager* layout_manager = | |
198 GetDockedLayoutManagerAtPoint(last_location_); | |
199 const DockedAlignment alignment = layout_manager->CalculateAlignment(); | |
200 const gfx::Rect& bounds(window->GetBoundsInScreen()); | |
201 | |
202 // Check if the window is touching the edge - it may need to get docked. | |
203 if (alignment == DOCKED_ALIGNMENT_NONE) | |
204 return layout_manager->GetAlignmentOfWindow(window); | |
205 | |
206 // Both bounds and pointer location are checked because some drags involve | |
207 // stickiness at the workspace-to-dock boundary and so the |location| may be | |
208 // outside of the |bounds|. | |
209 // It is also possible that all the docked windows are minimized or hidden | |
210 // in which case the dragged window needs to be exactly touching the same | |
211 // edge that those docked windows were aligned before they got minimized. | |
212 // TODO(varkha): Consider eliminating sticky behavior on that boundary when | |
213 // a pointer enters docked area. | |
214 if ((layout_manager->docked_bounds().Intersects(bounds) && | |
215 layout_manager->docked_bounds().Contains(last_location_)) || | |
216 alignment == layout_manager->GetAlignmentOfWindow(window)) { | |
217 // A window is being added to other docked windows (on the same side). | |
218 return alignment; | |
219 } | |
220 return DOCKED_ALIGNMENT_NONE; | |
221 } | |
222 | |
223 bool DockedWindowResizer::MaybeSnapToEdge(const gfx::Rect& bounds, | 184 bool DockedWindowResizer::MaybeSnapToEdge(const gfx::Rect& bounds, |
224 gfx::Point* offset) { | 185 gfx::Point* offset) { |
225 aura::Window* dock_container = Shell::GetContainer( | 186 // Windows only snap magnetically when they were previously docked. |
226 wm::GetRootWindowAt(last_location_), | 187 if (!was_docked_) |
227 kShellWindowId_DockedContainer); | 188 return false; |
228 DockedAlignment dock_alignment = | 189 DockedAlignment dock_alignment = dock_layout_->CalculateAlignment(); |
229 GetDockedLayoutManagerAtPoint(last_location_)->CalculateAlignment(); | |
230 gfx::Rect dock_bounds = ScreenAsh::ConvertRectFromScreen( | 190 gfx::Rect dock_bounds = ScreenAsh::ConvertRectFromScreen( |
231 GetTarget()->parent(), dock_container->GetBoundsInScreen()); | 191 GetTarget()->parent(), |
232 // Windows only snap magnetically when they are close to the edge of the | 192 dock_layout_->dock_container()->GetBoundsInScreen()); |
233 // screen and when the cursor is over other docked windows. | |
234 // When a window being dragged is the last window that was previously | |
235 // docked it is still allowed to magnetically snap to either side. | |
236 bool can_snap = was_docked_ || | |
237 (GetDraggedWindowAlignment() != DOCKED_ALIGNMENT_NONE); | |
238 if (!can_snap) | |
239 return false; | |
240 | 193 |
241 // Distance in pixels that the cursor must move past an edge for a window | 194 // Distance in pixels that the cursor must move past an edge for a window |
242 // to move beyond that edge. Same constant as in WorkspaceWindowResizer | 195 // to move beyond that edge. Same constant as in WorkspaceWindowResizer |
243 // is used for consistency. | 196 // is used for consistency. |
244 const int kStickyDistance = WorkspaceWindowResizer::kStickyDistancePixels; | 197 const int kStickyDistance = WorkspaceWindowResizer::kStickyDistancePixels; |
245 | 198 |
246 // Short-range magnetism when retaining docked state. Same constant as in | 199 // Short-range magnetism when retaining docked state. Same constant as in |
247 // MagnetismMatcher is used for consistency. | 200 // MagnetismMatcher is used for consistency. |
248 const int kSnapToDockDistance = MagnetismMatcher::kMagneticDistance; | 201 const int kSnapToDockDistance = MagnetismMatcher::kMagneticDistance; |
249 | 202 |
250 if (dock_alignment == DOCKED_ALIGNMENT_LEFT || | 203 if (dock_alignment == DOCKED_ALIGNMENT_LEFT || |
251 (dock_alignment == DOCKED_ALIGNMENT_NONE && was_docked_)) { | 204 dock_alignment == DOCKED_ALIGNMENT_NONE) { |
252 const int distance = bounds.x() - dock_bounds.x(); | 205 const int distance = bounds.x() - dock_bounds.x(); |
253 if (distance < (was_docked_ ? kSnapToDockDistance : 0) && | 206 if (distance < kSnapToDockDistance && distance > -kStickyDistance) { |
254 distance > -kStickyDistance) { | |
255 offset->set_x(-distance); | 207 offset->set_x(-distance); |
256 return true; | 208 return true; |
257 } | 209 } |
258 } | 210 } |
259 if (dock_alignment == DOCKED_ALIGNMENT_RIGHT || | 211 if (dock_alignment == DOCKED_ALIGNMENT_RIGHT || |
260 (dock_alignment == DOCKED_ALIGNMENT_NONE && was_docked_)) { | 212 dock_alignment == DOCKED_ALIGNMENT_NONE) { |
261 const int distance = dock_bounds.right() - bounds.right(); | 213 const int distance = dock_bounds.right() - bounds.right(); |
262 if (distance < (was_docked_ ? kSnapToDockDistance : 0) && | 214 if (distance < kSnapToDockDistance && distance > -kStickyDistance) { |
263 distance > -kStickyDistance) { | |
264 offset->set_x(distance); | 215 offset->set_x(distance); |
265 return true; | 216 return true; |
266 } | 217 } |
267 } | 218 } |
268 return false; | 219 return false; |
269 } | 220 } |
270 | 221 |
271 void DockedWindowResizer::StartedDragging() { | 222 void DockedWindowResizer::StartedDragging() { |
272 // Tell the dock layout manager that we are dragging this window. | 223 // Tell the dock layout manager that we are dragging this window. |
273 // At this point we are not yet animating the window as it may not be | 224 // At this point we are not yet animating the window as it may not be |
(...skipping 16 matching lines...) Expand all Loading... |
290 } | 241 } |
291 if (is_docked_) | 242 if (is_docked_) |
292 dock_layout_->DockDraggedWindow(GetTarget()); | 243 dock_layout_->DockDraggedWindow(GetTarget()); |
293 } | 244 } |
294 | 245 |
295 void DockedWindowResizer::FinishedDragging() { | 246 void DockedWindowResizer::FinishedDragging() { |
296 if (!did_move_or_resize_) | 247 if (!did_move_or_resize_) |
297 return; | 248 return; |
298 | 249 |
299 aura::Window* window = GetTarget(); | 250 aura::Window* window = GetTarget(); |
300 bool should_dock = was_docked_; | |
301 const bool attached_panel = | 251 const bool attached_panel = |
302 window->type() == aura::client::WINDOW_TYPE_PANEL && | 252 window->type() == aura::client::WINDOW_TYPE_PANEL && |
303 window->GetProperty(kPanelAttachedKey); | 253 window->GetProperty(kPanelAttachedKey); |
304 // If a window was previously docked then keep it docked if it is resized and | 254 const bool is_resized = |
305 // still aligned at the screen edge. | 255 details_.bounds_change & WindowResizer::kBoundsChange_Resizes; |
306 if ((was_docked_ || | 256 // No longer restore to pre-docked bounds if a window has been resized. |
307 ((details_.bounds_change & WindowResizer::kBoundsChange_Repositions) && | 257 if (is_resized && is_docked_) |
308 !(details_.bounds_change & WindowResizer::kBoundsChange_Resizes)))) { | 258 ClearRestoreBounds(window); |
309 should_dock = GetDraggedWindowAlignment() != DOCKED_ALIGNMENT_NONE; | |
310 } | |
311 | 259 |
312 // Check if the window needs to be docked or returned to workspace. | 260 // Check if the window needs to be docked or returned to workspace. |
313 aura::Window* dock_container = Shell::GetContainer( | 261 aura::Window* dock_container = Shell::GetContainer( |
314 window->GetRootWindow(), | 262 window->GetRootWindow(), |
315 kShellWindowId_DockedContainer); | 263 kShellWindowId_DockedContainer); |
316 if (!attached_panel && | 264 if ((is_resized || !attached_panel) && |
317 should_dock != (window->parent() == dock_container)) { | 265 is_docked_ != (window->parent() == dock_container)) { |
318 if (should_dock) { | 266 if (is_docked_) { |
319 dock_container->AddChild(window); | 267 dock_container->AddChild(window); |
320 } else if (window->parent()->id() == kShellWindowId_DockedContainer) { | 268 } else if (window->parent()->id() == kShellWindowId_DockedContainer) { |
321 // Reparent the window back to workspace. | 269 // Reparent the window back to workspace. |
322 // We need to be careful to give SetDefaultParentByRootWindow location in | 270 // We need to be careful to give SetDefaultParentByRootWindow location in |
323 // the right root window (matching the logic in DragWindowResizer) based | 271 // the right root window (matching the logic in DragWindowResizer) based |
324 // on which root window a mouse pointer is in. We want to undock into the | 272 // on which root window a mouse pointer is in. We want to undock into the |
325 // right screen near the edge of a multiscreen setup (based on where the | 273 // right screen near the edge of a multiscreen setup (based on where the |
326 // mouse is). | 274 // mouse is). |
327 gfx::Rect near_last_location(last_location_, gfx::Size()); | 275 gfx::Rect near_last_location(last_location_, gfx::Size()); |
328 // Reparenting will cause Relayout and possible dock shrinking. | 276 // Reparenting will cause Relayout and possible dock shrinking. |
329 window->SetDefaultParentByRootWindow(window->GetRootWindow(), | 277 window->SetDefaultParentByRootWindow(window->GetRootWindow(), |
330 near_last_location); | 278 near_last_location); |
331 } | 279 } |
332 } | 280 } |
333 dock_layout_->FinishDragging(); | 281 dock_layout_->FinishDragging(); |
334 | 282 |
335 // If we started the drag in one root window and moved into another root | 283 // If we started the drag in one root window and moved into another root |
336 // but then canceled the drag we may need to inform the original layout | 284 // but then canceled the drag we may need to inform the original layout |
337 // manager that the drag is finished. | 285 // manager that the drag is finished. |
338 if (initial_dock_layout_ != dock_layout_) | 286 if (initial_dock_layout_ != dock_layout_) |
339 initial_dock_layout_->FinishDragging(); | 287 initial_dock_layout_->FinishDragging(); |
340 is_docked_ = false; | 288 is_docked_ = false; |
341 } | 289 } |
342 | 290 |
343 void DockedWindowResizer::UpdateSnapPhantomWindow() { | |
344 if (!did_move_or_resize_ || details_.window_component != HTCAPTION) | |
345 return; | |
346 | |
347 if (!snap_phantom_window_controller_) { | |
348 snap_phantom_window_controller_.reset( | |
349 new PhantomWindowController(GetTarget())); | |
350 } | |
351 snap_phantom_window_controller_->Show(dock_layout_->dragged_bounds()); | |
352 } | |
353 | |
354 } // namespace internal | 291 } // namespace internal |
355 } // namespace ash | 292 } // namespace ash |
OLD | NEW |