OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 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_layout_manager.h" | 5 #include "ash/wm/dock/docked_window_layout_manager.h" |
6 | 6 |
| 7 #include "ash/ash_switches.h" |
7 #include "ash/launcher/launcher.h" | 8 #include "ash/launcher/launcher.h" |
8 #include "ash/screen_ash.h" | 9 #include "ash/screen_ash.h" |
9 #include "ash/shelf/shelf_layout_manager.h" | 10 #include "ash/shelf/shelf_layout_manager.h" |
10 #include "ash/shelf/shelf_types.h" | 11 #include "ash/shelf/shelf_types.h" |
11 #include "ash/shelf/shelf_widget.h" | 12 #include "ash/shelf/shelf_widget.h" |
12 #include "ash/shell.h" | 13 #include "ash/shell.h" |
13 #include "ash/shell_window_ids.h" | 14 #include "ash/shell_window_ids.h" |
14 #include "ash/wm/coordinate_conversion.h" | 15 #include "ash/wm/coordinate_conversion.h" |
15 #include "ash/wm/window_properties.h" | 16 #include "ash/wm/window_properties.h" |
16 #include "ash/wm/window_util.h" | 17 #include "ash/wm/window_util.h" |
| 18 #include "ash/wm/workspace/snap_types.h" |
17 #include "base/auto_reset.h" | 19 #include "base/auto_reset.h" |
| 20 #include "base/command_line.h" |
18 #include "third_party/skia/include/core/SkColor.h" | 21 #include "third_party/skia/include/core/SkColor.h" |
19 #include "ui/aura/client/activation_client.h" | 22 #include "ui/aura/client/activation_client.h" |
20 #include "ui/aura/client/aura_constants.h" | 23 #include "ui/aura/client/aura_constants.h" |
21 #include "ui/aura/focus_manager.h" | 24 #include "ui/aura/focus_manager.h" |
22 #include "ui/aura/root_window.h" | 25 #include "ui/aura/root_window.h" |
23 #include "ui/aura/window.h" | 26 #include "ui/aura/window.h" |
24 #include "ui/gfx/rect.h" | 27 #include "ui/gfx/rect.h" |
25 | 28 |
26 namespace ash { | 29 namespace ash { |
27 namespace internal { | 30 namespace internal { |
28 | 31 |
29 // Minimum, maximum width of the dock area and a width of the gap | 32 // Minimum, maximum width of the dock area and a width of the gap |
| 33 // static |
| 34 const int DockedWindowLayoutManager::kMaxDockWidth = 360; |
| 35 // static |
30 const int DockedWindowLayoutManager::kMinDockWidth = 200; | 36 const int DockedWindowLayoutManager::kMinDockWidth = 200; |
31 const int DockedWindowLayoutManager::kMaxDockWidth = 450; | 37 // static |
32 const int DockedWindowLayoutManager::kMinDockGap = 2; | 38 const int DockedWindowLayoutManager::kMinDockGap = 2; |
33 const int kWindowIdealSpacing = 4; | |
34 | 39 |
35 namespace { | 40 namespace { |
36 | 41 |
37 const SkColor kDockBackgroundColor = SkColorSetARGB(0xff, 0x10, 0x10, 0x10); | 42 const SkColor kDockBackgroundColor = SkColorSetARGB(0xff, 0x10, 0x10, 0x10); |
38 const float kDockBackgroundOpacity = 0.5f; | 43 const float kDockBackgroundOpacity = 0.5f; |
39 | 44 |
40 class DockedBackgroundWidget : public views::Widget { | 45 class DockedBackgroundWidget : public views::Widget { |
41 public: | 46 public: |
42 explicit DockedBackgroundWidget(aura::Window* container) { | 47 explicit DockedBackgroundWidget(aura::Window* container) { |
43 InitWidget(container); | 48 InitWidget(container); |
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
200 } | 205 } |
201 | 206 |
202 void DockedWindowLayoutManager::DockDraggedWindow(aura::Window* window) { | 207 void DockedWindowLayoutManager::DockDraggedWindow(aura::Window* window) { |
203 OnWindowDocked(window); | 208 OnWindowDocked(window); |
204 Relayout(); | 209 Relayout(); |
205 } | 210 } |
206 | 211 |
207 void DockedWindowLayoutManager::UndockDraggedWindow() { | 212 void DockedWindowLayoutManager::UndockDraggedWindow() { |
208 OnWindowUndocked(); | 213 OnWindowUndocked(); |
209 Relayout(); | 214 Relayout(); |
| 215 UpdateDockBounds(); |
210 is_dragged_from_dock_ = false; | 216 is_dragged_from_dock_ = false; |
211 } | 217 } |
212 | 218 |
213 void DockedWindowLayoutManager::FinishDragging() { | 219 void DockedWindowLayoutManager::FinishDragging() { |
214 DCHECK(dragged_window_); | 220 DCHECK(dragged_window_); |
215 if (is_dragged_window_docked_) | 221 if (is_dragged_window_docked_) |
216 OnWindowUndocked(); | 222 OnWindowUndocked(); |
217 DCHECK (!is_dragged_window_docked_); | 223 DCHECK (!is_dragged_window_docked_); |
218 // Stop observing a window unless it is docked container's child in which | 224 // Stop observing a window unless it is docked container's child in which |
219 // case it needs to keep being observed after the drag completes. | 225 // case it needs to keep being observed after the drag completes. |
220 if (dragged_window_->parent() != dock_container_) | 226 if (dragged_window_->parent() != dock_container_) { |
221 dragged_window_->RemoveObserver(this); | 227 dragged_window_->RemoveObserver(this); |
| 228 if (last_active_window_ == dragged_window_) |
| 229 last_active_window_ = NULL; |
| 230 } |
222 dragged_window_ = NULL; | 231 dragged_window_ = NULL; |
| 232 dragged_bounds_ = gfx::Rect(); |
223 Relayout(); | 233 Relayout(); |
224 UpdateDockBounds(); | 234 UpdateDockBounds(); |
225 } | 235 } |
226 | 236 |
227 void DockedWindowLayoutManager::SetLauncher(ash::Launcher* launcher) { | 237 void DockedWindowLayoutManager::SetLauncher(ash::Launcher* launcher) { |
228 DCHECK(!launcher_); | 238 DCHECK(!launcher_); |
229 DCHECK(!shelf_layout_manager_); | 239 DCHECK(!shelf_layout_manager_); |
230 launcher_ = launcher; | 240 launcher_ = launcher; |
231 if (launcher_->shelf_widget()) { | 241 if (launcher_->shelf_widget()) { |
232 shelf_layout_manager_ = ash::internal::ShelfLayoutManager::ForLauncher( | 242 shelf_layout_manager_ = ash::internal::ShelfLayoutManager::ForLauncher( |
233 launcher_->shelf_widget()->GetNativeWindow()); | 243 launcher_->shelf_widget()->GetNativeWindow()); |
234 WillChangeVisibilityState(shelf_layout_manager_->visibility_state()); | 244 WillChangeVisibilityState(shelf_layout_manager_->visibility_state()); |
235 shelf_layout_manager_->AddObserver(this); | 245 shelf_layout_manager_->AddObserver(this); |
236 } | 246 } |
237 } | 247 } |
238 | 248 |
239 DockedAlignment DockedWindowLayoutManager::GetAlignmentOfWindow( | 249 DockedAlignment DockedWindowLayoutManager::GetAlignmentOfWindow( |
240 const aura::Window* window) const { | 250 const aura::Window* window) const { |
241 const gfx::Rect& bounds(window->GetBoundsInScreen()); | 251 const gfx::Rect& bounds(window->GetBoundsInScreen()); |
242 const gfx::Rect docked_bounds = dock_container_->GetBoundsInScreen(); | |
243 | 252 |
244 // Do not allow docking if a window is vertically maximized (as is the case | 253 // Test overlap with an existing docked area first. |
245 // when it is snapped). | 254 if (docked_bounds_.Intersects(bounds) && |
246 const gfx::Rect work_area = | 255 alignment_ != DOCKED_ALIGNMENT_NONE) { |
247 Shell::GetScreen()->GetDisplayNearestWindow(dock_container_).work_area(); | 256 // A window is being added to other docked windows (on the same side). |
248 if (bounds.y() == work_area.y() && bounds.height() == work_area.height()) | 257 return alignment_; |
249 return DOCKED_ALIGNMENT_NONE; | 258 } |
250 | 259 |
251 // Do not allow docking on the same side as launcher shelf. | 260 const gfx::Rect container_bounds = dock_container_->GetBoundsInScreen(); |
252 ShelfAlignment shelf_alignment = SHELF_ALIGNMENT_BOTTOM; | 261 if (bounds.x() <= container_bounds.x() && |
253 if (launcher_) | 262 bounds.right() > container_bounds.x()) { |
254 shelf_alignment = launcher_->alignment(); | |
255 | |
256 if (bounds.x() == docked_bounds.x() && | |
257 shelf_alignment != SHELF_ALIGNMENT_LEFT) { | |
258 return DOCKED_ALIGNMENT_LEFT; | 263 return DOCKED_ALIGNMENT_LEFT; |
259 } | 264 } else if (bounds.x() < container_bounds.right() && |
260 if (bounds.right() == docked_bounds.right() && | 265 bounds.right() >= container_bounds.right()) { |
261 shelf_alignment != SHELF_ALIGNMENT_RIGHT) { | |
262 return DOCKED_ALIGNMENT_RIGHT; | 266 return DOCKED_ALIGNMENT_RIGHT; |
263 } | 267 } |
264 return DOCKED_ALIGNMENT_NONE; | 268 return DOCKED_ALIGNMENT_NONE; |
265 } | 269 } |
266 | 270 |
267 DockedAlignment DockedWindowLayoutManager::CalculateAlignment() const { | 271 DockedAlignment DockedWindowLayoutManager::CalculateAlignment() const { |
268 // Find a child that is not being dragged and is not a popup. | 272 // Find a child that is not being dragged and is not a popup. |
269 // If such exists the current alignment is returned - even if some of the | 273 // If such exists the current alignment is returned - even if some of the |
270 // children are hidden or minimized (so they can be restored without losing | 274 // children are hidden or minimized (so they can be restored without losing |
271 // the docked state). | 275 // the docked state). |
272 for (size_t i = 0; i < dock_container_->children().size(); ++i) { | 276 for (size_t i = 0; i < dock_container_->children().size(); ++i) { |
273 aura::Window* window(dock_container_->children()[i]); | 277 aura::Window* window(dock_container_->children()[i]); |
274 if (window != dragged_window_ && | 278 if (window != dragged_window_ && |
275 window->type() != aura::client::WINDOW_TYPE_POPUP) { | 279 window->type() != aura::client::WINDOW_TYPE_POPUP) { |
276 return alignment_; | 280 return alignment_; |
277 } | 281 } |
278 } | 282 } |
279 // No docked windows remain other than possibly the window being dragged. | 283 // No docked windows remain other than possibly the window being dragged. |
280 // Return |NONE| to indicate that windows may get docked on either side. | 284 // Return |NONE| to indicate that windows may get docked on either side. |
281 return DOCKED_ALIGNMENT_NONE; | 285 return DOCKED_ALIGNMENT_NONE; |
282 } | 286 } |
283 | 287 |
| 288 bool DockedWindowLayoutManager::CanDockWindow(aura::Window* window, |
| 289 SnapType edge) { |
| 290 if (!CommandLine::ForCurrentProcess()->HasSwitch( |
| 291 switches::kAshEnableDockedWindows)) { |
| 292 return false; |
| 293 } |
| 294 // Cannot dock on the other size from an existing dock. |
| 295 const DockedAlignment alignment = CalculateAlignment(); |
| 296 if ((edge == SNAP_LEFT && alignment == DOCKED_ALIGNMENT_RIGHT) || |
| 297 (edge == SNAP_RIGHT && alignment == DOCKED_ALIGNMENT_LEFT)) { |
| 298 return false; |
| 299 } |
| 300 |
| 301 // Do not allow docking on the same side as launcher shelf. |
| 302 ShelfAlignment shelf_alignment = SHELF_ALIGNMENT_BOTTOM; |
| 303 if (launcher_) |
| 304 shelf_alignment = launcher_->alignment(); |
| 305 if ((edge == SNAP_LEFT && shelf_alignment == SHELF_ALIGNMENT_LEFT) || |
| 306 (edge == SNAP_RIGHT && shelf_alignment == SHELF_ALIGNMENT_RIGHT)) { |
| 307 return false; |
| 308 } |
| 309 return true; |
| 310 } |
| 311 |
284 //////////////////////////////////////////////////////////////////////////////// | 312 //////////////////////////////////////////////////////////////////////////////// |
285 // DockLayoutManager, aura::LayoutManager implementation: | 313 // DockLayoutManager, aura::LayoutManager implementation: |
286 void DockedWindowLayoutManager::OnWindowResized() { | 314 void DockedWindowLayoutManager::OnWindowResized() { |
287 Relayout(); | 315 Relayout(); |
288 // When screen resizes update the insets even when dock width or alignment | 316 // When screen resizes update the insets even when dock width or alignment |
289 // does not change. | 317 // does not change. |
290 UpdateDockBounds(); | 318 UpdateDockBounds(); |
291 } | 319 } |
292 | 320 |
293 void DockedWindowLayoutManager::OnWindowAddedToLayout(aura::Window* child) { | 321 void DockedWindowLayoutManager::OnWindowAddedToLayout(aura::Window* child) { |
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
557 std::sort(visible_windows.begin(), | 585 std::sort(visible_windows.begin(), |
558 visible_windows.end(), | 586 visible_windows.end(), |
559 CompareWindowPos(is_dragged_from_dock_ ? dragged_window_ : NULL, | 587 CompareWindowPos(is_dragged_from_dock_ ? dragged_window_ : NULL, |
560 delta)); | 588 delta)); |
561 is_dragged_from_dock_ = true; | 589 is_dragged_from_dock_ = true; |
562 for (aura::Window::Windows::const_iterator iter = visible_windows.begin(); | 590 for (aura::Window::Windows::const_iterator iter = visible_windows.begin(); |
563 iter != visible_windows.end(); ++iter) { | 591 iter != visible_windows.end(); ++iter) { |
564 aura::Window* window = *iter; | 592 aura::Window* window = *iter; |
565 gfx::Rect bounds = window->GetBoundsInScreen(); | 593 gfx::Rect bounds = window->GetBoundsInScreen(); |
566 | 594 |
| 595 DockedAlignment alignment = alignment_; |
| 596 if (alignment == DOCKED_ALIGNMENT_NONE && window == dragged_window_) { |
| 597 alignment = GetAlignmentOfWindow(window); |
| 598 if (alignment == DOCKED_ALIGNMENT_NONE) |
| 599 bounds.set_size(gfx::Size()); |
| 600 } |
| 601 |
| 602 // Restrict width. |
| 603 if (bounds.width() > kMaxDockWidth) |
| 604 bounds.set_width(kMaxDockWidth); |
| 605 |
567 // Fan out windows evenly distributing the overlap or remaining free space. | 606 // Fan out windows evenly distributing the overlap or remaining free space. |
568 bounds.set_y(std::max(work_area.y(), | 607 bounds.set_y(std::max(work_area.y(), |
569 std::min(work_area.bottom() - bounds.height(), | 608 std::min(work_area.bottom() - bounds.height(), |
570 static_cast<int>(y_pos + 0.5)))); | 609 static_cast<int>(y_pos + 0.5)))); |
571 y_pos += bounds.height() + delta; | 610 y_pos += bounds.height() + delta; |
572 | 611 |
573 // All docked windows other than the one currently dragged remain stuck | 612 // All docked windows other than the one currently dragged remain stuck |
574 // to the screen edge. | 613 // to the screen edge. |
575 switch (alignment_) { | 614 switch (alignment) { |
576 case DOCKED_ALIGNMENT_LEFT: | 615 case DOCKED_ALIGNMENT_LEFT: |
577 bounds.set_x(dock_bounds.x()); | 616 bounds.set_x(dock_bounds.x()); |
578 break; | 617 break; |
579 case DOCKED_ALIGNMENT_RIGHT: | 618 case DOCKED_ALIGNMENT_RIGHT: |
580 bounds.set_x(dock_bounds.right() - bounds.width()); | 619 bounds.set_x(dock_bounds.right() - bounds.width()); |
581 break; | 620 break; |
582 case DOCKED_ALIGNMENT_NONE: | 621 case DOCKED_ALIGNMENT_NONE: |
583 break; | 622 break; |
584 } | 623 } |
585 if (window == dragged_window_) { | 624 if (window == dragged_window_) { |
586 dragged_bounds_ = bounds; | 625 dragged_bounds_ = bounds; |
587 continue; | 626 continue; |
588 } | 627 } |
| 628 // If the following asserts it is probably because not all the children |
| 629 // have been removed when dock was closed. |
589 DCHECK_NE(alignment_, DOCKED_ALIGNMENT_NONE); | 630 DCHECK_NE(alignment_, DOCKED_ALIGNMENT_NONE); |
590 // Keep the dock at least kMinDockWidth when all windows in it overhang. | 631 // Keep the dock at least kMinDockWidth when all windows in it overhang. |
591 docked_width_ = std::min(kMaxDockWidth, | 632 docked_width_ = std::min(kMaxDockWidth, |
592 std::max(docked_width_, | 633 std::max(docked_width_, |
593 bounds.width() > kMaxDockWidth ? | 634 bounds.width() > kMaxDockWidth ? |
594 kMinDockWidth : bounds.width())); | 635 kMinDockWidth : bounds.width())); |
595 bounds = ScreenAsh::ConvertRectFromScreen(dock_container_, bounds); | 636 bounds = ScreenAsh::ConvertRectFromScreen(dock_container_, bounds); |
596 SetChildBoundsDirect(window, bounds); | 637 SetChildBoundsDirect(window, bounds); |
597 } | 638 } |
598 UpdateStacking(active_window); | 639 UpdateStacking(active_window); |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
686 | 727 |
687 void DockedWindowLayoutManager::OnKeyboardBoundsChanging( | 728 void DockedWindowLayoutManager::OnKeyboardBoundsChanging( |
688 const gfx::Rect& keyboard_bounds) { | 729 const gfx::Rect& keyboard_bounds) { |
689 // This bounds change will have caused a change to the Shelf which does not | 730 // This bounds change will have caused a change to the Shelf which does not |
690 // propagate automatically to this class, so manually recalculate bounds. | 731 // propagate automatically to this class, so manually recalculate bounds. |
691 UpdateDockBounds(); | 732 UpdateDockBounds(); |
692 } | 733 } |
693 | 734 |
694 } // namespace internal | 735 } // namespace internal |
695 } // namespace ash | 736 } // namespace ash |
OLD | NEW |